]>
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 | //! | |
3b2f2976 | 27 | //! Having a catalog of all the different reasons an error can arise is |
1a4d82fc JJ |
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}; | |
abe05a73 XL |
60 | use super::region_constraints::GenericKind; |
61 | use super::lexical_region_resolve::RegionResolutionError; | |
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}; |
abe05a73 | 69 | use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; |
54a0048b | 70 | use ty::error::TypeError; |
7cac9316 | 71 | use syntax::ast::DUMMY_NODE_ID; |
32a655c1 | 72 | use syntax_pos::{Pos, Span}; |
cc61c64b | 73 | use errors::{DiagnosticBuilder, DiagnosticStyledString}; |
1a4d82fc | 74 | |
ea8adc8c XL |
75 | use rustc_data_structures::indexed_vec::Idx; |
76 | ||
8bb4bdeb XL |
77 | mod note; |
78 | ||
041b39d2 | 79 | mod need_type_info; |
3b2f2976 | 80 | |
041b39d2 | 81 | mod named_anon_conflict; |
3b2f2976 XL |
82 | #[macro_use] |
83 | mod util; | |
ea8adc8c | 84 | mod different_lifetimes; |
041b39d2 | 85 | |
a7813a04 XL |
86 | impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
87 | pub fn note_and_explain_region(self, | |
ea8adc8c | 88 | region_scope_tree: ®ion::ScopeTree, |
9cc50fc6 | 89 | err: &mut DiagnosticBuilder, |
c1a9b12d | 90 | prefix: &str, |
7cac9316 | 91 | region: ty::Region<'tcx>, |
c1a9b12d | 92 | suffix: &str) { |
e9174d1e | 93 | fn item_scope_tag(item: &hir::Item) -> &'static str { |
c1a9b12d | 94 | match item.node { |
e9174d1e SL |
95 | hir::ItemImpl(..) => "impl", |
96 | hir::ItemStruct(..) => "struct", | |
9e0c209e | 97 | hir::ItemUnion(..) => "union", |
e9174d1e SL |
98 | hir::ItemEnum(..) => "enum", |
99 | hir::ItemTrait(..) => "trait", | |
100 | hir::ItemFn(..) => "function body", | |
c1a9b12d SL |
101 | _ => "item" |
102 | } | |
62682a34 | 103 | } |
62682a34 | 104 | |
476ff2be SL |
105 | fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str { |
106 | match item.node { | |
32a655c1 SL |
107 | hir::TraitItemKind::Method(..) => "method body", |
108 | hir::TraitItemKind::Const(..) | | |
109 | hir::TraitItemKind::Type(..) => "associated item" | |
476ff2be SL |
110 | } |
111 | } | |
112 | ||
113 | fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str { | |
114 | match item.node { | |
115 | hir::ImplItemKind::Method(..) => "method body", | |
116 | hir::ImplItemKind::Const(..) | | |
117 | hir::ImplItemKind::Type(_) => "associated item" | |
118 | } | |
119 | } | |
120 | ||
a7813a04 XL |
121 | fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, |
122 | heading: &str, span: Span) | |
123 | -> (String, Option<Span>) { | |
ea8adc8c | 124 | let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo()); |
7cac9316 | 125 | (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), |
c1a9b12d | 126 | Some(span)) |
62682a34 SL |
127 | } |
128 | ||
9e0c209e | 129 | let (description, span) = match *region { |
c1a9b12d SL |
130 | ty::ReScope(scope) => { |
131 | let new_string; | |
132 | let unknown_scope = || { | |
133 | format!("{}unknown scope: {:?}{}. Please report a bug.", | |
134 | prefix, scope, suffix) | |
135 | }; | |
ea8adc8c XL |
136 | let span = scope.span(self, region_scope_tree); |
137 | let tag = match self.hir.find(scope.node_id(self, region_scope_tree)) { | |
32a655c1 SL |
138 | Some(hir_map::NodeBlock(_)) => "block", |
139 | Some(hir_map::NodeExpr(expr)) => match expr.node { | |
e9174d1e SL |
140 | hir::ExprCall(..) => "call", |
141 | hir::ExprMethodCall(..) => "method call", | |
9e0c209e SL |
142 | hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", |
143 | hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) => "while let", | |
144 | hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) => "for", | |
e9174d1e | 145 | hir::ExprMatch(..) => "match", |
c1a9b12d SL |
146 | _ => "expression", |
147 | }, | |
32a655c1 SL |
148 | Some(hir_map::NodeStmt(_)) => "statement", |
149 | Some(hir_map::NodeItem(it)) => item_scope_tag(&it), | |
150 | Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it), | |
151 | Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it), | |
c1a9b12d | 152 | Some(_) | None => { |
9cc50fc6 SL |
153 | err.span_note(span, &unknown_scope()); |
154 | return; | |
c1a9b12d SL |
155 | } |
156 | }; | |
ea8adc8c XL |
157 | let scope_decorated_tag = match scope.data() { |
158 | region::ScopeData::Node(_) => tag, | |
159 | region::ScopeData::CallSite(_) => { | |
9cc50fc6 SL |
160 | "scope of call-site for function" |
161 | } | |
ea8adc8c | 162 | region::ScopeData::Arguments(_) => { |
a7813a04 | 163 | "scope of function body" |
c1a9b12d | 164 | } |
ea8adc8c | 165 | region::ScopeData::Destruction(_) => { |
c1a9b12d SL |
166 | new_string = format!("destruction scope surrounding {}", tag); |
167 | &new_string[..] | |
168 | } | |
ea8adc8c | 169 | region::ScopeData::Remainder(r) => { |
c1a9b12d | 170 | new_string = format!("block suffix following statement {}", |
ea8adc8c | 171 | r.first_statement_index.index()); |
c1a9b12d SL |
172 | &new_string[..] |
173 | } | |
174 | }; | |
175 | explain_span(self, scope_decorated_tag, span) | |
176 | } | |
62682a34 | 177 | |
7cac9316 XL |
178 | ty::ReEarlyBound(_) | |
179 | ty::ReFree(_) => { | |
abe05a73 | 180 | let scope = region.free_region_binding_scope(self); |
7cac9316 XL |
181 | let prefix = match *region { |
182 | ty::ReEarlyBound(ref br) => { | |
183 | format!("the lifetime {} as defined on", br.name) | |
184 | } | |
185 | ty::ReFree(ref fr) => { | |
186 | match fr.bound_region { | |
187 | ty::BrAnon(idx) => { | |
188 | format!("the anonymous lifetime #{} defined on", idx + 1) | |
189 | } | |
190 | ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(), | |
191 | _ => { | |
192 | format!("the lifetime {} as defined on", | |
193 | fr.bound_region) | |
194 | } | |
195 | } | |
c1a9b12d | 196 | } |
7cac9316 | 197 | _ => bug!() |
c1a9b12d SL |
198 | }; |
199 | ||
7cac9316 XL |
200 | let node = self.hir.as_local_node_id(scope) |
201 | .unwrap_or(DUMMY_NODE_ID); | |
476ff2be | 202 | let unknown; |
32a655c1 SL |
203 | let tag = match self.hir.find(node) { |
204 | Some(hir_map::NodeBlock(_)) | | |
205 | Some(hir_map::NodeExpr(_)) => "body", | |
206 | Some(hir_map::NodeItem(it)) => item_scope_tag(&it), | |
207 | Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it), | |
208 | Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it), | |
476ff2be SL |
209 | |
210 | // this really should not happen, but it does: | |
211 | // FIXME(#27942) | |
212 | Some(_) => { | |
213 | unknown = format!("unexpected node ({}) for scope {:?}. \ | |
214 | Please report a bug.", | |
7cac9316 | 215 | self.hir.node_to_string(node), scope); |
476ff2be | 216 | &unknown |
c1a9b12d | 217 | } |
476ff2be SL |
218 | None => { |
219 | unknown = format!("unknown node for scope {:?}. \ | |
7cac9316 | 220 | Please report a bug.", scope); |
476ff2be | 221 | &unknown |
c1a9b12d | 222 | } |
476ff2be | 223 | }; |
32a655c1 | 224 | let (msg, opt_span) = explain_span(self, tag, self.hir.span(node)); |
476ff2be | 225 | (format!("{} {}", prefix, msg), opt_span) |
62682a34 | 226 | } |
62682a34 | 227 | |
c1a9b12d | 228 | ty::ReStatic => ("the static lifetime".to_owned(), None), |
62682a34 | 229 | |
c1a9b12d | 230 | ty::ReEmpty => ("the empty lifetime".to_owned(), None), |
62682a34 | 231 | |
e9174d1e SL |
232 | // FIXME(#13998) ReSkolemized should probably print like |
233 | // ReFree rather than dumping Debug output on the user. | |
234 | // | |
235 | // We shouldn't really be having unification failures with ReVar | |
236 | // and ReLateBound though. | |
3157f602 XL |
237 | ty::ReSkolemized(..) | |
238 | ty::ReVar(_) | | |
239 | ty::ReLateBound(..) | | |
240 | ty::ReErased => { | |
c1a9b12d SL |
241 | (format!("lifetime {:?}", region), None) |
242 | } | |
243 | }; | |
244 | let message = format!("{}{}{}", prefix, description, suffix); | |
245 | if let Some(span) = span { | |
9cc50fc6 | 246 | err.span_note(span, &message); |
c1a9b12d | 247 | } else { |
9cc50fc6 | 248 | err.note(&message); |
62682a34 | 249 | } |
62682a34 SL |
250 | } |
251 | } | |
1a4d82fc | 252 | |
a7813a04 | 253 | impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { |
ea8adc8c XL |
254 | pub fn report_region_errors(&self, |
255 | region_scope_tree: ®ion::ScopeTree, | |
256 | errors: &Vec<RegionResolutionError<'tcx>>) { | |
54a0048b SL |
257 | debug!("report_region_errors(): {} errors to start", errors.len()); |
258 | ||
abe05a73 XL |
259 | if self.tcx.sess.opts.debugging_opts.nll { |
260 | for error in errors { | |
261 | match *error { | |
262 | RegionResolutionError::ConcreteFailure(ref origin, ..) | | |
263 | RegionResolutionError::GenericBoundFailure(ref origin, ..) => { | |
264 | self.tcx.sess.span_warn( | |
265 | origin.span(), | |
266 | "not reporting region error due to -Znll"); | |
267 | } | |
268 | ||
269 | RegionResolutionError::SubSupConflict(ref rvo, ..) => { | |
270 | self.tcx.sess.span_warn( | |
271 | rvo.span(), | |
272 | "not reporting region error due to -Znll"); | |
273 | } | |
274 | } | |
275 | } | |
276 | ||
277 | return; | |
278 | } | |
279 | ||
54a0048b SL |
280 | // try to pre-process the errors, which will group some of them |
281 | // together into a `ProcessedErrors` group: | |
32a655c1 | 282 | let errors = self.process_errors(errors); |
54a0048b SL |
283 | |
284 | debug!("report_region_errors: {} errors after preprocessing", errors.len()); | |
285 | ||
85aaf69f | 286 | for error in errors { |
c30ab7b3 | 287 | debug!("report_region_errors: error = {:?}", error); |
1a4d82fc | 288 | |
3b2f2976 | 289 | if !self.try_report_named_anon_conflict(&error) && |
abe05a73 XL |
290 | !self.try_report_anon_anon_conflict(&error) |
291 | { | |
292 | match error.clone() { | |
293 | // These errors could indicate all manner of different | |
294 | // problems with many different solutions. Rather | |
295 | // than generate a "one size fits all" error, what we | |
296 | // attempt to do is go through a number of specific | |
297 | // scenarios and try to find the best way to present | |
298 | // the error. If all of these fails, we fall back to a rather | |
299 | // general bit of code that displays the error information | |
300 | RegionResolutionError::ConcreteFailure(origin, sub, sup) => { | |
301 | self.report_concrete_failure(region_scope_tree, origin, sub, sup).emit(); | |
302 | } | |
303 | ||
304 | RegionResolutionError::GenericBoundFailure(kind, param_ty, sub) => { | |
305 | self.report_generic_bound_failure(region_scope_tree, kind, param_ty, sub); | |
306 | } | |
307 | ||
308 | RegionResolutionError::SubSupConflict(var_origin, | |
309 | sub_origin, | |
310 | sub_r, | |
311 | sup_origin, | |
312 | sup_r) => { | |
ea8adc8c XL |
313 | self.report_sub_sup_conflict(region_scope_tree, |
314 | var_origin, | |
3b2f2976 XL |
315 | sub_origin, |
316 | sub_r, | |
317 | sup_origin, | |
318 | sup_r); | |
abe05a73 XL |
319 | } |
320 | } | |
1a4d82fc JJ |
321 | } |
322 | } | |
323 | } | |
324 | ||
325 | // This method goes through all the errors and try to group certain types | |
326 | // of error together, for the purpose of suggesting explicit lifetime | |
327 | // parameters to the user. This is done so that we can have a more | |
328 | // complete view of what lifetimes should be the same. | |
329 | // If the return value is an empty vector, it means that processing | |
54a0048b SL |
330 | // failed (so the return value of this method should not be used). |
331 | // | |
332 | // The method also attempts to weed out messages that seem like | |
333 | // duplicates that will be unhelpful to the end-user. But | |
334 | // obviously it never weeds out ALL errors. | |
1a4d82fc | 335 | fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) |
32a655c1 | 336 | -> Vec<RegionResolutionError<'tcx>> { |
1a4d82fc | 337 | debug!("process_errors()"); |
54a0048b | 338 | |
32a655c1 SL |
339 | // We want to avoid reporting generic-bound failures if we can |
340 | // avoid it: these have a very high rate of being unhelpful in | |
341 | // practice. This is because they are basically secondary | |
342 | // checks that test the state of the region graph after the | |
343 | // rest of inference is done, and the other kinds of errors | |
344 | // indicate that the region constraint graph is internally | |
345 | // inconsistent, so these test results are likely to be | |
346 | // meaningless. | |
347 | // | |
348 | // Therefore, we filter them out of the list unless they are | |
349 | // the only thing in the list. | |
350 | ||
351 | let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e { | |
abe05a73 XL |
352 | RegionResolutionError::GenericBoundFailure(..) => true, |
353 | RegionResolutionError::ConcreteFailure(..) | | |
354 | RegionResolutionError::SubSupConflict(..) => false, | |
32a655c1 | 355 | }; |
1a4d82fc | 356 | |
ea8adc8c XL |
357 | |
358 | let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { | |
32a655c1 SL |
359 | errors.clone() |
360 | } else { | |
361 | errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect() | |
ea8adc8c XL |
362 | }; |
363 | ||
364 | // sort the errors by span, for better error message stability. | |
365 | errors.sort_by_key(|u| match *u { | |
abe05a73 XL |
366 | RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), |
367 | RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), | |
368 | RegionResolutionError::SubSupConflict(ref rvo, _, _, _, _) => rvo.span(), | |
ea8adc8c XL |
369 | }); |
370 | errors | |
1a4d82fc JJ |
371 | } |
372 | ||
e9174d1e | 373 | /// Adds a note if the types come from similarly named crates |
9cc50fc6 SL |
374 | fn check_and_note_conflicting_crates(&self, |
375 | err: &mut DiagnosticBuilder, | |
376 | terr: &TypeError<'tcx>, | |
377 | sp: Span) { | |
378 | let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| { | |
e9174d1e SL |
379 | // Only external crates, if either is from a local |
380 | // module we could have false positives | |
381 | if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { | |
54a0048b SL |
382 | let exp_path = self.tcx.item_path_str(did1); |
383 | let found_path = self.tcx.item_path_str(did2); | |
041b39d2 XL |
384 | let exp_abs_path = self.tcx.absolute_item_path_str(did1); |
385 | let found_abs_path = self.tcx.absolute_item_path_str(did2); | |
54a0048b | 386 | // We compare strings because DefPath can be different |
e9174d1e | 387 | // for imported and non-imported crates |
041b39d2 XL |
388 | if exp_path == found_path |
389 | || exp_abs_path == found_abs_path { | |
ea8adc8c | 390 | let crate_name = self.tcx.crate_name(did1.krate); |
9cc50fc6 SL |
391 | err.span_note(sp, &format!("Perhaps two different versions \ |
392 | of crate `{}` are being used?", | |
393 | crate_name)); | |
e9174d1e SL |
394 | } |
395 | } | |
396 | }; | |
397 | match *terr { | |
398 | TypeError::Sorts(ref exp_found) => { | |
399 | // if they are both "path types", there's a chance of ambiguity | |
400 | // due to different versions of the same crate | |
401 | match (&exp_found.expected.sty, &exp_found.found.sty) { | |
9e0c209e | 402 | (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => { |
9cc50fc6 | 403 | report_path_match(err, exp_adt.did, found_adt.did); |
e9174d1e SL |
404 | }, |
405 | _ => () | |
406 | } | |
407 | }, | |
408 | TypeError::Traits(ref exp_found) => { | |
9cc50fc6 | 409 | report_path_match(err, exp_found.expected, exp_found.found); |
e9174d1e SL |
410 | }, |
411 | _ => () // FIXME(#22750) handle traits and stuff | |
412 | } | |
413 | } | |
414 | ||
5bcae85e SL |
415 | fn note_error_origin(&self, |
416 | err: &mut DiagnosticBuilder<'tcx>, | |
476ff2be | 417 | cause: &ObligationCause<'tcx>) |
5bcae85e | 418 | { |
476ff2be SL |
419 | match cause.code { |
420 | ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source { | |
5bcae85e SL |
421 | hir::MatchSource::IfLetDesugar {..} => { |
422 | err.span_note(arm_span, "`if let` arm with an incompatible type"); | |
423 | } | |
424 | _ => { | |
425 | err.span_note(arm_span, "match arm with an incompatible type"); | |
426 | } | |
427 | }, | |
428 | _ => () | |
429 | } | |
430 | } | |
431 | ||
cc61c64b XL |
432 | /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` |
433 | /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and | |
434 | /// populate `other_value` with `other_ty`. | |
435 | /// | |
436 | /// ```text | |
437 | /// Foo<Bar<Qux>> | |
438 | /// ^^^^--------^ this is highlighted | |
439 | /// | | | |
440 | /// | this type argument is exactly the same as the other type, not highlighted | |
441 | /// this is highlighted | |
442 | /// Bar<Qux> | |
443 | /// -------- this type is the same as a type argument in the other type, not highlighted | |
444 | /// ``` | |
445 | fn highlight_outer(&self, | |
3b2f2976 XL |
446 | value: &mut DiagnosticStyledString, |
447 | other_value: &mut DiagnosticStyledString, | |
cc61c64b XL |
448 | name: String, |
449 | sub: &ty::subst::Substs<'tcx>, | |
450 | pos: usize, | |
ea8adc8c | 451 | other_ty: &Ty<'tcx>) { |
cc61c64b XL |
452 | // `value` and `other_value` hold two incomplete type representation for display. |
453 | // `name` is the path of both types being compared. `sub` | |
454 | value.push_highlighted(name); | |
455 | let len = sub.len(); | |
456 | if len > 0 { | |
457 | value.push_highlighted("<"); | |
458 | } | |
459 | ||
460 | // Output the lifetimes fot the first type | |
461 | let lifetimes = sub.regions().map(|lifetime| { | |
462 | let s = format!("{}", lifetime); | |
463 | if s.is_empty() { | |
464 | "'_".to_string() | |
465 | } else { | |
466 | s | |
467 | } | |
468 | }).collect::<Vec<_>>().join(", "); | |
469 | if !lifetimes.is_empty() { | |
470 | if sub.regions().count() < len { | |
471 | value.push_normal(lifetimes + &", "); | |
472 | } else { | |
473 | value.push_normal(lifetimes); | |
474 | } | |
475 | } | |
476 | ||
477 | // Highlight all the type arguments that aren't at `pos` and compare the type argument at | |
478 | // `pos` and `other_ty`. | |
479 | for (i, type_arg) in sub.types().enumerate() { | |
480 | if i == pos { | |
481 | let values = self.cmp(type_arg, other_ty); | |
482 | value.0.extend((values.0).0); | |
483 | other_value.0.extend((values.1).0); | |
484 | } else { | |
485 | value.push_highlighted(format!("{}", type_arg)); | |
486 | } | |
487 | ||
488 | if len > 0 && i != len - 1 { | |
489 | value.push_normal(", "); | |
490 | } | |
491 | //self.push_comma(&mut value, &mut other_value, len, i); | |
492 | } | |
493 | if len > 0 { | |
494 | value.push_highlighted(">"); | |
495 | } | |
496 | } | |
497 | ||
498 | /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, | |
499 | /// as that is the difference to the other type. | |
500 | /// | |
501 | /// For the following code: | |
502 | /// | |
503 | /// ```norun | |
504 | /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>(); | |
505 | /// ``` | |
506 | /// | |
507 | /// The type error output will behave in the following way: | |
508 | /// | |
509 | /// ```text | |
510 | /// Foo<Bar<Qux>> | |
511 | /// ^^^^--------^ this is highlighted | |
512 | /// | | | |
513 | /// | this type argument is exactly the same as the other type, not highlighted | |
514 | /// this is highlighted | |
515 | /// Bar<Qux> | |
516 | /// -------- this type is the same as a type argument in the other type, not highlighted | |
517 | /// ``` | |
518 | fn cmp_type_arg(&self, | |
519 | mut t1_out: &mut DiagnosticStyledString, | |
520 | mut t2_out: &mut DiagnosticStyledString, | |
521 | path: String, | |
522 | sub: &ty::subst::Substs<'tcx>, | |
523 | other_path: String, | |
ea8adc8c | 524 | other_ty: &Ty<'tcx>) -> Option<()> { |
cc61c64b XL |
525 | for (i, ta) in sub.types().enumerate() { |
526 | if &ta == other_ty { | |
527 | self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); | |
528 | return Some(()); | |
529 | } | |
530 | if let &ty::TyAdt(def, _) = &ta.sty { | |
531 | let path_ = self.tcx.item_path_str(def.did.clone()); | |
532 | if path_ == other_path { | |
533 | self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); | |
534 | return Some(()); | |
535 | } | |
536 | } | |
537 | } | |
538 | None | |
539 | } | |
540 | ||
541 | /// Add a `,` to the type representation only if it is appropriate. | |
542 | fn push_comma(&self, | |
543 | value: &mut DiagnosticStyledString, | |
544 | other_value: &mut DiagnosticStyledString, | |
545 | len: usize, | |
546 | pos: usize) { | |
547 | if len > 0 && pos != len - 1 { | |
548 | value.push_normal(", "); | |
549 | other_value.push_normal(", "); | |
550 | } | |
551 | } | |
552 | ||
553 | /// Compare two given types, eliding parts that are the same between them and highlighting | |
554 | /// relevant differences, and return two representation of those types for highlighted printing. | |
ea8adc8c | 555 | fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) |
cc61c64b XL |
556 | -> (DiagnosticStyledString, DiagnosticStyledString) |
557 | { | |
558 | match (&t1.sty, &t2.sty) { | |
559 | (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { | |
560 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); | |
561 | let path1 = self.tcx.item_path_str(def1.did.clone()); | |
562 | let path2 = self.tcx.item_path_str(def2.did.clone()); | |
563 | if def1.did == def2.did { | |
564 | // Easy case. Replace same types with `_` to shorten the output and highlight | |
565 | // the differing ones. | |
566 | // let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>(); | |
567 | // Foo<Bar, _> | |
568 | // Foo<Quz, _> | |
569 | // --- ^ type argument elided | |
570 | // | | |
571 | // highlighted in output | |
572 | values.0.push_normal(path1); | |
573 | values.1.push_normal(path2); | |
574 | ||
575 | // Only draw `<...>` if there're lifetime/type arguments. | |
576 | let len = sub1.len(); | |
577 | if len > 0 { | |
578 | values.0.push_normal("<"); | |
579 | values.1.push_normal("<"); | |
580 | } | |
581 | ||
7cac9316 | 582 | fn lifetime_display(lifetime: Region) -> String { |
cc61c64b XL |
583 | let s = format!("{}", lifetime); |
584 | if s.is_empty() { | |
585 | "'_".to_string() | |
586 | } else { | |
587 | s | |
588 | } | |
589 | } | |
590 | // At one point we'd like to elide all lifetimes here, they are irrelevant for | |
591 | // all diagnostics that use this output | |
592 | // | |
593 | // Foo<'x, '_, Bar> | |
594 | // Foo<'y, '_, Qux> | |
595 | // ^^ ^^ --- type arguments are not elided | |
596 | // | | | |
597 | // | elided as they were the same | |
598 | // not elided, they were different, but irrelevant | |
599 | let lifetimes = sub1.regions().zip(sub2.regions()); | |
600 | for (i, lifetimes) in lifetimes.enumerate() { | |
601 | let l1 = lifetime_display(lifetimes.0); | |
602 | let l2 = lifetime_display(lifetimes.1); | |
603 | if l1 == l2 { | |
604 | values.0.push_normal("'_"); | |
605 | values.1.push_normal("'_"); | |
606 | } else { | |
607 | values.0.push_highlighted(l1); | |
608 | values.1.push_highlighted(l2); | |
609 | } | |
610 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
611 | } | |
612 | ||
613 | // We're comparing two types with the same path, so we compare the type | |
614 | // arguments for both. If they are the same, do not highlight and elide from the | |
615 | // output. | |
616 | // Foo<_, Bar> | |
617 | // Foo<_, Qux> | |
618 | // ^ elided type as this type argument was the same in both sides | |
619 | let type_arguments = sub1.types().zip(sub2.types()); | |
620 | let regions_len = sub1.regions().collect::<Vec<_>>().len(); | |
621 | for (i, (ta1, ta2)) in type_arguments.enumerate() { | |
622 | let i = i + regions_len; | |
623 | if ta1 == ta2 { | |
624 | values.0.push_normal("_"); | |
625 | values.1.push_normal("_"); | |
626 | } else { | |
627 | let (x1, x2) = self.cmp(ta1, ta2); | |
628 | (values.0).0.extend(x1.0); | |
629 | (values.1).0.extend(x2.0); | |
630 | } | |
631 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
632 | } | |
633 | ||
634 | // Close the type argument bracket. | |
635 | // Only draw `<...>` if there're lifetime/type arguments. | |
636 | if len > 0 { | |
637 | values.0.push_normal(">"); | |
638 | values.1.push_normal(">"); | |
639 | } | |
640 | values | |
641 | } else { | |
642 | // Check for case: | |
643 | // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>(); | |
644 | // Foo<Bar<Qux> | |
645 | // ------- this type argument is exactly the same as the other type | |
646 | // Bar<Qux> | |
647 | if self.cmp_type_arg(&mut values.0, | |
648 | &mut values.1, | |
649 | path1.clone(), | |
650 | sub1, | |
651 | path2.clone(), | |
652 | &t2).is_some() { | |
653 | return values; | |
654 | } | |
655 | // Check for case: | |
656 | // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>(); | |
657 | // Bar<Qux> | |
658 | // Foo<Bar<Qux>> | |
659 | // ------- this type argument is exactly the same as the other type | |
660 | if self.cmp_type_arg(&mut values.1, | |
661 | &mut values.0, | |
662 | path2, | |
663 | sub2, | |
664 | path1, | |
665 | &t1).is_some() { | |
666 | return values; | |
667 | } | |
668 | ||
669 | // We couldn't find anything in common, highlight everything. | |
670 | // let x: Bar<Qux> = y::<Foo<Zar>>(); | |
671 | (DiagnosticStyledString::highlighted(format!("{}", t1)), | |
672 | DiagnosticStyledString::highlighted(format!("{}", t2))) | |
673 | } | |
674 | } | |
675 | _ => { | |
676 | if t1 == t2 { | |
677 | // The two types are the same, elide and don't highlight. | |
678 | (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) | |
679 | } else { | |
680 | // We couldn't find anything in common, highlight everything. | |
681 | (DiagnosticStyledString::highlighted(format!("{}", t1)), | |
682 | DiagnosticStyledString::highlighted(format!("{}", t2))) | |
683 | } | |
684 | } | |
685 | } | |
686 | } | |
687 | ||
5bcae85e SL |
688 | pub fn note_type_err(&self, |
689 | diag: &mut DiagnosticBuilder<'tcx>, | |
476ff2be | 690 | cause: &ObligationCause<'tcx>, |
9e0c209e | 691 | secondary_span: Option<(Span, String)>, |
5bcae85e SL |
692 | values: Option<ValuePairs<'tcx>>, |
693 | terr: &TypeError<'tcx>) | |
694 | { | |
abe05a73 XL |
695 | let (expected_found, exp_found, is_simple_error) = match values { |
696 | None => (None, None, false), | |
8bb4bdeb | 697 | Some(values) => { |
abe05a73 | 698 | let (is_simple_error, exp_found) = match values { |
8bb4bdeb | 699 | ValuePairs::Types(exp_found) => { |
abe05a73 XL |
700 | let is_simple_err = exp_found.expected.is_primitive() |
701 | && exp_found.found.is_primitive(); | |
702 | ||
703 | (is_simple_err, Some(exp_found)) | |
8bb4bdeb | 704 | } |
abe05a73 | 705 | _ => (false, None), |
8bb4bdeb XL |
706 | }; |
707 | let vals = match self.values_str(&values) { | |
708 | Some((expected, found)) => Some((expected, found)), | |
709 | None => { | |
710 | // Derived error. Cancel the emitter. | |
711 | self.tcx.sess.diagnostic().cancel(diag); | |
712 | return | |
713 | } | |
714 | }; | |
abe05a73 | 715 | (vals, exp_found, is_simple_error) |
5bcae85e SL |
716 | } |
717 | }; | |
718 | ||
476ff2be | 719 | let span = cause.span; |
5bcae85e | 720 | |
abe05a73 XL |
721 | diag.span_label(span, terr.to_string()); |
722 | if let Some((sp, msg)) = secondary_span { | |
723 | diag.span_label(sp, msg); | |
724 | } | |
725 | ||
5bcae85e | 726 | if let Some((expected, found)) = expected_found { |
8bb4bdeb | 727 | match (terr, is_simple_error, expected == found) { |
cc61c64b | 728 | (&TypeError::Sorts(ref values), false, true) => { |
8bb4bdeb | 729 | diag.note_expected_found_extra( |
cc61c64b | 730 | &"type", expected, found, |
8bb4bdeb XL |
731 | &format!(" ({})", values.expected.sort_string(self.tcx)), |
732 | &format!(" ({})", values.found.sort_string(self.tcx))); | |
733 | } | |
abe05a73 XL |
734 | (_, false, _) => { |
735 | if let Some(exp_found) = exp_found { | |
736 | let (def_id, ret_ty) = match exp_found.found.sty { | |
737 | TypeVariants::TyFnDef(def, _) => { | |
738 | (Some(def), Some(self.tcx.fn_sig(def).output())) | |
739 | } | |
740 | _ => (None, None) | |
741 | }; | |
742 | ||
743 | let exp_is_struct = match exp_found.expected.sty { | |
744 | TypeVariants::TyAdt(def, _) => def.is_struct(), | |
745 | _ => false | |
746 | }; | |
747 | ||
748 | if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) { | |
749 | if exp_is_struct && exp_found.expected == ret_ty.0 { | |
750 | let message = format!( | |
751 | "did you mean `{}(/* fields */)`?", | |
752 | self.tcx.item_path_str(def_id) | |
753 | ); | |
754 | diag.span_label(cause.span, message); | |
755 | } | |
756 | } | |
757 | } | |
758 | ||
cc61c64b | 759 | diag.note_expected_found(&"type", expected, found); |
9e0c209e | 760 | } |
8bb4bdeb | 761 | _ => (), |
5bcae85e SL |
762 | } |
763 | } | |
764 | ||
5bcae85e SL |
765 | self.check_and_note_conflicting_crates(diag, terr, span); |
766 | self.tcx.note_and_explain_type_err(diag, terr, span); | |
abe05a73 XL |
767 | |
768 | // It reads better to have the error origin as the final | |
769 | // thing. | |
770 | self.note_error_origin(diag, &cause); | |
5bcae85e SL |
771 | } |
772 | ||
a7813a04 XL |
773 | pub fn report_and_explain_type_error(&self, |
774 | trace: TypeTrace<'tcx>, | |
775 | terr: &TypeError<'tcx>) | |
5bcae85e SL |
776 | -> DiagnosticBuilder<'tcx> |
777 | { | |
abe05a73 XL |
778 | debug!("report_and_explain_type_error(trace={:?}, terr={:?})", |
779 | trace, | |
780 | terr); | |
781 | ||
476ff2be SL |
782 | let span = trace.cause.span; |
783 | let failure_str = trace.cause.as_failure_str(); | |
784 | let mut diag = match trace.cause.code { | |
785 | ObligationCauseCode::IfExpressionWithNoElse => { | |
c30ab7b3 | 786 | struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) |
32a655c1 SL |
787 | } |
788 | ObligationCauseCode::MainFunctionType => { | |
789 | struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) | |
790 | } | |
c30ab7b3 SL |
791 | _ => { |
792 | struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) | |
32a655c1 | 793 | } |
c30ab7b3 | 794 | }; |
476ff2be | 795 | self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); |
5bcae85e | 796 | diag |
1a4d82fc JJ |
797 | } |
798 | ||
cc61c64b XL |
799 | fn values_str(&self, values: &ValuePairs<'tcx>) |
800 | -> Option<(DiagnosticStyledString, DiagnosticStyledString)> | |
801 | { | |
1a4d82fc | 802 | match *values { |
cc61c64b | 803 | infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), |
1a4d82fc | 804 | infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), |
5bcae85e | 805 | infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), |
1a4d82fc JJ |
806 | } |
807 | } | |
808 | ||
cc61c64b | 809 | fn expected_found_str_ty(&self, |
ea8adc8c | 810 | exp_found: &ty::error::ExpectedFound<Ty<'tcx>>) |
cc61c64b XL |
811 | -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { |
812 | let exp_found = self.resolve_type_vars_if_possible(exp_found); | |
813 | if exp_found.references_error() { | |
814 | return None; | |
815 | } | |
816 | ||
817 | Some(self.cmp(exp_found.expected, exp_found.found)) | |
818 | } | |
819 | ||
820 | /// Returns a string of the form "expected `{}`, found `{}`". | |
5bcae85e | 821 | fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>( |
1a4d82fc | 822 | &self, |
e9174d1e | 823 | exp_found: &ty::error::ExpectedFound<T>) |
cc61c64b | 824 | -> Option<(DiagnosticStyledString, DiagnosticStyledString)> |
1a4d82fc | 825 | { |
5bcae85e SL |
826 | let exp_found = self.resolve_type_vars_if_possible(exp_found); |
827 | if exp_found.references_error() { | |
1a4d82fc JJ |
828 | return None; |
829 | } | |
830 | ||
cc61c64b XL |
831 | Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), |
832 | DiagnosticStyledString::highlighted(format!("{}", exp_found.found)))) | |
1a4d82fc JJ |
833 | } |
834 | ||
835 | fn report_generic_bound_failure(&self, | |
ea8adc8c | 836 | region_scope_tree: ®ion::ScopeTree, |
1a4d82fc JJ |
837 | origin: SubregionOrigin<'tcx>, |
838 | bound_kind: GenericKind<'tcx>, | |
7cac9316 | 839 | sub: Region<'tcx>) |
1a4d82fc | 840 | { |
ea8adc8c XL |
841 | // Attempt to obtain the span of the parameter so we can |
842 | // suggest adding an explicit lifetime bound to it. | |
843 | let type_param_span = match (self.in_progress_tables, bound_kind) { | |
844 | (Some(ref table), GenericKind::Param(ref param)) => { | |
845 | let table = table.borrow(); | |
846 | table.local_id_root.and_then(|did| { | |
847 | let generics = self.tcx.generics_of(did); | |
848 | // Account for the case where `did` corresponds to `Self`, which doesn't have | |
849 | // the expected type argument. | |
850 | if !param.is_self() { | |
851 | let type_param = generics.type_param(param, self.tcx); | |
852 | let hir = &self.tcx.hir; | |
853 | hir.as_local_node_id(type_param.def_id).map(|id| { | |
854 | // Get the `hir::TyParam` to verify wether it already has any bounds. | |
855 | // We do this to avoid suggesting code that ends up as `T: 'a'b`, | |
856 | // instead we suggest `T: 'a + 'b` in that case. | |
857 | let has_lifetimes = if let hir_map::NodeTyParam(ref p) = hir.get(id) { | |
858 | p.bounds.len() > 0 | |
859 | } else { | |
860 | false | |
861 | }; | |
862 | let sp = hir.span(id); | |
863 | // `sp` only covers `T`, change it so that it covers | |
864 | // `T:` when appropriate | |
865 | let sp = if has_lifetimes { | |
866 | sp.to(sp.next_point().next_point()) | |
867 | } else { | |
868 | sp | |
869 | }; | |
870 | (sp, has_lifetimes) | |
871 | }) | |
872 | } else { | |
873 | None | |
874 | } | |
875 | }) | |
876 | } | |
877 | _ => None, | |
878 | }; | |
1a4d82fc JJ |
879 | |
880 | let labeled_user_string = match bound_kind { | |
881 | GenericKind::Param(ref p) => | |
62682a34 | 882 | format!("the parameter type `{}`", p), |
1a4d82fc | 883 | GenericKind::Projection(ref p) => |
62682a34 | 884 | format!("the associated type `{}`", p), |
1a4d82fc JJ |
885 | }; |
886 | ||
c30ab7b3 | 887 | if let SubregionOrigin::CompareImplMethodObligation { |
abe05a73 | 888 | span, item_name, impl_item_def_id, trait_item_def_id, |
c30ab7b3 SL |
889 | } = origin { |
890 | self.report_extra_impl_obligation(span, | |
891 | item_name, | |
892 | impl_item_def_id, | |
893 | trait_item_def_id, | |
abe05a73 | 894 | &format!("`{}: {}`", bound_kind, sub)) |
c30ab7b3 SL |
895 | .emit(); |
896 | return; | |
897 | } | |
898 | ||
ea8adc8c XL |
899 | fn binding_suggestion<'tcx, S: fmt::Display>(err: &mut DiagnosticBuilder<'tcx>, |
900 | type_param_span: Option<(Span, bool)>, | |
901 | bound_kind: GenericKind<'tcx>, | |
902 | sub: S) { | |
903 | let consider = &format!("consider adding an explicit lifetime bound `{}: {}`...", | |
904 | bound_kind, | |
905 | sub); | |
906 | if let Some((sp, has_lifetimes)) = type_param_span { | |
907 | let tail = if has_lifetimes { | |
908 | " + " | |
909 | } else { | |
910 | "" | |
911 | }; | |
912 | let suggestion = format!("{}: {}{}", bound_kind, sub, tail); | |
913 | err.span_suggestion_short(sp, consider, suggestion); | |
914 | } else { | |
915 | err.help(consider); | |
916 | } | |
917 | } | |
918 | ||
9e0c209e | 919 | let mut err = match *sub { |
7cac9316 | 920 | ty::ReEarlyBound(_) | |
1a4d82fc JJ |
921 | ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { |
922 | // Does the required lifetime have a nice name we can print? | |
9cc50fc6 SL |
923 | let mut err = struct_span_err!(self.tcx.sess, |
924 | origin.span(), | |
925 | E0309, | |
926 | "{} may not live long enough", | |
927 | labeled_user_string); | |
ea8adc8c | 928 | binding_suggestion(&mut err, type_param_span, bound_kind, sub); |
9cc50fc6 | 929 | err |
1a4d82fc JJ |
930 | } |
931 | ||
932 | ty::ReStatic => { | |
933 | // Does the required lifetime have a nice name we can print? | |
9cc50fc6 SL |
934 | let mut err = struct_span_err!(self.tcx.sess, |
935 | origin.span(), | |
936 | E0310, | |
937 | "{} may not live long enough", | |
938 | labeled_user_string); | |
ea8adc8c | 939 | binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); |
9cc50fc6 | 940 | err |
1a4d82fc JJ |
941 | } |
942 | ||
943 | _ => { | |
944 | // If not, be less specific. | |
9cc50fc6 SL |
945 | let mut err = struct_span_err!(self.tcx.sess, |
946 | origin.span(), | |
947 | E0311, | |
948 | "{} may not live long enough", | |
949 | labeled_user_string); | |
a7813a04 XL |
950 | err.help(&format!("consider adding an explicit lifetime bound for `{}`", |
951 | bound_kind)); | |
c1a9b12d | 952 | self.tcx.note_and_explain_region( |
ea8adc8c | 953 | region_scope_tree, |
9cc50fc6 | 954 | &mut err, |
c34b1796 | 955 | &format!("{} must be valid for ", labeled_user_string), |
1a4d82fc JJ |
956 | sub, |
957 | "..."); | |
9cc50fc6 | 958 | err |
1a4d82fc | 959 | } |
9cc50fc6 | 960 | }; |
e9174d1e | 961 | |
9cc50fc6 SL |
962 | self.note_region_origin(&mut err, &origin); |
963 | err.emit(); | |
1a4d82fc JJ |
964 | } |
965 | ||
1a4d82fc | 966 | fn report_sub_sup_conflict(&self, |
ea8adc8c | 967 | region_scope_tree: ®ion::ScopeTree, |
1a4d82fc JJ |
968 | var_origin: RegionVariableOrigin, |
969 | sub_origin: SubregionOrigin<'tcx>, | |
7cac9316 | 970 | sub_region: Region<'tcx>, |
1a4d82fc | 971 | sup_origin: SubregionOrigin<'tcx>, |
7cac9316 | 972 | sup_region: Region<'tcx>) { |
9cc50fc6 | 973 | let mut err = self.report_inference_failure(var_origin); |
1a4d82fc | 974 | |
ea8adc8c | 975 | self.tcx.note_and_explain_region(region_scope_tree, &mut err, |
1a4d82fc JJ |
976 | "first, the lifetime cannot outlive ", |
977 | sup_region, | |
978 | "..."); | |
979 | ||
9cc50fc6 | 980 | self.note_region_origin(&mut err, &sup_origin); |
1a4d82fc | 981 | |
ea8adc8c | 982 | self.tcx.note_and_explain_region(region_scope_tree, &mut err, |
1a4d82fc JJ |
983 | "but, the lifetime must be valid for ", |
984 | sub_region, | |
985 | "..."); | |
986 | ||
9cc50fc6 SL |
987 | self.note_region_origin(&mut err, &sub_origin); |
988 | err.emit(); | |
1a4d82fc | 989 | } |
1a4d82fc JJ |
990 | } |
991 | ||
a7813a04 | 992 | impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { |
1a4d82fc | 993 | fn report_inference_failure(&self, |
9cc50fc6 SL |
994 | var_origin: RegionVariableOrigin) |
995 | -> DiagnosticBuilder<'tcx> { | |
62682a34 SL |
996 | let br_string = |br: ty::BoundRegion| { |
997 | let mut s = br.to_string(); | |
998 | if !s.is_empty() { | |
999 | s.push_str(" "); | |
1000 | } | |
1001 | s | |
1002 | }; | |
1a4d82fc JJ |
1003 | let var_description = match var_origin { |
1004 | infer::MiscVariable(_) => "".to_string(), | |
1005 | infer::PatternRegion(_) => " for pattern".to_string(), | |
1006 | infer::AddrOfRegion(_) => " for borrow expression".to_string(), | |
1a4d82fc JJ |
1007 | infer::Autoref(_) => " for autoref".to_string(), |
1008 | infer::Coercion(_) => " for automatic coercion".to_string(), | |
1009 | infer::LateBoundRegion(_, br, infer::FnCall) => { | |
62682a34 SL |
1010 | format!(" for lifetime parameter {}in function call", |
1011 | br_string(br)) | |
1a4d82fc JJ |
1012 | } |
1013 | infer::LateBoundRegion(_, br, infer::HigherRankedType) => { | |
62682a34 | 1014 | format!(" for lifetime parameter {}in generic type", br_string(br)) |
1a4d82fc | 1015 | } |
3b2f2976 | 1016 | infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => { |
62682a34 | 1017 | format!(" for lifetime parameter {}in trait containing associated type `{}`", |
3b2f2976 | 1018 | br_string(br), self.tcx.associated_item(def_id).name) |
1a4d82fc | 1019 | } |
ea8adc8c | 1020 | infer::EarlyBoundRegion(_, name) => { |
1a4d82fc | 1021 | format!(" for lifetime parameter `{}`", |
c1a9b12d | 1022 | name) |
1a4d82fc JJ |
1023 | } |
1024 | infer::BoundRegionInCoherence(name) => { | |
1025 | format!(" for lifetime parameter `{}` in coherence check", | |
c1a9b12d | 1026 | name) |
1a4d82fc JJ |
1027 | } |
1028 | infer::UpvarRegion(ref upvar_id, _) => { | |
ea8adc8c XL |
1029 | let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); |
1030 | let var_name = self.tcx.hir.name(var_node_id); | |
1031 | format!(" for capture of `{}` by closure", var_name) | |
1a4d82fc | 1032 | } |
abe05a73 | 1033 | infer::NLL(..) => bug!("NLL variable found in lexical phase"), |
1a4d82fc JJ |
1034 | }; |
1035 | ||
9cc50fc6 | 1036 | struct_span_err!(self.tcx.sess, var_origin.span(), E0495, |
b039eaaf SL |
1037 | "cannot infer an appropriate lifetime{} \ |
1038 | due to conflicting requirements", | |
9cc50fc6 | 1039 | var_description) |
1a4d82fc | 1040 | } |
1a4d82fc JJ |
1041 | } |
1042 | ||
476ff2be SL |
1043 | impl<'tcx> ObligationCause<'tcx> { |
1044 | fn as_failure_str(&self) -> &'static str { | |
1045 | use traits::ObligationCauseCode::*; | |
1046 | match self.code { | |
1047 | CompareImplMethodObligation { .. } => "method not compatible with trait", | |
1048 | MatchExpressionArm { source, .. } => match source { | |
1049 | hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", | |
1050 | _ => "match arms have incompatible types", | |
1051 | }, | |
1052 | IfExpression => "if and else have incompatible types", | |
1053 | IfExpressionWithNoElse => "if may be missing an else clause", | |
1054 | EquatePredicate => "equality predicate not satisfied", | |
1055 | MainFunctionType => "main function has wrong type", | |
1056 | StartFunctionType => "start function has wrong type", | |
1057 | IntrinsicType => "intrinsic has wrong type", | |
1058 | MethodReceiver => "mismatched method receiver", | |
1059 | _ => "mismatched types", | |
1060 | } | |
1061 | } | |
1062 | ||
1063 | fn as_requirement_str(&self) -> &'static str { | |
1064 | use traits::ObligationCauseCode::*; | |
1065 | match self.code { | |
1066 | CompareImplMethodObligation { .. } => "method type is compatible with trait", | |
1067 | ExprAssignable => "expression is assignable", | |
1068 | MatchExpressionArm { source, .. } => match source { | |
1069 | hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types", | |
1070 | _ => "match arms have compatible types", | |
1071 | }, | |
1072 | IfExpression => "if and else have compatible types", | |
1073 | IfExpressionWithNoElse => "if missing an else returns ()", | |
1074 | EquatePredicate => "equality where clause is satisfied", | |
1075 | MainFunctionType => "`main` function has the correct type", | |
1076 | StartFunctionType => "`start` function has the correct type", | |
1077 | IntrinsicType => "intrinsic has the correct type", | |
1078 | MethodReceiver => "method receiver has the correct type", | |
1079 | _ => "types are compatible", | |
1080 | } | |
1081 | } | |
1082 | } |