]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2013 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 | //! Error Reporting Code for the inference engine | |
12 | //! | |
13 | //! Because of the way inference, and in particular region inference, | |
14 | //! works, it often happens that errors are not detected until far after | |
15 | //! the relevant line of code has been type-checked. Therefore, there is | |
16 | //! an elaborate system to track why a particular constraint in the | |
17 | //! inference graph arose so that we can explain to the user what gave | |
18 | //! rise to a particular error. | |
19 | //! | |
20 | //! The basis of the system are the "origin" types. An "origin" is the | |
21 | //! reason that a constraint or inference variable arose. There are | |
22 | //! different "origin" enums for different kinds of constraints/variables | |
23 | //! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has | |
24 | //! a span, but also more information so that we can generate a meaningful | |
25 | //! error message. | |
26 | //! | |
27 | //! Having a catalogue of all the different reasons an error can arise is | |
28 | //! also useful for other reasons, like cross-referencing FAQs etc, though | |
29 | //! we are not really taking advantage of this yet. | |
30 | //! | |
31 | //! # Region Inference | |
32 | //! | |
33 | //! Region inference is particularly tricky because it always succeeds "in | |
34 | //! the moment" and simply registers a constraint. Then, at the end, we | |
35 | //! can compute the full graph and report errors, so we need to be able to | |
36 | //! store and later report what gave rise to the conflicting constraints. | |
37 | //! | |
38 | //! # Subtype Trace | |
39 | //! | |
40 | //! Determining whether `T1 <: T2` often involves a number of subtypes and | |
41 | //! subconstraints along the way. A "TypeTrace" is an extended version | |
42 | //! of an origin that traces the types and other values that were being | |
43 | //! compared. It is not necessarily comprehensive (in fact, at the time of | |
44 | //! this writing it only tracks the root values being compared) but I'd | |
45 | //! like to extend it to include significant "waypoints". For example, if | |
46 | //! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2 | |
47 | //! <: T4` fails, I'd like the trace to include enough information to say | |
48 | //! "in the 2nd element of the tuple". Similarly, failures when comparing | |
49 | //! arguments or return types in fn types should be able to cite the | |
50 | //! specific position, etc. | |
51 | //! | |
52 | //! # Reality vs plan | |
53 | //! | |
54 | //! Of course, there is still a LOT of code in typeck that has yet to be | |
55 | //! ported to this system, and which relies on string concatenation at the | |
56 | //! time of error detection. | |
57 | ||
8bb4bdeb XL |
58 | use infer; |
59 | use super::{InferCtxt, TypeTrace, SubregionOrigin, RegionVariableOrigin, ValuePairs}; | |
60 | use super::region_inference::{RegionResolutionError, ConcreteFailure, SubSupConflict, | |
61 | GenericBoundFailure, GenericKind}; | |
e9174d1e | 62 | |
8bb4bdeb | 63 | use std::fmt; |
54a0048b | 64 | use hir; |
8bb4bdeb | 65 | use hir::map as hir_map; |
54a0048b | 66 | use hir::def_id::DefId; |
62682a34 | 67 | use middle::region; |
476ff2be | 68 | use traits::{ObligationCause, ObligationCauseCode}; |
5bcae85e | 69 | use ty::{self, TyCtxt, TypeFoldable}; |
8bb4bdeb | 70 | use ty::{Region, Issue32330}; |
54a0048b | 71 | use ty::error::TypeError; |
7cac9316 | 72 | use syntax::ast::DUMMY_NODE_ID; |
32a655c1 | 73 | use syntax_pos::{Pos, Span}; |
cc61c64b | 74 | use errors::{DiagnosticBuilder, DiagnosticStyledString}; |
1a4d82fc | 75 | |
8bb4bdeb XL |
76 | mod note; |
77 | ||
a7813a04 XL |
78 | impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
79 | pub fn note_and_explain_region(self, | |
9cc50fc6 | 80 | err: &mut DiagnosticBuilder, |
c1a9b12d | 81 | prefix: &str, |
7cac9316 | 82 | region: ty::Region<'tcx>, |
c1a9b12d | 83 | suffix: &str) { |
e9174d1e | 84 | fn item_scope_tag(item: &hir::Item) -> &'static str { |
c1a9b12d | 85 | match item.node { |
e9174d1e SL |
86 | hir::ItemImpl(..) => "impl", |
87 | hir::ItemStruct(..) => "struct", | |
9e0c209e | 88 | hir::ItemUnion(..) => "union", |
e9174d1e SL |
89 | hir::ItemEnum(..) => "enum", |
90 | hir::ItemTrait(..) => "trait", | |
91 | hir::ItemFn(..) => "function body", | |
c1a9b12d SL |
92 | _ => "item" |
93 | } | |
62682a34 | 94 | } |
62682a34 | 95 | |
476ff2be SL |
96 | fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str { |
97 | match item.node { | |
32a655c1 SL |
98 | hir::TraitItemKind::Method(..) => "method body", |
99 | hir::TraitItemKind::Const(..) | | |
100 | hir::TraitItemKind::Type(..) => "associated item" | |
476ff2be SL |
101 | } |
102 | } | |
103 | ||
104 | fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str { | |
105 | match item.node { | |
106 | hir::ImplItemKind::Method(..) => "method body", | |
107 | hir::ImplItemKind::Const(..) | | |
108 | hir::ImplItemKind::Type(_) => "associated item" | |
109 | } | |
110 | } | |
111 | ||
a7813a04 XL |
112 | fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, |
113 | heading: &str, span: Span) | |
114 | -> (String, Option<Span>) { | |
c1a9b12d | 115 | let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo); |
7cac9316 | 116 | (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), |
c1a9b12d | 117 | Some(span)) |
62682a34 SL |
118 | } |
119 | ||
9e0c209e | 120 | let (description, span) = match *region { |
c1a9b12d SL |
121 | ty::ReScope(scope) => { |
122 | let new_string; | |
123 | let unknown_scope = || { | |
124 | format!("{}unknown scope: {:?}{}. Please report a bug.", | |
125 | prefix, scope, suffix) | |
126 | }; | |
7cac9316 | 127 | let span = match scope.span(&self.hir) { |
c1a9b12d | 128 | Some(s) => s, |
9cc50fc6 SL |
129 | None => { |
130 | err.note(&unknown_scope()); | |
131 | return; | |
132 | } | |
c1a9b12d | 133 | }; |
7cac9316 | 134 | let tag = match self.hir.find(scope.node_id()) { |
32a655c1 SL |
135 | Some(hir_map::NodeBlock(_)) => "block", |
136 | Some(hir_map::NodeExpr(expr)) => match expr.node { | |
e9174d1e SL |
137 | hir::ExprCall(..) => "call", |
138 | hir::ExprMethodCall(..) => "method call", | |
9e0c209e SL |
139 | hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", |
140 | hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) => "while let", | |
141 | hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) => "for", | |
e9174d1e | 142 | hir::ExprMatch(..) => "match", |
c1a9b12d SL |
143 | _ => "expression", |
144 | }, | |
32a655c1 SL |
145 | Some(hir_map::NodeStmt(_)) => "statement", |
146 | Some(hir_map::NodeItem(it)) => item_scope_tag(&it), | |
147 | Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it), | |
148 | Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it), | |
c1a9b12d | 149 | Some(_) | None => { |
9cc50fc6 SL |
150 | err.span_note(span, &unknown_scope()); |
151 | return; | |
c1a9b12d SL |
152 | } |
153 | }; | |
7cac9316 XL |
154 | let scope_decorated_tag = match scope { |
155 | region::CodeExtent::Misc(_) => tag, | |
156 | region::CodeExtent::CallSiteScope(_) => { | |
9cc50fc6 SL |
157 | "scope of call-site for function" |
158 | } | |
7cac9316 | 159 | region::CodeExtent::ParameterScope(_) => { |
a7813a04 | 160 | "scope of function body" |
c1a9b12d | 161 | } |
7cac9316 | 162 | region::CodeExtent::DestructionScope(_) => { |
c1a9b12d SL |
163 | new_string = format!("destruction scope surrounding {}", tag); |
164 | &new_string[..] | |
165 | } | |
7cac9316 | 166 | region::CodeExtent::Remainder(r) => { |
c1a9b12d SL |
167 | new_string = format!("block suffix following statement {}", |
168 | r.first_statement_index); | |
169 | &new_string[..] | |
170 | } | |
171 | }; | |
172 | explain_span(self, scope_decorated_tag, span) | |
173 | } | |
62682a34 | 174 | |
7cac9316 XL |
175 | ty::ReEarlyBound(_) | |
176 | ty::ReFree(_) => { | |
177 | let scope = match *region { | |
178 | ty::ReEarlyBound(ref br) => { | |
179 | self.parent_def_id(br.def_id).unwrap() | |
c1a9b12d | 180 | } |
7cac9316 XL |
181 | ty::ReFree(ref fr) => fr.scope, |
182 | _ => bug!() | |
183 | }; | |
184 | let prefix = match *region { | |
185 | ty::ReEarlyBound(ref br) => { | |
186 | format!("the lifetime {} as defined on", br.name) | |
187 | } | |
188 | ty::ReFree(ref fr) => { | |
189 | match fr.bound_region { | |
190 | ty::BrAnon(idx) => { | |
191 | format!("the anonymous lifetime #{} defined on", idx + 1) | |
192 | } | |
193 | ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(), | |
194 | _ => { | |
195 | format!("the lifetime {} as defined on", | |
196 | fr.bound_region) | |
197 | } | |
198 | } | |
c1a9b12d | 199 | } |
7cac9316 | 200 | _ => bug!() |
c1a9b12d SL |
201 | }; |
202 | ||
7cac9316 XL |
203 | let node = self.hir.as_local_node_id(scope) |
204 | .unwrap_or(DUMMY_NODE_ID); | |
476ff2be | 205 | let unknown; |
32a655c1 SL |
206 | let tag = match self.hir.find(node) { |
207 | Some(hir_map::NodeBlock(_)) | | |
208 | Some(hir_map::NodeExpr(_)) => "body", | |
209 | Some(hir_map::NodeItem(it)) => item_scope_tag(&it), | |
210 | Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it), | |
211 | Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it), | |
476ff2be SL |
212 | |
213 | // this really should not happen, but it does: | |
214 | // FIXME(#27942) | |
215 | Some(_) => { | |
216 | unknown = format!("unexpected node ({}) for scope {:?}. \ | |
217 | Please report a bug.", | |
7cac9316 | 218 | self.hir.node_to_string(node), scope); |
476ff2be | 219 | &unknown |
c1a9b12d | 220 | } |
476ff2be SL |
221 | None => { |
222 | unknown = format!("unknown node for scope {:?}. \ | |
7cac9316 | 223 | Please report a bug.", scope); |
476ff2be | 224 | &unknown |
c1a9b12d | 225 | } |
476ff2be | 226 | }; |
32a655c1 | 227 | let (msg, opt_span) = explain_span(self, tag, self.hir.span(node)); |
476ff2be | 228 | (format!("{} {}", prefix, msg), opt_span) |
62682a34 | 229 | } |
62682a34 | 230 | |
c1a9b12d | 231 | ty::ReStatic => ("the static lifetime".to_owned(), None), |
62682a34 | 232 | |
c1a9b12d | 233 | ty::ReEmpty => ("the empty lifetime".to_owned(), None), |
62682a34 | 234 | |
e9174d1e SL |
235 | // FIXME(#13998) ReSkolemized should probably print like |
236 | // ReFree rather than dumping Debug output on the user. | |
237 | // | |
238 | // We shouldn't really be having unification failures with ReVar | |
239 | // and ReLateBound though. | |
3157f602 XL |
240 | ty::ReSkolemized(..) | |
241 | ty::ReVar(_) | | |
242 | ty::ReLateBound(..) | | |
243 | ty::ReErased => { | |
c1a9b12d SL |
244 | (format!("lifetime {:?}", region), None) |
245 | } | |
246 | }; | |
247 | let message = format!("{}{}{}", prefix, description, suffix); | |
248 | if let Some(span) = span { | |
9cc50fc6 | 249 | err.span_note(span, &message); |
c1a9b12d | 250 | } else { |
9cc50fc6 | 251 | err.note(&message); |
62682a34 | 252 | } |
62682a34 SL |
253 | } |
254 | } | |
1a4d82fc | 255 | |
a7813a04 XL |
256 | impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { |
257 | pub fn report_region_errors(&self, | |
258 | errors: &Vec<RegionResolutionError<'tcx>>) { | |
54a0048b SL |
259 | debug!("report_region_errors(): {} errors to start", errors.len()); |
260 | ||
261 | // try to pre-process the errors, which will group some of them | |
262 | // together into a `ProcessedErrors` group: | |
32a655c1 | 263 | let errors = self.process_errors(errors); |
54a0048b SL |
264 | |
265 | debug!("report_region_errors: {} errors after preprocessing", errors.len()); | |
266 | ||
85aaf69f | 267 | for error in errors { |
c30ab7b3 | 268 | debug!("report_region_errors: error = {:?}", error); |
1a4d82fc JJ |
269 | match error.clone() { |
270 | ConcreteFailure(origin, sub, sup) => { | |
54a0048b | 271 | self.report_concrete_failure(origin, sub, sup).emit(); |
1a4d82fc JJ |
272 | } |
273 | ||
e9174d1e SL |
274 | GenericBoundFailure(kind, param_ty, sub) => { |
275 | self.report_generic_bound_failure(kind, param_ty, sub); | |
1a4d82fc JJ |
276 | } |
277 | ||
278 | SubSupConflict(var_origin, | |
279 | sub_origin, sub_r, | |
280 | sup_origin, sup_r) => { | |
281 | self.report_sub_sup_conflict(var_origin, | |
282 | sub_origin, sub_r, | |
283 | sup_origin, sup_r); | |
284 | } | |
1a4d82fc JJ |
285 | } |
286 | } | |
287 | } | |
288 | ||
289 | // This method goes through all the errors and try to group certain types | |
290 | // of error together, for the purpose of suggesting explicit lifetime | |
291 | // parameters to the user. This is done so that we can have a more | |
292 | // complete view of what lifetimes should be the same. | |
293 | // If the return value is an empty vector, it means that processing | |
54a0048b SL |
294 | // failed (so the return value of this method should not be used). |
295 | // | |
296 | // The method also attempts to weed out messages that seem like | |
297 | // duplicates that will be unhelpful to the end-user. But | |
298 | // obviously it never weeds out ALL errors. | |
1a4d82fc | 299 | fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) |
32a655c1 | 300 | -> Vec<RegionResolutionError<'tcx>> { |
1a4d82fc | 301 | debug!("process_errors()"); |
54a0048b | 302 | |
32a655c1 SL |
303 | // We want to avoid reporting generic-bound failures if we can |
304 | // avoid it: these have a very high rate of being unhelpful in | |
305 | // practice. This is because they are basically secondary | |
306 | // checks that test the state of the region graph after the | |
307 | // rest of inference is done, and the other kinds of errors | |
308 | // indicate that the region constraint graph is internally | |
309 | // inconsistent, so these test results are likely to be | |
310 | // meaningless. | |
311 | // | |
312 | // Therefore, we filter them out of the list unless they are | |
313 | // the only thing in the list. | |
314 | ||
315 | let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e { | |
316 | ConcreteFailure(..) => false, | |
317 | SubSupConflict(..) => false, | |
318 | GenericBoundFailure(..) => true, | |
319 | }; | |
1a4d82fc | 320 | |
32a655c1 SL |
321 | if errors.iter().all(|e| is_bound_failure(e)) { |
322 | errors.clone() | |
323 | } else { | |
324 | errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect() | |
1a4d82fc JJ |
325 | } |
326 | } | |
327 | ||
e9174d1e | 328 | /// Adds a note if the types come from similarly named crates |
9cc50fc6 SL |
329 | fn check_and_note_conflicting_crates(&self, |
330 | err: &mut DiagnosticBuilder, | |
331 | terr: &TypeError<'tcx>, | |
332 | sp: Span) { | |
333 | let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| { | |
e9174d1e SL |
334 | // Only external crates, if either is from a local |
335 | // module we could have false positives | |
336 | if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { | |
54a0048b SL |
337 | let exp_path = self.tcx.item_path_str(did1); |
338 | let found_path = self.tcx.item_path_str(did2); | |
339 | // We compare strings because DefPath can be different | |
e9174d1e SL |
340 | // for imported and non-imported crates |
341 | if exp_path == found_path { | |
92a42be0 | 342 | let crate_name = self.tcx.sess.cstore.crate_name(did1.krate); |
9cc50fc6 SL |
343 | err.span_note(sp, &format!("Perhaps two different versions \ |
344 | of crate `{}` are being used?", | |
345 | crate_name)); | |
e9174d1e SL |
346 | } |
347 | } | |
348 | }; | |
349 | match *terr { | |
350 | TypeError::Sorts(ref exp_found) => { | |
351 | // if they are both "path types", there's a chance of ambiguity | |
352 | // due to different versions of the same crate | |
353 | match (&exp_found.expected.sty, &exp_found.found.sty) { | |
9e0c209e | 354 | (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => { |
9cc50fc6 | 355 | report_path_match(err, exp_adt.did, found_adt.did); |
e9174d1e SL |
356 | }, |
357 | _ => () | |
358 | } | |
359 | }, | |
360 | TypeError::Traits(ref exp_found) => { | |
9cc50fc6 | 361 | report_path_match(err, exp_found.expected, exp_found.found); |
e9174d1e SL |
362 | }, |
363 | _ => () // FIXME(#22750) handle traits and stuff | |
364 | } | |
365 | } | |
366 | ||
5bcae85e SL |
367 | fn note_error_origin(&self, |
368 | err: &mut DiagnosticBuilder<'tcx>, | |
476ff2be | 369 | cause: &ObligationCause<'tcx>) |
5bcae85e | 370 | { |
476ff2be SL |
371 | match cause.code { |
372 | ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source { | |
5bcae85e SL |
373 | hir::MatchSource::IfLetDesugar {..} => { |
374 | err.span_note(arm_span, "`if let` arm with an incompatible type"); | |
375 | } | |
376 | _ => { | |
377 | err.span_note(arm_span, "match arm with an incompatible type"); | |
378 | } | |
379 | }, | |
380 | _ => () | |
381 | } | |
382 | } | |
383 | ||
cc61c64b XL |
384 | /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` |
385 | /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and | |
386 | /// populate `other_value` with `other_ty`. | |
387 | /// | |
388 | /// ```text | |
389 | /// Foo<Bar<Qux>> | |
390 | /// ^^^^--------^ this is highlighted | |
391 | /// | | | |
392 | /// | this type argument is exactly the same as the other type, not highlighted | |
393 | /// this is highlighted | |
394 | /// Bar<Qux> | |
395 | /// -------- this type is the same as a type argument in the other type, not highlighted | |
396 | /// ``` | |
397 | fn highlight_outer(&self, | |
398 | mut value: &mut DiagnosticStyledString, | |
399 | mut other_value: &mut DiagnosticStyledString, | |
400 | name: String, | |
401 | sub: &ty::subst::Substs<'tcx>, | |
402 | pos: usize, | |
403 | other_ty: &ty::Ty<'tcx>) { | |
404 | // `value` and `other_value` hold two incomplete type representation for display. | |
405 | // `name` is the path of both types being compared. `sub` | |
406 | value.push_highlighted(name); | |
407 | let len = sub.len(); | |
408 | if len > 0 { | |
409 | value.push_highlighted("<"); | |
410 | } | |
411 | ||
412 | // Output the lifetimes fot the first type | |
413 | let lifetimes = sub.regions().map(|lifetime| { | |
414 | let s = format!("{}", lifetime); | |
415 | if s.is_empty() { | |
416 | "'_".to_string() | |
417 | } else { | |
418 | s | |
419 | } | |
420 | }).collect::<Vec<_>>().join(", "); | |
421 | if !lifetimes.is_empty() { | |
422 | if sub.regions().count() < len { | |
423 | value.push_normal(lifetimes + &", "); | |
424 | } else { | |
425 | value.push_normal(lifetimes); | |
426 | } | |
427 | } | |
428 | ||
429 | // Highlight all the type arguments that aren't at `pos` and compare the type argument at | |
430 | // `pos` and `other_ty`. | |
431 | for (i, type_arg) in sub.types().enumerate() { | |
432 | if i == pos { | |
433 | let values = self.cmp(type_arg, other_ty); | |
434 | value.0.extend((values.0).0); | |
435 | other_value.0.extend((values.1).0); | |
436 | } else { | |
437 | value.push_highlighted(format!("{}", type_arg)); | |
438 | } | |
439 | ||
440 | if len > 0 && i != len - 1 { | |
441 | value.push_normal(", "); | |
442 | } | |
443 | //self.push_comma(&mut value, &mut other_value, len, i); | |
444 | } | |
445 | if len > 0 { | |
446 | value.push_highlighted(">"); | |
447 | } | |
448 | } | |
449 | ||
450 | /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, | |
451 | /// as that is the difference to the other type. | |
452 | /// | |
453 | /// For the following code: | |
454 | /// | |
455 | /// ```norun | |
456 | /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>(); | |
457 | /// ``` | |
458 | /// | |
459 | /// The type error output will behave in the following way: | |
460 | /// | |
461 | /// ```text | |
462 | /// Foo<Bar<Qux>> | |
463 | /// ^^^^--------^ this is highlighted | |
464 | /// | | | |
465 | /// | this type argument is exactly the same as the other type, not highlighted | |
466 | /// this is highlighted | |
467 | /// Bar<Qux> | |
468 | /// -------- this type is the same as a type argument in the other type, not highlighted | |
469 | /// ``` | |
470 | fn cmp_type_arg(&self, | |
471 | mut t1_out: &mut DiagnosticStyledString, | |
472 | mut t2_out: &mut DiagnosticStyledString, | |
473 | path: String, | |
474 | sub: &ty::subst::Substs<'tcx>, | |
475 | other_path: String, | |
476 | other_ty: &ty::Ty<'tcx>) -> Option<()> { | |
477 | for (i, ta) in sub.types().enumerate() { | |
478 | if &ta == other_ty { | |
479 | self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); | |
480 | return Some(()); | |
481 | } | |
482 | if let &ty::TyAdt(def, _) = &ta.sty { | |
483 | let path_ = self.tcx.item_path_str(def.did.clone()); | |
484 | if path_ == other_path { | |
485 | self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); | |
486 | return Some(()); | |
487 | } | |
488 | } | |
489 | } | |
490 | None | |
491 | } | |
492 | ||
493 | /// Add a `,` to the type representation only if it is appropriate. | |
494 | fn push_comma(&self, | |
495 | value: &mut DiagnosticStyledString, | |
496 | other_value: &mut DiagnosticStyledString, | |
497 | len: usize, | |
498 | pos: usize) { | |
499 | if len > 0 && pos != len - 1 { | |
500 | value.push_normal(", "); | |
501 | other_value.push_normal(", "); | |
502 | } | |
503 | } | |
504 | ||
505 | /// Compare two given types, eliding parts that are the same between them and highlighting | |
506 | /// relevant differences, and return two representation of those types for highlighted printing. | |
507 | fn cmp(&self, t1: ty::Ty<'tcx>, t2: ty::Ty<'tcx>) | |
508 | -> (DiagnosticStyledString, DiagnosticStyledString) | |
509 | { | |
510 | match (&t1.sty, &t2.sty) { | |
511 | (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { | |
512 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); | |
513 | let path1 = self.tcx.item_path_str(def1.did.clone()); | |
514 | let path2 = self.tcx.item_path_str(def2.did.clone()); | |
515 | if def1.did == def2.did { | |
516 | // Easy case. Replace same types with `_` to shorten the output and highlight | |
517 | // the differing ones. | |
518 | // let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>(); | |
519 | // Foo<Bar, _> | |
520 | // Foo<Quz, _> | |
521 | // --- ^ type argument elided | |
522 | // | | |
523 | // highlighted in output | |
524 | values.0.push_normal(path1); | |
525 | values.1.push_normal(path2); | |
526 | ||
527 | // Only draw `<...>` if there're lifetime/type arguments. | |
528 | let len = sub1.len(); | |
529 | if len > 0 { | |
530 | values.0.push_normal("<"); | |
531 | values.1.push_normal("<"); | |
532 | } | |
533 | ||
7cac9316 | 534 | fn lifetime_display(lifetime: Region) -> String { |
cc61c64b XL |
535 | let s = format!("{}", lifetime); |
536 | if s.is_empty() { | |
537 | "'_".to_string() | |
538 | } else { | |
539 | s | |
540 | } | |
541 | } | |
542 | // At one point we'd like to elide all lifetimes here, they are irrelevant for | |
543 | // all diagnostics that use this output | |
544 | // | |
545 | // Foo<'x, '_, Bar> | |
546 | // Foo<'y, '_, Qux> | |
547 | // ^^ ^^ --- type arguments are not elided | |
548 | // | | | |
549 | // | elided as they were the same | |
550 | // not elided, they were different, but irrelevant | |
551 | let lifetimes = sub1.regions().zip(sub2.regions()); | |
552 | for (i, lifetimes) in lifetimes.enumerate() { | |
553 | let l1 = lifetime_display(lifetimes.0); | |
554 | let l2 = lifetime_display(lifetimes.1); | |
555 | if l1 == l2 { | |
556 | values.0.push_normal("'_"); | |
557 | values.1.push_normal("'_"); | |
558 | } else { | |
559 | values.0.push_highlighted(l1); | |
560 | values.1.push_highlighted(l2); | |
561 | } | |
562 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
563 | } | |
564 | ||
565 | // We're comparing two types with the same path, so we compare the type | |
566 | // arguments for both. If they are the same, do not highlight and elide from the | |
567 | // output. | |
568 | // Foo<_, Bar> | |
569 | // Foo<_, Qux> | |
570 | // ^ elided type as this type argument was the same in both sides | |
571 | let type_arguments = sub1.types().zip(sub2.types()); | |
572 | let regions_len = sub1.regions().collect::<Vec<_>>().len(); | |
573 | for (i, (ta1, ta2)) in type_arguments.enumerate() { | |
574 | let i = i + regions_len; | |
575 | if ta1 == ta2 { | |
576 | values.0.push_normal("_"); | |
577 | values.1.push_normal("_"); | |
578 | } else { | |
579 | let (x1, x2) = self.cmp(ta1, ta2); | |
580 | (values.0).0.extend(x1.0); | |
581 | (values.1).0.extend(x2.0); | |
582 | } | |
583 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
584 | } | |
585 | ||
586 | // Close the type argument bracket. | |
587 | // Only draw `<...>` if there're lifetime/type arguments. | |
588 | if len > 0 { | |
589 | values.0.push_normal(">"); | |
590 | values.1.push_normal(">"); | |
591 | } | |
592 | values | |
593 | } else { | |
594 | // Check for case: | |
595 | // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>(); | |
596 | // Foo<Bar<Qux> | |
597 | // ------- this type argument is exactly the same as the other type | |
598 | // Bar<Qux> | |
599 | if self.cmp_type_arg(&mut values.0, | |
600 | &mut values.1, | |
601 | path1.clone(), | |
602 | sub1, | |
603 | path2.clone(), | |
604 | &t2).is_some() { | |
605 | return values; | |
606 | } | |
607 | // Check for case: | |
608 | // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>(); | |
609 | // Bar<Qux> | |
610 | // Foo<Bar<Qux>> | |
611 | // ------- this type argument is exactly the same as the other type | |
612 | if self.cmp_type_arg(&mut values.1, | |
613 | &mut values.0, | |
614 | path2, | |
615 | sub2, | |
616 | path1, | |
617 | &t1).is_some() { | |
618 | return values; | |
619 | } | |
620 | ||
621 | // We couldn't find anything in common, highlight everything. | |
622 | // let x: Bar<Qux> = y::<Foo<Zar>>(); | |
623 | (DiagnosticStyledString::highlighted(format!("{}", t1)), | |
624 | DiagnosticStyledString::highlighted(format!("{}", t2))) | |
625 | } | |
626 | } | |
627 | _ => { | |
628 | if t1 == t2 { | |
629 | // The two types are the same, elide and don't highlight. | |
630 | (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) | |
631 | } else { | |
632 | // We couldn't find anything in common, highlight everything. | |
633 | (DiagnosticStyledString::highlighted(format!("{}", t1)), | |
634 | DiagnosticStyledString::highlighted(format!("{}", t2))) | |
635 | } | |
636 | } | |
637 | } | |
638 | } | |
639 | ||
5bcae85e SL |
640 | pub fn note_type_err(&self, |
641 | diag: &mut DiagnosticBuilder<'tcx>, | |
476ff2be | 642 | cause: &ObligationCause<'tcx>, |
9e0c209e | 643 | secondary_span: Option<(Span, String)>, |
5bcae85e SL |
644 | values: Option<ValuePairs<'tcx>>, |
645 | terr: &TypeError<'tcx>) | |
646 | { | |
8bb4bdeb XL |
647 | let (expected_found, is_simple_error) = match values { |
648 | None => (None, false), | |
649 | Some(values) => { | |
650 | let is_simple_error = match values { | |
651 | ValuePairs::Types(exp_found) => { | |
652 | exp_found.expected.is_primitive() && exp_found.found.is_primitive() | |
653 | } | |
654 | _ => false, | |
655 | }; | |
656 | let vals = match self.values_str(&values) { | |
657 | Some((expected, found)) => Some((expected, found)), | |
658 | None => { | |
659 | // Derived error. Cancel the emitter. | |
660 | self.tcx.sess.diagnostic().cancel(diag); | |
661 | return | |
662 | } | |
663 | }; | |
664 | (vals, is_simple_error) | |
5bcae85e SL |
665 | } |
666 | }; | |
667 | ||
476ff2be | 668 | let span = cause.span; |
5bcae85e SL |
669 | |
670 | if let Some((expected, found)) = expected_found { | |
8bb4bdeb | 671 | match (terr, is_simple_error, expected == found) { |
cc61c64b | 672 | (&TypeError::Sorts(ref values), false, true) => { |
8bb4bdeb | 673 | diag.note_expected_found_extra( |
cc61c64b | 674 | &"type", expected, found, |
8bb4bdeb XL |
675 | &format!(" ({})", values.expected.sort_string(self.tcx)), |
676 | &format!(" ({})", values.found.sort_string(self.tcx))); | |
677 | } | |
678 | (_, false, _) => { | |
cc61c64b | 679 | diag.note_expected_found(&"type", expected, found); |
9e0c209e | 680 | } |
8bb4bdeb | 681 | _ => (), |
5bcae85e SL |
682 | } |
683 | } | |
684 | ||
7cac9316 | 685 | diag.span_label(span, terr.to_string()); |
9e0c209e | 686 | if let Some((sp, msg)) = secondary_span { |
7cac9316 | 687 | diag.span_label(sp, msg); |
9e0c209e | 688 | } |
5bcae85e | 689 | |
476ff2be | 690 | self.note_error_origin(diag, &cause); |
5bcae85e SL |
691 | self.check_and_note_conflicting_crates(diag, terr, span); |
692 | self.tcx.note_and_explain_type_err(diag, terr, span); | |
693 | } | |
694 | ||
8bb4bdeb XL |
695 | pub fn note_issue_32330(&self, |
696 | diag: &mut DiagnosticBuilder<'tcx>, | |
697 | terr: &TypeError<'tcx>) | |
698 | { | |
699 | debug!("note_issue_32330: terr={:?}", terr); | |
700 | match *terr { | |
701 | TypeError::RegionsInsufficientlyPolymorphic(_, _, Some(box Issue32330 { | |
702 | fn_def_id, region_name | |
703 | })) | | |
704 | TypeError::RegionsOverlyPolymorphic(_, _, Some(box Issue32330 { | |
705 | fn_def_id, region_name | |
706 | })) => { | |
707 | diag.note( | |
708 | &format!("lifetime parameter `{0}` declared on fn `{1}` \ | |
709 | appears only in the return type, \ | |
710 | but here is required to be higher-ranked, \ | |
711 | which means that `{0}` must appear in both \ | |
712 | argument and return types", | |
713 | region_name, | |
714 | self.tcx.item_path_str(fn_def_id))); | |
715 | diag.note( | |
716 | &format!("this error is the result of a recent bug fix; \ | |
717 | for more information, see issue #33685 \ | |
718 | <https://github.com/rust-lang/rust/issues/33685>")); | |
719 | } | |
720 | _ => {} | |
721 | } | |
722 | } | |
723 | ||
a7813a04 XL |
724 | pub fn report_and_explain_type_error(&self, |
725 | trace: TypeTrace<'tcx>, | |
726 | terr: &TypeError<'tcx>) | |
5bcae85e SL |
727 | -> DiagnosticBuilder<'tcx> |
728 | { | |
476ff2be SL |
729 | let span = trace.cause.span; |
730 | let failure_str = trace.cause.as_failure_str(); | |
731 | let mut diag = match trace.cause.code { | |
732 | ObligationCauseCode::IfExpressionWithNoElse => { | |
c30ab7b3 | 733 | struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) |
32a655c1 SL |
734 | } |
735 | ObligationCauseCode::MainFunctionType => { | |
736 | struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) | |
737 | } | |
c30ab7b3 SL |
738 | _ => { |
739 | struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) | |
32a655c1 | 740 | } |
c30ab7b3 | 741 | }; |
476ff2be | 742 | self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); |
8bb4bdeb | 743 | self.note_issue_32330(&mut diag, terr); |
5bcae85e | 744 | diag |
1a4d82fc JJ |
745 | } |
746 | ||
cc61c64b XL |
747 | fn values_str(&self, values: &ValuePairs<'tcx>) |
748 | -> Option<(DiagnosticStyledString, DiagnosticStyledString)> | |
749 | { | |
1a4d82fc | 750 | match *values { |
cc61c64b | 751 | infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), |
1a4d82fc | 752 | infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), |
5bcae85e | 753 | infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), |
1a4d82fc JJ |
754 | } |
755 | } | |
756 | ||
cc61c64b XL |
757 | fn expected_found_str_ty(&self, |
758 | exp_found: &ty::error::ExpectedFound<ty::Ty<'tcx>>) | |
759 | -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { | |
760 | let exp_found = self.resolve_type_vars_if_possible(exp_found); | |
761 | if exp_found.references_error() { | |
762 | return None; | |
763 | } | |
764 | ||
765 | Some(self.cmp(exp_found.expected, exp_found.found)) | |
766 | } | |
767 | ||
768 | /// Returns a string of the form "expected `{}`, found `{}`". | |
5bcae85e | 769 | fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>( |
1a4d82fc | 770 | &self, |
e9174d1e | 771 | exp_found: &ty::error::ExpectedFound<T>) |
cc61c64b | 772 | -> Option<(DiagnosticStyledString, DiagnosticStyledString)> |
1a4d82fc | 773 | { |
5bcae85e SL |
774 | let exp_found = self.resolve_type_vars_if_possible(exp_found); |
775 | if exp_found.references_error() { | |
1a4d82fc JJ |
776 | return None; |
777 | } | |
778 | ||
cc61c64b XL |
779 | Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), |
780 | DiagnosticStyledString::highlighted(format!("{}", exp_found.found)))) | |
1a4d82fc JJ |
781 | } |
782 | ||
783 | fn report_generic_bound_failure(&self, | |
784 | origin: SubregionOrigin<'tcx>, | |
785 | bound_kind: GenericKind<'tcx>, | |
7cac9316 | 786 | sub: Region<'tcx>) |
1a4d82fc JJ |
787 | { |
788 | // FIXME: it would be better to report the first error message | |
789 | // with the span of the parameter itself, rather than the span | |
790 | // where the error was detected. But that span is not readily | |
791 | // accessible. | |
792 | ||
793 | let labeled_user_string = match bound_kind { | |
794 | GenericKind::Param(ref p) => | |
62682a34 | 795 | format!("the parameter type `{}`", p), |
1a4d82fc | 796 | GenericKind::Projection(ref p) => |
62682a34 | 797 | format!("the associated type `{}`", p), |
1a4d82fc JJ |
798 | }; |
799 | ||
c30ab7b3 SL |
800 | if let SubregionOrigin::CompareImplMethodObligation { |
801 | span, item_name, impl_item_def_id, trait_item_def_id, lint_id | |
802 | } = origin { | |
803 | self.report_extra_impl_obligation(span, | |
804 | item_name, | |
805 | impl_item_def_id, | |
806 | trait_item_def_id, | |
807 | &format!("`{}: {}`", bound_kind, sub), | |
808 | lint_id) | |
809 | .emit(); | |
810 | return; | |
811 | } | |
812 | ||
9e0c209e | 813 | let mut err = match *sub { |
7cac9316 | 814 | ty::ReEarlyBound(_) | |
1a4d82fc JJ |
815 | ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { |
816 | // Does the required lifetime have a nice name we can print? | |
9cc50fc6 SL |
817 | let mut err = struct_span_err!(self.tcx.sess, |
818 | origin.span(), | |
819 | E0309, | |
820 | "{} may not live long enough", | |
821 | labeled_user_string); | |
a7813a04 XL |
822 | err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...", |
823 | bound_kind, | |
824 | sub)); | |
9cc50fc6 | 825 | err |
1a4d82fc JJ |
826 | } |
827 | ||
828 | ty::ReStatic => { | |
829 | // Does the required lifetime have a nice name we can print? | |
9cc50fc6 SL |
830 | let mut err = struct_span_err!(self.tcx.sess, |
831 | origin.span(), | |
832 | E0310, | |
833 | "{} may not live long enough", | |
834 | labeled_user_string); | |
a7813a04 XL |
835 | err.help(&format!("consider adding an explicit lifetime \ |
836 | bound `{}: 'static`...", | |
837 | bound_kind)); | |
9cc50fc6 | 838 | err |
1a4d82fc JJ |
839 | } |
840 | ||
841 | _ => { | |
842 | // If not, be less specific. | |
9cc50fc6 SL |
843 | let mut err = struct_span_err!(self.tcx.sess, |
844 | origin.span(), | |
845 | E0311, | |
846 | "{} may not live long enough", | |
847 | labeled_user_string); | |
a7813a04 XL |
848 | err.help(&format!("consider adding an explicit lifetime bound for `{}`", |
849 | bound_kind)); | |
c1a9b12d | 850 | self.tcx.note_and_explain_region( |
9cc50fc6 | 851 | &mut err, |
c34b1796 | 852 | &format!("{} must be valid for ", labeled_user_string), |
1a4d82fc JJ |
853 | sub, |
854 | "..."); | |
9cc50fc6 | 855 | err |
1a4d82fc | 856 | } |
9cc50fc6 | 857 | }; |
e9174d1e | 858 | |
9cc50fc6 SL |
859 | self.note_region_origin(&mut err, &origin); |
860 | err.emit(); | |
1a4d82fc JJ |
861 | } |
862 | ||
1a4d82fc JJ |
863 | fn report_sub_sup_conflict(&self, |
864 | var_origin: RegionVariableOrigin, | |
865 | sub_origin: SubregionOrigin<'tcx>, | |
7cac9316 | 866 | sub_region: Region<'tcx>, |
1a4d82fc | 867 | sup_origin: SubregionOrigin<'tcx>, |
7cac9316 | 868 | sup_region: Region<'tcx>) { |
9cc50fc6 | 869 | let mut err = self.report_inference_failure(var_origin); |
1a4d82fc | 870 | |
9cc50fc6 | 871 | self.tcx.note_and_explain_region(&mut err, |
1a4d82fc JJ |
872 | "first, the lifetime cannot outlive ", |
873 | sup_region, | |
874 | "..."); | |
875 | ||
9cc50fc6 | 876 | self.note_region_origin(&mut err, &sup_origin); |
1a4d82fc | 877 | |
9cc50fc6 | 878 | self.tcx.note_and_explain_region(&mut err, |
1a4d82fc JJ |
879 | "but, the lifetime must be valid for ", |
880 | sub_region, | |
881 | "..."); | |
882 | ||
9cc50fc6 SL |
883 | self.note_region_origin(&mut err, &sub_origin); |
884 | err.emit(); | |
1a4d82fc | 885 | } |
1a4d82fc JJ |
886 | } |
887 | ||
a7813a04 | 888 | impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { |
1a4d82fc | 889 | fn report_inference_failure(&self, |
9cc50fc6 SL |
890 | var_origin: RegionVariableOrigin) |
891 | -> DiagnosticBuilder<'tcx> { | |
62682a34 SL |
892 | let br_string = |br: ty::BoundRegion| { |
893 | let mut s = br.to_string(); | |
894 | if !s.is_empty() { | |
895 | s.push_str(" "); | |
896 | } | |
897 | s | |
898 | }; | |
1a4d82fc JJ |
899 | let var_description = match var_origin { |
900 | infer::MiscVariable(_) => "".to_string(), | |
901 | infer::PatternRegion(_) => " for pattern".to_string(), | |
902 | infer::AddrOfRegion(_) => " for borrow expression".to_string(), | |
1a4d82fc JJ |
903 | infer::Autoref(_) => " for autoref".to_string(), |
904 | infer::Coercion(_) => " for automatic coercion".to_string(), | |
905 | infer::LateBoundRegion(_, br, infer::FnCall) => { | |
62682a34 SL |
906 | format!(" for lifetime parameter {}in function call", |
907 | br_string(br)) | |
1a4d82fc JJ |
908 | } |
909 | infer::LateBoundRegion(_, br, infer::HigherRankedType) => { | |
62682a34 | 910 | format!(" for lifetime parameter {}in generic type", br_string(br)) |
1a4d82fc JJ |
911 | } |
912 | infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => { | |
62682a34 | 913 | format!(" for lifetime parameter {}in trait containing associated type `{}`", |
c1a9b12d | 914 | br_string(br), type_name) |
1a4d82fc | 915 | } |
8bb4bdeb | 916 | infer::EarlyBoundRegion(_, name, _) => { |
1a4d82fc | 917 | format!(" for lifetime parameter `{}`", |
c1a9b12d | 918 | name) |
1a4d82fc JJ |
919 | } |
920 | infer::BoundRegionInCoherence(name) => { | |
921 | format!(" for lifetime parameter `{}` in coherence check", | |
c1a9b12d | 922 | name) |
1a4d82fc JJ |
923 | } |
924 | infer::UpvarRegion(ref upvar_id, _) => { | |
925 | format!(" for capture of `{}` by closure", | |
c1a9b12d | 926 | self.tcx.local_var_name_str(upvar_id.var_id).to_string()) |
1a4d82fc JJ |
927 | } |
928 | }; | |
929 | ||
9cc50fc6 | 930 | struct_span_err!(self.tcx.sess, var_origin.span(), E0495, |
b039eaaf SL |
931 | "cannot infer an appropriate lifetime{} \ |
932 | due to conflicting requirements", | |
9cc50fc6 | 933 | var_description) |
1a4d82fc | 934 | } |
1a4d82fc JJ |
935 | } |
936 | ||
476ff2be SL |
937 | impl<'tcx> ObligationCause<'tcx> { |
938 | fn as_failure_str(&self) -> &'static str { | |
939 | use traits::ObligationCauseCode::*; | |
940 | match self.code { | |
941 | CompareImplMethodObligation { .. } => "method not compatible with trait", | |
942 | MatchExpressionArm { source, .. } => match source { | |
943 | hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", | |
944 | _ => "match arms have incompatible types", | |
945 | }, | |
946 | IfExpression => "if and else have incompatible types", | |
947 | IfExpressionWithNoElse => "if may be missing an else clause", | |
948 | EquatePredicate => "equality predicate not satisfied", | |
949 | MainFunctionType => "main function has wrong type", | |
950 | StartFunctionType => "start function has wrong type", | |
951 | IntrinsicType => "intrinsic has wrong type", | |
952 | MethodReceiver => "mismatched method receiver", | |
953 | _ => "mismatched types", | |
954 | } | |
955 | } | |
956 | ||
957 | fn as_requirement_str(&self) -> &'static str { | |
958 | use traits::ObligationCauseCode::*; | |
959 | match self.code { | |
960 | CompareImplMethodObligation { .. } => "method type is compatible with trait", | |
961 | ExprAssignable => "expression is assignable", | |
962 | MatchExpressionArm { source, .. } => match source { | |
963 | hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types", | |
964 | _ => "match arms have compatible types", | |
965 | }, | |
966 | IfExpression => "if and else have compatible types", | |
967 | IfExpressionWithNoElse => "if missing an else returns ()", | |
968 | EquatePredicate => "equality where clause is satisfied", | |
969 | MainFunctionType => "`main` function has the correct type", | |
970 | StartFunctionType => "`start` function has the correct type", | |
971 | IntrinsicType => "intrinsic has the correct type", | |
972 | MethodReceiver => "method receiver has the correct type", | |
973 | _ => "types are compatible", | |
974 | } | |
975 | } | |
976 | } |