@@ -2026,87 +2026,102 @@ impl<'tcx> RegionInferenceContext<'tcx> {
20262026 | NllRegionVariableOrigin :: Existential { from_forall : true } => false ,
20272027 } ;
20282028
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+ }
20452097 } ;
20462098
20472099 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
20492101 } else {
2050- path. iter ( ) . position ( interesting_to_blame )
2102+ path. iter ( ) . enumerate ( ) . min_by_key ( | ( _ , c ) | constraint_interest ( c ) ) . unwrap ( ) . 0
20512103 } ;
20522104
20532105 debug ! ( ?best_choice, ?blame_source) ;
20542106
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]
21092122 }
2123+ } else {
2124+ path[ best_choice]
21102125 } ;
21112126
21122127 let blame_constraint = BlameConstraint {
0 commit comments