]>
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, | |
cc61c64b | 26 | pub found: T, |
e9174d1e SL |
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, |
7cac9316 XL |
39 | RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), |
40 | RegionsNotSame(Region<'tcx>, Region<'tcx>), | |
41 | RegionsNoOverlap(Region<'tcx>, Region<'tcx>), | |
42 | RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>, Option<Box<ty::Issue32330>>), | |
43 | RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>, 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, _, _) => { |
7cac9316 XL |
120 | write!(f, |
121 | "expected bound lifetime parameter{}{}, found concrete lifetime", | |
122 | if br.is_named() { " " } else { "" }, | |
123 | br) | |
e9174d1e | 124 | } |
8bb4bdeb | 125 | RegionsOverlyPolymorphic(br, _, _) => { |
7cac9316 XL |
126 | write!(f, |
127 | "expected concrete lifetime, found bound lifetime parameter{}{}", | |
128 | if br.is_named() { " " } else { "" }, | |
129 | br) | |
e9174d1e SL |
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 | }), | |
e9174d1e SL |
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 | } | |
e9174d1e SL |
157 | ProjectionNameMismatched(ref values) => { |
158 | write!(f, "expected {}, found {}", | |
159 | values.expected, | |
160 | 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 | } | |
476ff2be SL |
172 | ExistentialMismatch(ref values) => { |
173 | report_maybe_different(f, format!("trait `{}`", values.expected), | |
174 | format!("trait `{}`", values.found)) | |
175 | } | |
e9174d1e SL |
176 | } |
177 | } | |
178 | } | |
179 | ||
a7813a04 | 180 | impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { |
9e0c209e | 181 | pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { |
e9174d1e SL |
182 | match self.sty { |
183 | ty::TyBool | ty::TyChar | ty::TyInt(_) | | |
5bcae85e | 184 | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), |
8bb4bdeb | 185 | ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(), |
e9174d1e | 186 | |
9e0c209e | 187 | ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), |
e9174d1e SL |
188 | ty::TyArray(_, n) => format!("array of {} elements", n), |
189 | ty::TySlice(_) => "slice".to_string(), | |
190 | ty::TyRawPtr(_) => "*-ptr".to_string(), | |
5bcae85e SL |
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 | } | |
54a0048b SL |
209 | ty::TyFnDef(..) => format!("fn item"), |
210 | ty::TyFnPtr(_) => "fn pointer".to_string(), | |
476ff2be SL |
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()))) | |
e9174d1e SL |
214 | } |
215 | ty::TyClosure(..) => "closure".to_string(), | |
8bb4bdeb | 216 | ty::TyTuple(..) => "tuple".to_string(), |
e9174d1e SL |
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) => { | |
9e0c209e | 225 | if p.is_self() { |
e9174d1e SL |
226 | "Self".to_string() |
227 | } else { | |
228 | "type parameter".to_string() | |
229 | } | |
230 | } | |
5bcae85e | 231 | ty::TyAnon(..) => "anonymized type".to_string(), |
e9174d1e SL |
232 | ty::TyError => "type error".to_string(), |
233 | } | |
234 | } | |
235 | } | |
236 | ||
a7813a04 XL |
237 | impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
238 | pub fn note_and_explain_type_err(self, | |
9cc50fc6 SL |
239 | db: &mut DiagnosticBuilder, |
240 | err: &TypeError<'tcx>, | |
241 | sp: Span) { | |
e9174d1e SL |
242 | use self::TypeError::*; |
243 | ||
244 | match err.clone() { | |
245 | RegionsDoesNotOutlive(subregion, superregion) => { | |
9cc50fc6 SL |
246 | self.note_and_explain_region(db, "", subregion, "..."); |
247 | self.note_and_explain_region(db, "...does not necessarily outlive ", | |
e9174d1e SL |
248 | superregion, ""); |
249 | } | |
250 | RegionsNotSame(region1, region2) => { | |
9cc50fc6 SL |
251 | self.note_and_explain_region(db, "", region1, "..."); |
252 | self.note_and_explain_region(db, "...is not the same lifetime as ", | |
e9174d1e SL |
253 | region2, ""); |
254 | } | |
255 | RegionsNoOverlap(region1, region2) => { | |
9cc50fc6 SL |
256 | self.note_and_explain_region(db, "", region1, "..."); |
257 | self.note_and_explain_region(db, "...does not overlap ", | |
e9174d1e SL |
258 | region2, ""); |
259 | } | |
8bb4bdeb | 260 | RegionsInsufficientlyPolymorphic(_, conc_region, _) => { |
9cc50fc6 | 261 | self.note_and_explain_region(db, "concrete lifetime that was found is ", |
e9174d1e SL |
262 | conc_region, ""); |
263 | } | |
8bb4bdeb | 264 | RegionsOverlyPolymorphic(_, &ty::ReVar(_), _) => { |
e9174d1e SL |
265 | // don't bother to print out the message below for |
266 | // inference variables, it's not very illuminating. | |
267 | } | |
8bb4bdeb | 268 | RegionsOverlyPolymorphic(_, conc_region, _) => { |
9cc50fc6 | 269 | self.note_and_explain_region(db, "expected concrete lifetime is ", |
e9174d1e SL |
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" { | |
9cc50fc6 | 276 | db.span_note(sp, |
92a42be0 | 277 | "no two closures, even if identical, have the same type"); |
9cc50fc6 | 278 | db.span_help(sp, |
92a42be0 | 279 | "consider boxing your closure and/or using it as a trait object"); |
e9174d1e SL |
280 | } |
281 | }, | |
282 | TyParamDefaultMismatch(values) => { | |
283 | let expected = values.expected; | |
284 | let found = values.found; | |
9cc50fc6 SL |
285 | db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`", |
286 | expected.ty, | |
287 | found.ty)); | |
e9174d1e | 288 | |
32a655c1 | 289 | match self.hir.span_if_local(expected.def_id) { |
b039eaaf | 290 | Some(span) => { |
9cc50fc6 | 291 | db.span_note(span, "a default was defined here..."); |
e9174d1e | 292 | } |
b039eaaf | 293 | None => { |
8bb4bdeb | 294 | let item_def_id = self.parent(expected.def_id).unwrap(); |
9cc50fc6 | 295 | db.note(&format!("a default is defined on `{}`", |
8bb4bdeb | 296 | self.item_path_str(item_def_id))); |
e9174d1e SL |
297 | } |
298 | } | |
299 | ||
9cc50fc6 | 300 | db.span_note( |
e9174d1e | 301 | expected.origin_span, |
92a42be0 | 302 | "...that was applied to an unconstrained type variable here"); |
e9174d1e | 303 | |
32a655c1 | 304 | match self.hir.span_if_local(found.def_id) { |
b039eaaf | 305 | Some(span) => { |
9cc50fc6 | 306 | db.span_note(span, "a second default was defined here..."); |
e9174d1e | 307 | } |
b039eaaf | 308 | None => { |
8bb4bdeb | 309 | let item_def_id = self.parent(found.def_id).unwrap(); |
9cc50fc6 | 310 | db.note(&format!("a second default is defined on `{}`", |
8bb4bdeb | 311 | self.item_path_str(item_def_id))); |
e9174d1e SL |
312 | } |
313 | } | |
314 | ||
9cc50fc6 SL |
315 | db.span_note(found.origin_span, |
316 | "...that also applies to the same type variable here"); | |
e9174d1e SL |
317 | } |
318 | _ => {} | |
319 | } | |
320 | } | |
321 | } |