1 use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter};
2 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
3 use rustc_errors::pluralize;
5 use rustc_hir::def::{CtorOf, DefKind};
6 use rustc_hir::def_id::DefId;
7 use rustc_span::symbol::Symbol;
8 use rustc_target::spec::abi;
10 use std::collections::hash_map::DefaultHasher;
13 use std::hash::Hasher;
14 use std::path::PathBuf;
16 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
17 pub struct ExpectedFound<T> {
22 impl<T> ExpectedFound<T> {
23 pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
25 ExpectedFound { expected: a, found: b }
27 ExpectedFound { expected: b, found: a }
32 // Data structures used in type unification
33 #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
34 #[rustc_pass_by_value]
35 pub enum TypeError<'tcx> {
37 ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
38 PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
39 UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
40 AbiMismatch(ExpectedFound<abi::Abi>),
42 ArgumentMutability(usize),
43 TupleSize(ExpectedFound<usize>),
44 FixedArraySize(ExpectedFound<u64>),
46 FieldMisMatch(Symbol, Symbol),
48 RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
49 RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
50 RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>),
51 RegionsPlaceholderMismatch,
53 Sorts(ExpectedFound<Ty<'tcx>>),
54 ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize),
55 IntMismatch(ExpectedFound<ty::IntVarValue>),
56 FloatMismatch(ExpectedFound<ty::FloatTy>),
57 Traits(ExpectedFound<DefId>),
58 VariadicMismatch(ExpectedFound<bool>),
60 /// Instantiating a type variable with the given type would have
61 /// created a cycle (because it appears somewhere within that
64 CyclicConst(ty::Const<'tcx>),
65 ProjectionMismatched(ExpectedFound<DefId>),
66 ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>),
67 ConstMismatch(ExpectedFound<ty::Const<'tcx>>),
70 /// Safe `#[target_feature]` functions are not assignable to safe function pointers.
71 TargetFeatureCast(DefId),
75 pub fn involves_regions(self) -> bool {
77 TypeError::RegionsDoesNotOutlive(_, _)
78 | TypeError::RegionsInsufficientlyPolymorphic(_, _)
79 | TypeError::RegionsOverlyPolymorphic(_, _)
80 | TypeError::RegionsPlaceholderMismatch => true,
86 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
87 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
88 /// afterwards to present additional details, particularly when it comes to lifetime-related
90 impl<'tcx> fmt::Display for TypeError<'tcx> {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 use self::TypeError::*;
93 fn report_maybe_different(
94 f: &mut fmt::Formatter<'_>,
98 // A naive approach to making sure that we're not reporting silly errors such as:
99 // (expected closure, found closure).
100 if expected == found {
101 write!(f, "expected {}, found a different {}", expected, found)
103 write!(f, "expected {}, found {}", expected, found)
107 let br_string = |br: ty::BoundRegionKind| match br {
108 ty::BrNamed(_, name) => format!(" {}", name),
113 CyclicTy(_) => write!(f, "cyclic type of infinite size"),
114 CyclicConst(_) => write!(f, "encountered a self-referencing constant"),
115 Mismatch => write!(f, "types differ"),
116 ConstnessMismatch(values) => {
117 write!(f, "expected {} bound, found {} bound", values.expected, values.found)
119 PolarityMismatch(values) => {
120 write!(f, "expected {} polarity, found {} polarity", values.expected, values.found)
122 UnsafetyMismatch(values) => {
123 write!(f, "expected {} fn, found {} fn", values.expected, values.found)
125 AbiMismatch(values) => {
126 write!(f, "expected {} fn, found {} fn", values.expected, values.found)
128 ArgumentMutability(_) | Mutability => write!(f, "types differ in mutability"),
129 TupleSize(values) => write!(
131 "expected a tuple with {} element{}, found one with {} element{}",
133 pluralize!(values.expected),
135 pluralize!(values.found)
137 FixedArraySize(values) => write!(
139 "expected an array with a fixed size of {} element{}, found one with {} element{}",
141 pluralize!(values.expected),
143 pluralize!(values.found)
145 ArgCount => write!(f, "incorrect number of function parameters"),
146 FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
147 RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
148 // Actually naming the region here is a bit confusing because context is lacking
149 RegionsInsufficientlyPolymorphic(..) => {
150 write!(f, "one type is more general than the other")
152 RegionsOverlyPolymorphic(br, _) => write!(
154 "expected concrete lifetime, found bound lifetime parameter{}",
157 RegionsPlaceholderMismatch => write!(f, "one type is more general than the other"),
158 ArgumentSorts(values, _) | Sorts(values) => ty::tls::with(|tcx| {
159 let (mut expected, mut found) = with_forced_trimmed_paths!((
160 values.expected.sort_string(tcx),
161 values.found.sort_string(tcx),
163 if expected == found {
164 expected = values.expected.sort_string(tcx);
165 found = values.found.sort_string(tcx);
167 report_maybe_different(f, &expected, &found)
169 Traits(values) => ty::tls::with(|tcx| {
170 let (mut expected, mut found) = with_forced_trimmed_paths!((
171 tcx.def_path_str(values.expected),
172 tcx.def_path_str(values.found),
174 if expected == found {
175 expected = tcx.def_path_str(values.expected);
176 found = tcx.def_path_str(values.found);
178 report_maybe_different(
180 &format!("trait `{expected}`"),
181 &format!("trait `{found}`"),
184 IntMismatch(ref values) => {
185 let expected = match values.expected {
186 ty::IntVarValue::IntType(ty) => ty.name_str(),
187 ty::IntVarValue::UintType(ty) => ty.name_str(),
189 let found = match values.found {
190 ty::IntVarValue::IntType(ty) => ty.name_str(),
191 ty::IntVarValue::UintType(ty) => ty.name_str(),
193 write!(f, "expected `{}`, found `{}`", expected, found)
195 FloatMismatch(ref values) => {
198 "expected `{}`, found `{}`",
199 values.expected.name_str(),
200 values.found.name_str()
203 VariadicMismatch(ref values) => write!(
205 "expected {} fn, found {} function",
206 if values.expected { "variadic" } else { "non-variadic" },
207 if values.found { "variadic" } else { "non-variadic" }
209 ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
212 "expected {}, found {}",
213 tcx.def_path_str(values.expected),
214 tcx.def_path_str(values.found)
217 ExistentialMismatch(ref values) => report_maybe_different(
219 &format!("trait `{}`", values.expected),
220 &format!("trait `{}`", values.found),
222 ConstMismatch(ref values) => {
223 write!(f, "expected `{}`, found `{}`", values.expected, values.found)
225 IntrinsicCast => write!(f, "cannot coerce intrinsics to function pointers"),
226 TargetFeatureCast(_) => write!(
228 "cannot coerce functions with `#[target_feature]` to safe function pointers"
234 impl<'tcx> TypeError<'tcx> {
235 pub fn must_include_note(self) -> bool {
236 use self::TypeError::*;
238 CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
239 | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
240 | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
241 | VariadicMismatch(_) | TargetFeatureCast(_) => false,
244 | ArgumentMutability(_)
248 | RegionsDoesNotOutlive(..)
249 | RegionsInsufficientlyPolymorphic(..)
250 | RegionsOverlyPolymorphic(..)
251 | RegionsPlaceholderMismatch
253 | ProjectionMismatched(_)
254 | ExistentialMismatch(_)
256 | IntrinsicCast => true,
261 impl<'tcx> Ty<'tcx> {
262 pub fn sort_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
264 ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
265 format!("`{}`", self).into()
267 ty::Tuple(ref tys) if tys.is_empty() => format!("`{}`", self).into(),
269 ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did())).into(),
270 ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
272 if t.is_simple_ty() {
273 return format!("array `{}`", self).into();
276 let n = tcx.lift(n).unwrap();
277 if let ty::ConstKind::Value(v) = n.kind() {
278 if let Some(n) = v.try_to_machine_usize(tcx) {
279 return format!("array of {} element{}", n, pluralize!(n)).into();
284 ty::Slice(ty) if ty.is_simple_ty() => format!("slice `{}`", self).into(),
285 ty::Slice(_) => "slice".into(),
286 ty::RawPtr(tymut) => {
287 let tymut_string = match tymut.mutbl {
288 hir::Mutability::Mut => tymut.to_string(),
289 hir::Mutability::Not => format!("const {}", tymut.ty),
292 if tymut_string != "_" && (tymut.ty.is_simple_text() || tymut_string.len() < "const raw pointer".len()) {
293 format!("`*{}`", tymut_string).into()
295 // Unknown type name, it's long or has type arguments
299 ty::Ref(_, ty, mutbl) => {
300 let tymut = ty::TypeAndMut { ty, mutbl };
301 let tymut_string = tymut.to_string();
303 if tymut_string != "_"
304 && (ty.is_simple_text() || tymut_string.len() < "mutable reference".len())
306 format!("`&{}`", tymut_string).into()
308 // Unknown type name, it's long or has type arguments
310 hir::Mutability::Mut => "mutable reference",
316 ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
317 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
318 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
319 _ => "fn item".into(),
321 ty::FnPtr(_) => "fn pointer".into(),
322 ty::Dynamic(ref inner, ..) if let Some(principal) = inner.principal() => {
323 format!("trait object `dyn {}`", tcx.def_path_str(principal.def_id())).into()
325 ty::Dynamic(..) => "trait object".into(),
326 ty::Closure(..) => "closure".into(),
327 ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
328 ty::GeneratorWitness(..) |
329 ty::GeneratorWitnessMIR(..) => "generator witness".into(),
330 ty::Tuple(..) => "tuple".into(),
331 ty::Infer(ty::TyVar(_)) => "inferred type".into(),
332 ty::Infer(ty::IntVar(_)) => "integer".into(),
333 ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
334 ty::Placeholder(..) => "placeholder type".into(),
335 ty::Bound(..) => "bound type".into(),
336 ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
337 ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
338 ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
339 ty::Alias(ty::Projection, _) => "associated type".into(),
340 ty::Param(p) => format!("type parameter `{}`", p).into(),
341 ty::Alias(ty::Opaque, ..) => "opaque type".into(),
342 ty::Error(_) => "type error".into(),
346 pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
356 | ty::Never => "type".into(),
357 ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(),
358 ty::Adt(def, _) => def.descr().into(),
359 ty::Foreign(_) => "extern type".into(),
360 ty::Array(..) => "array".into(),
361 ty::Slice(_) => "slice".into(),
362 ty::RawPtr(_) => "raw pointer".into(),
363 ty::Ref(.., mutbl) => match mutbl {
364 hir::Mutability::Mut => "mutable reference",
368 ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
369 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
370 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
371 _ => "fn item".into(),
373 ty::FnPtr(_) => "fn pointer".into(),
374 ty::Dynamic(..) => "trait object".into(),
375 ty::Closure(..) => "closure".into(),
376 ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
377 ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(),
378 ty::Tuple(..) => "tuple".into(),
379 ty::Placeholder(..) => "higher-ranked type".into(),
380 ty::Bound(..) => "bound type variable".into(),
381 ty::Alias(ty::Projection, _) => "associated type".into(),
382 ty::Param(_) => "type parameter".into(),
383 ty::Alias(ty::Opaque, ..) => "opaque type".into(),
388 impl<'tcx> TyCtxt<'tcx> {
389 pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
390 let width = self.sess.diagnostic_width();
391 let length_limit = width.saturating_sub(30);
392 let mut type_limit = 50;
393 let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
394 .pretty_print_type(ty)
395 .expect("could not write to `String`")
397 if regular.len() <= width {
398 return (regular, None);
402 // Look for the longest properly trimmed path that still fits in length_limit.
403 short = with_forced_trimmed_paths!(
404 FmtPrinter::new_with_limit(
406 hir::def::Namespace::TypeNS,
407 rustc_session::Limit(type_limit),
409 .pretty_print_type(ty)
410 .expect("could not write to `String`")
413 if short.len() <= length_limit || type_limit == 0 {
418 if regular == short {
419 return (regular, None);
421 // Multiple types might be shortened in a single error, ensure we create a file for each.
422 let mut s = DefaultHasher::new();
424 let hash = s.finish();
425 let path = self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None);
426 match std::fs::write(&path, ®ular) {
427 Ok(_) => (short, Some(path)),
428 Err(_) => (regular, None),