]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/error.rs
Rollup merge of #40521 - TimNN:panic-free-shift, r=alexcrichton
[rust.git] / src / librustc / ty / error.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use hir::def_id::DefId;
12 use infer::type_variable;
13 use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
14
15 use std::fmt;
16 use syntax::abi;
17 use syntax::ast::{self, Name};
18 use errors::DiagnosticBuilder;
19 use syntax_pos::Span;
20
21 use hir;
22
23 #[derive(Clone, Copy, Debug)]
24 pub struct ExpectedFound<T> {
25     pub expected: T,
26     pub found: T,
27 }
28
29 // Data structures used in type unification
30 #[derive(Clone, Debug)]
31 pub enum TypeError<'tcx> {
32     Mismatch,
33     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
34     AbiMismatch(ExpectedFound<abi::Abi>),
35     Mutability,
36     TupleSize(ExpectedFound<usize>),
37     FixedArraySize(ExpectedFound<usize>),
38     ArgCount,
39     RegionsDoesNotOutlive(&'tcx Region, &'tcx Region),
40     RegionsNotSame(&'tcx Region, &'tcx Region),
41     RegionsNoOverlap(&'tcx Region, &'tcx Region),
42     RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region),
43     RegionsOverlyPolymorphic(BoundRegion, &'tcx Region),
44     Sorts(ExpectedFound<Ty<'tcx>>),
45     IntMismatch(ExpectedFound<ty::IntVarValue>),
46     FloatMismatch(ExpectedFound<ast::FloatTy>),
47     Traits(ExpectedFound<DefId>),
48     VariadicMismatch(ExpectedFound<bool>),
49     CyclicTy,
50     ProjectionNameMismatched(ExpectedFound<Name>),
51     ProjectionBoundsLength(ExpectedFound<usize>),
52     TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
53     ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
54 }
55
56 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
57 pub enum UnconstrainedNumeric {
58     UnconstrainedFloat,
59     UnconstrainedInt,
60     Neither,
61 }
62
63 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
64 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
65 /// afterwards to present additional details, particularly when it comes to lifetime-related
66 /// errors.
67 impl<'tcx> fmt::Display for TypeError<'tcx> {
68     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69         use self::TypeError::*;
70         fn report_maybe_different(f: &mut fmt::Formatter,
71                                   expected: String, found: String) -> fmt::Result {
72             // A naive approach to making sure that we're not reporting silly errors such as:
73             // (expected closure, found closure).
74             if expected == found {
75                 write!(f, "expected {}, found a different {}", expected, found)
76             } else {
77                 write!(f, "expected {}, found {}", expected, found)
78             }
79         }
80
81         match *self {
82             CyclicTy => write!(f, "cyclic type of infinite size"),
83             Mismatch => write!(f, "types differ"),
84             UnsafetyMismatch(values) => {
85                 write!(f, "expected {} fn, found {} fn",
86                        values.expected,
87                        values.found)
88             }
89             AbiMismatch(values) => {
90                 write!(f, "expected {} fn, found {} fn",
91                        values.expected,
92                        values.found)
93             }
94             Mutability => write!(f, "types differ in mutability"),
95             FixedArraySize(values) => {
96                 write!(f, "expected an array with a fixed size of {} elements, \
97                            found one with {} elements",
98                        values.expected,
99                        values.found)
100             }
101             TupleSize(values) => {
102                 write!(f, "expected a tuple with {} elements, \
103                            found one with {} elements",
104                        values.expected,
105                        values.found)
106             }
107             ArgCount => {
108                 write!(f, "incorrect number of function parameters")
109             }
110             RegionsDoesNotOutlive(..) => {
111                 write!(f, "lifetime mismatch")
112             }
113             RegionsNotSame(..) => {
114                 write!(f, "lifetimes are not the same")
115             }
116             RegionsNoOverlap(..) => {
117                 write!(f, "lifetimes do not intersect")
118             }
119             RegionsInsufficientlyPolymorphic(br, _) => {
120                 write!(f, "expected bound lifetime parameter {}, \
121                            found concrete lifetime", br)
122             }
123             RegionsOverlyPolymorphic(br, _) => {
124                 write!(f, "expected concrete lifetime, \
125                            found bound lifetime parameter {}", br)
126             }
127             Sorts(values) => ty::tls::with(|tcx| {
128                 report_maybe_different(f, values.expected.sort_string(tcx),
129                                        values.found.sort_string(tcx))
130             }),
131             Traits(values) => ty::tls::with(|tcx| {
132                 report_maybe_different(f,
133                                        format!("trait `{}`",
134                                                tcx.item_path_str(values.expected)),
135                                        format!("trait `{}`",
136                                                tcx.item_path_str(values.found)))
137             }),
138             IntMismatch(ref values) => {
139                 write!(f, "expected `{:?}`, found `{:?}`",
140                        values.expected,
141                        values.found)
142             }
143             FloatMismatch(ref values) => {
144                 write!(f, "expected `{:?}`, found `{:?}`",
145                        values.expected,
146                        values.found)
147             }
148             VariadicMismatch(ref values) => {
149                 write!(f, "expected {} fn, found {} function",
150                        if values.expected { "variadic" } else { "non-variadic" },
151                        if values.found { "variadic" } else { "non-variadic" })
152             }
153             ProjectionNameMismatched(ref values) => {
154                 write!(f, "expected {}, found {}",
155                        values.expected,
156                        values.found)
157             }
158             ProjectionBoundsLength(ref values) => {
159                 write!(f, "expected {} associated type bindings, found {}",
160                        values.expected,
161                        values.found)
162             },
163             TyParamDefaultMismatch(ref values) => {
164                 write!(f, "conflicting type parameter defaults `{}` and `{}`",
165                        values.expected.ty,
166                        values.found.ty)
167             }
168             ExistentialMismatch(ref values) => {
169                 report_maybe_different(f, format!("trait `{}`", values.expected),
170                                        format!("trait `{}`", values.found))
171             }
172         }
173     }
174 }
175
176 impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
177     pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String {
178         match self.sty {
179             ty::TyBool | ty::TyChar | ty::TyInt(_) |
180             ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(),
181             ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
182
183             ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
184             ty::TyArray(_, n) => format!("array of {} elements", n),
185             ty::TySlice(_) => "slice".to_string(),
186             ty::TyRawPtr(_) => "*-ptr".to_string(),
187             ty::TyRef(region, tymut) => {
188                 let tymut_string = tymut.to_string();
189                 if tymut_string == "_" ||         //unknown type name,
190                    tymut_string.len() > 10 ||     //name longer than saying "reference",
191                    region.to_string() != ""       //... or a complex type
192                 {
193                     match tymut {
194                         ty::TypeAndMut{mutbl, ..} => {
195                             format!("{}reference", match mutbl {
196                                 hir::Mutability::MutMutable => "mutable ",
197                                 _ => ""
198                             })
199                         }
200                     }
201                 } else {
202                     format!("&{}", tymut_string)
203                 }
204             }
205             ty::TyFnDef(..) => format!("fn item"),
206             ty::TyFnPtr(_) => "fn pointer".to_string(),
207             ty::TyDynamic(ref inner, ..) => {
208                 inner.principal().map_or_else(|| "trait".to_string(),
209                     |p| format!("trait {}", tcx.item_path_str(p.def_id())))
210             }
211             ty::TyClosure(..) => "closure".to_string(),
212             ty::TyTuple(..) => "tuple".to_string(),
213             ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
214             ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
215             ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(),
216             ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(),
217             ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(),
218             ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
219             ty::TyProjection(_) => "associated type".to_string(),
220             ty::TyParam(ref p) => {
221                 if p.is_self() {
222                     "Self".to_string()
223                 } else {
224                     "type parameter".to_string()
225                 }
226             }
227             ty::TyAnon(..) => "anonymized type".to_string(),
228             ty::TyError => "type error".to_string(),
229         }
230     }
231 }
232
233 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
234     pub fn note_and_explain_type_err(self,
235                                      db: &mut DiagnosticBuilder,
236                                      err: &TypeError<'tcx>,
237                                      sp: Span) {
238         use self::TypeError::*;
239
240         match err.clone() {
241             RegionsDoesNotOutlive(subregion, superregion) => {
242                 self.note_and_explain_region(db, "", subregion, "...");
243                 self.note_and_explain_region(db, "...does not necessarily outlive ",
244                                            superregion, "");
245             }
246             RegionsNotSame(region1, region2) => {
247                 self.note_and_explain_region(db, "", region1, "...");
248                 self.note_and_explain_region(db, "...is not the same lifetime as ",
249                                            region2, "");
250             }
251             RegionsNoOverlap(region1, region2) => {
252                 self.note_and_explain_region(db, "", region1, "...");
253                 self.note_and_explain_region(db, "...does not overlap ",
254                                            region2, "");
255             }
256             RegionsInsufficientlyPolymorphic(_, conc_region) => {
257                 self.note_and_explain_region(db, "concrete lifetime that was found is ",
258                                            conc_region, "");
259             }
260             RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => {
261                 // don't bother to print out the message below for
262                 // inference variables, it's not very illuminating.
263             }
264             RegionsOverlyPolymorphic(_, conc_region) => {
265                 self.note_and_explain_region(db, "expected concrete lifetime is ",
266                                            conc_region, "");
267             }
268             Sorts(values) => {
269                 let expected_str = values.expected.sort_string(self);
270                 let found_str = values.found.sort_string(self);
271                 if expected_str == found_str && expected_str == "closure" {
272                     db.span_note(sp,
273                         "no two closures, even if identical, have the same type");
274                     db.span_help(sp,
275                         "consider boxing your closure and/or using it as a trait object");
276                 }
277             },
278             TyParamDefaultMismatch(values) => {
279                 let expected = values.expected;
280                 let found = values.found;
281                 db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`",
282                                           expected.ty,
283                                           found.ty));
284
285                 match self.hir.span_if_local(expected.def_id) {
286                     Some(span) => {
287                         db.span_note(span, "a default was defined here...");
288                     }
289                     None => {
290                         let item_def_id = self.parent(expected.def_id).unwrap();
291                         db.note(&format!("a default is defined on `{}`",
292                                          self.item_path_str(item_def_id)));
293                     }
294                 }
295
296                 db.span_note(
297                     expected.origin_span,
298                     "...that was applied to an unconstrained type variable here");
299
300                 match self.hir.span_if_local(found.def_id) {
301                     Some(span) => {
302                         db.span_note(span, "a second default was defined here...");
303                     }
304                     None => {
305                         let item_def_id = self.parent(found.def_id).unwrap();
306                         db.note(&format!("a second default is defined on `{}`",
307                                          self.item_path_str(item_def_id)));
308                     }
309                 }
310
311                 db.span_note(found.origin_span,
312                              "...that also applies to the same type variable here");
313             }
314             _ => {}
315         }
316     }
317 }