1 //! Error Reporting Code for the inference engine
3 //! Because of the way inference, and in particular region inference,
4 //! works, it often happens that errors are not detected until far after
5 //! the relevant line of code has been type-checked. Therefore, there is
6 //! an elaborate system to track why a particular constraint in the
7 //! inference graph arose so that we can explain to the user what gave
8 //! rise to a particular error.
10 //! The basis of the system are the "origin" types. An "origin" is the
11 //! reason that a constraint or inference variable arose. There are
12 //! different "origin" enums for different kinds of constraints/variables
13 //! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has
14 //! a span, but also more information so that we can generate a meaningful
17 //! Having a catalog of all the different reasons an error can arise is
18 //! also useful for other reasons, like cross-referencing FAQs etc, though
19 //! we are not really taking advantage of this yet.
21 //! # Region Inference
23 //! Region inference is particularly tricky because it always succeeds "in
24 //! the moment" and simply registers a constraint. Then, at the end, we
25 //! can compute the full graph and report errors, so we need to be able to
26 //! store and later report what gave rise to the conflicting constraints.
30 //! Determining whether `T1 <: T2` often involves a number of subtypes and
31 //! subconstraints along the way. A "TypeTrace" is an extended version
32 //! of an origin that traces the types and other values that were being
33 //! compared. It is not necessarily comprehensive (in fact, at the time of
34 //! this writing it only tracks the root values being compared) but I'd
35 //! like to extend it to include significant "waypoints". For example, if
36 //! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2
37 //! <: T4` fails, I'd like the trace to include enough information to say
38 //! "in the 2nd element of the tuple". Similarly, failures when comparing
39 //! arguments or return types in fn types should be able to cite the
40 //! specific position, etc.
44 //! Of course, there is still a LOT of code in typeck that has yet to be
45 //! ported to this system, and which relies on string concatenation at the
46 //! time of error detection.
48 use super::lexical_region_resolve
::RegionResolutionError
;
49 use super::region_constraints
::GenericKind
;
50 use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}
;
53 use crate::hir
::def_id
::DefId
;
55 use crate::infer
::{self, SuppressRegionErrors}
;
56 use crate::infer
::opaque_types
;
57 use crate::middle
::region
;
59 IfExpressionCause
, MatchExpressionArmCause
, ObligationCause
, ObligationCauseCode
,
61 use crate::ty
::error
::TypeError
;
62 use crate::ty
::{self, subst::{Subst, SubstsRef}
, Region
, Ty
, TyCtxt
, TypeFoldable
};
64 use errors
::{Applicability, DiagnosticBuilder, DiagnosticStyledString}
;
65 use rustc_error_codes
::*;
66 use rustc_target
::spec
::abi
;
67 use syntax_pos
::{Pos, Span}
;
73 pub use need_type_info
::TypeAnnotationNeeded
;
75 pub mod nice_region_error
;
77 impl<'tcx
> TyCtxt
<'tcx
> {
78 pub fn note_and_explain_region(
80 region_scope_tree
: ®ion
::ScopeTree
,
81 err
: &mut DiagnosticBuilder
<'_
>,
83 region
: ty
::Region
<'tcx
>,
86 let (description
, span
) = match *region
{
87 ty
::ReScope(scope
) => {
89 let unknown_scope
= || {
91 "{}unknown scope: {:?}{}. Please report a bug.",
95 let span
= scope
.span(self, region_scope_tree
);
96 let tag
= match self.hir().find(scope
.hir_id(region_scope_tree
)) {
97 Some(Node
::Block(_
)) => "block",
98 Some(Node
::Expr(expr
)) => match expr
.kind
{
99 hir
::ExprKind
::Call(..) => "call",
100 hir
::ExprKind
::MethodCall(..) => "method call",
101 hir
::ExprKind
::Match(.., hir
::MatchSource
::IfLetDesugar { .. }
) => "if let",
102 hir
::ExprKind
::Match(.., hir
::MatchSource
::WhileLetDesugar
) => "while let",
103 hir
::ExprKind
::Match(.., hir
::MatchSource
::ForLoopDesugar
) => "for",
104 hir
::ExprKind
::Match(..) => "match",
107 Some(Node
::Stmt(_
)) => "statement",
108 Some(Node
::Item(it
)) => Self::item_scope_tag(&it
),
109 Some(Node
::TraitItem(it
)) => Self::trait_item_scope_tag(&it
),
110 Some(Node
::ImplItem(it
)) => Self::impl_item_scope_tag(&it
),
112 err
.span_note(span
, &unknown_scope());
116 let scope_decorated_tag
= match scope
.data
{
117 region
::ScopeData
::Node
=> tag
,
118 region
::ScopeData
::CallSite
=> "scope of call-site for function",
119 region
::ScopeData
::Arguments
=> "scope of function body",
120 region
::ScopeData
::Destruction
=> {
121 new_string
= format
!("destruction scope surrounding {}", tag
);
124 region
::ScopeData
::Remainder(first_statement_index
) => {
125 new_string
= format
!(
126 "block suffix following statement {}",
127 first_statement_index
.index()
132 self.explain_span(scope_decorated_tag
, span
)
135 ty
::ReEarlyBound(_
) | ty
::ReFree(_
) | ty
::ReStatic
=> {
136 self.msg_span_from_free_region(region
)
139 ty
::ReEmpty
=> ("the empty lifetime".to_owned(), None
),
141 ty
::RePlaceholder(_
) => (format
!("any other region"), None
),
143 // FIXME(#13998) RePlaceholder should probably print like
144 // ReFree rather than dumping Debug output on the user.
146 // We shouldn't really be having unification failures with ReVar
147 // and ReLateBound though.
148 ty
::ReVar(_
) | ty
::ReLateBound(..) | ty
::ReErased
=> {
149 (format
!("lifetime {:?}", region
), None
)
152 // We shouldn't encounter an error message with ReClosureBound.
153 ty
::ReClosureBound(..) => {
154 bug
!("encountered unexpected ReClosureBound: {:?}", region
,);
158 TyCtxt
::emit_msg_span(err
, prefix
, description
, span
, suffix
);
161 pub fn note_and_explain_free_region(
163 err
: &mut DiagnosticBuilder
<'_
>,
165 region
: ty
::Region
<'tcx
>,
168 let (description
, span
) = self.msg_span_from_free_region(region
);
170 TyCtxt
::emit_msg_span(err
, prefix
, description
, span
, suffix
);
173 fn msg_span_from_free_region(self, region
: ty
::Region
<'tcx
>) -> (String
, Option
<Span
>) {
175 ty
::ReEarlyBound(_
) | ty
::ReFree(_
) => {
176 self.msg_span_from_early_bound_and_free_regions(region
)
178 ty
::ReStatic
=> ("the static lifetime".to_owned(), None
),
179 ty
::ReEmpty
=> ("an empty lifetime".to_owned(), None
),
180 _
=> bug
!("{:?}", region
),
184 fn msg_span_from_early_bound_and_free_regions(
186 region
: ty
::Region
<'tcx
>,
187 ) -> (String
, Option
<Span
>) {
188 let cm
= self.sess
.source_map();
190 let scope
= region
.free_region_binding_scope(self);
191 let node
= self.hir().as_local_hir_id(scope
).unwrap_or(hir
::DUMMY_HIR_ID
);
192 let tag
= match self.hir().find(node
) {
193 Some(Node
::Block(_
)) | Some(Node
::Expr(_
)) => "body",
194 Some(Node
::Item(it
)) => Self::item_scope_tag(&it
),
195 Some(Node
::TraitItem(it
)) => Self::trait_item_scope_tag(&it
),
196 Some(Node
::ImplItem(it
)) => Self::impl_item_scope_tag(&it
),
199 let (prefix
, span
) = match *region
{
200 ty
::ReEarlyBound(ref br
) => {
201 let mut sp
= cm
.def_span(self.hir().span(node
));
202 if let Some(param
) = self.hir()
204 .and_then(|generics
| generics
.get_named(br
.name
))
208 (format
!("the lifetime `{}` as defined on", br
.name
), sp
)
210 ty
::ReFree(ty
::FreeRegion
{
211 bound_region
: ty
::BoundRegion
::BrNamed(_
, name
),
214 let mut sp
= cm
.def_span(self.hir().span(node
));
215 if let Some(param
) = self.hir()
217 .and_then(|generics
| generics
.get_named(name
))
221 (format
!("the lifetime `{}` as defined on", name
), sp
)
223 ty
::ReFree(ref fr
) => match fr
.bound_region
{
225 format
!("the anonymous lifetime #{} defined on", idx
+ 1),
226 self.hir().span(node
),
229 format
!("the lifetime `{}` as defined on", region
),
230 cm
.def_span(self.hir().span(node
)),
235 let (msg
, opt_span
) = self.explain_span(tag
, span
);
236 (format
!("{} {}", prefix
, msg
), opt_span
)
240 err
: &mut DiagnosticBuilder
<'_
>,
246 let message
= format
!("{}{}{}", prefix
, description
, suffix
);
248 if let Some(span
) = span
{
249 err
.span_note(span
, &message
);
255 fn item_scope_tag(item
: &hir
::Item
) -> &'
static str {
257 hir
::ItemKind
::Impl(..) => "impl",
258 hir
::ItemKind
::Struct(..) => "struct",
259 hir
::ItemKind
::Union(..) => "union",
260 hir
::ItemKind
::Enum(..) => "enum",
261 hir
::ItemKind
::Trait(..) => "trait",
262 hir
::ItemKind
::Fn(..) => "function body",
267 fn trait_item_scope_tag(item
: &hir
::TraitItem
) -> &'
static str {
269 hir
::TraitItemKind
::Method(..) => "method body",
270 hir
::TraitItemKind
::Const(..) | hir
::TraitItemKind
::Type(..) => "associated item",
274 fn impl_item_scope_tag(item
: &hir
::ImplItem
) -> &'
static str {
276 hir
::ImplItemKind
::Method(..) => "method body",
277 hir
::ImplItemKind
::Const(..)
278 | hir
::ImplItemKind
::OpaqueTy(..)
279 | hir
::ImplItemKind
::TyAlias(..) => "associated item",
283 fn explain_span(self, heading
: &str, span
: Span
) -> (String
, Option
<Span
>) {
284 let lo
= self.sess
.source_map().lookup_char_pos(span
.lo());
286 format
!("the {} at {}:{}", heading
, lo
.line
, lo
.col
.to_usize() + 1),
292 impl<'a
, 'tcx
> InferCtxt
<'a
, 'tcx
> {
293 pub fn report_region_errors(
295 region_scope_tree
: ®ion
::ScopeTree
,
296 errors
: &Vec
<RegionResolutionError
<'tcx
>>,
297 suppress
: SuppressRegionErrors
,
300 "report_region_errors(): {} errors to start, suppress = {:?}",
305 if suppress
.suppressed() {
309 // try to pre-process the errors, which will group some of them
310 // together into a `ProcessedErrors` group:
311 let errors
= self.process_errors(errors
);
314 "report_region_errors: {} errors after preprocessing",
318 for error
in errors
{
319 debug
!("report_region_errors: error = {:?}", error
);
321 if !self.try_report_nice_region_error(&error
) {
322 match error
.clone() {
323 // These errors could indicate all manner of different
324 // problems with many different solutions. Rather
325 // than generate a "one size fits all" error, what we
326 // attempt to do is go through a number of specific
327 // scenarios and try to find the best way to present
328 // the error. If all of these fails, we fall back to a rather
329 // general bit of code that displays the error information
330 RegionResolutionError
::ConcreteFailure(origin
, sub
, sup
) => {
331 if sub
.is_placeholder() || sup
.is_placeholder() {
332 self.report_placeholder_failure(region_scope_tree
, origin
, sub
, sup
)
335 self.report_concrete_failure(region_scope_tree
, origin
, sub
, sup
)
340 RegionResolutionError
::GenericBoundFailure(origin
, param_ty
, sub
) => {
341 self.report_generic_bound_failure(
350 RegionResolutionError
::SubSupConflict(
358 if sub_r
.is_placeholder() {
359 self.report_placeholder_failure(
366 } else if sup_r
.is_placeholder() {
367 self.report_placeholder_failure(
375 self.report_sub_sup_conflict(
386 RegionResolutionError
::MemberConstraintFailure
{
393 let hidden_ty
= self.resolve_vars_if_possible(&hidden_ty
);
394 opaque_types
::unexpected_hidden_region_diagnostic(
396 Some(region_scope_tree
),
407 // This method goes through all the errors and try to group certain types
408 // of error together, for the purpose of suggesting explicit lifetime
409 // parameters to the user. This is done so that we can have a more
410 // complete view of what lifetimes should be the same.
411 // If the return value is an empty vector, it means that processing
412 // failed (so the return value of this method should not be used).
414 // The method also attempts to weed out messages that seem like
415 // duplicates that will be unhelpful to the end-user. But
416 // obviously it never weeds out ALL errors.
419 errors
: &Vec
<RegionResolutionError
<'tcx
>>,
420 ) -> Vec
<RegionResolutionError
<'tcx
>> {
421 debug
!("process_errors()");
423 // We want to avoid reporting generic-bound failures if we can
424 // avoid it: these have a very high rate of being unhelpful in
425 // practice. This is because they are basically secondary
426 // checks that test the state of the region graph after the
427 // rest of inference is done, and the other kinds of errors
428 // indicate that the region constraint graph is internally
429 // inconsistent, so these test results are likely to be
432 // Therefore, we filter them out of the list unless they are
433 // the only thing in the list.
435 let is_bound_failure
= |e
: &RegionResolutionError
<'tcx
>| match *e
{
436 RegionResolutionError
::GenericBoundFailure(..) => true,
437 RegionResolutionError
::ConcreteFailure(..)
438 | RegionResolutionError
::SubSupConflict(..)
439 | RegionResolutionError
::MemberConstraintFailure { .. }
=> false,
442 let mut errors
= if errors
.iter().all(|e
| is_bound_failure(e
)) {
447 .filter(|&e
| !is_bound_failure(e
))
452 // sort the errors by span, for better error message stability.
453 errors
.sort_by_key(|u
| match *u
{
454 RegionResolutionError
::ConcreteFailure(ref sro
, _
, _
) => sro
.span(),
455 RegionResolutionError
::GenericBoundFailure(ref sro
, _
, _
) => sro
.span(),
456 RegionResolutionError
::SubSupConflict(_
, ref rvo
, _
, _
, _
, _
) => rvo
.span(),
457 RegionResolutionError
::MemberConstraintFailure { span, .. }
=> span
,
462 /// Adds a note if the types come from similarly named crates
463 fn check_and_note_conflicting_crates(
465 err
: &mut DiagnosticBuilder
<'_
>,
466 terr
: &TypeError
<'tcx
>,
468 use hir
::def_id
::CrateNum
;
469 use hir
::map
::DisambiguatedDefPathData
;
470 use ty
::print
::Printer
;
471 use ty
::subst
::GenericArg
;
473 struct AbsolutePathPrinter
<'tcx
> {
477 struct NonTrivialPath
;
479 impl<'tcx
> Printer
<'tcx
> for AbsolutePathPrinter
<'tcx
> {
480 type Error
= NonTrivialPath
;
482 type Path
= Vec
<String
>;
485 type DynExistential
= !;
488 fn tcx
<'a
>(&'a
self) -> TyCtxt
<'tcx
> {
494 _region
: ty
::Region
<'_
>,
495 ) -> Result
<Self::Region
, Self::Error
> {
502 ) -> Result
<Self::Type
, Self::Error
> {
506 fn print_dyn_existential(
508 _predicates
: &'tcx ty
::List
<ty
::ExistentialPredicate
<'tcx
>>,
509 ) -> Result
<Self::DynExistential
, Self::Error
> {
515 _ct
: &'tcx ty
::Const
<'tcx
>,
516 ) -> Result
<Self::Const
, Self::Error
> {
523 ) -> Result
<Self::Path
, Self::Error
> {
524 Ok(vec
![self.tcx
.original_crate_name(cnum
).to_string()])
529 _trait_ref
: Option
<ty
::TraitRef
<'tcx
>>,
530 ) -> Result
<Self::Path
, Self::Error
> {
536 _print_prefix
: impl FnOnce(Self) -> Result
<Self::Path
, Self::Error
>,
537 _disambiguated_data
: &DisambiguatedDefPathData
,
539 _trait_ref
: Option
<ty
::TraitRef
<'tcx
>>,
540 ) -> Result
<Self::Path
, Self::Error
> {
545 print_prefix
: impl FnOnce(Self) -> Result
<Self::Path
, Self::Error
>,
546 disambiguated_data
: &DisambiguatedDefPathData
,
547 ) -> Result
<Self::Path
, Self::Error
> {
548 let mut path
= print_prefix(self)?
;
549 path
.push(disambiguated_data
.data
.as_symbol().to_string());
552 fn path_generic_args(
554 print_prefix
: impl FnOnce(Self) -> Result
<Self::Path
, Self::Error
>,
555 _args
: &[GenericArg
<'tcx
>],
556 ) -> Result
<Self::Path
, Self::Error
> {
561 let report_path_match
= |err
: &mut DiagnosticBuilder
<'_
>, did1
: DefId
, did2
: DefId
| {
562 // Only external crates, if either is from a local
563 // module we could have false positives
564 if !(did1
.is_local() || did2
.is_local()) && did1
.krate
!= did2
.krate
{
565 let abs_path
= |def_id
| {
566 AbsolutePathPrinter { tcx: self.tcx }
567 .print_def_path(def_id
, &[])
570 // We compare strings because DefPath can be different
571 // for imported and non-imported crates
572 let same_path
= || -> Result
<_
, NonTrivialPath
> {
574 self.tcx
.def_path_str(did1
) == self.tcx
.def_path_str(did2
) ||
575 abs_path(did1
)?
== abs_path(did2
)?
578 if same_path().unwrap_or(false) {
579 let crate_name
= self.tcx
.crate_name(did1
.krate
);
581 "perhaps two different versions of crate `{}` are being used?",
588 TypeError
::Sorts(ref exp_found
) => {
589 // if they are both "path types", there's a chance of ambiguity
590 // due to different versions of the same crate
591 if let (&ty
::Adt(exp_adt
, _
), &ty
::Adt(found_adt
, _
))
592 = (&exp_found
.expected
.kind
, &exp_found
.found
.kind
)
594 report_path_match(err
, exp_adt
.did
, found_adt
.did
);
597 TypeError
::Traits(ref exp_found
) => {
598 report_path_match(err
, exp_found
.expected
, exp_found
.found
);
600 _
=> (), // FIXME(#22750) handle traits and stuff
604 fn note_error_origin(
606 err
: &mut DiagnosticBuilder
<'tcx
>,
607 cause
: &ObligationCause
<'tcx
>,
608 exp_found
: Option
<ty
::error
::ExpectedFound
<Ty
<'tcx
>>>,
611 ObligationCauseCode
::MatchExpressionArmPattern { span, ty }
=> {
612 if ty
.is_suggestable() { // don't show type `_`
613 err
.span_label(span
, format
!("this match expression has type `{}`", ty
));
615 if let Some(ty
::error
::ExpectedFound { found, .. }
) = exp_found
{
616 if ty
.is_box() && ty
.boxed_ty() == found
{
617 if let Ok(snippet
) = self.tcx
.sess
.source_map().span_to_snippet(span
) {
620 "consider dereferencing the boxed value",
621 format
!("*{}", snippet
),
622 Applicability
::MachineApplicable
,
628 ObligationCauseCode
::MatchExpressionArm(box MatchExpressionArmCause
{
635 hir
::MatchSource
::IfLetDesugar { .. }
=> {
636 let msg
= "`if let` arms have incompatible types";
637 err
.span_label(cause
.span
, msg
);
639 hir
::MatchSource
::TryDesugar
=> {
640 if let Some(ty
::error
::ExpectedFound { expected, .. }
) = exp_found
{
641 let discrim_expr
= self.tcx
.hir().expect_expr(discrim_hir_id
);
642 let discrim_ty
= if let hir
::ExprKind
::Call(_
, args
) = &discrim_expr
.kind
{
643 let arg_expr
= args
.first().expect("try desugaring call w/out arg");
644 self.in_progress_tables
.and_then(|tables
| {
645 tables
.borrow().expr_ty_opt(arg_expr
)
648 bug
!("try desugaring w/out call expr as discriminant");
652 Some(ty
) if expected
== ty
=> {
653 let source_map
= self.tcx
.sess
.source_map();
655 source_map
.end_point(cause
.span
),
656 "try removing this `?`",
658 Applicability
::MachineApplicable
,
666 // `last_ty` can be `!`, `expected` will have better info when present.
667 let t
= self.resolve_vars_if_possible(&match exp_found
{
668 Some(ty
::error
::ExpectedFound { expected, .. }
) => expected
,
671 let msg
= "`match` arms have incompatible types";
672 err
.span_label(cause
.span
, msg
);
673 if prior_arms
.len() <= 4 {
674 for sp
in prior_arms
{
675 err
.span_label( *sp
, format
!("this is found to be of type `{}`", t
));
677 } else if let Some(sp
) = prior_arms
.last() {
680 format
!("this and all prior arms are found to be of type `{}`", t
),
685 ObligationCauseCode
::IfExpression(box IfExpressionCause { then, outer, semicolon }
) => {
686 err
.span_label(then
, "expected because of this");
687 outer
.map(|sp
| err
.span_label(sp
, "if and else have incompatible types"));
688 if let Some(sp
) = semicolon
{
689 err
.span_suggestion_short(
691 "consider removing this semicolon",
693 Applicability
::MachineApplicable
,
701 /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
702 /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
703 /// populate `other_value` with `other_ty`.
707 /// ^^^^--------^ this is highlighted
709 /// | this type argument is exactly the same as the other type, not highlighted
710 /// this is highlighted
712 /// -------- this type is the same as a type argument in the other type, not highlighted
716 value
: &mut DiagnosticStyledString
,
717 other_value
: &mut DiagnosticStyledString
,
719 sub
: ty
::subst
::SubstsRef
<'tcx
>,
723 // `value` and `other_value` hold two incomplete type representation for display.
724 // `name` is the path of both types being compared. `sub`
725 value
.push_highlighted(name
);
728 value
.push_highlighted("<");
731 // Output the lifetimes for the first type
732 let lifetimes
= sub
.regions()
734 let s
= lifetime
.to_string();
743 if !lifetimes
.is_empty() {
744 if sub
.regions().count() < len
{
745 value
.push_normal(lifetimes
+ &", ");
747 value
.push_normal(lifetimes
);
751 // Highlight all the type arguments that aren't at `pos` and compare the type argument at
752 // `pos` and `other_ty`.
753 for (i
, type_arg
) in sub
.types().enumerate() {
755 let values
= self.cmp(type_arg
, other_ty
);
756 value
.0.extend((values
.0).0);
757 other_value
.0.extend((values
.1).0);
759 value
.push_highlighted(type_arg
.to_string());
762 if len
> 0 && i
!= len
- 1 {
763 value
.push_normal(", ");
767 value
.push_highlighted(">");
771 /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`,
772 /// as that is the difference to the other type.
774 /// For the following code:
777 /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>();
780 /// The type error output will behave in the following way:
784 /// ^^^^--------^ this is highlighted
786 /// | this type argument is exactly the same as the other type, not highlighted
787 /// this is highlighted
789 /// -------- this type is the same as a type argument in the other type, not highlighted
793 mut t1_out
: &mut DiagnosticStyledString
,
794 mut t2_out
: &mut DiagnosticStyledString
,
796 sub
: ty
::subst
::SubstsRef
<'tcx
>,
800 for (i
, ta
) in sub
.types().enumerate() {
802 self.highlight_outer(&mut t1_out
, &mut t2_out
, path
, sub
, i
, &other_ty
);
805 if let &ty
::Adt(def
, _
) = &ta
.kind
{
806 let path_
= self.tcx
.def_path_str(def
.did
.clone());
807 if path_
== other_path
{
808 self.highlight_outer(&mut t1_out
, &mut t2_out
, path
, sub
, i
, &other_ty
);
816 /// Adds a `,` to the type representation only if it is appropriate.
819 value
: &mut DiagnosticStyledString
,
820 other_value
: &mut DiagnosticStyledString
,
824 if len
> 0 && pos
!= len
- 1 {
825 value
.push_normal(", ");
826 other_value
.push_normal(", ");
830 /// For generic types with parameters with defaults, remove the parameters corresponding to
831 /// the defaults. This repeats a lot of the logic found in `ty::print::pretty`.
832 fn strip_generic_default_params(
835 substs
: ty
::subst
::SubstsRef
<'tcx
>,
836 ) -> SubstsRef
<'tcx
> {
837 let generics
= self.tcx
.generics_of(def_id
);
838 let mut num_supplied_defaults
= 0;
839 let mut type_params
= generics
.params
.iter().rev().filter_map(|param
| match param
.kind
{
840 ty
::GenericParamDefKind
::Lifetime
=> None
,
841 ty
::GenericParamDefKind
::Type { has_default, .. }
=> Some((param
.def_id
, has_default
)),
842 ty
::GenericParamDefKind
::Const
=> None
, // FIXME(const_generics:defaults)
845 let has_default
= type_params
.peek().map(|(_
, has_default
)| has_default
);
846 *has_default
.unwrap_or(&false)
849 let types
= substs
.types().rev();
850 for ((def_id
, has_default
), actual
) in type_params
.zip(types
) {
854 if self.tcx
.type_of(def_id
).subst(self.tcx
, substs
) != actual
{
857 num_supplied_defaults
+= 1;
860 let len
= generics
.params
.len();
861 let mut generics
= generics
.clone();
862 generics
.params
.truncate(len
- num_supplied_defaults
);
863 substs
.truncate_to(self.tcx
, &generics
)
866 /// Given two `fn` signatures highlight only sub-parts that are different.
869 sig1
: &ty
::PolyFnSig
<'tcx
>,
870 sig2
: &ty
::PolyFnSig
<'tcx
>,
871 ) -> (DiagnosticStyledString
, DiagnosticStyledString
) {
872 let get_lifetimes
= |sig
| {
873 use crate::hir
::def
::Namespace
;
874 let mut s
= String
::new();
875 let (_
, (sig
, reg
)) = ty
::print
::FmtPrinter
::new(self.tcx
, &mut s
, Namespace
::TypeNS
)
876 .name_all_regions(sig
)
878 let lts
: Vec
<String
> = reg
.into_iter().map(|(_
, kind
)| kind
.to_string()).collect();
882 format
!("for<{}> ", lts
.join(", "))
886 let (lt1
, sig1
) = get_lifetimes(sig1
);
887 let (lt2
, sig2
) = get_lifetimes(sig2
);
889 // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
891 DiagnosticStyledString
::normal("".to_string()),
892 DiagnosticStyledString
::normal("".to_string()),
895 // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
897 values
.0.push(sig1
.unsafety
.prefix_str(), sig1
.unsafety
!= sig2
.unsafety
);
898 values
.1.push(sig2
.unsafety
.prefix_str(), sig1
.unsafety
!= sig2
.unsafety
);
900 // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
902 if sig1
.abi
!= abi
::Abi
::Rust
{
903 values
.0.push(format
!("extern {} ", sig1
.abi
), sig1
.abi
!= sig2
.abi
);
905 if sig2
.abi
!= abi
::Abi
::Rust
{
906 values
.1.push(format
!("extern {} ", sig2
.abi
), sig1
.abi
!= sig2
.abi
);
909 // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
911 let lifetime_diff
= lt1
!= lt2
;
912 values
.0.push(lt1
, lifetime_diff
);
913 values
.1.push(lt2
, lifetime_diff
);
915 // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
917 values
.0.push_normal("fn(");
918 values
.1.push_normal("fn(");
920 // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
922 let len1
= sig1
.inputs().len();
923 let len2
= sig2
.inputs().len();
925 for (i
, (l
, r
)) in sig1
.inputs().iter().zip(sig2
.inputs().iter()).enumerate() {
926 let (x1
, x2
) = self.cmp(l
, r
);
927 (values
.0).0.extend(x1
.0
);
928 (values
.1).0.extend(x2
.0
);
929 self.push_comma(&mut values
.0, &mut values
.1, len1
, i
);
932 for (i
, l
) in sig1
.inputs().iter().enumerate() {
933 values
.0.push_highlighted(l
.to_string());
935 values
.0.push_highlighted(", ");
938 for (i
, r
) in sig2
.inputs().iter().enumerate() {
939 values
.1.push_highlighted(r
.to_string());
941 values
.1.push_highlighted(", ");
948 values
.0.push_normal(", ");
950 values
.0.push("...", !sig2
.c_variadic
);
954 values
.1.push_normal(", ");
956 values
.1.push("...", !sig1
.c_variadic
);
959 // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
961 values
.0.push_normal(")");
962 values
.1.push_normal(")");
964 // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
966 let output1
= sig1
.output();
967 let output2
= sig2
.output();
968 let (x1
, x2
) = self.cmp(output1
, output2
);
969 if !output1
.is_unit() {
970 values
.0.push_normal(" -> ");
971 (values
.0).0.extend(x1
.0
);
973 if !output2
.is_unit() {
974 values
.1.push_normal(" -> ");
975 (values
.1).0.extend(x2
.0
);
980 /// Compares two given types, eliding parts that are the same between them and highlighting
981 /// relevant differences, and return two representation of those types for highlighted printing.
982 fn cmp(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) -> (DiagnosticStyledString
, DiagnosticStyledString
) {
983 debug
!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1
, t1
.kind
, t2
, t2
.kind
);
986 fn equals
<'tcx
>(a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> bool
{
987 match (&a
.kind
, &b
.kind
) {
988 (a
, b
) if *a
== *b
=> true,
989 (&ty
::Int(_
), &ty
::Infer(ty
::InferTy
::IntVar(_
)))
990 | (&ty
::Infer(ty
::InferTy
::IntVar(_
)), &ty
::Int(_
))
991 | (&ty
::Infer(ty
::InferTy
::IntVar(_
)), &ty
::Infer(ty
::InferTy
::IntVar(_
)))
992 | (&ty
::Float(_
), &ty
::Infer(ty
::InferTy
::FloatVar(_
)))
993 | (&ty
::Infer(ty
::InferTy
::FloatVar(_
)), &ty
::Float(_
))
994 | (&ty
::Infer(ty
::InferTy
::FloatVar(_
)), &ty
::Infer(ty
::InferTy
::FloatVar(_
))) => {
1001 fn push_ty_ref
<'tcx
>(
1002 r
: &ty
::Region
<'tcx
>,
1004 mutbl
: hir
::Mutability
,
1005 s
: &mut DiagnosticStyledString
,
1007 let mut r
= r
.to_string();
1013 s
.push_highlighted(format
!("&{}{}", r
, mutbl
.prefix_str()));
1014 s
.push_normal(ty
.to_string());
1017 // process starts here
1018 match (&t1
.kind
, &t2
.kind
) {
1019 (&ty
::Adt(def1
, sub1
), &ty
::Adt(def2
, sub2
)) => {
1020 let sub_no_defaults_1
= self.strip_generic_default_params(def1
.did
, sub1
);
1021 let sub_no_defaults_2
= self.strip_generic_default_params(def2
.did
, sub2
);
1022 let mut values
= (DiagnosticStyledString
::new(), DiagnosticStyledString
::new());
1023 let path1
= self.tcx
.def_path_str(def1
.did
.clone());
1024 let path2
= self.tcx
.def_path_str(def2
.did
.clone());
1025 if def1
.did
== def2
.did
{
1026 // Easy case. Replace same types with `_` to shorten the output and highlight
1027 // the differing ones.
1028 // let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>();
1031 // --- ^ type argument elided
1033 // highlighted in output
1034 values
.0.push_normal(path1
);
1035 values
.1.push_normal(path2
);
1037 // Avoid printing out default generic parameters that are common to both
1039 let len1
= sub_no_defaults_1
.len();
1040 let len2
= sub_no_defaults_2
.len();
1041 let common_len
= cmp
::min(len1
, len2
);
1042 let remainder1
: Vec
<_
> = sub1
.types().skip(common_len
).collect();
1043 let remainder2
: Vec
<_
> = sub2
.types().skip(common_len
).collect();
1044 let common_default_params
= remainder1
1047 .zip(remainder2
.iter().rev())
1048 .filter(|(a
, b
)| a
== b
)
1050 let len
= sub1
.len() - common_default_params
;
1051 let consts_offset
= len
- sub1
.consts().count();
1053 // Only draw `<...>` if there're lifetime/type arguments.
1055 values
.0.push_normal("<");
1056 values
.1.push_normal("<");
1059 fn lifetime_display(lifetime
: Region
<'_
>) -> String
{
1060 let s
= lifetime
.to_string();
1067 // At one point we'd like to elide all lifetimes here, they are irrelevant for
1068 // all diagnostics that use this output
1072 // ^^ ^^ --- type arguments are not elided
1074 // | elided as they were the same
1075 // not elided, they were different, but irrelevant
1076 let lifetimes
= sub1
.regions().zip(sub2
.regions());
1077 for (i
, lifetimes
) in lifetimes
.enumerate() {
1078 let l1
= lifetime_display(lifetimes
.0);
1079 let l2
= lifetime_display(lifetimes
.1);
1080 if lifetimes
.0 == lifetimes
.1 {
1081 values
.0.push_normal("'_");
1082 values
.1.push_normal("'_");
1084 values
.0.push_highlighted(l1
);
1085 values
.1.push_highlighted(l2
);
1087 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
1090 // We're comparing two types with the same path, so we compare the type
1091 // arguments for both. If they are the same, do not highlight and elide from the
1095 // ^ elided type as this type argument was the same in both sides
1096 let type_arguments
= sub1
.types().zip(sub2
.types());
1097 let regions_len
= sub1
.regions().count();
1098 let num_display_types
= consts_offset
- regions_len
;
1099 for (i
, (ta1
, ta2
)) in type_arguments
.take(num_display_types
).enumerate() {
1100 let i
= i
+ regions_len
;
1102 values
.0.push_normal("_");
1103 values
.1.push_normal("_");
1105 let (x1
, x2
) = self.cmp(ta1
, ta2
);
1106 (values
.0).0.extend(x1
.0
);
1107 (values
.1).0.extend(x2
.0
);
1109 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
1112 // Do the same for const arguments, if they are equal, do not highlight and
1113 // elide them from the output.
1114 let const_arguments
= sub1
.consts().zip(sub2
.consts());
1115 for (i
, (ca1
, ca2
)) in const_arguments
.enumerate() {
1116 let i
= i
+ consts_offset
;
1118 values
.0.push_normal("_");
1119 values
.1.push_normal("_");
1121 values
.0.push_highlighted(ca1
.to_string());
1122 values
.1.push_highlighted(ca2
.to_string());
1124 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
1127 // Close the type argument bracket.
1128 // Only draw `<...>` if there're lifetime/type arguments.
1130 values
.0.push_normal(">");
1131 values
.1.push_normal(">");
1136 // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>();
1138 // ------- this type argument is exactly the same as the other type
1140 if self.cmp_type_arg(
1152 // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>();
1155 // ------- this type argument is exactly the same as the other type
1156 if self.cmp_type_arg(
1168 // We can't find anything in common, highlight relevant part of type path.
1169 // let x: foo::bar::Baz<Qux> = y:<foo::bar::Bar<Zar>>();
1170 // foo::bar::Baz<Qux>
1171 // foo::bar::Bar<Zar>
1172 // -------- this part of the path is different
1174 let t1_str
= t1
.to_string();
1175 let t2_str
= t2
.to_string();
1176 let min_len
= t1_str
.len().min(t2_str
.len());
1178 const SEPARATOR
: &str = "::";
1179 let separator_len
= SEPARATOR
.len();
1180 let split_idx
: usize =
1181 t1_str
.split(SEPARATOR
)
1182 .zip(t2_str
.split(SEPARATOR
))
1183 .take_while(|(mod1_str
, mod2_str
)| mod1_str
== mod2_str
)
1184 .map(|(mod_str
, _
)| mod_str
.len() + separator_len
)
1187 debug
!("cmp: separator_len={}, split_idx={}, min_len={}",
1188 separator_len
, split_idx
, min_len
1191 if split_idx
>= min_len
{
1192 // paths are identical, highlight everything
1194 DiagnosticStyledString
::highlighted(t1_str
),
1195 DiagnosticStyledString
::highlighted(t2_str
)
1198 let (common
, uniq1
) = t1_str
.split_at(split_idx
);
1199 let (_
, uniq2
) = t2_str
.split_at(split_idx
);
1200 debug
!("cmp: common={}, uniq1={}, uniq2={}", common
, uniq1
, uniq2
);
1202 values
.0.push_normal(common
);
1203 values
.0.push_highlighted(uniq1
);
1204 values
.1.push_normal(common
);
1205 values
.1.push_highlighted(uniq2
);
1212 // When finding T != &T, highlight only the borrow
1213 (&ty
::Ref(r1
, ref_ty1
, mutbl1
), _
) if equals(&ref_ty1
, &t2
) => {
1214 let mut values
= (DiagnosticStyledString
::new(), DiagnosticStyledString
::new());
1215 push_ty_ref(&r1
, ref_ty1
, mutbl1
, &mut values
.0);
1216 values
.1.push_normal(t2
.to_string());
1219 (_
, &ty
::Ref(r2
, ref_ty2
, mutbl2
)) if equals(&t1
, &ref_ty2
) => {
1220 let mut values
= (DiagnosticStyledString
::new(), DiagnosticStyledString
::new());
1221 values
.0.push_normal(t1
.to_string());
1222 push_ty_ref(&r2
, ref_ty2
, mutbl2
, &mut values
.1);
1226 // When encountering &T != &mut T, highlight only the borrow
1227 (&ty
::Ref(r1
, ref_ty1
, mutbl1
), &ty
::Ref(r2
, ref_ty2
, mutbl2
))
1228 if equals(&ref_ty1
, &ref_ty2
) =>
1230 let mut values
= (DiagnosticStyledString
::new(), DiagnosticStyledString
::new());
1231 push_ty_ref(&r1
, ref_ty1
, mutbl1
, &mut values
.0);
1232 push_ty_ref(&r2
, ref_ty2
, mutbl2
, &mut values
.1);
1236 // When encountering tuples of the same size, highlight only the differing types
1237 (&ty
::Tuple(substs1
), &ty
::Tuple(substs2
)) if substs1
.len() == substs2
.len() => {
1239 DiagnosticStyledString
::normal("("),
1240 DiagnosticStyledString
::normal("("),
1242 let len
= substs1
.len();
1243 for (i
, (left
, right
)) in substs1
.types().zip(substs2
.types()).enumerate() {
1244 let (x1
, x2
) = self.cmp(left
, right
);
1245 (values
.0).0.extend(x1
.0
);
1246 (values
.1).0.extend(x2
.0
);
1247 self.push_comma(&mut values
.0, &mut values
.1, len
, i
);
1249 if len
== 1 { // Keep the output for single element tuples as `(ty,)`.
1250 values
.0.push_normal(",");
1251 values
.1.push_normal(",");
1253 values
.0.push_normal(")");
1254 values
.1.push_normal(")");
1258 (ty
::FnDef(did1
, substs1
), ty
::FnDef(did2
, substs2
)) => {
1259 let sig1
= self.tcx
.fn_sig(*did1
).subst(self.tcx
, substs1
);
1260 let sig2
= self.tcx
.fn_sig(*did2
).subst(self.tcx
, substs2
);
1261 let mut values
= self.cmp_fn_sig(&sig1
, &sig2
);
1262 let path1
= format
!(" {{{}}}", self.tcx
.def_path_str_with_substs(*did1
, substs1
));
1263 let path2
= format
!(" {{{}}}", self.tcx
.def_path_str_with_substs(*did2
, substs2
));
1264 let same_path
= path1
== path2
;
1265 values
.0.push(path1
, !same_path
);
1266 values
.1.push(path2
, !same_path
);
1270 (ty
::FnDef(did1
, substs1
), ty
::FnPtr(sig2
)) => {
1271 let sig1
= self.tcx
.fn_sig(*did1
).subst(self.tcx
, substs1
);
1272 let mut values
= self.cmp_fn_sig(&sig1
, sig2
);
1273 values
.0.push_normal(format
!(
1275 self.tcx
.def_path_str_with_substs(*did1
, substs1
)),
1280 (ty
::FnPtr(sig1
), ty
::FnDef(did2
, substs2
)) => {
1281 let sig2
= self.tcx
.fn_sig(*did2
).subst(self.tcx
, substs2
);
1282 let mut values
= self.cmp_fn_sig(sig1
, &sig2
);
1283 values
.1.push_normal(format
!(
1285 self.tcx
.def_path_str_with_substs(*did2
, substs2
)),
1290 (ty
::FnPtr(sig1
), ty
::FnPtr(sig2
)) => {
1291 self.cmp_fn_sig(sig1
, sig2
)
1296 // The two types are the same, elide and don't highlight.
1298 DiagnosticStyledString
::normal("_"),
1299 DiagnosticStyledString
::normal("_"),
1302 // We couldn't find anything in common, highlight everything.
1304 DiagnosticStyledString
::highlighted(t1
.to_string()),
1305 DiagnosticStyledString
::highlighted(t2
.to_string()),
1312 pub fn note_type_err(
1314 diag
: &mut DiagnosticBuilder
<'tcx
>,
1315 cause
: &ObligationCause
<'tcx
>,
1316 secondary_span
: Option
<(Span
, String
)>,
1317 mut values
: Option
<ValuePairs
<'tcx
>>,
1318 terr
: &TypeError
<'tcx
>,
1320 // For some types of errors, expected-found does not make
1321 // sense, so just ignore the values we were given.
1323 TypeError
::CyclicTy(_
) => {
1329 debug
!("note_type_err(diag={:?})", diag
);
1330 let (expected_found
, exp_found
, is_simple_error
) = match values
{
1331 None
=> (None
, None
, false),
1333 let (is_simple_error
, exp_found
) = match values
{
1334 ValuePairs
::Types(exp_found
) => {
1335 let is_simple_err
= exp_found
.expected
.is_simple_text()
1336 && exp_found
.found
.is_simple_text();
1338 (is_simple_err
, Some(exp_found
))
1342 let vals
= match self.values_str(&values
) {
1343 Some((expected
, found
)) => Some((expected
, found
)),
1345 // Derived error. Cancel the emitter.
1350 (vals
, exp_found
, is_simple_error
)
1354 let span
= cause
.span(self.tcx
);
1356 // Ignore msg for object safe coercion
1357 // since E0038 message will be printed
1359 TypeError
::ObjectUnsafeCoercion(_
) => {}
1361 diag
.span_label(span
, terr
.to_string());
1362 if let Some((sp
, msg
)) = secondary_span
{
1363 diag
.span_label(sp
, msg
);
1368 if let Some((expected
, found
)) = expected_found
{
1369 let expected_label
= exp_found
.map_or("type".into(), |ef
| ef
.expected
.prefix_string());
1370 let found_label
= exp_found
.map_or("type".into(), |ef
| ef
.found
.prefix_string());
1371 match (&terr
, expected
== found
) {
1372 (TypeError
::Sorts(values
), extra
) => {
1373 let sort_string
= |ty
: Ty
<'tcx
>| match (extra
, &ty
.kind
) {
1374 (true, ty
::Opaque(def_id
, _
)) => format
!(
1375 " (opaque type at {})",
1376 self.tcx
.sess
.source_map()
1377 .mk_substr_filename(self.tcx
.def_span(*def_id
)),
1379 (true, _
) => format
!(" ({})", ty
.sort_string(self.tcx
)),
1380 (false, _
) => "".to_string(),
1382 if !(values
.expected
.is_simple_text() && values
.found
.is_simple_text()) || (
1383 exp_found
.map_or(false, |ef
| {
1384 // This happens when the type error is a subset of the expectation,
1385 // like when you have two references but one is `usize` and the other
1386 // is `f32`. In those cases we still want to show the `note`. If the
1387 // value from `ef` is `Infer(_)`, then we ignore it.
1388 if !ef
.expected
.is_ty_infer() {
1389 ef
.expected
!= values
.expected
1390 } else if !ef
.found
.is_ty_infer() {
1391 ef
.found
!= values
.found
1397 diag
.note_expected_found_extra(
1402 &sort_string(values
.expected
),
1403 &sort_string(values
.found
),
1407 (TypeError
::ObjectUnsafeCoercion(_
), _
) => {
1408 diag
.note_unsuccessfull_coercion(found
, expected
);
1412 "note_type_err: exp_found={:?}, expected={:?} found={:?}",
1413 exp_found
, expected
, found
1415 if !is_simple_error
|| terr
.must_include_note() {
1416 diag
.note_expected_found(&expected_label
, expected
, &found_label
, found
);
1421 if let Some(exp_found
) = exp_found
{
1422 self.suggest_as_ref_where_appropriate(span
, &exp_found
, diag
);
1425 // In some (most?) cases cause.body_id points to actual body, but in some cases
1426 // it's a actual definition. According to the comments (e.g. in
1427 // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
1428 // is relied upon by some other code. This might (or might not) need cleanup.
1429 let body_owner_def_id
= self.tcx
.hir().opt_local_def_id(cause
.body_id
)
1430 .unwrap_or_else(|| {
1431 self.tcx
.hir().body_owner_def_id(hir
::BodyId { hir_id: cause.body_id }
)
1433 self.check_and_note_conflicting_crates(diag
, terr
);
1434 self.tcx
.note_and_explain_type_err(diag
, terr
, span
, body_owner_def_id
);
1436 // It reads better to have the error origin as the final
1438 self.note_error_origin(diag
, &cause
, exp_found
);
1441 /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
1443 fn suggest_as_ref_where_appropriate(
1446 exp_found
: &ty
::error
::ExpectedFound
<Ty
<'tcx
>>,
1447 diag
: &mut DiagnosticBuilder
<'tcx
>,
1449 match (&exp_found
.expected
.kind
, &exp_found
.found
.kind
) {
1450 (ty
::Adt(exp_def
, exp_substs
), ty
::Ref(_
, found_ty
, _
)) => {
1451 if let ty
::Adt(found_def
, found_substs
) = found_ty
.kind
{
1452 let path_str
= format
!("{:?}", exp_def
);
1453 if exp_def
== &found_def
{
1454 let opt_msg
= "you can convert from `&Option<T>` to `Option<&T>` using \
1456 let result_msg
= "you can convert from `&Result<T, E>` to \
1457 `Result<&T, &E>` using `.as_ref()`";
1458 let have_as_ref
= &[
1459 ("std::option::Option", opt_msg
),
1460 ("core::option::Option", opt_msg
),
1461 ("std::result::Result", result_msg
),
1462 ("core::result::Result", result_msg
),
1464 if let Some(msg
) = have_as_ref
.iter()
1465 .filter_map(|(path
, msg
)| if &path_str
== path
{
1471 let mut show_suggestion
= true;
1472 for (exp_ty
, found_ty
) in exp_substs
.types().zip(found_substs
.types()) {
1474 ty
::Ref(_
, exp_ty
, _
) => {
1475 match (&exp_ty
.kind
, &found_ty
.kind
) {
1479 (ty
::Infer(_
), _
) => {}
1480 _
if ty
::TyS
::same_type(exp_ty
, found_ty
) => {}
1481 _
=> show_suggestion
= false,
1484 ty
::Param(_
) | ty
::Infer(_
) => {}
1485 _
=> show_suggestion
= false,
1488 if let (Ok(snippet
), true) = (
1489 self.tcx
.sess
.source_map().span_to_snippet(span
),
1492 diag
.span_suggestion(
1495 format
!("{}.as_ref()", snippet
),
1496 Applicability
::MachineApplicable
,
1507 pub fn report_and_explain_type_error(
1509 trace
: TypeTrace
<'tcx
>,
1510 terr
: &TypeError
<'tcx
>,
1511 ) -> DiagnosticBuilder
<'tcx
> {
1513 "report_and_explain_type_error(trace={:?}, terr={:?})",
1517 let span
= trace
.cause
.span(self.tcx
);
1518 let failure_code
= trace
.cause
.as_failure_code(terr
);
1519 let mut diag
= match failure_code
{
1520 FailureCode
::Error0038(did
) => {
1521 let violations
= self.tcx
.object_safety_violations(did
);
1522 self.tcx
.report_object_safety_error(span
, did
, violations
)
1524 FailureCode
::Error0317(failure_str
) => {
1525 struct_span_err
!(self.tcx
.sess
, span
, E0317
, "{}", failure_str
)
1527 FailureCode
::Error0580(failure_str
) => {
1528 struct_span_err
!(self.tcx
.sess
, span
, E0580
, "{}", failure_str
)
1530 FailureCode
::Error0308(failure_str
) => {
1531 struct_span_err
!(self.tcx
.sess
, span
, E0308
, "{}", failure_str
)
1533 FailureCode
::Error0644(failure_str
) => {
1534 struct_span_err
!(self.tcx
.sess
, span
, E0644
, "{}", failure_str
)
1537 self.note_type_err(&mut diag
, &trace
.cause
, None
, Some(trace
.values
), terr
);
1543 values
: &ValuePairs
<'tcx
>,
1544 ) -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)> {
1546 infer
::Types(ref exp_found
) => self.expected_found_str_ty(exp_found
),
1547 infer
::Regions(ref exp_found
) => self.expected_found_str(exp_found
),
1548 infer
::Consts(ref exp_found
) => self.expected_found_str(exp_found
),
1549 infer
::TraitRefs(ref exp_found
) => {
1550 let pretty_exp_found
= ty
::error
::ExpectedFound
{
1551 expected
: exp_found
.expected
.print_only_trait_path(),
1552 found
: exp_found
.found
.print_only_trait_path()
1554 self.expected_found_str(&pretty_exp_found
)
1556 infer
::PolyTraitRefs(ref exp_found
) => {
1557 let pretty_exp_found
= ty
::error
::ExpectedFound
{
1558 expected
: exp_found
.expected
.print_only_trait_path(),
1559 found
: exp_found
.found
.print_only_trait_path()
1561 self.expected_found_str(&pretty_exp_found
)
1566 fn expected_found_str_ty(
1568 exp_found
: &ty
::error
::ExpectedFound
<Ty
<'tcx
>>,
1569 ) -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)> {
1570 let exp_found
= self.resolve_vars_if_possible(exp_found
);
1571 if exp_found
.references_error() {
1575 Some(self.cmp(exp_found
.expected
, exp_found
.found
))
1578 /// Returns a string of the form "expected `{}`, found `{}`".
1579 fn expected_found_str
<T
: fmt
::Display
+ TypeFoldable
<'tcx
>>(
1581 exp_found
: &ty
::error
::ExpectedFound
<T
>,
1582 ) -> Option
<(DiagnosticStyledString
, DiagnosticStyledString
)> {
1583 let exp_found
= self.resolve_vars_if_possible(exp_found
);
1584 if exp_found
.references_error() {
1589 DiagnosticStyledString
::highlighted(exp_found
.expected
.to_string()),
1590 DiagnosticStyledString
::highlighted(exp_found
.found
.to_string()),
1594 pub fn report_generic_bound_failure(
1596 region_scope_tree
: ®ion
::ScopeTree
,
1598 origin
: Option
<SubregionOrigin
<'tcx
>>,
1599 bound_kind
: GenericKind
<'tcx
>,
1602 self.construct_generic_bound_failure(region_scope_tree
, span
, origin
, bound_kind
, sub
)
1606 pub fn construct_generic_bound_failure(
1608 region_scope_tree
: ®ion
::ScopeTree
,
1610 origin
: Option
<SubregionOrigin
<'tcx
>>,
1611 bound_kind
: GenericKind
<'tcx
>,
1613 ) -> DiagnosticBuilder
<'a
> {
1614 // Attempt to obtain the span of the parameter so we can
1615 // suggest adding an explicit lifetime bound to it.
1616 let type_param_span
= match (self.in_progress_tables
, bound_kind
) {
1617 (Some(ref table
), GenericKind
::Param(ref param
)) => {
1618 let table
= table
.borrow();
1619 table
.local_id_root
.and_then(|did
| {
1620 let generics
= self.tcx
.generics_of(did
);
1621 // Account for the case where `did` corresponds to `Self`, which doesn't have
1622 // the expected type argument.
1623 if !(generics
.has_self
&& param
.index
== 0) {
1624 let type_param
= generics
.type_param(param
, self.tcx
);
1625 let hir
= &self.tcx
.hir();
1626 hir
.as_local_hir_id(type_param
.def_id
).map(|id
| {
1627 // Get the `hir::Param` to verify whether it already has any bounds.
1628 // We do this to avoid suggesting code that ends up as `T: 'a'b`,
1629 // instead we suggest `T: 'a + 'b` in that case.
1630 let mut has_bounds
= false;
1631 if let Node
::GenericParam(param
) = hir
.get(id
) {
1632 has_bounds
= !param
.bounds
.is_empty();
1634 let sp
= hir
.span(id
);
1635 // `sp` only covers `T`, change it so that it covers
1636 // `T:` when appropriate
1637 let is_impl_trait
= bound_kind
.to_string().starts_with("impl ");
1638 let sp
= if has_bounds
&& !is_impl_trait
{
1642 .next_point(self.tcx
.sess
.source_map().next_point(sp
)))
1646 (sp
, has_bounds
, is_impl_trait
)
1656 let labeled_user_string
= match bound_kind
{
1657 GenericKind
::Param(ref p
) => format
!("the parameter type `{}`", p
),
1658 GenericKind
::Projection(ref p
) => format
!("the associated type `{}`", p
),
1661 if let Some(SubregionOrigin
::CompareImplMethodObligation
{
1668 return self.report_extra_impl_obligation(
1673 &format
!("`{}: {}`", bound_kind
, sub
),
1677 fn binding_suggestion
<'tcx
, S
: fmt
::Display
>(
1678 err
: &mut DiagnosticBuilder
<'tcx
>,
1679 type_param_span
: Option
<(Span
, bool
, bool
)>,
1680 bound_kind
: GenericKind
<'tcx
>,
1683 let consider
= format
!(
1684 "consider adding an explicit lifetime bound {}",
1685 if type_param_span
.map(|(_
, _
, is_impl_trait
)| is_impl_trait
).unwrap_or(false) {
1686 format
!(" `{}` to `{}`...", sub
, bound_kind
)
1688 format
!("`{}: {}`...", bound_kind
, sub
)
1691 if let Some((sp
, has_lifetimes
, is_impl_trait
)) = type_param_span
{
1692 let suggestion
= if is_impl_trait
{
1693 format
!("{} + {}", bound_kind
, sub
)
1695 let tail
= if has_lifetimes { " + " }
else { "" }
;
1696 format
!("{}: {}{}", bound_kind
, sub
, tail
)
1698 err
.span_suggestion_short(
1702 Applicability
::MaybeIncorrect
, // Issue #41966
1705 err
.help(&consider
);
1709 let mut err
= match *sub
{
1711 | ty
::ReFree(ty
::FreeRegion
{
1712 bound_region
: ty
::BrNamed(..),
1715 // Does the required lifetime have a nice name we can print?
1716 let mut err
= struct_span_err
!(
1720 "{} may not live long enough",
1723 binding_suggestion(&mut err
, type_param_span
, bound_kind
, sub
);
1728 // Does the required lifetime have a nice name we can print?
1729 let mut err
= struct_span_err
!(
1733 "{} may not live long enough",
1736 binding_suggestion(&mut err
, type_param_span
, bound_kind
, "'static");
1741 // If not, be less specific.
1742 let mut err
= struct_span_err
!(
1746 "{} may not live long enough",
1750 "consider adding an explicit lifetime bound for `{}`",
1753 self.tcx
.note_and_explain_region(
1756 &format
!("{} must be valid for ", labeled_user_string
),
1764 if let Some(origin
) = origin
{
1765 self.note_region_origin(&mut err
, &origin
);
1770 fn report_sub_sup_conflict(
1772 region_scope_tree
: ®ion
::ScopeTree
,
1773 var_origin
: RegionVariableOrigin
,
1774 sub_origin
: SubregionOrigin
<'tcx
>,
1775 sub_region
: Region
<'tcx
>,
1776 sup_origin
: SubregionOrigin
<'tcx
>,
1777 sup_region
: Region
<'tcx
>,
1779 let mut err
= self.report_inference_failure(var_origin
);
1781 self.tcx
.note_and_explain_region(
1784 "first, the lifetime cannot outlive ",
1789 match (&sup_origin
, &sub_origin
) {
1790 (&infer
::Subtype(ref sup_trace
), &infer
::Subtype(ref sub_trace
)) => {
1791 debug
!("report_sub_sup_conflict: var_origin={:?}", var_origin
);
1792 debug
!("report_sub_sup_conflict: sub_region={:?}", sub_region
);
1793 debug
!("report_sub_sup_conflict: sub_origin={:?}", sub_origin
);
1794 debug
!("report_sub_sup_conflict: sup_region={:?}", sup_region
);
1795 debug
!("report_sub_sup_conflict: sup_origin={:?}", sup_origin
);
1796 debug
!("report_sub_sup_conflict: sup_trace={:?}", sup_trace
);
1797 debug
!("report_sub_sup_conflict: sub_trace={:?}", sub_trace
);
1798 debug
!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace
.values
);
1799 debug
!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace
.values
);
1801 if let (Some((sup_expected
, sup_found
)), Some((sub_expected
, sub_found
))) = (
1802 self.values_str(&sup_trace
.values
),
1803 self.values_str(&sub_trace
.values
),
1805 if sub_expected
== sup_expected
&& sub_found
== sup_found
{
1806 self.tcx
.note_and_explain_region(
1809 "...but the lifetime must also be valid for ",
1813 err
.span_note(sup_trace
.cause
.span
, &format
!(
1814 "...so that the {}",
1815 sup_trace
.cause
.as_requirement_str()
1818 err
.note_expected_found(
1832 self.note_region_origin(&mut err
, &sup_origin
);
1834 self.tcx
.note_and_explain_region(
1837 "but, the lifetime must be valid for ",
1842 self.note_region_origin(&mut err
, &sub_origin
);
1847 impl<'a
, 'tcx
> InferCtxt
<'a
, 'tcx
> {
1848 fn report_inference_failure(
1850 var_origin
: RegionVariableOrigin
,
1851 ) -> DiagnosticBuilder
<'tcx
> {
1852 let br_string
= |br
: ty
::BoundRegion
| {
1853 let mut s
= match br
{
1854 ty
::BrNamed(_
, name
) => name
.to_string(),
1862 let var_description
= match var_origin
{
1863 infer
::MiscVariable(_
) => String
::new(),
1864 infer
::PatternRegion(_
) => " for pattern".to_string(),
1865 infer
::AddrOfRegion(_
) => " for borrow expression".to_string(),
1866 infer
::Autoref(_
) => " for autoref".to_string(),
1867 infer
::Coercion(_
) => " for automatic coercion".to_string(),
1868 infer
::LateBoundRegion(_
, br
, infer
::FnCall
) => {
1869 format
!(" for lifetime parameter {}in function call", br_string(br
))
1871 infer
::LateBoundRegion(_
, br
, infer
::HigherRankedType
) => {
1872 format
!(" for lifetime parameter {}in generic type", br_string(br
))
1874 infer
::LateBoundRegion(_
, br
, infer
::AssocTypeProjection(def_id
)) => format
!(
1875 " for lifetime parameter {}in trait containing associated type `{}`",
1877 self.tcx
.associated_item(def_id
).ident
1879 infer
::EarlyBoundRegion(_
, name
) => format
!(" for lifetime parameter `{}`", name
),
1880 infer
::BoundRegionInCoherence(name
) => {
1881 format
!(" for lifetime parameter `{}` in coherence check", name
)
1883 infer
::UpvarRegion(ref upvar_id
, _
) => {
1884 let var_name
= self.tcx
.hir().name(upvar_id
.var_path
.hir_id
);
1885 format
!(" for capture of `{}` by closure", var_name
)
1887 infer
::NLL(..) => bug
!("NLL variable found in lexical phase"),
1894 "cannot infer an appropriate lifetime{} \
1895 due to conflicting requirements",
1903 Error0317(&'
static str),
1904 Error0580(&'
static str),
1905 Error0308(&'
static str),
1906 Error0644(&'
static str),
1909 impl<'tcx
> ObligationCause
<'tcx
> {
1910 fn as_failure_code(&self, terr
: &TypeError
<'tcx
>) -> FailureCode
{
1911 use self::FailureCode
::*;
1912 use crate::traits
::ObligationCauseCode
::*;
1914 CompareImplMethodObligation { .. }
=> Error0308("method not compatible with trait"),
1915 MatchExpressionArm(box MatchExpressionArmCause { source, .. }
) =>
1916 Error0308(match source
{
1917 hir
::MatchSource
::IfLetDesugar { .. }
=>
1918 "`if let` arms have incompatible types",
1919 hir
::MatchSource
::TryDesugar
=> {
1920 "try expression alternatives have incompatible types"
1922 _
=> "match arms have incompatible types",
1924 IfExpression { .. }
=> Error0308("if and else have incompatible types"),
1925 IfExpressionWithNoElse
=> Error0317("if may be missing an else clause"),
1926 MainFunctionType
=> Error0580("main function has wrong type"),
1927 StartFunctionType
=> Error0308("start function has wrong type"),
1928 IntrinsicType
=> Error0308("intrinsic has wrong type"),
1929 MethodReceiver
=> Error0308("mismatched `self` parameter type"),
1931 // In the case where we have no more specific thing to
1932 // say, also take a look at the error code, maybe we can
1935 TypeError
::CyclicTy(ty
) if ty
.is_closure() || ty
.is_generator() => {
1936 Error0644("closure/generator type that references itself")
1938 TypeError
::IntrinsicCast
=> {
1939 Error0308("cannot coerce intrinsics to function pointers")
1941 TypeError
::ObjectUnsafeCoercion(did
) => Error0038(did
.clone()),
1942 _
=> Error0308("mismatched types"),
1947 fn as_requirement_str(&self) -> &'
static str {
1948 use crate::traits
::ObligationCauseCode
::*;
1950 CompareImplMethodObligation { .. }
=> "method type is compatible with trait",
1951 ExprAssignable
=> "expression is assignable",
1952 MatchExpressionArm(box MatchExpressionArmCause { source, .. }
) => match source
{
1953 hir
::MatchSource
::IfLetDesugar { .. }
=> "`if let` arms have compatible types",
1954 _
=> "match arms have compatible types",
1956 IfExpression { .. }
=> "if and else have incompatible types",
1957 IfExpressionWithNoElse
=> "if missing an else returns ()",
1958 MainFunctionType
=> "`main` function has the correct type",
1959 StartFunctionType
=> "`start` function has the correct type",
1960 IntrinsicType
=> "intrinsic has the correct type",
1961 MethodReceiver
=> "method receiver has the correct type",
1962 _
=> "types are compatible",