]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
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 | ||
54a0048b SL |
11 | use hir::def_id::DefId; |
12 | use ty::subst; | |
13 | use infer::type_variable; | |
14 | use ty::{self, BoundRegion, Region, Ty, TyCtxt}; | |
e9174d1e SL |
15 | |
16 | use std::fmt; | |
17 | use syntax::abi; | |
b039eaaf | 18 | use syntax::ast::{self, Name}; |
3157f602 XL |
19 | use errors::DiagnosticBuilder; |
20 | use syntax_pos::Span; | |
e9174d1e | 21 | |
54a0048b | 22 | use hir; |
e9174d1e SL |
23 | |
24 | #[derive(Clone, Copy, Debug)] | |
25 | pub struct ExpectedFound<T> { | |
26 | pub expected: T, | |
27 | pub found: T | |
28 | } | |
29 | ||
30 | // Data structures used in type unification | |
31 | #[derive(Clone, Debug)] | |
32 | pub enum TypeError<'tcx> { | |
33 | Mismatch, | |
34 | UnsafetyMismatch(ExpectedFound<hir::Unsafety>), | |
35 | AbiMismatch(ExpectedFound<abi::Abi>), | |
36 | Mutability, | |
37 | BoxMutability, | |
38 | PtrMutability, | |
39 | RefMutability, | |
40 | VecMutability, | |
41 | TupleSize(ExpectedFound<usize>), | |
42 | FixedArraySize(ExpectedFound<usize>), | |
43 | TyParamSize(ExpectedFound<usize>), | |
44 | ArgCount, | |
45 | RegionsDoesNotOutlive(Region, Region), | |
46 | RegionsNotSame(Region, Region), | |
47 | RegionsNoOverlap(Region, Region), | |
48 | RegionsInsufficientlyPolymorphic(BoundRegion, Region), | |
49 | RegionsOverlyPolymorphic(BoundRegion, Region), | |
50 | Sorts(ExpectedFound<Ty<'tcx>>), | |
51 | IntegerAsChar, | |
52 | IntMismatch(ExpectedFound<ty::IntVarValue>), | |
b039eaaf | 53 | FloatMismatch(ExpectedFound<ast::FloatTy>), |
e9174d1e SL |
54 | Traits(ExpectedFound<DefId>), |
55 | BuiltinBoundsMismatch(ExpectedFound<ty::BuiltinBounds>), | |
56 | VariadicMismatch(ExpectedFound<bool>), | |
57 | CyclicTy, | |
58 | ConvergenceMismatch(ExpectedFound<bool>), | |
59 | ProjectionNameMismatched(ExpectedFound<Name>), | |
60 | ProjectionBoundsLength(ExpectedFound<usize>), | |
61 | TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>) | |
62 | } | |
63 | ||
64 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] | |
65 | pub enum UnconstrainedNumeric { | |
66 | UnconstrainedFloat, | |
67 | UnconstrainedInt, | |
68 | Neither, | |
69 | } | |
70 | ||
71 | /// Explains the source of a type err in a short, human readable way. This is meant to be placed | |
72 | /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` | |
73 | /// afterwards to present additional details, particularly when it comes to lifetime-related | |
74 | /// errors. | |
75 | impl<'tcx> fmt::Display for TypeError<'tcx> { | |
76 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
77 | use self::TypeError::*; | |
78 | fn report_maybe_different(f: &mut fmt::Formatter, | |
79 | expected: String, found: String) -> fmt::Result { | |
80 | // A naive approach to making sure that we're not reporting silly errors such as: | |
81 | // (expected closure, found closure). | |
82 | if expected == found { | |
83 | write!(f, "expected {}, found a different {}", expected, found) | |
84 | } else { | |
85 | write!(f, "expected {}, found {}", expected, found) | |
86 | } | |
87 | } | |
88 | ||
89 | match *self { | |
90 | CyclicTy => write!(f, "cyclic type of infinite size"), | |
91 | Mismatch => write!(f, "types differ"), | |
92 | UnsafetyMismatch(values) => { | |
93 | write!(f, "expected {} fn, found {} fn", | |
94 | values.expected, | |
95 | values.found) | |
96 | } | |
97 | AbiMismatch(values) => { | |
98 | write!(f, "expected {} fn, found {} fn", | |
99 | values.expected, | |
100 | values.found) | |
101 | } | |
102 | Mutability => write!(f, "values differ in mutability"), | |
103 | BoxMutability => { | |
104 | write!(f, "boxed values differ in mutability") | |
105 | } | |
106 | VecMutability => write!(f, "vectors differ in mutability"), | |
107 | PtrMutability => write!(f, "pointers differ in mutability"), | |
108 | RefMutability => write!(f, "references differ in mutability"), | |
109 | TyParamSize(values) => { | |
110 | write!(f, "expected a type with {} type params, \ | |
111 | found one with {} type params", | |
112 | values.expected, | |
113 | values.found) | |
114 | } | |
115 | FixedArraySize(values) => { | |
116 | write!(f, "expected an array with a fixed size of {} elements, \ | |
117 | found one with {} elements", | |
118 | values.expected, | |
119 | values.found) | |
120 | } | |
121 | TupleSize(values) => { | |
122 | write!(f, "expected a tuple with {} elements, \ | |
123 | found one with {} elements", | |
124 | values.expected, | |
125 | values.found) | |
126 | } | |
127 | ArgCount => { | |
128 | write!(f, "incorrect number of function parameters") | |
129 | } | |
130 | RegionsDoesNotOutlive(..) => { | |
131 | write!(f, "lifetime mismatch") | |
132 | } | |
133 | RegionsNotSame(..) => { | |
134 | write!(f, "lifetimes are not the same") | |
135 | } | |
136 | RegionsNoOverlap(..) => { | |
137 | write!(f, "lifetimes do not intersect") | |
138 | } | |
139 | RegionsInsufficientlyPolymorphic(br, _) => { | |
140 | write!(f, "expected bound lifetime parameter {}, \ | |
141 | found concrete lifetime", br) | |
142 | } | |
143 | RegionsOverlyPolymorphic(br, _) => { | |
144 | write!(f, "expected concrete lifetime, \ | |
145 | found bound lifetime parameter {}", br) | |
146 | } | |
147 | Sorts(values) => ty::tls::with(|tcx| { | |
148 | report_maybe_different(f, values.expected.sort_string(tcx), | |
149 | values.found.sort_string(tcx)) | |
150 | }), | |
151 | Traits(values) => ty::tls::with(|tcx| { | |
152 | report_maybe_different(f, | |
153 | format!("trait `{}`", | |
154 | tcx.item_path_str(values.expected)), | |
155 | format!("trait `{}`", | |
156 | tcx.item_path_str(values.found))) | |
157 | }), | |
158 | BuiltinBoundsMismatch(values) => { | |
159 | if values.expected.is_empty() { | |
160 | write!(f, "expected no bounds, found `{}`", | |
161 | values.found) | |
162 | } else if values.found.is_empty() { | |
163 | write!(f, "expected bounds `{}`, found no bounds", | |
164 | values.expected) | |
165 | } else { | |
166 | write!(f, "expected bounds `{}`, found bounds `{}`", | |
167 | values.expected, | |
168 | values.found) | |
169 | } | |
170 | } | |
171 | IntegerAsChar => { | |
172 | write!(f, "expected an integral type, found `char`") | |
173 | } | |
174 | IntMismatch(ref values) => { | |
175 | write!(f, "expected `{:?}`, found `{:?}`", | |
176 | values.expected, | |
177 | values.found) | |
178 | } | |
179 | FloatMismatch(ref values) => { | |
180 | write!(f, "expected `{:?}`, found `{:?}`", | |
181 | values.expected, | |
182 | values.found) | |
183 | } | |
184 | VariadicMismatch(ref values) => { | |
185 | write!(f, "expected {} fn, found {} function", | |
186 | if values.expected { "variadic" } else { "non-variadic" }, | |
187 | if values.found { "variadic" } else { "non-variadic" }) | |
188 | } | |
189 | ConvergenceMismatch(ref values) => { | |
190 | write!(f, "expected {} fn, found {} function", | |
191 | if values.expected { "converging" } else { "diverging" }, | |
192 | if values.found { "converging" } else { "diverging" }) | |
193 | } | |
194 | ProjectionNameMismatched(ref values) => { | |
195 | write!(f, "expected {}, found {}", | |
196 | values.expected, | |
197 | values.found) | |
198 | } | |
199 | ProjectionBoundsLength(ref values) => { | |
200 | write!(f, "expected {} associated type bindings, found {}", | |
201 | values.expected, | |
202 | values.found) | |
203 | }, | |
204 | TyParamDefaultMismatch(ref values) => { | |
205 | write!(f, "conflicting type parameter defaults `{}` and `{}`", | |
206 | values.expected.ty, | |
207 | values.found.ty) | |
208 | } | |
209 | } | |
210 | } | |
211 | } | |
212 | ||
a7813a04 XL |
213 | impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { |
214 | fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { | |
e9174d1e SL |
215 | match self.sty { |
216 | ty::TyBool | ty::TyChar | ty::TyInt(_) | | |
5bcae85e | 217 | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), |
e9174d1e SL |
218 | ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), |
219 | ||
a7813a04 | 220 | ty::TyEnum(def, _) => format!("enum `{}`", tcx.item_path_str(def.did)), |
e9174d1e SL |
221 | ty::TyBox(_) => "box".to_string(), |
222 | ty::TyArray(_, n) => format!("array of {} elements", n), | |
223 | ty::TySlice(_) => "slice".to_string(), | |
224 | ty::TyRawPtr(_) => "*-ptr".to_string(), | |
5bcae85e SL |
225 | ty::TyRef(region, tymut) => { |
226 | let tymut_string = tymut.to_string(); | |
227 | if tymut_string == "_" || //unknown type name, | |
228 | tymut_string.len() > 10 || //name longer than saying "reference", | |
229 | region.to_string() != "" //... or a complex type | |
230 | { | |
231 | match tymut { | |
232 | ty::TypeAndMut{mutbl, ..} => { | |
233 | format!("{}reference", match mutbl { | |
234 | hir::Mutability::MutMutable => "mutable ", | |
235 | _ => "" | |
236 | }) | |
237 | } | |
238 | } | |
239 | } else { | |
240 | format!("&{}", tymut_string) | |
241 | } | |
242 | } | |
54a0048b SL |
243 | ty::TyFnDef(..) => format!("fn item"), |
244 | ty::TyFnPtr(_) => "fn pointer".to_string(), | |
e9174d1e | 245 | ty::TyTrait(ref inner) => { |
a7813a04 | 246 | format!("trait {}", tcx.item_path_str(inner.principal_def_id())) |
e9174d1e SL |
247 | } |
248 | ty::TyStruct(def, _) => { | |
a7813a04 | 249 | format!("struct `{}`", tcx.item_path_str(def.did)) |
e9174d1e SL |
250 | } |
251 | ty::TyClosure(..) => "closure".to_string(), | |
252 | ty::TyTuple(_) => "tuple".to_string(), | |
253 | ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), | |
254 | ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(), | |
255 | ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(), | |
256 | ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(), | |
257 | ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(), | |
258 | ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(), | |
259 | ty::TyProjection(_) => "associated type".to_string(), | |
260 | ty::TyParam(ref p) => { | |
261 | if p.space == subst::SelfSpace { | |
262 | "Self".to_string() | |
263 | } else { | |
264 | "type parameter".to_string() | |
265 | } | |
266 | } | |
5bcae85e | 267 | ty::TyAnon(..) => "anonymized type".to_string(), |
e9174d1e SL |
268 | ty::TyError => "type error".to_string(), |
269 | } | |
270 | } | |
271 | } | |
272 | ||
a7813a04 XL |
273 | impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
274 | pub fn note_and_explain_type_err(self, | |
9cc50fc6 SL |
275 | db: &mut DiagnosticBuilder, |
276 | err: &TypeError<'tcx>, | |
277 | sp: Span) { | |
e9174d1e SL |
278 | use self::TypeError::*; |
279 | ||
280 | match err.clone() { | |
281 | RegionsDoesNotOutlive(subregion, superregion) => { | |
9cc50fc6 SL |
282 | self.note_and_explain_region(db, "", subregion, "..."); |
283 | self.note_and_explain_region(db, "...does not necessarily outlive ", | |
e9174d1e SL |
284 | superregion, ""); |
285 | } | |
286 | RegionsNotSame(region1, region2) => { | |
9cc50fc6 SL |
287 | self.note_and_explain_region(db, "", region1, "..."); |
288 | self.note_and_explain_region(db, "...is not the same lifetime as ", | |
e9174d1e SL |
289 | region2, ""); |
290 | } | |
291 | RegionsNoOverlap(region1, region2) => { | |
9cc50fc6 SL |
292 | self.note_and_explain_region(db, "", region1, "..."); |
293 | self.note_and_explain_region(db, "...does not overlap ", | |
e9174d1e SL |
294 | region2, ""); |
295 | } | |
296 | RegionsInsufficientlyPolymorphic(_, conc_region) => { | |
9cc50fc6 | 297 | self.note_and_explain_region(db, "concrete lifetime that was found is ", |
e9174d1e SL |
298 | conc_region, ""); |
299 | } | |
300 | RegionsOverlyPolymorphic(_, ty::ReVar(_)) => { | |
301 | // don't bother to print out the message below for | |
302 | // inference variables, it's not very illuminating. | |
303 | } | |
304 | RegionsOverlyPolymorphic(_, conc_region) => { | |
9cc50fc6 | 305 | self.note_and_explain_region(db, "expected concrete lifetime is ", |
e9174d1e SL |
306 | conc_region, ""); |
307 | } | |
308 | Sorts(values) => { | |
309 | let expected_str = values.expected.sort_string(self); | |
310 | let found_str = values.found.sort_string(self); | |
311 | if expected_str == found_str && expected_str == "closure" { | |
9cc50fc6 | 312 | db.span_note(sp, |
92a42be0 | 313 | "no two closures, even if identical, have the same type"); |
9cc50fc6 | 314 | db.span_help(sp, |
92a42be0 | 315 | "consider boxing your closure and/or using it as a trait object"); |
e9174d1e SL |
316 | } |
317 | }, | |
318 | TyParamDefaultMismatch(values) => { | |
319 | let expected = values.expected; | |
320 | let found = values.found; | |
9cc50fc6 SL |
321 | db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`", |
322 | expected.ty, | |
323 | found.ty)); | |
e9174d1e | 324 | |
b039eaaf SL |
325 | match |
326 | self.map.as_local_node_id(expected.def_id) | |
327 | .and_then(|node_id| self.map.opt_span(node_id)) | |
328 | { | |
329 | Some(span) => { | |
9cc50fc6 | 330 | db.span_note(span, "a default was defined here..."); |
e9174d1e | 331 | } |
b039eaaf | 332 | None => { |
9cc50fc6 SL |
333 | db.note(&format!("a default is defined on `{}`", |
334 | self.item_path_str(expected.def_id))); | |
e9174d1e SL |
335 | } |
336 | } | |
337 | ||
9cc50fc6 | 338 | db.span_note( |
e9174d1e | 339 | expected.origin_span, |
92a42be0 | 340 | "...that was applied to an unconstrained type variable here"); |
e9174d1e | 341 | |
b039eaaf SL |
342 | match |
343 | self.map.as_local_node_id(found.def_id) | |
344 | .and_then(|node_id| self.map.opt_span(node_id)) | |
345 | { | |
346 | Some(span) => { | |
9cc50fc6 | 347 | db.span_note(span, "a second default was defined here..."); |
e9174d1e | 348 | } |
b039eaaf | 349 | None => { |
9cc50fc6 SL |
350 | db.note(&format!("a second default is defined on `{}`", |
351 | self.item_path_str(found.def_id))); | |
e9174d1e SL |
352 | } |
353 | } | |
354 | ||
9cc50fc6 SL |
355 | db.span_note(found.origin_span, |
356 | "...that also applies to the same type variable here"); | |
e9174d1e SL |
357 | } |
358 | _ => {} | |
359 | } | |
360 | } | |
361 | } |