]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/error.rs
Aggregation of drive-by cosmetic changes.
[rust.git] / src / librustc / ty / error.rs
1 use crate::hir;
2 use crate::hir::def_id::DefId;
3 use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt};
4
5 use errors::{Applicability, DiagnosticBuilder};
6 use rustc_target::spec::abi;
7 use syntax::ast;
8 use syntax::errors::pluralize;
9 use syntax_pos::Span;
10
11 use std::borrow::Cow;
12 use std::fmt;
13
14 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
15 pub struct ExpectedFound<T> {
16     pub expected: T,
17     pub found: T,
18 }
19
20 // Data structures used in type unification
21 #[derive(Clone, Debug, TypeFoldable)]
22 pub enum TypeError<'tcx> {
23     Mismatch,
24     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
25     AbiMismatch(ExpectedFound<abi::Abi>),
26     Mutability,
27     TupleSize(ExpectedFound<usize>),
28     FixedArraySize(ExpectedFound<u64>),
29     ArgCount,
30
31     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
32     RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
33     RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
34     RegionsPlaceholderMismatch,
35
36     Sorts(ExpectedFound<Ty<'tcx>>),
37     IntMismatch(ExpectedFound<ty::IntVarValue>),
38     FloatMismatch(ExpectedFound<ast::FloatTy>),
39     Traits(ExpectedFound<DefId>),
40     VariadicMismatch(ExpectedFound<bool>),
41
42     /// Instantiating a type variable with the given type would have
43     /// created a cycle (because it appears somewhere within that
44     /// type).
45     CyclicTy(Ty<'tcx>),
46     ProjectionMismatched(ExpectedFound<DefId>),
47     ProjectionBoundsLength(ExpectedFound<usize>),
48     ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
49     ObjectUnsafeCoercion(DefId),
50     ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
51
52     IntrinsicCast,
53 }
54
55 pub enum UnconstrainedNumeric {
56     UnconstrainedFloat,
57     UnconstrainedInt,
58     Neither,
59 }
60
61 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
62 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
63 /// afterwards to present additional details, particularly when it comes to lifetime-related
64 /// errors.
65 impl<'tcx> fmt::Display for TypeError<'tcx> {
66     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67         use self::TypeError::*;
68         fn report_maybe_different(f: &mut fmt::Formatter<'_>,
69                                   expected: &str, found: &str) -> fmt::Result {
70             // A naive approach to making sure that we're not reporting silly errors such as:
71             // (expected closure, found closure).
72             if expected == found {
73                 write!(f, "expected {}, found a different {}", expected, found)
74             } else {
75                 write!(f, "expected {}, found {}", expected, found)
76             }
77         }
78
79         let br_string = |br: ty::BoundRegion| {
80             match br {
81                 ty::BrNamed(_, name) => format!(" {}", name),
82                 _ => String::new(),
83             }
84         };
85
86         match *self {
87             CyclicTy(_) => write!(f, "cyclic type of infinite size"),
88             Mismatch => write!(f, "types differ"),
89             UnsafetyMismatch(values) => {
90                 write!(f, "expected {} fn, found {} fn",
91                        values.expected,
92                        values.found)
93             }
94             AbiMismatch(values) => {
95                 write!(f, "expected {} fn, found {} fn",
96                        values.expected,
97                        values.found)
98             }
99             Mutability => write!(f, "types differ in mutability"),
100             TupleSize(values) => {
101                 write!(f, "expected a tuple with {} element{}, \
102                            found one with {} element{}",
103                        values.expected,
104                        pluralize!(values.expected),
105                        values.found,
106                        pluralize!(values.found))
107             }
108             FixedArraySize(values) => {
109                 write!(f, "expected an array with a fixed size of {} element{}, \
110                            found one with {} element{}",
111                        values.expected,
112                        pluralize!(values.expected),
113                        values.found,
114                        pluralize!(values.found))
115             }
116             ArgCount => {
117                 write!(f, "incorrect number of function parameters")
118             }
119             RegionsDoesNotOutlive(..) => {
120                 write!(f, "lifetime mismatch")
121             }
122             RegionsInsufficientlyPolymorphic(br, _) => {
123                 write!(f,
124                        "expected bound lifetime parameter{}, found concrete lifetime",
125                        br_string(br))
126             }
127             RegionsOverlyPolymorphic(br, _) => {
128                 write!(f,
129                        "expected concrete lifetime, found bound lifetime parameter{}",
130                        br_string(br))
131             }
132             RegionsPlaceholderMismatch => {
133                 write!(f, "one type is more general than the other")
134             }
135             Sorts(values) => ty::tls::with(|tcx| {
136                 report_maybe_different(f, &values.expected.sort_string(tcx),
137                                        &values.found.sort_string(tcx))
138             }),
139             Traits(values) => ty::tls::with(|tcx| {
140                 report_maybe_different(f,
141                                        &format!("trait `{}`",
142                                                 tcx.def_path_str(values.expected)),
143                                        &format!("trait `{}`",
144                                                 tcx.def_path_str(values.found)))
145             }),
146             IntMismatch(ref values) => {
147                 write!(f, "expected `{:?}`, found `{:?}`",
148                        values.expected,
149                        values.found)
150             }
151             FloatMismatch(ref values) => {
152                 write!(f, "expected `{:?}`, found `{:?}`",
153                        values.expected,
154                        values.found)
155             }
156             VariadicMismatch(ref values) => {
157                 write!(f, "expected {} fn, found {} function",
158                        if values.expected { "variadic" } else { "non-variadic" },
159                        if values.found { "variadic" } else { "non-variadic" })
160             }
161             ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
162                 write!(f, "expected {}, found {}",
163                        tcx.def_path_str(values.expected),
164                        tcx.def_path_str(values.found))
165             }),
166             ProjectionBoundsLength(ref values) => {
167                 write!(f, "expected {} associated type binding{}, found {}",
168                        values.expected,
169                        pluralize!(values.expected),
170                        values.found)
171             },
172             ExistentialMismatch(ref values) => {
173                 report_maybe_different(f, &format!("trait `{}`", values.expected),
174                                        &format!("trait `{}`", values.found))
175             }
176             ConstMismatch(ref values) => {
177                 write!(f, "expected `{}`, found `{}`", values.expected, values.found)
178             }
179             IntrinsicCast => {
180                 write!(f, "cannot coerce intrinsics to function pointers")
181             }
182             ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"),
183         }
184     }
185 }
186
187 impl<'tcx> ty::TyS<'tcx> {
188     pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
189         match self.kind {
190             ty::Bool | ty::Char | ty::Int(_) |
191             ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => self.to_string().into(),
192             ty::Tuple(ref tys) if tys.is_empty() => self.to_string().into(),
193
194             ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
195             ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
196             ty::Array(_, n) => {
197                 let n = tcx.lift(&n).unwrap();
198                 match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
199                     Some(n) => {
200                         format!("array of {} element{}", n, pluralize!(n)).into()
201                     }
202                     None => "array".into(),
203                 }
204             }
205             ty::Slice(_) => "slice".into(),
206             ty::RawPtr(_) => "*-ptr".into(),
207             ty::Ref(region, ty, mutbl) => {
208                 let tymut = ty::TypeAndMut { ty, mutbl };
209                 let tymut_string = tymut.to_string();
210                 if tymut_string == "_" ||         //unknown type name,
211                    tymut_string.len() > 10 ||     //name longer than saying "reference",
212                    region.to_string() != "'_"     //... or a complex type
213                 {
214                     format!("{}reference", match mutbl {
215                         hir::Mutability::Mutable => "mutable ",
216                         _ => ""
217                     }).into()
218                 } else {
219                     format!("&{}", tymut_string).into()
220                 }
221             }
222             ty::FnDef(..) => "fn item".into(),
223             ty::FnPtr(_) => "fn pointer".into(),
224             ty::Dynamic(ref inner, ..) => {
225                 if let Some(principal) = inner.principal() {
226                     format!("trait {}", tcx.def_path_str(principal.def_id())).into()
227                 } else {
228                     "trait".into()
229                 }
230             }
231             ty::Closure(..) => "closure".into(),
232             ty::Generator(..) => "generator".into(),
233             ty::GeneratorWitness(..) => "generator witness".into(),
234             ty::Tuple(..) => "tuple".into(),
235             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
236             ty::Infer(ty::IntVar(_)) => "integer".into(),
237             ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
238             ty::Placeholder(..) => "placeholder type".into(),
239             ty::Bound(..) => "bound type".into(),
240             ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
241             ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
242             ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
243             ty::Projection(_) => "associated type".into(),
244             ty::UnnormalizedProjection(_) => "non-normalized associated type".into(),
245             ty::Param(p) => format!("type parameter `{}`", p).into(),
246             ty::Opaque(..) => "opaque type".into(),
247             ty::Error => "type error".into(),
248         }
249     }
250 }
251
252 impl<'tcx> TyCtxt<'tcx> {
253     pub fn note_and_explain_type_err(
254         self,
255         db: &mut DiagnosticBuilder<'_>,
256         err: &TypeError<'tcx>,
257         sp: Span,
258         body_owner_def_id: DefId,
259     ) {
260         use self::TypeError::*;
261
262         match err {
263             Sorts(values) => {
264                 let expected_str = values.expected.sort_string(self);
265                 let found_str = values.found.sort_string(self);
266                 if expected_str == found_str && expected_str == "closure" {
267                     db.note("no two closures, even if identical, have the same type");
268                     db.help("consider boxing your closure and/or using it as a trait object");
269                 }
270                 if expected_str == found_str && expected_str == "opaque type" { // Issue #63167
271                     db.note("distinct uses of `impl Trait` result in different opaque types");
272                     let e_str = values.expected.to_string();
273                     let f_str = values.found.to_string();
274                     if &e_str == &f_str && &e_str == "impl std::future::Future" {
275                         // FIXME: use non-string based check.
276                         db.help("if both `Future`s have the same `Output` type, consider \
277                                  `.await`ing on both of them");
278                     }
279                 }
280                 match (&values.expected.kind, &values.found.kind) {
281                     (ty::Float(_), ty::Infer(ty::IntVar(_))) => if let Ok( // Issue #53280
282                         snippet,
283                     ) = self.sess.source_map().span_to_snippet(sp) {
284                         if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
285                             db.span_suggestion(
286                                 sp,
287                                 "use a float literal",
288                                 format!("{}.0", snippet),
289                                 Applicability::MachineApplicable
290                             );
291                         }
292                     },
293                     (ty::Param(expected), ty::Param(found)) => {
294                         let generics = self.generics_of(body_owner_def_id);
295                         let e_span = self.def_span(generics.type_param(expected, self).def_id);
296                         if !sp.contains(e_span) {
297                             db.span_label(e_span, "expected type parameter");
298                         }
299                         let f_span = self.def_span(generics.type_param(found, self).def_id);
300                         if !sp.contains(f_span) {
301                             db.span_label(f_span, "found type parameter");
302                         }
303                         db.note("a type parameter was expected, but a different one was found; \
304                                  you might be missing a type parameter or trait bound");
305                         db.note("for more information, visit \
306                                  https://doc.rust-lang.org/book/ch10-02-traits.html\
307                                  #traits-as-parameters");
308                     }
309                     (ty::Projection(_), ty::Projection(_)) => {
310                         db.note("an associated type was expected, but a different one was found");
311                     }
312                     (ty::Param(_), ty::Projection(_)) | (ty::Projection(_), ty::Param(_)) => {
313                         db.note("you might be missing a type parameter or trait bound");
314                     }
315                     (ty::Param(p), _) | (_, ty::Param(p)) => {
316                         let generics = self.generics_of(body_owner_def_id);
317                         let p_span = self.def_span(generics.type_param(p, self).def_id);
318                         if !sp.contains(p_span) {
319                             db.span_label(p_span, "this type parameter");
320                         }
321                         db.help("type parameters must be constrained to match other types");
322                         if self.sess.teach(&db.get_code().unwrap()) {
323                             db.help("given a type parameter `T` and a method `foo`:
324 ```
325 trait Trait<T> { fn foo(&self) -> T; }
326 ```
327 the only ways to implement method `foo` are:
328 - constrain `T` with an explicit type:
329 ```
330 impl Trait<String> for X {
331     fn foo(&self) -> String { String::new() }
332 }
333 ```
334 - add a trait bound to `T` and call a method on that trait that returns `Self`:
335 ```
336 impl<T: std::default::Default> Trait<T> for X {
337     fn foo(&self) -> T { <T as std::default::Default>::default() }
338 }
339 ```
340 - change `foo` to return an argument of type `T`:
341 ```
342 impl<T> Trait<T> for X {
343     fn foo(&self, x: T) -> T { x }
344 }
345 ```");
346                         }
347                         db.note("for more information, visit \
348                                  https://doc.rust-lang.org/book/ch10-02-traits.html\
349                                  #traits-as-parameters");
350                     }
351                     (ty::Projection(_), _) => {
352                         db.note(&format!(
353                             "consider constraining the associated type `{}` to `{}` or calling a \
354                              method that returns `{}`",
355                             values.expected,
356                             values.found,
357                             values.expected,
358                         ));
359                         if self.sess.teach(&db.get_code().unwrap()) {
360                             db.help("given an associated type `T` and a method `foo`:
361 ```
362 trait Trait {
363     type T;
364     fn foo(&self) -> Self::T;
365 }
366 ```
367 the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
368 ```
369 impl Trait for X {
370     type T = String;
371     fn foo(&self) -> Self::T { String::new() }
372 }
373 ```");
374                         }
375                         db.note("for more information, visit \
376                                  https://doc.rust-lang.org/book/ch19-03-advanced-traits.html");
377                     }
378                     (_, ty::Projection(_)) => {
379                         db.note(&format!(
380                             "consider constraining the associated type `{}` to `{}`",
381                             values.found,
382                             values.expected,
383                         ));
384                         db.note("for more information, visit \
385                                  https://doc.rust-lang.org/book/ch19-03-advanced-traits.html");
386                     }
387                     _ => {}
388                 }
389                 debug!(
390                     "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})",
391                     values.expected,
392                     values.expected.kind,
393                     values.found,
394                     values.found.kind,
395                 );
396             },
397             CyclicTy(ty) => {
398                 // Watch out for various cases of cyclic types and try to explain.
399                 if ty.is_closure() || ty.is_generator() {
400                     db.note("closures cannot capture themselves or take themselves as argument;\n\
401                              this error may be the result of a recent compiler bug-fix,\n\
402                              see https://github.com/rust-lang/rust/issues/46062 for more details");
403                 }
404             }
405             _ => {}
406         }
407     }
408 }