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