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.
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.
11 //! Error Reporting Code for the inference engine
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.
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
27 //! Having a catalog of all the different reasons an error can arise is
28 //! also useful for other reasons, like cross-referencing FAQs etc, though
29 //! we are not really taking advantage of this yet.
31 //! # Region Inference
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.
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.
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.
59 use super::{InferCtxt, TypeTrace, SubregionOrigin, RegionVariableOrigin, ValuePairs}
;
60 use super::region_inference
::{RegionResolutionError
, ConcreteFailure
, SubSupConflict
,
61 GenericBoundFailure
, GenericKind
};
65 use hir
::map
as hir_map
;
66 use hir
::def_id
::DefId
;
68 use traits
::{ObligationCause, ObligationCauseCode}
;
69 use ty
::{self, Region, Ty, TyCtxt, TypeFoldable}
;
70 use ty
::error
::TypeError
;
71 use syntax
::ast
::DUMMY_NODE_ID
;
72 use syntax_pos
::{Pos, Span}
;
73 use errors
::{DiagnosticBuilder, DiagnosticStyledString}
;
75 use rustc_data_structures
::indexed_vec
::Idx
;
81 mod named_anon_conflict
;
84 mod different_lifetimes
;
86 impl<'a
, 'gcx
, 'tcx
> TyCtxt
<'a
, 'gcx
, 'tcx
> {
87 pub fn note_and_explain_region(self,
88 region_scope_tree
: ®ion
::ScopeTree
,
89 err
: &mut DiagnosticBuilder
,
91 region
: ty
::Region
<'tcx
>,
93 fn item_scope_tag(item
: &hir
::Item
) -> &'
static str {
95 hir
::ItemImpl(..) => "impl",
96 hir
::ItemStruct(..) => "struct",
97 hir
::ItemUnion(..) => "union",
98 hir
::ItemEnum(..) => "enum",
99 hir
::ItemTrait(..) => "trait",
100 hir
::ItemFn(..) => "function body",
105 fn trait_item_scope_tag(item
: &hir
::TraitItem
) -> &'
static str {
107 hir
::TraitItemKind
::Method(..) => "method body",
108 hir
::TraitItemKind
::Const(..) |
109 hir
::TraitItemKind
::Type(..) => "associated item"
113 fn impl_item_scope_tag(item
: &hir
::ImplItem
) -> &'
static str {
115 hir
::ImplItemKind
::Method(..) => "method body",
116 hir
::ImplItemKind
::Const(..) |
117 hir
::ImplItemKind
::Type(_
) => "associated item"
121 fn explain_span
<'a
, 'gcx
, 'tcx
>(tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
122 heading
: &str, span
: Span
)
123 -> (String
, Option
<Span
>) {
124 let lo
= tcx
.sess
.codemap().lookup_char_pos_adj(span
.lo());
125 (format
!("the {} at {}:{}", heading
, lo
.line
, lo
.col
.to_usize() + 1),
129 let (description
, span
) = match *region
{
130 ty
::ReScope(scope
) => {
132 let unknown_scope
= || {
133 format
!("{}unknown scope: {:?}{}. Please report a bug.",
134 prefix
, scope
, suffix
)
136 let span
= scope
.span(self, region_scope_tree
);
137 let tag
= match self.hir
.find(scope
.node_id(self, region_scope_tree
)) {
138 Some(hir_map
::NodeBlock(_
)) => "block",
139 Some(hir_map
::NodeExpr(expr
)) => match expr
.node
{
140 hir
::ExprCall(..) => "call",
141 hir
::ExprMethodCall(..) => "method call",
142 hir
::ExprMatch(.., hir
::MatchSource
::IfLetDesugar { .. }
) => "if let",
143 hir
::ExprMatch(.., hir
::MatchSource
::WhileLetDesugar
) => "while let",
144 hir
::ExprMatch(.., hir
::MatchSource
::ForLoopDesugar
) => "for",
145 hir
::ExprMatch(..) => "match",
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
),
153 err
.span_note(span
, &unknown_scope());
157 let scope_decorated_tag
= match scope
.data() {
158 region
::ScopeData
::Node(_
) => tag
,
159 region
::ScopeData
::CallSite(_
) => {
160 "scope of call-site for function"
162 region
::ScopeData
::Arguments(_
) => {
163 "scope of function body"
165 region
::ScopeData
::Destruction(_
) => {
166 new_string
= format
!("destruction scope surrounding {}", tag
);
169 region
::ScopeData
::Remainder(r
) => {
170 new_string
= format
!("block suffix following statement {}",
171 r
.first_statement_index
.index());
175 explain_span(self, scope_decorated_tag
, span
)
178 ty
::ReEarlyBound(_
) |
180 let scope
= match *region
{
181 ty
::ReEarlyBound(ref br
) => {
182 self.parent_def_id(br
.def_id
).unwrap()
184 ty
::ReFree(ref fr
) => fr
.scope
,
187 let prefix
= match *region
{
188 ty
::ReEarlyBound(ref br
) => {
189 format
!("the lifetime {} as defined on", br
.name
)
191 ty
::ReFree(ref fr
) => {
192 match fr
.bound_region
{
194 format
!("the anonymous lifetime #{} defined on", idx
+ 1)
196 ty
::BrFresh(_
) => "an anonymous lifetime defined on".to_owned(),
198 format
!("the lifetime {} as defined on",
206 let node
= self.hir
.as_local_node_id(scope
)
207 .unwrap_or(DUMMY_NODE_ID
);
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
),
216 // this really should not happen, but it does:
219 unknown
= format
!("unexpected node ({}) for scope {:?}. \
220 Please report a bug.",
221 self.hir
.node_to_string(node
), scope
);
225 unknown
= format
!("unknown node for scope {:?}. \
226 Please report a bug.", scope
);
230 let (msg
, opt_span
) = explain_span(self, tag
, self.hir
.span(node
));
231 (format
!("{} {}", prefix
, msg
), opt_span
)
234 ty
::ReStatic
=> ("the static lifetime".to_owned(), None
),
236 ty
::ReEmpty
=> ("the empty lifetime".to_owned(), None
),
238 // FIXME(#13998) ReSkolemized should probably print like
239 // ReFree rather than dumping Debug output on the user.
241 // We shouldn't really be having unification failures with ReVar
242 // and ReLateBound though.
243 ty
::ReSkolemized(..) |
245 ty
::ReLateBound(..) |
247 (format
!("lifetime {:?}", region
), None
)
250 let message
= format
!("{}{}{}", prefix
, description
, suffix
);
251 if let Some(span
) = span
{
252 err
.span_note(span
, &message
);
259 impl<'a
, 'gcx
, 'tcx
> InferCtxt
<'a
, 'gcx
, 'tcx
> {
260 pub fn report_region_errors(&self,
261 region_scope_tree
: ®ion
::ScopeTree
,
262 errors
: &Vec
<RegionResolutionError
<'tcx
>>) {
263 debug
!("report_region_errors(): {} errors to start", errors
.len());
265 // try to pre-process the errors, which will group some of them
266 // together into a `ProcessedErrors` group:
267 let errors
= self.process_errors(errors
);
269 debug
!("report_region_errors: {} errors after preprocessing", errors
.len());
271 for error
in errors
{
272 debug
!("report_region_errors: error = {:?}", error
);
274 if !self.try_report_named_anon_conflict(&error
) &&
275 !self.try_report_anon_anon_conflict(&error
) {
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
) => {
286 self.report_concrete_failure(region_scope_tree
, origin
, sub
, sup
).emit();
289 GenericBoundFailure(kind
, param_ty
, sub
) => {
290 self.report_generic_bound_failure(region_scope_tree
, kind
, param_ty
, sub
);
293 SubSupConflict(var_origin
, sub_origin
, sub_r
, sup_origin
, sup_r
) => {
294 self.report_sub_sup_conflict(region_scope_tree
,
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
311 // failed (so the return value of this method should not be used).
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.
316 fn process_errors(&self, errors
: &Vec
<RegionResolutionError
<'tcx
>>)
317 -> Vec
<RegionResolutionError
<'tcx
>> {
318 debug
!("process_errors()");
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
329 // Therefore, we filter them out of the list unless they are
330 // the only thing in the list.
332 let is_bound_failure
= |e
: &RegionResolutionError
<'tcx
>| match *e
{
333 ConcreteFailure(..) => false,
334 SubSupConflict(..) => false,
335 GenericBoundFailure(..) => true,
339 let mut errors
= if errors
.iter().all(|e
| is_bound_failure(e
)) {
342 errors
.iter().filter(|&e
| !is_bound_failure(e
)).cloned().collect()
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(),
354 /// Adds a note if the types come from similarly named crates
355 fn check_and_note_conflicting_crates(&self,
356 err
: &mut DiagnosticBuilder
,
357 terr
: &TypeError
<'tcx
>,
359 let report_path_match
= |err
: &mut DiagnosticBuilder
, did1
: DefId
, did2
: DefId
| {
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
{
363 let exp_path
= self.tcx
.item_path_str(did1
);
364 let found_path
= self.tcx
.item_path_str(did2
);
365 let exp_abs_path
= self.tcx
.absolute_item_path_str(did1
);
366 let found_abs_path
= self.tcx
.absolute_item_path_str(did2
);
367 // We compare strings because DefPath can be different
368 // for imported and non-imported crates
369 if exp_path
== found_path
370 || exp_abs_path
== found_abs_path
{
371 let crate_name
= self.tcx
.crate_name(did1
.krate
);
372 err
.span_note(sp
, &format
!("Perhaps two different versions \
373 of crate `{}` are being used?",
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
) {
383 (&ty
::TyAdt(exp_adt
, _
), &ty
::TyAdt(found_adt
, _
)) => {
384 report_path_match(err
, exp_adt
.did
, found_adt
.did
);
389 TypeError
::Traits(ref exp_found
) => {
390 report_path_match(err
, exp_found
.expected
, exp_found
.found
);
392 _
=> () // FIXME(#22750) handle traits and stuff
396 fn note_error_origin(&self,
397 err
: &mut DiagnosticBuilder
<'tcx
>,
398 cause
: &ObligationCause
<'tcx
>)
401 ObligationCauseCode
::MatchExpressionArm { arm_span, source }
=> match source
{
402 hir
::MatchSource
::IfLetDesugar {..}
=> {
403 err
.span_note(arm_span
, "`if let` arm with an incompatible type");
406 err
.span_note(arm_span
, "match arm with an incompatible type");
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`.
419 /// ^^^^--------^ this is highlighted
421 /// | this type argument is exactly the same as the other type, not highlighted
422 /// this is highlighted
424 /// -------- this type is the same as a type argument in the other type, not highlighted
426 fn highlight_outer(&self,
427 value
: &mut DiagnosticStyledString
,
428 other_value
: &mut DiagnosticStyledString
,
430 sub
: &ty
::subst
::Substs
<'tcx
>,
432 other_ty
: &Ty
<'tcx
>) {
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
);
438 value
.push_highlighted("<");
441 // Output the lifetimes fot the first type
442 let lifetimes
= sub
.regions().map(|lifetime
| {
443 let s
= format
!("{}", lifetime
);
449 }).collect
::<Vec
<_
>>().join(", ");
450 if !lifetimes
.is_empty() {
451 if sub
.regions().count() < len
{
452 value
.push_normal(lifetimes
+ &", ");
454 value
.push_normal(lifetimes
);
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() {
462 let values
= self.cmp(type_arg
, other_ty
);
463 value
.0.extend((values
.0).0);
464 other_value
.0.extend((values
.1).0);
466 value
.push_highlighted(format
!("{}", type_arg
));
469 if len
> 0 && i
!= len
- 1 {
470 value
.push_normal(", ");
472 //self.push_comma(&mut value, &mut other_value, len, i);
475 value
.push_highlighted(">");
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.
482 /// For the following code:
485 /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>();
488 /// The type error output will behave in the following way:
492 /// ^^^^--------^ this is highlighted
494 /// | this type argument is exactly the same as the other type, not highlighted
495 /// this is highlighted
497 /// -------- this type is the same as a type argument in the other type, not highlighted
499 fn cmp_type_arg(&self,
500 mut t1_out
: &mut DiagnosticStyledString
,
501 mut t2_out
: &mut DiagnosticStyledString
,
503 sub
: &ty
::subst
::Substs
<'tcx
>,
505 other_ty
: &Ty
<'tcx
>) -> Option
<()> {
506 for (i
, ta
) in sub
.types().enumerate() {
508 self.highlight_outer(&mut t1_out
, &mut t2_out
, path
, sub
, i
, &other_ty
);
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
);
522 /// Add a `,` to the type representation only if it is appropriate.
524 value
: &mut DiagnosticStyledString
,
525 other_value
: &mut DiagnosticStyledString
,
528 if len
> 0 && pos
!= len
- 1 {
529 value
.push_normal(", ");
530 other_value
.push_normal(", ");
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.
536 fn cmp(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>)
537 -> (DiagnosticStyledString
, DiagnosticStyledString
)
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>>();
550 // --- ^ type argument elided
552 // highlighted in output
553 values
.0.push_normal(path1
);
554 values
.1.push_normal(path2
);
556 // Only draw `<...>` if there're lifetime/type arguments.
557 let len
= sub1
.len();
559 values
.0.push_normal("<");
560 values
.1.push_normal("<");
563 fn lifetime_display(lifetime
: Region
) -> String
{
564 let s
= format
!("{}", lifetime
);
571 // At one point we'd like to elide all lifetimes here, they are irrelevant for
572 // all diagnostics that use this output
576 // ^^ ^^ --- type arguments are not elided
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);
585 values
.0.push_normal("'_");
586 values
.1.push_normal("'_");
588 values
.0.push_highlighted(l1
);
589 values
.1.push_highlighted(l2
);
591 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
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
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
;
605 values
.0.push_normal("_");
606 values
.1.push_normal("_");
608 let (x1
, x2
) = self.cmp(ta1
, ta2
);
609 (values
.0).0.extend(x1
.0
);
610 (values
.1).0.extend(x2
.0
);
612 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
615 // Close the type argument bracket.
616 // Only draw `<...>` if there're lifetime/type arguments.
618 values
.0.push_normal(">");
619 values
.1.push_normal(">");
624 // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>();
626 // ------- this type argument is exactly the same as the other type
628 if self.cmp_type_arg(&mut values
.0,
637 // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>();
640 // ------- this type argument is exactly the same as the other type
641 if self.cmp_type_arg(&mut values
.1,
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
)))
658 // The two types are the same, elide and don't highlight.
659 (DiagnosticStyledString
::normal("_"), DiagnosticStyledString
::normal("_"))
661 // We couldn't find anything in common, highlight everything.
662 (DiagnosticStyledString
::highlighted(format
!("{}", t1
)),
663 DiagnosticStyledString
::highlighted(format
!("{}", t2
)))
669 pub fn note_type_err(&self,
670 diag
: &mut DiagnosticBuilder
<'tcx
>,
671 cause
: &ObligationCause
<'tcx
>,
672 secondary_span
: Option
<(Span
, String
)>,
673 values
: Option
<ValuePairs
<'tcx
>>,
674 terr
: &TypeError
<'tcx
>)
676 let (expected_found
, is_simple_error
) = match values
{
677 None
=> (None
, false),
679 let is_simple_error
= match values
{
680 ValuePairs
::Types(exp_found
) => {
681 exp_found
.expected
.is_primitive() && exp_found
.found
.is_primitive()
685 let vals
= match self.values_str(&values
) {
686 Some((expected
, found
)) => Some((expected
, found
)),
688 // Derived error. Cancel the emitter.
689 self.tcx
.sess
.diagnostic().cancel(diag
);
693 (vals
, is_simple_error
)
697 let span
= cause
.span
;
699 if let Some((expected
, found
)) = expected_found
{
700 match (terr
, is_simple_error
, expected
== found
) {
701 (&TypeError
::Sorts(ref values
), false, true) => {
702 diag
.note_expected_found_extra(
703 &"type", expected
, found
,
704 &format
!(" ({})", values
.expected
.sort_string(self.tcx
)),
705 &format
!(" ({})", values
.found
.sort_string(self.tcx
)));
708 diag
.note_expected_found(&"type", expected
, found
);
714 diag
.span_label(span
, terr
.to_string());
715 if let Some((sp
, msg
)) = secondary_span
{
716 diag
.span_label(sp
, msg
);
719 self.note_error_origin(diag
, &cause
);
720 self.check_and_note_conflicting_crates(diag
, terr
, span
);
721 self.tcx
.note_and_explain_type_err(diag
, terr
, span
);
724 pub fn report_and_explain_type_error(&self,
725 trace
: TypeTrace
<'tcx
>,
726 terr
: &TypeError
<'tcx
>)
727 -> DiagnosticBuilder
<'tcx
>
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
=> {
733 struct_span_err
!(self.tcx
.sess
, span
, E0317
, "{}", failure_str
)
735 ObligationCauseCode
::MainFunctionType
=> {
736 struct_span_err
!(self.tcx
.sess
, span
, E0580
, "{}", failure_str
)
739 struct_span_err
!(self.tcx
.sess
, span
, E0308
, "{}", failure_str
)
742 self.note_type_err(&mut diag
, &trace
.cause
, None
, Some(trace
.values
), terr
);
746 fn values_str(&self, values
: &ValuePairs
<'tcx
>)
747 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)>
750 infer
::Types(ref exp_found
) => self.expected_found_str_ty(exp_found
),
751 infer
::TraitRefs(ref exp_found
) => self.expected_found_str(exp_found
),
752 infer
::PolyTraitRefs(ref exp_found
) => self.expected_found_str(exp_found
),
756 fn expected_found_str_ty(&self,
757 exp_found
: &ty
::error
::ExpectedFound
<Ty
<'tcx
>>)
758 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)> {
759 let exp_found
= self.resolve_type_vars_if_possible(exp_found
);
760 if exp_found
.references_error() {
764 Some(self.cmp(exp_found
.expected
, exp_found
.found
))
767 /// Returns a string of the form "expected `{}`, found `{}`".
768 fn expected_found_str
<T
: fmt
::Display
+ TypeFoldable
<'tcx
>>(
770 exp_found
: &ty
::error
::ExpectedFound
<T
>)
771 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)>
773 let exp_found
= self.resolve_type_vars_if_possible(exp_found
);
774 if exp_found
.references_error() {
778 Some((DiagnosticStyledString
::highlighted(format
!("{}", exp_found
.expected
)),
779 DiagnosticStyledString
::highlighted(format
!("{}", exp_found
.found
))))
782 fn report_generic_bound_failure(&self,
783 region_scope_tree
: ®ion
::ScopeTree
,
784 origin
: SubregionOrigin
<'tcx
>,
785 bound_kind
: GenericKind
<'tcx
>,
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
) {
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())
827 let labeled_user_string
= match bound_kind
{
828 GenericKind
::Param(ref p
) =>
829 format
!("the parameter type `{}`", p
),
830 GenericKind
::Projection(ref p
) =>
831 format
!("the associated type `{}`", p
),
834 if let SubregionOrigin
::CompareImplMethodObligation
{
835 span
, item_name
, impl_item_def_id
, trait_item_def_id
, lint_id
837 self.report_extra_impl_obligation(span
,
841 &format
!("`{}: {}`", bound_kind
, sub
),
847 fn binding_suggestion
<'tcx
, S
: fmt
::Display
>(err
: &mut DiagnosticBuilder
<'tcx
>,
848 type_param_span
: Option
<(Span
, bool
)>,
849 bound_kind
: GenericKind
<'tcx
>,
851 let consider
= &format
!("consider adding an explicit lifetime bound `{}: {}`...",
854 if let Some((sp
, has_lifetimes
)) = type_param_span
{
855 let tail
= if has_lifetimes
{
860 let suggestion
= format
!("{}: {}{}", bound_kind
, sub
, tail
);
861 err
.span_suggestion_short(sp
, consider
, suggestion
);
867 let mut err
= match *sub
{
868 ty
::ReEarlyBound(_
) |
869 ty
::ReFree(ty
::FreeRegion {bound_region: ty::BrNamed(..), ..}
) => {
870 // Does the required lifetime have a nice name we can print?
871 let mut err
= struct_span_err
!(self.tcx
.sess
,
874 "{} may not live long enough",
875 labeled_user_string
);
876 binding_suggestion(&mut err
, type_param_span
, bound_kind
, sub
);
881 // Does the required lifetime have a nice name we can print?
882 let mut err
= struct_span_err
!(self.tcx
.sess
,
885 "{} may not live long enough",
886 labeled_user_string
);
887 binding_suggestion(&mut err
, type_param_span
, bound_kind
, "'static");
892 // If not, be less specific.
893 let mut err
= struct_span_err
!(self.tcx
.sess
,
896 "{} may not live long enough",
897 labeled_user_string
);
898 err
.help(&format
!("consider adding an explicit lifetime bound for `{}`",
900 self.tcx
.note_and_explain_region(
903 &format
!("{} must be valid for ", labeled_user_string
),
910 self.note_region_origin(&mut err
, &origin
);
914 fn report_sub_sup_conflict(&self,
915 region_scope_tree
: ®ion
::ScopeTree
,
916 var_origin
: RegionVariableOrigin
,
917 sub_origin
: SubregionOrigin
<'tcx
>,
918 sub_region
: Region
<'tcx
>,
919 sup_origin
: SubregionOrigin
<'tcx
>,
920 sup_region
: Region
<'tcx
>) {
921 let mut err
= self.report_inference_failure(var_origin
);
923 self.tcx
.note_and_explain_region(region_scope_tree
, &mut err
,
924 "first, the lifetime cannot outlive ",
928 self.note_region_origin(&mut err
, &sup_origin
);
930 self.tcx
.note_and_explain_region(region_scope_tree
, &mut err
,
931 "but, the lifetime must be valid for ",
935 self.note_region_origin(&mut err
, &sub_origin
);
940 impl<'a
, 'gcx
, 'tcx
> InferCtxt
<'a
, 'gcx
, 'tcx
> {
941 fn report_inference_failure(&self,
942 var_origin
: RegionVariableOrigin
)
943 -> DiagnosticBuilder
<'tcx
> {
944 let br_string
= |br
: ty
::BoundRegion
| {
945 let mut s
= br
.to_string();
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(),
955 infer
::Autoref(_
) => " for autoref".to_string(),
956 infer
::Coercion(_
) => " for automatic coercion".to_string(),
957 infer
::LateBoundRegion(_
, br
, infer
::FnCall
) => {
958 format
!(" for lifetime parameter {}in function call",
961 infer
::LateBoundRegion(_
, br
, infer
::HigherRankedType
) => {
962 format
!(" for lifetime parameter {}in generic type", br_string(br
))
964 infer
::LateBoundRegion(_
, br
, infer
::AssocTypeProjection(def_id
)) => {
965 format
!(" for lifetime parameter {}in trait containing associated type `{}`",
966 br_string(br
), self.tcx
.associated_item(def_id
).name
)
968 infer
::EarlyBoundRegion(_
, name
) => {
969 format
!(" for lifetime parameter `{}`",
972 infer
::BoundRegionInCoherence(name
) => {
973 format
!(" for lifetime parameter `{}` in coherence check",
976 infer
::UpvarRegion(ref upvar_id
, _
) => {
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
)
983 struct_span_err
!(self.tcx
.sess
, var_origin
.span(), E0495
,
984 "cannot infer an appropriate lifetime{} \
985 due to conflicting requirements",
990 impl<'tcx
> ObligationCause
<'tcx
> {
991 fn as_failure_str(&self) -> &'
static str {
992 use traits
::ObligationCauseCode
::*;
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",
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",
1010 fn as_requirement_str(&self) -> &'
static str {
1011 use traits
::ObligationCauseCode
::*;
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",
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",