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