]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/error.rs
Rollup merge of #106978 - mejrs:mir_build3, r=davidtwco
[rust.git] / compiler / rustc_middle / src / ty / error.rs
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::fmt;
12 use std::hash::Hash;
13 use std::hash::Hasher;
14 use std::path::PathBuf;
15
16 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
17 pub struct ExpectedFound<T> {
18     pub expected: T,
19     pub found: T,
20 }
21
22 impl<T> ExpectedFound<T> {
23     pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
24         if a_is_expected {
25             ExpectedFound { expected: a, found: b }
26         } else {
27             ExpectedFound { expected: b, found: a }
28         }
29     }
30 }
31
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> {
36     Mismatch,
37     ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
38     PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
39     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
40     AbiMismatch(ExpectedFound<abi::Abi>),
41     Mutability,
42     ArgumentMutability(usize),
43     TupleSize(ExpectedFound<usize>),
44     FixedArraySize(ExpectedFound<u64>),
45     ArgCount,
46     FieldMisMatch(Symbol, Symbol),
47
48     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
49     RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
50     RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>),
51     RegionsPlaceholderMismatch,
52
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>),
59
60     /// Instantiating a type variable with the given type would have
61     /// created a cycle (because it appears somewhere within that
62     /// type).
63     CyclicTy(Ty<'tcx>),
64     CyclicConst(ty::Const<'tcx>),
65     ProjectionMismatched(ExpectedFound<DefId>),
66     ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>),
67     ConstMismatch(ExpectedFound<ty::Const<'tcx>>),
68
69     IntrinsicCast,
70     /// Safe `#[target_feature]` functions are not assignable to safe function pointers.
71     TargetFeatureCast(DefId),
72 }
73
74 impl TypeError<'_> {
75     pub fn involves_regions(self) -> bool {
76         match self {
77             TypeError::RegionsDoesNotOutlive(_, _)
78             | TypeError::RegionsInsufficientlyPolymorphic(_, _)
79             | TypeError::RegionsOverlyPolymorphic(_, _)
80             | TypeError::RegionsPlaceholderMismatch => true,
81             _ => false,
82         }
83     }
84 }
85
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
89 /// errors.
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<'_>,
95             expected: &str,
96             found: &str,
97         ) -> fmt::Result {
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)
102             } else {
103                 write!(f, "expected {}, found {}", expected, found)
104             }
105         }
106
107         let br_string = |br: ty::BoundRegionKind| match br {
108             ty::BrNamed(_, name) => format!(" {}", name),
109             _ => String::new(),
110         };
111
112         match *self {
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)
118             }
119             PolarityMismatch(values) => {
120                 write!(f, "expected {} polarity, found {} polarity", values.expected, values.found)
121             }
122             UnsafetyMismatch(values) => {
123                 write!(f, "expected {} fn, found {} fn", values.expected, values.found)
124             }
125             AbiMismatch(values) => {
126                 write!(f, "expected {} fn, found {} fn", values.expected, values.found)
127             }
128             ArgumentMutability(_) | Mutability => write!(f, "types differ in mutability"),
129             TupleSize(values) => write!(
130                 f,
131                 "expected a tuple with {} element{}, found one with {} element{}",
132                 values.expected,
133                 pluralize!(values.expected),
134                 values.found,
135                 pluralize!(values.found)
136             ),
137             FixedArraySize(values) => write!(
138                 f,
139                 "expected an array with a fixed size of {} element{}, found one with {} element{}",
140                 values.expected,
141                 pluralize!(values.expected),
142                 values.found,
143                 pluralize!(values.found)
144             ),
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")
151             }
152             RegionsOverlyPolymorphic(br, _) => write!(
153                 f,
154                 "expected concrete lifetime, found bound lifetime parameter{}",
155                 br_string(br)
156             ),
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),
162                 ));
163                 if expected == found {
164                     expected = values.expected.sort_string(tcx);
165                     found = values.found.sort_string(tcx);
166                 }
167                 report_maybe_different(f, &expected, &found)
168             }),
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),
173                 ));
174                 if expected == found {
175                     expected = tcx.def_path_str(values.expected);
176                     found = tcx.def_path_str(values.found);
177                 }
178                 report_maybe_different(
179                     f,
180                     &format!("trait `{expected}`"),
181                     &format!("trait `{found}`"),
182                 )
183             }),
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(),
188                 };
189                 let found = match values.found {
190                     ty::IntVarValue::IntType(ty) => ty.name_str(),
191                     ty::IntVarValue::UintType(ty) => ty.name_str(),
192                 };
193                 write!(f, "expected `{}`, found `{}`", expected, found)
194             }
195             FloatMismatch(ref values) => {
196                 write!(
197                     f,
198                     "expected `{}`, found `{}`",
199                     values.expected.name_str(),
200                     values.found.name_str()
201                 )
202             }
203             VariadicMismatch(ref values) => write!(
204                 f,
205                 "expected {} fn, found {} function",
206                 if values.expected { "variadic" } else { "non-variadic" },
207                 if values.found { "variadic" } else { "non-variadic" }
208             ),
209             ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
210                 write!(
211                     f,
212                     "expected {}, found {}",
213                     tcx.def_path_str(values.expected),
214                     tcx.def_path_str(values.found)
215                 )
216             }),
217             ExistentialMismatch(ref values) => report_maybe_different(
218                 f,
219                 &format!("trait `{}`", values.expected),
220                 &format!("trait `{}`", values.found),
221             ),
222             ConstMismatch(ref values) => {
223                 write!(f, "expected `{}`, found `{}`", values.expected, values.found)
224             }
225             IntrinsicCast => write!(f, "cannot coerce intrinsics to function pointers"),
226             TargetFeatureCast(_) => write!(
227                 f,
228                 "cannot coerce functions with `#[target_feature]` to safe function pointers"
229             ),
230         }
231     }
232 }
233
234 impl<'tcx> TypeError<'tcx> {
235     pub fn must_include_note(self) -> bool {
236         use self::TypeError::*;
237         match self {
238             CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
239             | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
240             | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
241             | VariadicMismatch(_) | TargetFeatureCast(_) => false,
242
243             Mutability
244             | ArgumentMutability(_)
245             | TupleSize(_)
246             | ArgCount
247             | FieldMisMatch(..)
248             | RegionsDoesNotOutlive(..)
249             | RegionsInsufficientlyPolymorphic(..)
250             | RegionsOverlyPolymorphic(..)
251             | RegionsPlaceholderMismatch
252             | Traits(_)
253             | ProjectionMismatched(_)
254             | ExistentialMismatch(_)
255             | ConstMismatch(_)
256             | IntrinsicCast => true,
257         }
258     }
259 }
260
261 impl<'tcx> Ty<'tcx> {
262     pub fn sort_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
263         match *self.kind() {
264             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
265                 format!("`{}`", self).into()
266             }
267             ty::Tuple(ref tys) if tys.is_empty() => format!("`{}`", self).into(),
268
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(),
271             ty::Array(t, n) => {
272                 if t.is_simple_ty() {
273                     return format!("array `{}`", self).into();
274                 }
275
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();
280                     }
281                 }
282                 "array".into()
283             }
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),
290                 };
291
292                 if tymut_string != "_" && (tymut.ty.is_simple_text() || tymut_string.len() < "const raw pointer".len()) {
293                     format!("`*{}`", tymut_string).into()
294                 } else {
295                     // Unknown type name, it's long or has type arguments
296                     "raw pointer".into()
297                 }
298             },
299             ty::Ref(_, ty, mutbl) => {
300                 let tymut = ty::TypeAndMut { ty, mutbl };
301                 let tymut_string = tymut.to_string();
302
303                 if tymut_string != "_"
304                     && (ty.is_simple_text() || tymut_string.len() < "mutable reference".len())
305                 {
306                     format!("`&{}`", tymut_string).into()
307                 } else {
308                     // Unknown type name, it's long or has type arguments
309                     match mutbl {
310                         hir::Mutability::Mut => "mutable reference",
311                         _ => "reference",
312                     }
313                     .into()
314                 }
315             }
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(),
320             },
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()
324             }
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(..) => "generator witness".into(),
329             ty::Tuple(..) => "tuple".into(),
330             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
331             ty::Infer(ty::IntVar(_)) => "integer".into(),
332             ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
333             ty::Placeholder(..) => "placeholder type".into(),
334             ty::Bound(..) => "bound type".into(),
335             ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
336             ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
337             ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
338             ty::Alias(ty::Projection, _) => "associated type".into(),
339             ty::Param(p) => format!("type parameter `{}`", p).into(),
340             ty::Alias(ty::Opaque, ..) => "opaque type".into(),
341             ty::Error(_) => "type error".into(),
342         }
343     }
344
345     pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
346         match *self.kind() {
347             ty::Infer(_)
348             | ty::Error(_)
349             | ty::Bool
350             | ty::Char
351             | ty::Int(_)
352             | ty::Uint(_)
353             | ty::Float(_)
354             | ty::Str
355             | ty::Never => "type".into(),
356             ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(),
357             ty::Adt(def, _) => def.descr().into(),
358             ty::Foreign(_) => "extern type".into(),
359             ty::Array(..) => "array".into(),
360             ty::Slice(_) => "slice".into(),
361             ty::RawPtr(_) => "raw pointer".into(),
362             ty::Ref(.., mutbl) => match mutbl {
363                 hir::Mutability::Mut => "mutable reference",
364                 _ => "reference",
365             }
366             .into(),
367             ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
368                 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
369                 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
370                 _ => "fn item".into(),
371             },
372             ty::FnPtr(_) => "fn pointer".into(),
373             ty::Dynamic(..) => "trait object".into(),
374             ty::Closure(..) => "closure".into(),
375             ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
376             ty::GeneratorWitness(..) => "generator witness".into(),
377             ty::Tuple(..) => "tuple".into(),
378             ty::Placeholder(..) => "higher-ranked type".into(),
379             ty::Bound(..) => "bound type variable".into(),
380             ty::Alias(ty::Projection, _) => "associated type".into(),
381             ty::Param(_) => "type parameter".into(),
382             ty::Alias(ty::Opaque, ..) => "opaque type".into(),
383         }
384     }
385 }
386
387 impl<'tcx> TyCtxt<'tcx> {
388     pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
389         let width = self.sess.diagnostic_width();
390         let length_limit = width.saturating_sub(30);
391         let mut type_limit = 50;
392         let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
393             .pretty_print_type(ty)
394             .expect("could not write to `String`")
395             .into_buffer();
396         if regular.len() <= width {
397             return (regular, None);
398         }
399         let mut short;
400         loop {
401             // Look for the longest properly trimmed path that still fits in length_limit.
402             short = with_forced_trimmed_paths!(
403                 FmtPrinter::new_with_limit(
404                     self,
405                     hir::def::Namespace::TypeNS,
406                     rustc_session::Limit(type_limit),
407                 )
408                 .pretty_print_type(ty)
409                 .expect("could not write to `String`")
410                 .into_buffer()
411             );
412             if short.len() <= length_limit || type_limit == 0 {
413                 break;
414             }
415             type_limit -= 1;
416         }
417         if regular == short {
418             return (regular, None);
419         }
420         // Multiple types might be shortened in a single error, ensure we create a file for each.
421         let mut s = DefaultHasher::new();
422         ty.hash(&mut s);
423         let hash = s.finish();
424         let path = self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None);
425         match std::fs::write(&path, &regular) {
426             Ok(_) => (short, Some(path)),
427             Err(_) => (regular, None),
428         }
429     }
430 }