]>
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 | 12 | use infer::type_variable; |
8bb4bdeb | 13 | use ty::{self, BoundRegion, DefIdTree, 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, | |
e9174d1e SL |
36 | TupleSize(ExpectedFound<usize>), |
37 | FixedArraySize(ExpectedFound<usize>), | |
e9174d1e | 38 | ArgCount, |
9e0c209e SL |
39 | RegionsDoesNotOutlive(&'tcx Region, &'tcx Region), |
40 | RegionsNotSame(&'tcx Region, &'tcx Region), | |
41 | RegionsNoOverlap(&'tcx Region, &'tcx Region), | |
8bb4bdeb XL |
42 | RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region, Option<Box<ty::Issue32330>>), |
43 | RegionsOverlyPolymorphic(BoundRegion, &'tcx Region, Option<Box<ty::Issue32330>>), | |
e9174d1e | 44 | Sorts(ExpectedFound<Ty<'tcx>>), |
e9174d1e | 45 | IntMismatch(ExpectedFound<ty::IntVarValue>), |
b039eaaf | 46 | FloatMismatch(ExpectedFound<ast::FloatTy>), |
e9174d1e | 47 | Traits(ExpectedFound<DefId>), |
e9174d1e SL |
48 | VariadicMismatch(ExpectedFound<bool>), |
49 | CyclicTy, | |
e9174d1e SL |
50 | ProjectionNameMismatched(ExpectedFound<Name>), |
51 | ProjectionBoundsLength(ExpectedFound<usize>), | |
476ff2be SL |
52 | TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>), |
53 | ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>), | |
e9174d1e SL |
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 | } | |
9e0c209e | 94 | Mutability => write!(f, "types differ in mutability"), |
e9174d1e SL |
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 | } | |
8bb4bdeb | 119 | RegionsInsufficientlyPolymorphic(br, _, _) => { |
e9174d1e SL |
120 | write!(f, "expected bound lifetime parameter {}, \ |
121 | found concrete lifetime", br) | |
122 | } | |
8bb4bdeb | 123 | RegionsOverlyPolymorphic(br, _, _) => { |
e9174d1e SL |
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 | }), | |
e9174d1e SL |
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 | } | |
e9174d1e SL |
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 | } | |
476ff2be SL |
168 | ExistentialMismatch(ref values) => { |
169 | report_maybe_different(f, format!("trait `{}`", values.expected), | |
170 | format!("trait `{}`", values.found)) | |
171 | } | |
e9174d1e SL |
172 | } |
173 | } | |
174 | } | |
175 | ||
a7813a04 | 176 | impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { |
9e0c209e | 177 | pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { |
e9174d1e SL |
178 | match self.sty { |
179 | ty::TyBool | ty::TyChar | ty::TyInt(_) | | |
5bcae85e | 180 | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), |
8bb4bdeb | 181 | ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(), |
e9174d1e | 182 | |
9e0c209e | 183 | ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), |
e9174d1e SL |
184 | ty::TyArray(_, n) => format!("array of {} elements", n), |
185 | ty::TySlice(_) => "slice".to_string(), | |
186 | ty::TyRawPtr(_) => "*-ptr".to_string(), | |
5bcae85e SL |
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 | } | |
54a0048b SL |
205 | ty::TyFnDef(..) => format!("fn item"), |
206 | ty::TyFnPtr(_) => "fn pointer".to_string(), | |
476ff2be SL |
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()))) | |
e9174d1e SL |
210 | } |
211 | ty::TyClosure(..) => "closure".to_string(), | |
8bb4bdeb | 212 | ty::TyTuple(..) => "tuple".to_string(), |
e9174d1e SL |
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) => { | |
9e0c209e | 221 | if p.is_self() { |
e9174d1e SL |
222 | "Self".to_string() |
223 | } else { | |
224 | "type parameter".to_string() | |
225 | } | |
226 | } | |
5bcae85e | 227 | ty::TyAnon(..) => "anonymized type".to_string(), |
e9174d1e SL |
228 | ty::TyError => "type error".to_string(), |
229 | } | |
230 | } | |
231 | } | |
232 | ||
a7813a04 XL |
233 | impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
234 | pub fn note_and_explain_type_err(self, | |
9cc50fc6 SL |
235 | db: &mut DiagnosticBuilder, |
236 | err: &TypeError<'tcx>, | |
237 | sp: Span) { | |
e9174d1e SL |
238 | use self::TypeError::*; |
239 | ||
240 | match err.clone() { | |
241 | RegionsDoesNotOutlive(subregion, superregion) => { | |
9cc50fc6 SL |
242 | self.note_and_explain_region(db, "", subregion, "..."); |
243 | self.note_and_explain_region(db, "...does not necessarily outlive ", | |
e9174d1e SL |
244 | superregion, ""); |
245 | } | |
246 | RegionsNotSame(region1, region2) => { | |
9cc50fc6 SL |
247 | self.note_and_explain_region(db, "", region1, "..."); |
248 | self.note_and_explain_region(db, "...is not the same lifetime as ", | |
e9174d1e SL |
249 | region2, ""); |
250 | } | |
251 | RegionsNoOverlap(region1, region2) => { | |
9cc50fc6 SL |
252 | self.note_and_explain_region(db, "", region1, "..."); |
253 | self.note_and_explain_region(db, "...does not overlap ", | |
e9174d1e SL |
254 | region2, ""); |
255 | } | |
8bb4bdeb | 256 | RegionsInsufficientlyPolymorphic(_, conc_region, _) => { |
9cc50fc6 | 257 | self.note_and_explain_region(db, "concrete lifetime that was found is ", |
e9174d1e SL |
258 | conc_region, ""); |
259 | } | |
8bb4bdeb | 260 | RegionsOverlyPolymorphic(_, &ty::ReVar(_), _) => { |
e9174d1e SL |
261 | // don't bother to print out the message below for |
262 | // inference variables, it's not very illuminating. | |
263 | } | |
8bb4bdeb | 264 | RegionsOverlyPolymorphic(_, conc_region, _) => { |
9cc50fc6 | 265 | self.note_and_explain_region(db, "expected concrete lifetime is ", |
e9174d1e SL |
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" { | |
9cc50fc6 | 272 | db.span_note(sp, |
92a42be0 | 273 | "no two closures, even if identical, have the same type"); |
9cc50fc6 | 274 | db.span_help(sp, |
92a42be0 | 275 | "consider boxing your closure and/or using it as a trait object"); |
e9174d1e SL |
276 | } |
277 | }, | |
278 | TyParamDefaultMismatch(values) => { | |
279 | let expected = values.expected; | |
280 | let found = values.found; | |
9cc50fc6 SL |
281 | db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`", |
282 | expected.ty, | |
283 | found.ty)); | |
e9174d1e | 284 | |
32a655c1 | 285 | match self.hir.span_if_local(expected.def_id) { |
b039eaaf | 286 | Some(span) => { |
9cc50fc6 | 287 | db.span_note(span, "a default was defined here..."); |
e9174d1e | 288 | } |
b039eaaf | 289 | None => { |
8bb4bdeb | 290 | let item_def_id = self.parent(expected.def_id).unwrap(); |
9cc50fc6 | 291 | db.note(&format!("a default is defined on `{}`", |
8bb4bdeb | 292 | self.item_path_str(item_def_id))); |
e9174d1e SL |
293 | } |
294 | } | |
295 | ||
9cc50fc6 | 296 | db.span_note( |
e9174d1e | 297 | expected.origin_span, |
92a42be0 | 298 | "...that was applied to an unconstrained type variable here"); |
e9174d1e | 299 | |
32a655c1 | 300 | match self.hir.span_if_local(found.def_id) { |
b039eaaf | 301 | Some(span) => { |
9cc50fc6 | 302 | db.span_note(span, "a second default was defined here..."); |
e9174d1e | 303 | } |
b039eaaf | 304 | None => { |
8bb4bdeb | 305 | let item_def_id = self.parent(found.def_id).unwrap(); |
9cc50fc6 | 306 | db.note(&format!("a second default is defined on `{}`", |
8bb4bdeb | 307 | self.item_path_str(item_def_id))); |
e9174d1e SL |
308 | } |
309 | } | |
310 | ||
9cc50fc6 SL |
311 | db.span_note(found.origin_span, |
312 | "...that also applies to the same type variable here"); | |
e9174d1e SL |
313 | } |
314 | _ => {} | |
315 | } | |
316 | } | |
317 | } |