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, 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}
;
80 mod named_anon_conflict
;
83 mod anon_anon_conflict
;
85 impl<'a
, 'gcx
, 'tcx
> TyCtxt
<'a
, 'gcx
, 'tcx
> {
86 pub fn note_and_explain_region(self,
87 err
: &mut DiagnosticBuilder
,
89 region
: ty
::Region
<'tcx
>,
91 fn item_scope_tag(item
: &hir
::Item
) -> &'
static str {
93 hir
::ItemImpl(..) => "impl",
94 hir
::ItemStruct(..) => "struct",
95 hir
::ItemUnion(..) => "union",
96 hir
::ItemEnum(..) => "enum",
97 hir
::ItemTrait(..) => "trait",
98 hir
::ItemFn(..) => "function body",
103 fn trait_item_scope_tag(item
: &hir
::TraitItem
) -> &'
static str {
105 hir
::TraitItemKind
::Method(..) => "method body",
106 hir
::TraitItemKind
::Const(..) |
107 hir
::TraitItemKind
::Type(..) => "associated item"
111 fn impl_item_scope_tag(item
: &hir
::ImplItem
) -> &'
static str {
113 hir
::ImplItemKind
::Method(..) => "method body",
114 hir
::ImplItemKind
::Const(..) |
115 hir
::ImplItemKind
::Type(_
) => "associated item"
119 fn explain_span
<'a
, 'gcx
, 'tcx
>(tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
120 heading
: &str, span
: Span
)
121 -> (String
, Option
<Span
>) {
122 let lo
= tcx
.sess
.codemap().lookup_char_pos_adj(span
.lo
);
123 (format
!("the {} at {}:{}", heading
, lo
.line
, lo
.col
.to_usize() + 1),
127 let (description
, span
) = match *region
{
128 ty
::ReScope(scope
) => {
130 let unknown_scope
= || {
131 format
!("{}unknown scope: {:?}{}. Please report a bug.",
132 prefix
, scope
, suffix
)
134 let span
= match scope
.span(&self.hir
) {
137 err
.note(&unknown_scope());
141 let tag
= match self.hir
.find(scope
.node_id()) {
142 Some(hir_map
::NodeBlock(_
)) => "block",
143 Some(hir_map
::NodeExpr(expr
)) => match expr
.node
{
144 hir
::ExprCall(..) => "call",
145 hir
::ExprMethodCall(..) => "method call",
146 hir
::ExprMatch(.., hir
::MatchSource
::IfLetDesugar { .. }
) => "if let",
147 hir
::ExprMatch(.., hir
::MatchSource
::WhileLetDesugar
) => "while let",
148 hir
::ExprMatch(.., hir
::MatchSource
::ForLoopDesugar
) => "for",
149 hir
::ExprMatch(..) => "match",
152 Some(hir_map
::NodeStmt(_
)) => "statement",
153 Some(hir_map
::NodeItem(it
)) => item_scope_tag(&it
),
154 Some(hir_map
::NodeTraitItem(it
)) => trait_item_scope_tag(&it
),
155 Some(hir_map
::NodeImplItem(it
)) => impl_item_scope_tag(&it
),
157 err
.span_note(span
, &unknown_scope());
161 let scope_decorated_tag
= match scope
{
162 region
::CodeExtent
::Misc(_
) => tag
,
163 region
::CodeExtent
::CallSiteScope(_
) => {
164 "scope of call-site for function"
166 region
::CodeExtent
::ParameterScope(_
) => {
167 "scope of function body"
169 region
::CodeExtent
::DestructionScope(_
) => {
170 new_string
= format
!("destruction scope surrounding {}", tag
);
173 region
::CodeExtent
::Remainder(r
) => {
174 new_string
= format
!("block suffix following statement {}",
175 r
.first_statement_index
);
179 explain_span(self, scope_decorated_tag
, span
)
182 ty
::ReEarlyBound(_
) |
184 let scope
= match *region
{
185 ty
::ReEarlyBound(ref br
) => {
186 self.parent_def_id(br
.def_id
).unwrap()
188 ty
::ReFree(ref fr
) => fr
.scope
,
191 let prefix
= match *region
{
192 ty
::ReEarlyBound(ref br
) => {
193 format
!("the lifetime {} as defined on", br
.name
)
195 ty
::ReFree(ref fr
) => {
196 match fr
.bound_region
{
198 format
!("the anonymous lifetime #{} defined on", idx
+ 1)
200 ty
::BrFresh(_
) => "an anonymous lifetime defined on".to_owned(),
202 format
!("the lifetime {} as defined on",
210 let node
= self.hir
.as_local_node_id(scope
)
211 .unwrap_or(DUMMY_NODE_ID
);
213 let tag
= match self.hir
.find(node
) {
214 Some(hir_map
::NodeBlock(_
)) |
215 Some(hir_map
::NodeExpr(_
)) => "body",
216 Some(hir_map
::NodeItem(it
)) => item_scope_tag(&it
),
217 Some(hir_map
::NodeTraitItem(it
)) => trait_item_scope_tag(&it
),
218 Some(hir_map
::NodeImplItem(it
)) => impl_item_scope_tag(&it
),
220 // this really should not happen, but it does:
223 unknown
= format
!("unexpected node ({}) for scope {:?}. \
224 Please report a bug.",
225 self.hir
.node_to_string(node
), scope
);
229 unknown
= format
!("unknown node for scope {:?}. \
230 Please report a bug.", scope
);
234 let (msg
, opt_span
) = explain_span(self, tag
, self.hir
.span(node
));
235 (format
!("{} {}", prefix
, msg
), opt_span
)
238 ty
::ReStatic
=> ("the static lifetime".to_owned(), None
),
240 ty
::ReEmpty
=> ("the empty lifetime".to_owned(), None
),
242 // FIXME(#13998) ReSkolemized should probably print like
243 // ReFree rather than dumping Debug output on the user.
245 // We shouldn't really be having unification failures with ReVar
246 // and ReLateBound though.
247 ty
::ReSkolemized(..) |
249 ty
::ReLateBound(..) |
251 (format
!("lifetime {:?}", region
), None
)
254 let message
= format
!("{}{}{}", prefix
, description
, suffix
);
255 if let Some(span
) = span
{
256 err
.span_note(span
, &message
);
263 impl<'a
, 'gcx
, 'tcx
> InferCtxt
<'a
, 'gcx
, 'tcx
> {
265 pub fn report_region_errors(&self, errors
: &Vec
<RegionResolutionError
<'tcx
>>) {
266 debug
!("report_region_errors(): {} errors to start", errors
.len());
268 // try to pre-process the errors, which will group some of them
269 // together into a `ProcessedErrors` group:
270 let errors
= self.process_errors(errors
);
272 debug
!("report_region_errors: {} errors after preprocessing", errors
.len());
274 for error
in errors
{
275 debug
!("report_region_errors: error = {:?}", error
);
277 if !self.try_report_named_anon_conflict(&error
) &&
278 !self.try_report_anon_anon_conflict(&error
) {
280 match error
.clone() {
281 // These errors could indicate all manner of different
282 // problems with many different solutions. Rather
283 // than generate a "one size fits all" error, what we
284 // attempt to do is go through a number of specific
285 // scenarios and try to find the best way to present
286 // the error. If all of these fails, we fall back to a rather
287 // general bit of code that displays the error information
288 ConcreteFailure(origin
, sub
, sup
) => {
290 self.report_concrete_failure(origin
, sub
, sup
).emit();
293 GenericBoundFailure(kind
, param_ty
, sub
) => {
294 self.report_generic_bound_failure(kind
, param_ty
, sub
);
297 SubSupConflict(var_origin
, sub_origin
, sub_r
, sup_origin
, sup_r
) => {
298 self.report_sub_sup_conflict(var_origin
,
309 // This method goes through all the errors and try to group certain types
310 // of error together, for the purpose of suggesting explicit lifetime
311 // parameters to the user. This is done so that we can have a more
312 // complete view of what lifetimes should be the same.
313 // If the return value is an empty vector, it means that processing
314 // failed (so the return value of this method should not be used).
316 // The method also attempts to weed out messages that seem like
317 // duplicates that will be unhelpful to the end-user. But
318 // obviously it never weeds out ALL errors.
319 fn process_errors(&self, errors
: &Vec
<RegionResolutionError
<'tcx
>>)
320 -> Vec
<RegionResolutionError
<'tcx
>> {
321 debug
!("process_errors()");
323 // We want to avoid reporting generic-bound failures if we can
324 // avoid it: these have a very high rate of being unhelpful in
325 // practice. This is because they are basically secondary
326 // checks that test the state of the region graph after the
327 // rest of inference is done, and the other kinds of errors
328 // indicate that the region constraint graph is internally
329 // inconsistent, so these test results are likely to be
332 // Therefore, we filter them out of the list unless they are
333 // the only thing in the list.
335 let is_bound_failure
= |e
: &RegionResolutionError
<'tcx
>| match *e
{
336 ConcreteFailure(..) => false,
337 SubSupConflict(..) => false,
338 GenericBoundFailure(..) => true,
341 if errors
.iter().all(|e
| is_bound_failure(e
)) {
344 errors
.iter().filter(|&e
| !is_bound_failure(e
)).cloned().collect()
348 /// Adds a note if the types come from similarly named crates
349 fn check_and_note_conflicting_crates(&self,
350 err
: &mut DiagnosticBuilder
,
351 terr
: &TypeError
<'tcx
>,
353 let report_path_match
= |err
: &mut DiagnosticBuilder
, did1
: DefId
, did2
: DefId
| {
354 // Only external crates, if either is from a local
355 // module we could have false positives
356 if !(did1
.is_local() || did2
.is_local()) && did1
.krate
!= did2
.krate
{
357 let exp_path
= self.tcx
.item_path_str(did1
);
358 let found_path
= self.tcx
.item_path_str(did2
);
359 let exp_abs_path
= self.tcx
.absolute_item_path_str(did1
);
360 let found_abs_path
= self.tcx
.absolute_item_path_str(did2
);
361 // We compare strings because DefPath can be different
362 // for imported and non-imported crates
363 if exp_path
== found_path
364 || exp_abs_path
== found_abs_path
{
365 let crate_name
= self.tcx
.sess
.cstore
.crate_name(did1
.krate
);
366 err
.span_note(sp
, &format
!("Perhaps two different versions \
367 of crate `{}` are being used?",
373 TypeError
::Sorts(ref exp_found
) => {
374 // if they are both "path types", there's a chance of ambiguity
375 // due to different versions of the same crate
376 match (&exp_found
.expected
.sty
, &exp_found
.found
.sty
) {
377 (&ty
::TyAdt(exp_adt
, _
), &ty
::TyAdt(found_adt
, _
)) => {
378 report_path_match(err
, exp_adt
.did
, found_adt
.did
);
383 TypeError
::Traits(ref exp_found
) => {
384 report_path_match(err
, exp_found
.expected
, exp_found
.found
);
386 _
=> () // FIXME(#22750) handle traits and stuff
390 fn note_error_origin(&self,
391 err
: &mut DiagnosticBuilder
<'tcx
>,
392 cause
: &ObligationCause
<'tcx
>)
395 ObligationCauseCode
::MatchExpressionArm { arm_span, source }
=> match source
{
396 hir
::MatchSource
::IfLetDesugar {..}
=> {
397 err
.span_note(arm_span
, "`if let` arm with an incompatible type");
400 err
.span_note(arm_span
, "match arm with an incompatible type");
407 /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
408 /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
409 /// populate `other_value` with `other_ty`.
413 /// ^^^^--------^ this is highlighted
415 /// | this type argument is exactly the same as the other type, not highlighted
416 /// this is highlighted
418 /// -------- this type is the same as a type argument in the other type, not highlighted
420 fn highlight_outer(&self,
421 value
: &mut DiagnosticStyledString
,
422 other_value
: &mut DiagnosticStyledString
,
424 sub
: &ty
::subst
::Substs
<'tcx
>,
426 other_ty
: &ty
::Ty
<'tcx
>) {
427 // `value` and `other_value` hold two incomplete type representation for display.
428 // `name` is the path of both types being compared. `sub`
429 value
.push_highlighted(name
);
432 value
.push_highlighted("<");
435 // Output the lifetimes fot the first type
436 let lifetimes
= sub
.regions().map(|lifetime
| {
437 let s
= format
!("{}", lifetime
);
443 }).collect
::<Vec
<_
>>().join(", ");
444 if !lifetimes
.is_empty() {
445 if sub
.regions().count() < len
{
446 value
.push_normal(lifetimes
+ &", ");
448 value
.push_normal(lifetimes
);
452 // Highlight all the type arguments that aren't at `pos` and compare the type argument at
453 // `pos` and `other_ty`.
454 for (i
, type_arg
) in sub
.types().enumerate() {
456 let values
= self.cmp(type_arg
, other_ty
);
457 value
.0.extend((values
.0).0);
458 other_value
.0.extend((values
.1).0);
460 value
.push_highlighted(format
!("{}", type_arg
));
463 if len
> 0 && i
!= len
- 1 {
464 value
.push_normal(", ");
466 //self.push_comma(&mut value, &mut other_value, len, i);
469 value
.push_highlighted(">");
473 /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`,
474 /// as that is the difference to the other type.
476 /// For the following code:
479 /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>();
482 /// The type error output will behave in the following way:
486 /// ^^^^--------^ this is highlighted
488 /// | this type argument is exactly the same as the other type, not highlighted
489 /// this is highlighted
491 /// -------- this type is the same as a type argument in the other type, not highlighted
493 fn cmp_type_arg(&self,
494 mut t1_out
: &mut DiagnosticStyledString
,
495 mut t2_out
: &mut DiagnosticStyledString
,
497 sub
: &ty
::subst
::Substs
<'tcx
>,
499 other_ty
: &ty
::Ty
<'tcx
>) -> Option
<()> {
500 for (i
, ta
) in sub
.types().enumerate() {
502 self.highlight_outer(&mut t1_out
, &mut t2_out
, path
, sub
, i
, &other_ty
);
505 if let &ty
::TyAdt(def
, _
) = &ta
.sty
{
506 let path_
= self.tcx
.item_path_str(def
.did
.clone());
507 if path_
== other_path
{
508 self.highlight_outer(&mut t1_out
, &mut t2_out
, path
, sub
, i
, &other_ty
);
516 /// Add a `,` to the type representation only if it is appropriate.
518 value
: &mut DiagnosticStyledString
,
519 other_value
: &mut DiagnosticStyledString
,
522 if len
> 0 && pos
!= len
- 1 {
523 value
.push_normal(", ");
524 other_value
.push_normal(", ");
528 /// Compare two given types, eliding parts that are the same between them and highlighting
529 /// relevant differences, and return two representation of those types for highlighted printing.
530 fn cmp(&self, t1
: ty
::Ty
<'tcx
>, t2
: ty
::Ty
<'tcx
>)
531 -> (DiagnosticStyledString
, DiagnosticStyledString
)
533 match (&t1
.sty
, &t2
.sty
) {
534 (&ty
::TyAdt(def1
, sub1
), &ty
::TyAdt(def2
, sub2
)) => {
535 let mut values
= (DiagnosticStyledString
::new(), DiagnosticStyledString
::new());
536 let path1
= self.tcx
.item_path_str(def1
.did
.clone());
537 let path2
= self.tcx
.item_path_str(def2
.did
.clone());
538 if def1
.did
== def2
.did
{
539 // Easy case. Replace same types with `_` to shorten the output and highlight
540 // the differing ones.
541 // let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>();
544 // --- ^ type argument elided
546 // highlighted in output
547 values
.0.push_normal(path1
);
548 values
.1.push_normal(path2
);
550 // Only draw `<...>` if there're lifetime/type arguments.
551 let len
= sub1
.len();
553 values
.0.push_normal("<");
554 values
.1.push_normal("<");
557 fn lifetime_display(lifetime
: Region
) -> String
{
558 let s
= format
!("{}", lifetime
);
565 // At one point we'd like to elide all lifetimes here, they are irrelevant for
566 // all diagnostics that use this output
570 // ^^ ^^ --- type arguments are not elided
572 // | elided as they were the same
573 // not elided, they were different, but irrelevant
574 let lifetimes
= sub1
.regions().zip(sub2
.regions());
575 for (i
, lifetimes
) in lifetimes
.enumerate() {
576 let l1
= lifetime_display(lifetimes
.0);
577 let l2
= lifetime_display(lifetimes
.1);
579 values
.0.push_normal("'_");
580 values
.1.push_normal("'_");
582 values
.0.push_highlighted(l1
);
583 values
.1.push_highlighted(l2
);
585 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
588 // We're comparing two types with the same path, so we compare the type
589 // arguments for both. If they are the same, do not highlight and elide from the
593 // ^ elided type as this type argument was the same in both sides
594 let type_arguments
= sub1
.types().zip(sub2
.types());
595 let regions_len
= sub1
.regions().collect
::<Vec
<_
>>().len();
596 for (i
, (ta1
, ta2
)) in type_arguments
.enumerate() {
597 let i
= i
+ regions_len
;
599 values
.0.push_normal("_");
600 values
.1.push_normal("_");
602 let (x1
, x2
) = self.cmp(ta1
, ta2
);
603 (values
.0).0.extend(x1
.0
);
604 (values
.1).0.extend(x2
.0
);
606 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
609 // Close the type argument bracket.
610 // Only draw `<...>` if there're lifetime/type arguments.
612 values
.0.push_normal(">");
613 values
.1.push_normal(">");
618 // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>();
620 // ------- this type argument is exactly the same as the other type
622 if self.cmp_type_arg(&mut values
.0,
631 // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>();
634 // ------- this type argument is exactly the same as the other type
635 if self.cmp_type_arg(&mut values
.1,
644 // We couldn't find anything in common, highlight everything.
645 // let x: Bar<Qux> = y::<Foo<Zar>>();
646 (DiagnosticStyledString
::highlighted(format
!("{}", t1
)),
647 DiagnosticStyledString
::highlighted(format
!("{}", t2
)))
652 // The two types are the same, elide and don't highlight.
653 (DiagnosticStyledString
::normal("_"), DiagnosticStyledString
::normal("_"))
655 // We couldn't find anything in common, highlight everything.
656 (DiagnosticStyledString
::highlighted(format
!("{}", t1
)),
657 DiagnosticStyledString
::highlighted(format
!("{}", t2
)))
663 pub fn note_type_err(&self,
664 diag
: &mut DiagnosticBuilder
<'tcx
>,
665 cause
: &ObligationCause
<'tcx
>,
666 secondary_span
: Option
<(Span
, String
)>,
667 values
: Option
<ValuePairs
<'tcx
>>,
668 terr
: &TypeError
<'tcx
>)
670 let (expected_found
, is_simple_error
) = match values
{
671 None
=> (None
, false),
673 let is_simple_error
= match values
{
674 ValuePairs
::Types(exp_found
) => {
675 exp_found
.expected
.is_primitive() && exp_found
.found
.is_primitive()
679 let vals
= match self.values_str(&values
) {
680 Some((expected
, found
)) => Some((expected
, found
)),
682 // Derived error. Cancel the emitter.
683 self.tcx
.sess
.diagnostic().cancel(diag
);
687 (vals
, is_simple_error
)
691 let span
= cause
.span
;
693 if let Some((expected
, found
)) = expected_found
{
694 match (terr
, is_simple_error
, expected
== found
) {
695 (&TypeError
::Sorts(ref values
), false, true) => {
696 diag
.note_expected_found_extra(
697 &"type", expected
, found
,
698 &format
!(" ({})", values
.expected
.sort_string(self.tcx
)),
699 &format
!(" ({})", values
.found
.sort_string(self.tcx
)));
702 diag
.note_expected_found(&"type", expected
, found
);
708 diag
.span_label(span
, terr
.to_string());
709 if let Some((sp
, msg
)) = secondary_span
{
710 diag
.span_label(sp
, msg
);
713 self.note_error_origin(diag
, &cause
);
714 self.check_and_note_conflicting_crates(diag
, terr
, span
);
715 self.tcx
.note_and_explain_type_err(diag
, terr
, span
);
718 pub fn note_issue_32330(&self,
719 diag
: &mut DiagnosticBuilder
<'tcx
>,
720 terr
: &TypeError
<'tcx
>)
722 debug
!("note_issue_32330: terr={:?}", terr
);
724 TypeError
::RegionsInsufficientlyPolymorphic(_
, _
, Some(box Issue32330
{
725 fn_def_id
, region_name
727 TypeError
::RegionsOverlyPolymorphic(_
, _
, Some(box Issue32330
{
728 fn_def_id
, region_name
731 &format
!("lifetime parameter `{0}` declared on fn `{1}` \
732 appears only in the return type, \
733 but here is required to be higher-ranked, \
734 which means that `{0}` must appear in both \
735 argument and return types",
737 self.tcx
.item_path_str(fn_def_id
)));
739 &format
!("this error is the result of a recent bug fix; \
740 for more information, see issue #33685 \
741 <https://github.com/rust-lang/rust/issues/33685>"));
747 pub fn report_and_explain_type_error(&self,
748 trace
: TypeTrace
<'tcx
>,
749 terr
: &TypeError
<'tcx
>)
750 -> DiagnosticBuilder
<'tcx
>
752 let span
= trace
.cause
.span
;
753 let failure_str
= trace
.cause
.as_failure_str();
754 let mut diag
= match trace
.cause
.code
{
755 ObligationCauseCode
::IfExpressionWithNoElse
=> {
756 struct_span_err
!(self.tcx
.sess
, span
, E0317
, "{}", failure_str
)
758 ObligationCauseCode
::MainFunctionType
=> {
759 struct_span_err
!(self.tcx
.sess
, span
, E0580
, "{}", failure_str
)
762 struct_span_err
!(self.tcx
.sess
, span
, E0308
, "{}", failure_str
)
765 self.note_type_err(&mut diag
, &trace
.cause
, None
, Some(trace
.values
), terr
);
766 self.note_issue_32330(&mut diag
, terr
);
770 fn values_str(&self, values
: &ValuePairs
<'tcx
>)
771 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)>
774 infer
::Types(ref exp_found
) => self.expected_found_str_ty(exp_found
),
775 infer
::TraitRefs(ref exp_found
) => self.expected_found_str(exp_found
),
776 infer
::PolyTraitRefs(ref exp_found
) => self.expected_found_str(exp_found
),
780 fn expected_found_str_ty(&self,
781 exp_found
: &ty
::error
::ExpectedFound
<ty
::Ty
<'tcx
>>)
782 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)> {
783 let exp_found
= self.resolve_type_vars_if_possible(exp_found
);
784 if exp_found
.references_error() {
788 Some(self.cmp(exp_found
.expected
, exp_found
.found
))
791 /// Returns a string of the form "expected `{}`, found `{}`".
792 fn expected_found_str
<T
: fmt
::Display
+ TypeFoldable
<'tcx
>>(
794 exp_found
: &ty
::error
::ExpectedFound
<T
>)
795 -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)>
797 let exp_found
= self.resolve_type_vars_if_possible(exp_found
);
798 if exp_found
.references_error() {
802 Some((DiagnosticStyledString
::highlighted(format
!("{}", exp_found
.expected
)),
803 DiagnosticStyledString
::highlighted(format
!("{}", exp_found
.found
))))
806 fn report_generic_bound_failure(&self,
807 origin
: SubregionOrigin
<'tcx
>,
808 bound_kind
: GenericKind
<'tcx
>,
811 // FIXME: it would be better to report the first error message
812 // with the span of the parameter itself, rather than the span
813 // where the error was detected. But that span is not readily
816 let labeled_user_string
= match bound_kind
{
817 GenericKind
::Param(ref p
) =>
818 format
!("the parameter type `{}`", p
),
819 GenericKind
::Projection(ref p
) =>
820 format
!("the associated type `{}`", p
),
823 if let SubregionOrigin
::CompareImplMethodObligation
{
824 span
, item_name
, impl_item_def_id
, trait_item_def_id
, lint_id
826 self.report_extra_impl_obligation(span
,
830 &format
!("`{}: {}`", bound_kind
, sub
),
836 let mut err
= match *sub
{
837 ty
::ReEarlyBound(_
) |
838 ty
::ReFree(ty
::FreeRegion {bound_region: ty::BrNamed(..), ..}
) => {
839 // Does the required lifetime have a nice name we can print?
840 let mut err
= struct_span_err
!(self.tcx
.sess
,
843 "{} may not live long enough",
844 labeled_user_string
);
845 err
.help(&format
!("consider adding an explicit lifetime bound `{}: {}`...",
852 // Does the required lifetime have a nice name we can print?
853 let mut err
= struct_span_err
!(self.tcx
.sess
,
856 "{} may not live long enough",
857 labeled_user_string
);
858 err
.help(&format
!("consider adding an explicit lifetime \
859 bound `{}: 'static`...",
865 // If not, be less specific.
866 let mut err
= struct_span_err
!(self.tcx
.sess
,
869 "{} may not live long enough",
870 labeled_user_string
);
871 err
.help(&format
!("consider adding an explicit lifetime bound for `{}`",
873 self.tcx
.note_and_explain_region(
875 &format
!("{} must be valid for ", labeled_user_string
),
882 self.note_region_origin(&mut err
, &origin
);
886 fn report_sub_sup_conflict(&self,
887 var_origin
: RegionVariableOrigin
,
888 sub_origin
: SubregionOrigin
<'tcx
>,
889 sub_region
: Region
<'tcx
>,
890 sup_origin
: SubregionOrigin
<'tcx
>,
891 sup_region
: Region
<'tcx
>) {
892 let mut err
= self.report_inference_failure(var_origin
);
894 self.tcx
.note_and_explain_region(&mut err
,
895 "first, the lifetime cannot outlive ",
899 self.note_region_origin(&mut err
, &sup_origin
);
901 self.tcx
.note_and_explain_region(&mut err
,
902 "but, the lifetime must be valid for ",
906 self.note_region_origin(&mut err
, &sub_origin
);
911 impl<'a
, 'gcx
, 'tcx
> InferCtxt
<'a
, 'gcx
, 'tcx
> {
912 fn report_inference_failure(&self,
913 var_origin
: RegionVariableOrigin
)
914 -> DiagnosticBuilder
<'tcx
> {
915 let br_string
= |br
: ty
::BoundRegion
| {
916 let mut s
= br
.to_string();
922 let var_description
= match var_origin
{
923 infer
::MiscVariable(_
) => "".to_string(),
924 infer
::PatternRegion(_
) => " for pattern".to_string(),
925 infer
::AddrOfRegion(_
) => " for borrow expression".to_string(),
926 infer
::Autoref(_
) => " for autoref".to_string(),
927 infer
::Coercion(_
) => " for automatic coercion".to_string(),
928 infer
::LateBoundRegion(_
, br
, infer
::FnCall
) => {
929 format
!(" for lifetime parameter {}in function call",
932 infer
::LateBoundRegion(_
, br
, infer
::HigherRankedType
) => {
933 format
!(" for lifetime parameter {}in generic type", br_string(br
))
935 infer
::LateBoundRegion(_
, br
, infer
::AssocTypeProjection(def_id
)) => {
936 format
!(" for lifetime parameter {}in trait containing associated type `{}`",
937 br_string(br
), self.tcx
.associated_item(def_id
).name
)
939 infer
::EarlyBoundRegion(_
, name
, _
) => {
940 format
!(" for lifetime parameter `{}`",
943 infer
::BoundRegionInCoherence(name
) => {
944 format
!(" for lifetime parameter `{}` in coherence check",
947 infer
::UpvarRegion(ref upvar_id
, _
) => {
948 format
!(" for capture of `{}` by closure",
949 self.tcx
.local_var_name_str_def_index(upvar_id
.var_id
))
953 struct_span_err
!(self.tcx
.sess
, var_origin
.span(), E0495
,
954 "cannot infer an appropriate lifetime{} \
955 due to conflicting requirements",
960 impl<'tcx
> ObligationCause
<'tcx
> {
961 fn as_failure_str(&self) -> &'
static str {
962 use traits
::ObligationCauseCode
::*;
964 CompareImplMethodObligation { .. }
=> "method not compatible with trait",
965 MatchExpressionArm { source, .. }
=> match source
{
966 hir
::MatchSource
::IfLetDesugar{..}
=> "`if let` arms have incompatible types",
967 _
=> "match arms have incompatible types",
969 IfExpression
=> "if and else have incompatible types",
970 IfExpressionWithNoElse
=> "if may be missing an else clause",
971 EquatePredicate
=> "equality predicate not satisfied",
972 MainFunctionType
=> "main function has wrong type",
973 StartFunctionType
=> "start function has wrong type",
974 IntrinsicType
=> "intrinsic has wrong type",
975 MethodReceiver
=> "mismatched method receiver",
976 _
=> "mismatched types",
980 fn as_requirement_str(&self) -> &'
static str {
981 use traits
::ObligationCauseCode
::*;
983 CompareImplMethodObligation { .. }
=> "method type is compatible with trait",
984 ExprAssignable
=> "expression is assignable",
985 MatchExpressionArm { source, .. }
=> match source
{
986 hir
::MatchSource
::IfLetDesugar{..}
=> "`if let` arms have compatible types",
987 _
=> "match arms have compatible types",
989 IfExpression
=> "if and else have compatible types",
990 IfExpressionWithNoElse
=> "if missing an else returns ()",
991 EquatePredicate
=> "equality where clause is satisfied",
992 MainFunctionType
=> "`main` function has the correct type",
993 StartFunctionType
=> "`start` function has the correct type",
994 IntrinsicType
=> "intrinsic has the correct type",
995 MethodReceiver
=> "method receiver has the correct type",
996 _
=> "types are compatible",