• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
4 use rustc_hir as hir;
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;
9 use std::borrow::Cow;
10 use std::collections::hash_map::DefaultHasher;
11 use std::hash::{Hash, Hasher};
12 use std::path::PathBuf;
13 
14 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
15 pub struct ExpectedFound<T> {
16     pub expected: T,
17     pub found: T,
18 }
19 
20 impl<T> ExpectedFound<T> {
new(a_is_expected: bool, a: T, b: T) -> Self21     pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
22         if a_is_expected {
23             ExpectedFound { expected: a, found: b }
24         } else {
25             ExpectedFound { expected: b, found: a }
26         }
27     }
28 }
29 
30 // Data structures used in type unification
31 #[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)]
32 #[rustc_pass_by_value]
33 pub enum TypeError<'tcx> {
34     Mismatch,
35     ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
36     PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
37     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
38     AbiMismatch(ExpectedFound<abi::Abi>),
39     Mutability,
40     ArgumentMutability(usize),
41     TupleSize(ExpectedFound<usize>),
42     FixedArraySize(ExpectedFound<u64>),
43     ArgCount,
44     FieldMisMatch(Symbol, Symbol),
45 
46     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
47     RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
48     RegionsPlaceholderMismatch,
49 
50     Sorts(ExpectedFound<Ty<'tcx>>),
51     ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize),
52     IntMismatch(ExpectedFound<ty::IntVarValue>),
53     FloatMismatch(ExpectedFound<ty::FloatTy>),
54     Traits(ExpectedFound<DefId>),
55     VariadicMismatch(ExpectedFound<bool>),
56 
57     /// Instantiating a type variable with the given type would have
58     /// created a cycle (because it appears somewhere within that
59     /// type).
60     CyclicTy(Ty<'tcx>),
61     CyclicConst(ty::Const<'tcx>),
62     ProjectionMismatched(ExpectedFound<DefId>),
63     ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>),
64     ConstMismatch(ExpectedFound<ty::Const<'tcx>>),
65 
66     IntrinsicCast,
67     /// Safe `#[target_feature]` functions are not assignable to safe function pointers.
68     TargetFeatureCast(DefId),
69 }
70 
71 impl TypeError<'_> {
involves_regions(self) -> bool72     pub fn involves_regions(self) -> bool {
73         match self {
74             TypeError::RegionsDoesNotOutlive(_, _)
75             | TypeError::RegionsInsufficientlyPolymorphic(_, _)
76             | TypeError::RegionsPlaceholderMismatch => true,
77             _ => false,
78         }
79     }
80 }
81 
82 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
83 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
84 /// afterwards to present additional details, particularly when it comes to lifetime-related
85 /// errors.
86 impl<'tcx> TypeError<'tcx> {
to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str>87     pub fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> {
88         use self::TypeError::*;
89         fn report_maybe_different(expected: &str, found: &str) -> String {
90             // A naive approach to making sure that we're not reporting silly errors such as:
91             // (expected closure, found closure).
92             if expected == found {
93                 format!("expected {}, found a different {}", expected, found)
94             } else {
95                 format!("expected {}, found {}", expected, found)
96             }
97         }
98 
99         match self {
100             CyclicTy(_) => "cyclic type of infinite size".into(),
101             CyclicConst(_) => "encountered a self-referencing constant".into(),
102             Mismatch => "types differ".into(),
103             ConstnessMismatch(values) => {
104                 format!("expected {} bound, found {} bound", values.expected, values.found).into()
105             }
106             PolarityMismatch(values) => {
107                 format!("expected {} polarity, found {} polarity", values.expected, values.found)
108                     .into()
109             }
110             UnsafetyMismatch(values) => {
111                 format!("expected {} fn, found {} fn", values.expected, values.found).into()
112             }
113             AbiMismatch(values) => {
114                 format!("expected {} fn, found {} fn", values.expected, values.found).into()
115             }
116             ArgumentMutability(_) | Mutability => "types differ in mutability".into(),
117             TupleSize(values) => format!(
118                 "expected a tuple with {} element{}, found one with {} element{}",
119                 values.expected,
120                 pluralize!(values.expected),
121                 values.found,
122                 pluralize!(values.found)
123             )
124             .into(),
125             FixedArraySize(values) => format!(
126                 "expected an array with a fixed size of {} element{}, found one with {} element{}",
127                 values.expected,
128                 pluralize!(values.expected),
129                 values.found,
130                 pluralize!(values.found)
131             )
132             .into(),
133             ArgCount => "incorrect number of function parameters".into(),
134             FieldMisMatch(adt, field) => format!("field type mismatch: {}.{}", adt, field).into(),
135             RegionsDoesNotOutlive(..) => "lifetime mismatch".into(),
136             // Actually naming the region here is a bit confusing because context is lacking
137             RegionsInsufficientlyPolymorphic(..) => {
138                 "one type is more general than the other".into()
139             }
140             RegionsPlaceholderMismatch => "one type is more general than the other".into(),
141             ArgumentSorts(values, _) | Sorts(values) => {
142                 let expected = values.expected.sort_string(tcx);
143                 let found = values.found.sort_string(tcx);
144                 report_maybe_different(&expected, &found).into()
145             }
146             Traits(values) => {
147                 let (mut expected, mut found) = with_forced_trimmed_paths!((
148                     tcx.def_path_str(values.expected),
149                     tcx.def_path_str(values.found),
150                 ));
151                 if expected == found {
152                     expected = tcx.def_path_str(values.expected);
153                     found = tcx.def_path_str(values.found);
154                 }
155                 report_maybe_different(&format!("trait `{expected}`"), &format!("trait `{found}`"))
156                     .into()
157             }
158             IntMismatch(ref values) => {
159                 let expected = match values.expected {
160                     ty::IntVarValue::IntType(ty) => ty.name_str(),
161                     ty::IntVarValue::UintType(ty) => ty.name_str(),
162                 };
163                 let found = match values.found {
164                     ty::IntVarValue::IntType(ty) => ty.name_str(),
165                     ty::IntVarValue::UintType(ty) => ty.name_str(),
166                 };
167                 format!("expected `{}`, found `{}`", expected, found).into()
168             }
169             FloatMismatch(ref values) => format!(
170                 "expected `{}`, found `{}`",
171                 values.expected.name_str(),
172                 values.found.name_str()
173             )
174             .into(),
175             VariadicMismatch(ref values) => format!(
176                 "expected {} fn, found {} function",
177                 if values.expected { "variadic" } else { "non-variadic" },
178                 if values.found { "variadic" } else { "non-variadic" }
179             )
180             .into(),
181             ProjectionMismatched(ref values) => format!(
182                 "expected `{}`, found `{}`",
183                 tcx.def_path_str(values.expected),
184                 tcx.def_path_str(values.found)
185             )
186             .into(),
187             ExistentialMismatch(ref values) => report_maybe_different(
188                 &format!("trait `{}`", values.expected),
189                 &format!("trait `{}`", values.found),
190             )
191             .into(),
192             ConstMismatch(ref values) => {
193                 format!("expected `{}`, found `{}`", values.expected, values.found).into()
194             }
195             IntrinsicCast => "cannot coerce intrinsics to function pointers".into(),
196             TargetFeatureCast(_) => {
197                 "cannot coerce functions with `#[target_feature]` to safe function pointers".into()
198             }
199         }
200     }
201 }
202 
203 impl<'tcx> TypeError<'tcx> {
must_include_note(self) -> bool204     pub fn must_include_note(self) -> bool {
205         use self::TypeError::*;
206         match self {
207             CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
208             | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
209             | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
210             | VariadicMismatch(_) | TargetFeatureCast(_) => false,
211 
212             Mutability
213             | ArgumentMutability(_)
214             | TupleSize(_)
215             | ArgCount
216             | FieldMisMatch(..)
217             | RegionsDoesNotOutlive(..)
218             | RegionsInsufficientlyPolymorphic(..)
219             | RegionsPlaceholderMismatch
220             | Traits(_)
221             | ProjectionMismatched(_)
222             | ExistentialMismatch(_)
223             | ConstMismatch(_)
224             | IntrinsicCast => true,
225         }
226     }
227 }
228 
229 impl<'tcx> Ty<'tcx> {
sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str>230     pub fn sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> {
231         match *self.kind() {
232             ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
233             ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
234                 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
235                 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
236                 _ => "fn item".into(),
237             },
238             ty::FnPtr(_) => "fn pointer".into(),
239             ty::Dynamic(ref inner, ..) if let Some(principal) = inner.principal() => {
240                 format!("`dyn {}`", tcx.def_path_str(principal.def_id())).into()
241             }
242             ty::Dynamic(..) => "trait object".into(),
243             ty::Closure(..) => "closure".into(),
244             ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
245             ty::GeneratorWitness(..) |
246             ty::GeneratorWitnessMIR(..) => "generator witness".into(),
247             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
248             ty::Infer(ty::IntVar(_)) => "integer".into(),
249             ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
250             ty::Placeholder(..) => "placeholder type".into(),
251             ty::Bound(..) => "bound type".into(),
252             ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
253             ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
254             ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
255             ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
256             ty::Param(p) => format!("type parameter `{p}`").into(),
257             ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() },
258             ty::Error(_) => "type error".into(),
259             _ => {
260                 let width = tcx.sess.diagnostic_width();
261                 let length_limit = std::cmp::max(width / 4, 15);
262                 format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into()
263             }
264         }
265     }
266 
prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str>267     pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
268         match *self.kind() {
269             ty::Infer(_)
270             | ty::Error(_)
271             | ty::Bool
272             | ty::Char
273             | ty::Int(_)
274             | ty::Uint(_)
275             | ty::Float(_)
276             | ty::Str
277             | ty::Never => "type".into(),
278             ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(),
279             ty::Adt(def, _) => def.descr().into(),
280             ty::Foreign(_) => "extern type".into(),
281             ty::Array(..) => "array".into(),
282             ty::Slice(_) => "slice".into(),
283             ty::RawPtr(_) => "raw pointer".into(),
284             ty::Ref(.., mutbl) => match mutbl {
285                 hir::Mutability::Mut => "mutable reference",
286                 _ => "reference",
287             }
288             .into(),
289             ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
290                 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
291                 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
292                 _ => "fn item".into(),
293             },
294             ty::FnPtr(_) => "fn pointer".into(),
295             ty::Dynamic(..) => "trait object".into(),
296             ty::Closure(..) => "closure".into(),
297             ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
298             ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(),
299             ty::Tuple(..) => "tuple".into(),
300             ty::Placeholder(..) => "higher-ranked type".into(),
301             ty::Bound(..) => "bound type variable".into(),
302             ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
303             ty::Alias(ty::Weak, _) => "type alias".into(),
304             ty::Param(_) => "type parameter".into(),
305             ty::Alias(ty::Opaque, ..) => "opaque type".into(),
306         }
307     }
308 }
309 
310 impl<'tcx> TyCtxt<'tcx> {
ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String311     pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String {
312         let mut type_limit = 50;
313         let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
314             .pretty_print_type(ty)
315             .expect("could not write to `String`")
316             .into_buffer();
317         if regular.len() <= length_limit {
318             return regular;
319         }
320         let mut short;
321         loop {
322             // Look for the longest properly trimmed path that still fits in length_limit.
323             short = with_forced_trimmed_paths!(
324                 FmtPrinter::new_with_limit(
325                     self,
326                     hir::def::Namespace::TypeNS,
327                     rustc_session::Limit(type_limit),
328                 )
329                 .pretty_print_type(ty)
330                 .expect("could not write to `String`")
331                 .into_buffer()
332             );
333             if short.len() <= length_limit || type_limit == 0 {
334                 break;
335             }
336             type_limit -= 1;
337         }
338         short
339     }
340 
short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>)341     pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
342         let width = self.sess.diagnostic_width();
343         let length_limit = width.saturating_sub(30);
344         let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
345             .pretty_print_type(ty)
346             .expect("could not write to `String`")
347             .into_buffer();
348         if regular.len() <= width {
349             return (regular, None);
350         }
351         let short = self.ty_string_with_limit(ty, length_limit);
352         if regular == short {
353             return (regular, None);
354         }
355         // Multiple types might be shortened in a single error, ensure we create a file for each.
356         let mut s = DefaultHasher::new();
357         ty.hash(&mut s);
358         let hash = s.finish();
359         let path = self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None);
360         match std::fs::write(&path, &regular) {
361             Ok(_) => (short, Some(path)),
362             Err(_) => (regular, None),
363         }
364     }
365 }
366