@@ -2026,87 +2026,102 @@ impl<'tcx> RegionInferenceContext<'tcx> {
2026
2026
| NllRegionVariableOrigin :: Existential { from_forall : true } => false ,
2027
2027
} ;
2028
2028
2029
- let interesting_to_blame = |constraint : & OutlivesConstraint < ' tcx > | {
2030
- !matches ! (
2031
- constraint. category,
2032
- ConstraintCategory :: OpaqueType
2033
- | ConstraintCategory :: Boring
2034
- | ConstraintCategory :: BoringNoLocation
2035
- | ConstraintCategory :: Internal
2036
- | ConstraintCategory :: Predicate ( _)
2037
- | ConstraintCategory :: Assignment { has_interesting_ty: false }
2038
- ) && constraint. span . desugaring_kind ( ) . is_none_or ( |kind| {
2039
- // Try to avoid blaming constraints from desugarings, since they may not clearly
2040
- // clearly match what users have written. As an exception, allow blaming returns
2041
- // generated by `?` desugaring, since the correspondence is fairly clear.
2042
- kind == DesugaringKind :: QuestionMark
2043
- && matches ! ( constraint. category, ConstraintCategory :: Return ( _) )
2044
- } )
2029
+ // To pick a constraint to blame, we organize constraints by how interesting we expect them
2030
+ // to be in diagnostics, then pick the most interesting one closest to either the source or
2031
+ // the target on our constraint path.
2032
+ let constraint_interest = |constraint : & OutlivesConstraint < ' tcx > | {
2033
+ // Try to avoid blaming constraints from desugarings, since they may not clearly match
2034
+ // match what users have written. As an exception, allow blaming returns generated by
2035
+ // `?` desugaring, since the correspondence is fairly clear.
2036
+ let category = if let Some ( kind) = constraint. span . desugaring_kind ( )
2037
+ && ( kind != DesugaringKind :: QuestionMark
2038
+ || !matches ! ( constraint. category, ConstraintCategory :: Return ( _) ) )
2039
+ {
2040
+ ConstraintCategory :: Boring
2041
+ } else {
2042
+ constraint. category
2043
+ } ;
2044
+
2045
+ match category {
2046
+ // Returns usually provide a type to blame and have specially written diagnostics,
2047
+ // so prioritize them.
2048
+ ConstraintCategory :: Return ( _) => 0 ,
2049
+ // Unsizing coercions are interesting, since we have a note for that:
2050
+ // `BorrowExplanation::add_object_lifetime_default_note`.
2051
+ // FIXME(dianne): That note shouldn't depend on a coercion being blamed; see issue
2052
+ // #131008 for an example of where we currently don't emit it but should.
2053
+ // Once the note is handled properly, this case should be removed. Until then, it
2054
+ // should be as limited as possible; the note is prone to false positives and this
2055
+ // constraint usually isn't best to blame.
2056
+ ConstraintCategory :: Cast {
2057
+ unsize_to : Some ( unsize_ty) ,
2058
+ is_implicit_coercion : true ,
2059
+ } if target_region == self . universal_regions ( ) . fr_static
2060
+ // Mirror the note's condition, to minimize how often this diverts blame.
2061
+ && let ty:: Adt ( _, args) = unsize_ty. kind ( )
2062
+ && args. iter ( ) . any ( |arg| arg. as_type ( ) . is_some_and ( |ty| ty. is_trait ( ) ) )
2063
+ // Mimic old logic for this, to minimize false positives in tests.
2064
+ && !path
2065
+ . iter ( )
2066
+ . any ( |c| matches ! ( c. category, ConstraintCategory :: TypeAnnotation ) ) =>
2067
+ {
2068
+ 1
2069
+ }
2070
+ // Between other interesting constraints, order by their position on the `path`.
2071
+ ConstraintCategory :: Yield
2072
+ | ConstraintCategory :: UseAsConst
2073
+ | ConstraintCategory :: UseAsStatic
2074
+ | ConstraintCategory :: TypeAnnotation
2075
+ | ConstraintCategory :: Cast { .. }
2076
+ | ConstraintCategory :: CallArgument ( _)
2077
+ | ConstraintCategory :: CopyBound
2078
+ | ConstraintCategory :: SizedBound
2079
+ | ConstraintCategory :: Assignment { has_interesting_ty : true }
2080
+ | ConstraintCategory :: Usage
2081
+ | ConstraintCategory :: ClosureUpvar ( _) => 2 ,
2082
+ // Give assignments a lower priority when flagged as less likely to be interesting.
2083
+ // In particular, de-prioritize MIR assignments lowered from argument patterns.
2084
+ ConstraintCategory :: Assignment { has_interesting_ty : false } => 3 ,
2085
+ // We handle predicates and opaque types specially; don't prioritize them here.
2086
+ ConstraintCategory :: Predicate ( _) | ConstraintCategory :: OpaqueType => 4 ,
2087
+ // `Boring` constraints can correspond to user-written code and have useful spans,
2088
+ // but don't provide any other useful information for diagnostics.
2089
+ ConstraintCategory :: Boring => 5 ,
2090
+ // `BoringNoLocation` constraints can point to user-written code, but are less
2091
+ // specific, and are not used for relations that would make sense to blame.
2092
+ ConstraintCategory :: BoringNoLocation => 6 ,
2093
+ // Do not blame internal constraints.
2094
+ ConstraintCategory :: Internal => 7 ,
2095
+ ConstraintCategory :: IllegalUniverse => 8 ,
2096
+ }
2045
2097
} ;
2046
2098
2047
2099
let best_choice = if blame_source {
2048
- path. iter ( ) . rposition ( interesting_to_blame )
2100
+ path. iter ( ) . enumerate ( ) . rev ( ) . min_by_key ( | ( _ , c ) | constraint_interest ( c ) ) . unwrap ( ) . 0
2049
2101
} else {
2050
- path. iter ( ) . position ( interesting_to_blame )
2102
+ path. iter ( ) . enumerate ( ) . min_by_key ( | ( _ , c ) | constraint_interest ( c ) ) . unwrap ( ) . 0
2051
2103
} ;
2052
2104
2053
2105
debug ! ( ?best_choice, ?blame_source) ;
2054
2106
2055
- let best_constraint = match best_choice {
2056
- Some ( i)
2057
- if let Some ( next) = path. get ( i + 1 )
2058
- && matches ! ( path[ i] . category, ConstraintCategory :: Return ( _) )
2059
- && next. category == ConstraintCategory :: OpaqueType =>
2060
- {
2061
- // The return expression is being influenced by the return type being
2062
- // impl Trait, point at the return type and not the return expr.
2063
- * next
2064
- }
2065
-
2066
- Some ( i)
2067
- if path[ i] . category == ConstraintCategory :: Return ( ReturnConstraint :: Normal )
2068
- && let Some ( field) = path. iter ( ) . find_map ( |p| {
2069
- if let ConstraintCategory :: ClosureUpvar ( f) = p. category {
2070
- Some ( f)
2071
- } else {
2072
- None
2073
- }
2074
- } ) =>
2075
- {
2076
- OutlivesConstraint {
2077
- category : ConstraintCategory :: Return ( ReturnConstraint :: ClosureUpvar ( field) ) ,
2078
- ..path[ i]
2079
- }
2080
- }
2081
-
2082
- Some ( _)
2083
- if target_region == self . universal_regions ( ) . fr_static
2084
- && let Some ( old_best) = path. iter ( ) . min_by_key ( |p| p. category )
2085
- && matches ! ( old_best. category, ConstraintCategory :: Cast {
2086
- is_implicit_coercion: true ,
2087
- unsize_to: Some ( _)
2088
- } ) =>
2089
- {
2090
- // FIXME(dianne): This is a hack in order to emit the subdiagnostic
2091
- // `BorrowExplanation::add_object_lifetime_default_note` more often, e.g. on
2092
- // `tests/ui/traits/trait-object-lifetime-default-note.rs`. The subdiagnostic
2093
- // depends on a coercion being blamed, so we fall back to an earlier version of this
2094
- // function's blaming logic to keep the test result the same. A proper fix will
2095
- // require rewriting the subdiagnostic not to rely on a coercion being blamed.
2096
- // For examples of where notes are missing, see #131008 and
2097
- // `tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs`.
2098
- // As part of fixing those, this case should be removed.
2099
- * old_best
2100
- }
2101
-
2102
- Some ( i) => path[ i] ,
2103
-
2104
- None => {
2105
- // If that search fails, the only constraints on the path are those that we try not
2106
- // to blame. In that case, find what appears to be the most interesting point to
2107
- // report to the user via an even more ad-hoc guess.
2108
- * path. iter ( ) . min_by_key ( |p| p. category ) . unwrap ( )
2107
+ let best_constraint = if let Some ( next) = path. get ( best_choice + 1 )
2108
+ && matches ! ( path[ best_choice] . category, ConstraintCategory :: Return ( _) )
2109
+ && next. category == ConstraintCategory :: OpaqueType
2110
+ {
2111
+ // The return expression is being influenced by the return type being
2112
+ // impl Trait, point at the return type and not the return expr.
2113
+ * next
2114
+ } else if path[ best_choice] . category == ConstraintCategory :: Return ( ReturnConstraint :: Normal )
2115
+ && let Some ( field) = path. iter ( ) . find_map ( |p| {
2116
+ if let ConstraintCategory :: ClosureUpvar ( f) = p. category { Some ( f) } else { None }
2117
+ } )
2118
+ {
2119
+ OutlivesConstraint {
2120
+ category : ConstraintCategory :: Return ( ReturnConstraint :: ClosureUpvar ( field) ) ,
2121
+ ..path[ best_choice]
2109
2122
}
2123
+ } else {
2124
+ path[ best_choice]
2110
2125
} ;
2111
2126
2112
2127
let blame_constraint = BlameConstraint {
0 commit comments