]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/error.rs
Fixes issue #43205: ICE in Rvalue::Len evaluation.
[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;
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(Region<'tcx>, Region<'tcx>),
40     RegionsNotSame(Region<'tcx>, Region<'tcx>),
41     RegionsNoOverlap(Region<'tcx>, Region<'tcx>),
42     RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
43     RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
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     ProjectionMismatched(ExpectedFound<DefId>),
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,
121                        "expected bound lifetime parameter{}{}, found concrete lifetime",
122                        if br.is_named() { " " } else { "" },
123                        br)
124             }
125             RegionsOverlyPolymorphic(br, _) => {
126                 write!(f,
127                        "expected concrete lifetime, found bound lifetime parameter{}{}",
128                        if br.is_named() { " " } else { "" },
129                        br)
130             }
131             Sorts(values) => ty::tls::with(|tcx| {
132                 report_maybe_different(f, values.expected.sort_string(tcx),
133                                        values.found.sort_string(tcx))
134             }),
135             Traits(values) => ty::tls::with(|tcx| {
136                 report_maybe_different(f,
137                                        format!("trait `{}`",
138                                                tcx.item_path_str(values.expected)),
139                                        format!("trait `{}`",
140                                                tcx.item_path_str(values.found)))
141             }),
142             IntMismatch(ref values) => {
143                 write!(f, "expected `{:?}`, found `{:?}`",
144                        values.expected,
145                        values.found)
146             }
147             FloatMismatch(ref values) => {
148                 write!(f, "expected `{:?}`, found `{:?}`",
149                        values.expected,
150                        values.found)
151             }
152             VariadicMismatch(ref values) => {
153                 write!(f, "expected {} fn, found {} function",
154                        if values.expected { "variadic" } else { "non-variadic" },
155                        if values.found { "variadic" } else { "non-variadic" })
156             }
157             ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
158                 write!(f, "expected {}, found {}",
159                        tcx.item_path_str(values.expected),
160                        tcx.item_path_str(values.found))
161             }),
162             ProjectionBoundsLength(ref values) => {
163                 write!(f, "expected {} associated type bindings, found {}",
164                        values.expected,
165                        values.found)
166             },
167             TyParamDefaultMismatch(ref values) => {
168                 write!(f, "conflicting type parameter defaults `{}` and `{}`",
169                        values.expected.ty,
170                        values.found.ty)
171             }
172             ExistentialMismatch(ref values) => {
173                 report_maybe_different(f, format!("trait `{}`", values.expected),
174                                        format!("trait `{}`", values.found))
175             }
176         }
177     }
178 }
179
180 impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
181     pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String {
182         match self.sty {
183             ty::TyBool | ty::TyChar | ty::TyInt(_) |
184             ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(),
185             ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
186
187             ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
188             ty::TyArray(_, n) => format!("array of {} elements", n),
189             ty::TySlice(_) => "slice".to_string(),
190             ty::TyRawPtr(_) => "*-ptr".to_string(),
191             ty::TyRef(region, tymut) => {
192                 let tymut_string = tymut.to_string();
193                 if tymut_string == "_" ||         //unknown type name,
194                    tymut_string.len() > 10 ||     //name longer than saying "reference",
195                    region.to_string() != ""       //... or a complex type
196                 {
197                     match tymut {
198                         ty::TypeAndMut{mutbl, ..} => {
199                             format!("{}reference", match mutbl {
200                                 hir::Mutability::MutMutable => "mutable ",
201                                 _ => ""
202                             })
203                         }
204                     }
205                 } else {
206                     format!("&{}", tymut_string)
207                 }
208             }
209             ty::TyFnDef(..) => format!("fn item"),
210             ty::TyFnPtr(_) => "fn pointer".to_string(),
211             ty::TyDynamic(ref inner, ..) => {
212                 inner.principal().map_or_else(|| "trait".to_string(),
213                     |p| format!("trait {}", tcx.item_path_str(p.def_id())))
214             }
215             ty::TyClosure(..) => "closure".to_string(),
216             ty::TyTuple(..) => "tuple".to_string(),
217             ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
218             ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
219             ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(),
220             ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(),
221             ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(),
222             ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
223             ty::TyProjection(_) => "associated type".to_string(),
224             ty::TyParam(ref p) => {
225                 if p.is_self() {
226                     "Self".to_string()
227                 } else {
228                     "type parameter".to_string()
229                 }
230             }
231             ty::TyAnon(..) => "anonymized type".to_string(),
232             ty::TyError => "type error".to_string(),
233         }
234     }
235 }
236
237 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
238     pub fn note_and_explain_type_err(self,
239                                      db: &mut DiagnosticBuilder,
240                                      err: &TypeError<'tcx>,
241                                      sp: Span) {
242         use self::TypeError::*;
243
244         match err.clone() {
245             RegionsDoesNotOutlive(subregion, superregion) => {
246                 self.note_and_explain_region(db, "", subregion, "...");
247                 self.note_and_explain_region(db, "...does not necessarily outlive ",
248                                            superregion, "");
249             }
250             RegionsNotSame(region1, region2) => {
251                 self.note_and_explain_region(db, "", region1, "...");
252                 self.note_and_explain_region(db, "...is not the same lifetime as ",
253                                            region2, "");
254             }
255             RegionsNoOverlap(region1, region2) => {
256                 self.note_and_explain_region(db, "", region1, "...");
257                 self.note_and_explain_region(db, "...does not overlap ",
258                                            region2, "");
259             }
260             RegionsInsufficientlyPolymorphic(_, conc_region) => {
261                 self.note_and_explain_region(db, "concrete lifetime that was found is ",
262                                            conc_region, "");
263             }
264             RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => {
265                 // don't bother to print out the message below for
266                 // inference variables, it's not very illuminating.
267             }
268             RegionsOverlyPolymorphic(_, conc_region) => {
269                 self.note_and_explain_region(db, "expected concrete lifetime is ",
270                                            conc_region, "");
271             }
272             Sorts(values) => {
273                 let expected_str = values.expected.sort_string(self);
274                 let found_str = values.found.sort_string(self);
275                 if expected_str == found_str && expected_str == "closure" {
276                     db.span_note(sp,
277                         "no two closures, even if identical, have the same type");
278                     db.span_help(sp,
279                         "consider boxing your closure and/or using it as a trait object");
280                 }
281             },
282             TyParamDefaultMismatch(values) => {
283                 let expected = values.expected;
284                 let found = values.found;
285                 db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`",
286                                           expected.ty,
287                                           found.ty));
288
289                 match self.hir.span_if_local(expected.def_id) {
290                     Some(span) => {
291                         db.span_note(span, "a default was defined here...");
292                     }
293                     None => {
294                         let item_def_id = self.parent(expected.def_id).unwrap();
295                         db.note(&format!("a default is defined on `{}`",
296                                          self.item_path_str(item_def_id)));
297                     }
298                 }
299
300                 db.span_note(
301                     expected.origin_span,
302                     "...that was applied to an unconstrained type variable here");
303
304                 match self.hir.span_if_local(found.def_id) {
305                     Some(span) => {
306                         db.span_note(span, "a second default was defined here...");
307                     }
308                     None => {
309                         let item_def_id = self.parent(found.def_id).unwrap();
310                         db.note(&format!("a second default is defined on `{}`",
311                                          self.item_path_str(item_def_id)));
312                     }
313                 }
314
315                 db.span_note(found.origin_span,
316                              "...that also applies to the same type variable here");
317             }
318             _ => {}
319         }
320     }
321 }