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 catalogue of all the different reasons an error can arise is
28 //! also useful for other reasons, like cross-referencing FAQs etc, though
29 //! we are not really taking advantage of this yet.
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, TyCtxt, TypeFoldable}
;
70 use ty
::{Region, Issue32330}
;
71 use ty
::error
::TypeError
;
72 use syntax
::ast
::DUMMY_NODE_ID
;
73 use syntax_pos
::{Pos, Span}
;
74 use errors
::{DiagnosticBuilder, DiagnosticStyledString}
;
79 mod named_anon_conflict
;
81 impl<'a
, 'gcx
, 'tcx
> TyCtxt
<'a
, 'gcx
, 'tcx
> {
82 pub fn note_and_explain_region(self,
83 err
: &mut DiagnosticBuilder
,
85 region
: ty
::Region
<'tcx
>,
87 fn item_scope_tag(item
: &hir
::Item
) -> &'
static str {
89 hir
::ItemImpl(..) => "impl",
90 hir
::ItemStruct(..) => "struct",
91 hir
::ItemUnion(..) => "union",
92 hir
::ItemEnum(..) => "enum",
93 hir
::ItemTrait(..) => "trait",
94 hir
::ItemFn(..) => "function body",
99 fn trait_item_scope_tag(item
: &hir
::TraitItem
) -> &'
static str {
101 hir
::TraitItemKind
::Method(..) => "method body",
102 hir
::TraitItemKind
::Const(..) |
103 hir
::TraitItemKind
::Type(..) => "associated item"
107 fn impl_item_scope_tag(item
: &hir
::ImplItem
) -> &'
static str {
109 hir
::ImplItemKind
::Method(..) => "method body",
110 hir
::ImplItemKind
::Const(..) |
111 hir
::ImplItemKind
::Type(_
) => "associated item"
115 fn explain_span
<'a
, 'gcx
, 'tcx
>(tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
116 heading
: &str, span
: Span
)
117 -> (String
, Option
<Span
>) {
118 let lo
= tcx
.sess
.codemap().lookup_char_pos_adj(span
.lo
);
119 (format
!("the {} at {}:{}", heading
, lo
.line
, lo
.col
.to_usize() + 1),
123 let (description
, span
) = match *region
{
124 ty
::ReScope(scope
) => {
126 let unknown_scope
= || {
127 format
!("{}unknown scope: {:?}{}. Please report a bug.",
128 prefix
, scope
, suffix
)
130 let span
= match scope
.span(&self.hir
) {
133 err
.note(&unknown_scope());
137 let tag
= match self.hir
.find(scope
.node_id()) {
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
{
158 region
::CodeExtent
::Misc(_
) => tag
,
159 region
::CodeExtent
::CallSiteScope(_
) => {
160 "scope of call-site for function"
162 region
::CodeExtent
::ParameterScope(_
) => {
163 "scope of function body"
165 region
::CodeExtent
::DestructionScope(_
) => {
166 new_string
= format
!("destruction scope surrounding {}", tag
);
169 region
::CodeExtent
::Remainder(r
) => {
170 new_string
= format
!("block suffix following statement {}",
171 r
.first_statement_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
> {
261 pub fn report_region_errors(&self, errors
: &Vec
<RegionResolutionError
<'tcx
>>) {
262 debug
!("report_region_errors(): {} errors to start", errors
.len());
264 // try to pre-process the errors, which will group some of them
265 // together into a `ProcessedErrors` group:
266 let errors
= self.process_errors(errors
);
268 debug
!("report_region_errors: {} errors after preprocessing", errors
.len());
270 for error
in errors
{
271 debug
!("report_region_errors: error = {:?}", error
);
273 if !self.try_report_named_anon_conflict(&error
) {
274 match error
.clone() {
275 // These errors could indicate all manner of different
276 // problems with many different solutions. Rather
277 // than generate a "one size fits all" error, what we
278 // attempt to do is go through a number of specific
279 // scenarios and try to find the best way to present
280 // the error. If all of these fails, we fall back to a rather
281 // general bit of code that displays the error information
282 ConcreteFailure(origin
, sub
, sup
) => {
283 self.report_concrete_failure(origin
, sub
, sup
).emit();
285 GenericBoundFailure(kind
, param_ty
, sub
) => {
286 self.report_generic_bound_failure(kind
, param_ty
, sub
);
288 SubSupConflict(var_origin
,
290 sup_origin
, sup_r
) => {
291 self.report_sub_sup_conflict(var_origin
,
300 // This method goes through all the errors and try to group certain types
301 // of error together, for the purpose of suggesting explicit lifetime
302 // parameters to the user. This is done so that we can have a more
303 // complete view of what lifetimes should be the same.
304 // If the return value is an empty vector, it means that processing
305 // failed (so the return value of this method should not be used).
307 // The method also attempts to weed out messages that seem like
308 // duplicates that will be unhelpful to the end-user. But
309 // obviously it never weeds out ALL errors.
310 fn process_errors(&self, errors
: &Vec
<RegionResolutionError
<'tcx
>>)
311 -> Vec
<RegionResolutionError
<'tcx
>> {
312 debug
!("process_errors()");
314 // We want to avoid reporting generic-bound failures if we can
315 // avoid it: these have a very high rate of being unhelpful in
316 // practice. This is because they are basically secondary
317 // checks that test the state of the region graph after the
318 // rest of inference is done, and the other kinds of errors
319 // indicate that the region constraint graph is internally
320 // inconsistent, so these test results are likely to be
323 // Therefore, we filter them out of the list unless they are
324 // the only thing in the list.
326 let is_bound_failure
= |e
: &RegionResolutionError
<'tcx
>| match *e
{
327 ConcreteFailure(..) => false,
328 SubSupConflict(..) => false,
329 GenericBoundFailure(..) => true,
332 if errors
.iter().all(|e
| is_bound_failure(e
)) {
335 errors
.iter().filter(|&e
| !is_bound_failure(e
)).cloned().collect()
339 /// Adds a note if the types come from similarly named crates
340 fn check_and_note_conflicting_crates(&self,
341 err
: &mut DiagnosticBuilder
,
342 terr
: &TypeError
<'tcx
>,
344 let report_path_match
= |err
: &mut DiagnosticBuilder
, did1
: DefId
, did2
: DefId
| {
345 // Only external crates, if either is from a local
346 // module we could have false positives
347 if !(did1
.is_local() || did2
.is_local()) && did1
.krate
!= did2
.krate
{
348 let exp_path
= self.tcx
.item_path_str(did1
);
349 let found_path
= self.tcx
.item_path_str(did2
);
350 let exp_abs_path
= self.tcx
.absolute_item_path_str(did1
);
351 let found_abs_path
= self.tcx
.absolute_item_path_str(did2
);
352 // We compare strings because DefPath can be different
353 // for imported and non-imported crates
354 if exp_path
== found_path
355 || exp_abs_path
== found_abs_path
{
356 let crate_name
= self.tcx
.sess
.cstore
.crate_name(did1
.krate
);
357 err
.span_note(sp
, &format
!("Perhaps two different versions \
358 of crate `{}` are being used?",
364 TypeError
::Sorts(ref exp_found
) => {
365 // if they are both "path types", there's a chance of ambiguity
366 // due to different versions of the same crate
367 match (&exp_found
.expected
.sty
, &exp_found
.found
.sty
) {
368 (&ty
::TyAdt(exp_adt
, _
), &ty
::TyAdt(found_adt
, _
)) => {
369 report_path_match(err
, exp_adt
.did
, found_adt
.did
);
374 TypeError
::Traits(ref exp_found
) => {
375 report_path_match(err
, exp_found
.expected
, exp_found
.found
);
377 _
=> () // FIXME(#22750) handle traits and stuff
381 fn note_error_origin(&self,
382 err
: &mut DiagnosticBuilder
<'tcx
>,
383 cause
: &ObligationCause
<'tcx
>)
386 ObligationCauseCode
::MatchExpressionArm { arm_span, source }
=> match source
{
387 hir
::MatchSource
::IfLetDesugar {..}
=> {
388 err
.span_note(arm_span
, "`if let` arm with an incompatible type");
391 err
.span_note(arm_span
, "match arm with an incompatible type");
398 /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
399 /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
400 /// populate `other_value` with `other_ty`.
404 /// ^^^^--------^ this is highlighted
406 /// | this type argument is exactly the same as the other type, not highlighted
407 /// this is highlighted
409 /// -------- this type is the same as a type argument in the other type, not highlighted
411 fn highlight_outer(&self,
412 mut value
: &mut DiagnosticStyledString
,
413 mut other_value
: &mut DiagnosticStyledString
,
415 sub
: &ty
::subst
::Substs
<'tcx
>,
417 other_ty
: &ty
::Ty
<'tcx
>) {
418 // `value` and `other_value` hold two incomplete type representation for display.
419 // `name` is the path of both types being compared. `sub`
420 value
.push_highlighted(name
);
423 value
.push_highlighted("<");
426 // Output the lifetimes fot the first type
427 let lifetimes
= sub
.regions().map(|lifetime
| {
428 let s
= format
!("{}", lifetime
);
434 }).collect
::<Vec
<_
>>().join(", ");
435 if !lifetimes
.is_empty() {
436 if sub
.regions().count() < len
{
437 value
.push_normal(lifetimes
+ &", ");
439 value
.push_normal(lifetimes
);
443 // Highlight all the type arguments that aren't at `pos` and compare the type argument at
444 // `pos` and `other_ty`.
445 for (i
, type_arg
) in sub
.types().enumerate() {
447 let values
= self.cmp(type_arg
, other_ty
);
448 value
.0.extend((values
.0).0);
449 other_value
.0.extend((values
.1).0);
451 value
.push_highlighted(format
!("{}", type_arg
));
454 if len
> 0 && i
!= len
- 1 {
455 value
.push_normal(", ");
457 //self.push_comma(&mut value, &mut other_value, len, i);
460 value
.push_highlighted(">");
464 /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`,
465 /// as that is the difference to the other type.
467 /// For the following code:
470 /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>();
473 /// The type error output will behave in the following way:
477 /// ^^^^--------^ this is highlighted
479 /// | this type argument is exactly the same as the other type, not highlighted
480 /// this is highlighted
482 /// -------- this type is the same as a type argument in the other type, not highlighted
484 fn cmp_type_arg(&self,
485 mut t1_out
: &mut DiagnosticStyledString
,
486 mut t2_out
: &mut DiagnosticStyledString
,
488 sub
: &ty
::subst
::Substs
<'tcx
>,
490 other_ty
: &ty
::Ty
<'tcx
>) -> Option
<()> {
491 for (i
, ta
) in sub
.types().enumerate() {
493 self.highlight_outer(&mut t1_out
, &mut t2_out
, path
, sub
, i
, &other_ty
);
496 if let &ty
::TyAdt(def
, _
) = &ta
.sty
{
497 let path_
= self.tcx
.item_path_str(def
.did
.clone());
498 if path_
== other_path
{
499 self.highlight_outer(&mut t1_out
, &mut t2_out
, path
, sub
, i
, &other_ty
);
507 /// Add a `,` to the type representation only if it is appropriate.
509 value
: &mut DiagnosticStyledString
,
510 other_value
: &mut DiagnosticStyledString
,
513 if len
> 0 && pos
!= len
- 1 {
514 value
.push_normal(", ");
515 other_value
.push_normal(", ");
519 /// Compare two given types, eliding parts that are the same between them and highlighting
520 /// relevant differences, and return two representation of those types for highlighted printing.
521 fn cmp(&self, t1
: ty
::Ty
<'tcx
>, t2
: ty
::Ty
<'tcx
>)
522 -> (DiagnosticStyledString
, DiagnosticStyledString
)
524 match (&t1
.sty
, &t2
.sty
) {
525 (&ty
::TyAdt(def1
, sub1
), &ty
::TyAdt(def2
, sub2
)) => {
526 let mut values
= (DiagnosticStyledString
::new(), DiagnosticStyledString
::new());
527 let path1
= self.tcx
.item_path_str(def1
.did
.clone());
528 let path2
= self.tcx
.item_path_str(def2
.did
.clone());
529 if def1
.did
== def2
.did
{
530 // Easy case. Replace same types with `_` to shorten the output and highlight
531 // the differing ones.
532 // let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>();
535 // --- ^ type argument elided
537 // highlighted in output
538 values
.0.push_normal(path1
);
539 values
.1.push_normal(path2
);
541 // Only draw `<...>` if there're lifetime/type arguments.
542 let len
= sub1
.len();
544 values
.0.push_normal("<");
545 values
.1.push_normal("<");
548 fn lifetime_display(lifetime
: Region
) -> String
{
549 let s
= format
!("{}", lifetime
);
556 // At one point we'd like to elide all lifetimes here, they are irrelevant for
557 // all diagnostics that use this output
561 // ^^ ^^ --- type arguments are not elided
563 // | elided as they were the same
564 // not elided, they were different, but irrelevant
565 let lifetimes
= sub1
.regions().zip(sub2
.regions());
566 for (i
, lifetimes
) in lifetimes
.enumerate() {
567 let l1
= lifetime_display(lifetimes
.0);
568 let l2
= lifetime_display(lifetimes
.1);
570 values
.0.push_normal("'_");
571 values
.1.push_normal("'_");
573 values
.0.push_highlighted(l1
);
574 values
.1.push_highlighted(l2
);
576 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
579 // We're comparing two types with the same path, so we compare the type
580 // arguments for both. If they are the same, do not highlight and elide from the
584 // ^ elided type as this type argument was the same in both sides
585 let type_arguments
= sub1
.types().zip(sub2
.types());
586 let regions_len
= sub1
.regions().collect
::<Vec
<_
>>().len();
587 for (i
, (ta1
, ta2
)) in type_arguments
.enumerate() {
588 let i
= i
+ regions_len
;
590 values
.0.push_normal("_");
591 values
.1.push_normal("_");
593 let (x1
, x2
) = self.cmp(ta1
, ta2
);
594 (values
.0).0.extend(x1
.0
);
595 (values
.1).0.extend(x2
.0
);
597 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
600 // Close the type argument bracket.
601 // Only draw `<...>` if there're lifetime/type arguments.
603 values
.0.push_normal(">");
604 values
.1.push_normal(">");
609 // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>();
611 // ------- this type argument is exactly the same as the other type
613 if self.cmp_type_arg(&mut values
.0,
622 // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>();
625 // ------- this type argument is exactly the same as the other type
626 if self.cmp_type_arg(&mut values
.1,
635 // We couldn't find anything in common, highlight everything.
636 // let x: Bar<Qux> = y::<Foo<Zar>>();
637 (DiagnosticStyledString
::highlighted(format
!("{}", t1
)),
638 DiagnosticStyledString
::highlighted(format
!("{}", t2
)))
643 // The two types are the same, elide and don't highlight.
644 (DiagnosticStyledString
::normal("_"), DiagnosticStyledString
::normal("_"))
646 // We couldn't find anything in common, highlight everything.
647 (DiagnosticStyledString
::highlighted(format
!("{}", t1
)),
648 DiagnosticStyledString
::highlighted(format
!("{}", t2
)))
654 pub fn note_type_err(&self,
655 diag
: &mut DiagnosticBuilder
<'tcx
>,
656 cause
: &ObligationCause
<'tcx
>,
657 secondary_span
: Option
<(Span
, String
)>,
658 values
: Option
<ValuePairs
<'tcx
>>,
659 terr
: &TypeError
<'tcx
>)
661 let (expected_found
, is_simple_error
) = match values
{
662 None
=> (None
, false),
664 let is_simple_error
= match values
{
665 ValuePairs
::Types(exp_found
) => {
666 exp_found
.expected
.is_primitive() && exp_found
.found
.is_primitive()
670 let vals
= match self.values_str(&values
) {
671 Some((expected
, found
)) => Some((expected
, found
)),
673 // Derived error. Cancel the emitter.
674 self.tcx
.sess
.diagnostic().cancel(diag
);
678 (vals
, is_simple_error
)
682 let span
= cause
.span
;
684 if let Some((expected
, found
)) = expected_found
{
685 match (terr
, is_simple_error
, expected
== found
) {
686 (&TypeError
::Sorts(ref values
), false, true) => {
687 diag
.note_expected_found_extra(
688 &"type", expected
, found
,
689 &format
!(" ({})", values
.expected
.sort_string(self.tcx
)),
690 &format
!(" ({})", values
.found
.sort_string(self.tcx
)));
693 diag
.note_expected_found(&"type", expected
, found
);
699 diag
.span_label(span
, terr
.to_string());
700 if let Some((sp
, msg
)) = secondary_span
{
701 diag
.span_label(sp
, msg
);
704 self.note_error_origin(diag
, &cause
);
705 self.check_and_note_conflicting_crates(diag
, terr
, span
);
706 self.tcx
.note_and_explain_type_err(diag
, terr
, span
);
709 pub fn note_issue_32330(&self,
710 diag
: &mut DiagnosticBuilder
<'tcx
>,
711 terr
: &TypeError
<'tcx
>)
713 debug
!("note_issue_32330: terr={:?}", terr
);
715 TypeError
::RegionsInsufficientlyPolymorphic(_
, _
, Some(box Issue32330
{
716 fn_def_id
, region_name
718 TypeError
::RegionsOverlyPolymorphic(_
, _
, Some(box Issue32330
{
719 fn_def_id
, region_name
722 &format
!("lifetime parameter `{0}` declared on fn `{1}` \
723 appears only in the return type, \
724 but here is required to be higher-ranked, \
725 which means that `{0}` must appear in both \
726 argument and return types",
728 self.tcx
.item_path_str(fn_def_id
)));
730 &format
!("this error is the result of a recent bug fix; \
731 for more information, see issue #33685 \
732 <https://github.com/rust-lang/rust/issues/33685>"));
738 pub fn report_and_explain_type_error(&self,
739 trace
: TypeTrace
<'tcx
>,
740 terr
: &TypeError
<'tcx
>)
741 -> DiagnosticBuilder
<'tcx
>
743 let span
= trace
.cause
.span
;
744 let failure_str
= trace
.cause
.as_failure_str();
745 let mut diag
= match trace
.cause
.code
{
746 ObligationCauseCode
::IfExpressionWithNoElse
=> {
747 struct_span_err
!(self.tcx
.sess
, span
, E0317
, "{}", failure_str
)
749 ObligationCauseCode
::MainFunctionType
=> {
750 struct_span_err
!(self.tcx
.sess
, span
, E0580
, "{}", failure_str
)
753 struct_span_err
!(self.tcx
.sess
, span
, E0308
, "{}", failure_str
)
756 self.note_type_err(&mut diag
, &trace
.cause
, None
, Some(trace
.values
), terr
);
757 self.note_issue_32330(&mut diag
, terr
);
761 fn values_str(&self, values
: &ValuePairs
<'tcx
>)
762 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)>
765 infer
::Types(ref exp_found
) => self.expected_found_str_ty(exp_found
),
766 infer
::TraitRefs(ref exp_found
) => self.expected_found_str(exp_found
),
767 infer
::PolyTraitRefs(ref exp_found
) => self.expected_found_str(exp_found
),
771 fn expected_found_str_ty(&self,
772 exp_found
: &ty
::error
::ExpectedFound
<ty
::Ty
<'tcx
>>)
773 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)> {
774 let exp_found
= self.resolve_type_vars_if_possible(exp_found
);
775 if exp_found
.references_error() {
779 Some(self.cmp(exp_found
.expected
, exp_found
.found
))
782 /// Returns a string of the form "expected `{}`, found `{}`".
783 fn expected_found_str
<T
: fmt
::Display
+ TypeFoldable
<'tcx
>>(
785 exp_found
: &ty
::error
::ExpectedFound
<T
>)
786 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)>
788 let exp_found
= self.resolve_type_vars_if_possible(exp_found
);
789 if exp_found
.references_error() {
793 Some((DiagnosticStyledString
::highlighted(format
!("{}", exp_found
.expected
)),
794 DiagnosticStyledString
::highlighted(format
!("{}", exp_found
.found
))))
797 fn report_generic_bound_failure(&self,
798 origin
: SubregionOrigin
<'tcx
>,
799 bound_kind
: GenericKind
<'tcx
>,
802 // FIXME: it would be better to report the first error message
803 // with the span of the parameter itself, rather than the span
804 // where the error was detected. But that span is not readily
807 let labeled_user_string
= match bound_kind
{
808 GenericKind
::Param(ref p
) =>
809 format
!("the parameter type `{}`", p
),
810 GenericKind
::Projection(ref p
) =>
811 format
!("the associated type `{}`", p
),
814 if let SubregionOrigin
::CompareImplMethodObligation
{
815 span
, item_name
, impl_item_def_id
, trait_item_def_id
, lint_id
817 self.report_extra_impl_obligation(span
,
821 &format
!("`{}: {}`", bound_kind
, sub
),
827 let mut err
= match *sub
{
828 ty
::ReEarlyBound(_
) |
829 ty
::ReFree(ty
::FreeRegion {bound_region: ty::BrNamed(..), ..}
) => {
830 // Does the required lifetime have a nice name we can print?
831 let mut err
= struct_span_err
!(self.tcx
.sess
,
834 "{} may not live long enough",
835 labeled_user_string
);
836 err
.help(&format
!("consider adding an explicit lifetime bound `{}: {}`...",
843 // Does the required lifetime have a nice name we can print?
844 let mut err
= struct_span_err
!(self.tcx
.sess
,
847 "{} may not live long enough",
848 labeled_user_string
);
849 err
.help(&format
!("consider adding an explicit lifetime \
850 bound `{}: 'static`...",
856 // If not, be less specific.
857 let mut err
= struct_span_err
!(self.tcx
.sess
,
860 "{} may not live long enough",
861 labeled_user_string
);
862 err
.help(&format
!("consider adding an explicit lifetime bound for `{}`",
864 self.tcx
.note_and_explain_region(
866 &format
!("{} must be valid for ", labeled_user_string
),
873 self.note_region_origin(&mut err
, &origin
);
877 fn report_sub_sup_conflict(&self,
878 var_origin
: RegionVariableOrigin
,
879 sub_origin
: SubregionOrigin
<'tcx
>,
880 sub_region
: Region
<'tcx
>,
881 sup_origin
: SubregionOrigin
<'tcx
>,
882 sup_region
: Region
<'tcx
>) {
883 let mut err
= self.report_inference_failure(var_origin
);
885 self.tcx
.note_and_explain_region(&mut err
,
886 "first, the lifetime cannot outlive ",
890 self.note_region_origin(&mut err
, &sup_origin
);
892 self.tcx
.note_and_explain_region(&mut err
,
893 "but, the lifetime must be valid for ",
897 self.note_region_origin(&mut err
, &sub_origin
);
902 impl<'a
, 'gcx
, 'tcx
> InferCtxt
<'a
, 'gcx
, 'tcx
> {
903 fn report_inference_failure(&self,
904 var_origin
: RegionVariableOrigin
)
905 -> DiagnosticBuilder
<'tcx
> {
906 let br_string
= |br
: ty
::BoundRegion
| {
907 let mut s
= br
.to_string();
913 let var_description
= match var_origin
{
914 infer
::MiscVariable(_
) => "".to_string(),
915 infer
::PatternRegion(_
) => " for pattern".to_string(),
916 infer
::AddrOfRegion(_
) => " for borrow expression".to_string(),
917 infer
::Autoref(_
) => " for autoref".to_string(),
918 infer
::Coercion(_
) => " for automatic coercion".to_string(),
919 infer
::LateBoundRegion(_
, br
, infer
::FnCall
) => {
920 format
!(" for lifetime parameter {}in function call",
923 infer
::LateBoundRegion(_
, br
, infer
::HigherRankedType
) => {
924 format
!(" for lifetime parameter {}in generic type", br_string(br
))
926 infer
::LateBoundRegion(_
, br
, infer
::AssocTypeProjection(type_name
)) => {
927 format
!(" for lifetime parameter {}in trait containing associated type `{}`",
928 br_string(br
), type_name
)
930 infer
::EarlyBoundRegion(_
, name
, _
) => {
931 format
!(" for lifetime parameter `{}`",
934 infer
::BoundRegionInCoherence(name
) => {
935 format
!(" for lifetime parameter `{}` in coherence check",
938 infer
::UpvarRegion(ref upvar_id
, _
) => {
939 format
!(" for capture of `{}` by closure",
940 self.tcx
.local_var_name_str(upvar_id
.var_id
).to_string())
944 struct_span_err
!(self.tcx
.sess
, var_origin
.span(), E0495
,
945 "cannot infer an appropriate lifetime{} \
946 due to conflicting requirements",
951 impl<'tcx
> ObligationCause
<'tcx
> {
952 fn as_failure_str(&self) -> &'
static str {
953 use traits
::ObligationCauseCode
::*;
955 CompareImplMethodObligation { .. }
=> "method not compatible with trait",
956 MatchExpressionArm { source, .. }
=> match source
{
957 hir
::MatchSource
::IfLetDesugar{..}
=> "`if let` arms have incompatible types",
958 _
=> "match arms have incompatible types",
960 IfExpression
=> "if and else have incompatible types",
961 IfExpressionWithNoElse
=> "if may be missing an else clause",
962 EquatePredicate
=> "equality predicate not satisfied",
963 MainFunctionType
=> "main function has wrong type",
964 StartFunctionType
=> "start function has wrong type",
965 IntrinsicType
=> "intrinsic has wrong type",
966 MethodReceiver
=> "mismatched method receiver",
967 _
=> "mismatched types",
971 fn as_requirement_str(&self) -> &'
static str {
972 use traits
::ObligationCauseCode
::*;
974 CompareImplMethodObligation { .. }
=> "method type is compatible with trait",
975 ExprAssignable
=> "expression is assignable",
976 MatchExpressionArm { source, .. }
=> match source
{
977 hir
::MatchSource
::IfLetDesugar{..}
=> "`if let` arms have compatible types",
978 _
=> "match arms have compatible types",
980 IfExpression
=> "if and else have compatible types",
981 IfExpressionWithNoElse
=> "if missing an else returns ()",
982 EquatePredicate
=> "equality where clause is satisfied",
983 MainFunctionType
=> "`main` function has the correct type",
984 StartFunctionType
=> "`start` function has the correct type",
985 IntrinsicType
=> "intrinsic has the correct type",
986 MethodReceiver
=> "method receiver has the correct type",
987 _
=> "types are compatible",