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