@@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>(
49
49
let mut checked_wf_args = rustc_data_structures:: fx:: FxHashSet :: default ( ) ;
50
50
let mut wf_args = vec ! [ ty. into( ) ] ;
51
51
52
- let mut implied_bounds = vec ! [ ] ;
52
+ let mut outlives_bounds: Vec < ty:: OutlivesPredicate < ty:: GenericArg < ' tcx > , ty:: Region < ' tcx > > > =
53
+ vec ! [ ] ;
53
54
54
55
let mut fulfill_cx = <dyn TraitEngine < ' tcx > >:: new ( tcx) ;
55
56
@@ -65,41 +66,28 @@ fn compute_implied_outlives_bounds<'tcx>(
65
66
// than the ultimate set. (Note: normally there won't be
66
67
// unresolved inference variables here anyway, but there might be
67
68
// during typeck under some circumstances.)
69
+ //
70
+ // FIXME(@lcnr): It's not really "always fine", having fewer implied
71
+ // bounds can be backward incompatible, e.g. #101951 was caused by
72
+ // us not dealing with inference vars in `TypeOutlives` predicates.
68
73
let obligations = wf:: obligations ( infcx, param_env, hir:: CRATE_HIR_ID , 0 , arg, DUMMY_SP )
69
74
. unwrap_or_default ( ) ;
70
75
71
- // N.B., all of these predicates *ought* to be easily proven
72
- // true. In fact, their correctness is (mostly) implied by
73
- // other parts of the program. However, in #42552, we had
74
- // an annoying scenario where:
75
- //
76
- // - Some `T::Foo` gets normalized, resulting in a
77
- // variable `_1` and a `T: Trait<Foo=_1>` constraint
78
- // (not sure why it couldn't immediately get
79
- // solved). This result of `_1` got cached.
80
- // - These obligations were dropped on the floor here,
81
- // rather than being registered.
82
- // - Then later we would get a request to normalize
83
- // `T::Foo` which would result in `_1` being used from
84
- // the cache, but hence without the `T: Trait<Foo=_1>`
85
- // constraint. As a result, `_1` never gets resolved,
86
- // and we get an ICE (in dropck).
87
- //
88
- // Therefore, we register any predicates involving
89
- // inference variables. We restrict ourselves to those
90
- // involving inference variables both for efficiency and
91
- // to avoids duplicate errors that otherwise show up.
76
+ // While these predicates should all be implied by other parts of
77
+ // the program, they are still relevant as they may constrain
78
+ // inference variables, which is necessary to add the correct
79
+ // implied bounds in some cases, mostly when dealing with projections.
92
80
fulfill_cx. register_predicate_obligations (
93
81
infcx,
94
82
obligations. iter ( ) . filter ( |o| o. predicate . has_infer_types_or_consts ( ) ) . cloned ( ) ,
95
83
) ;
96
84
97
85
// From the full set of obligations, just filter down to the
98
86
// region relationships.
99
- implied_bounds . extend ( obligations. into_iter ( ) . flat_map ( |obligation| {
87
+ outlives_bounds . extend ( obligations. into_iter ( ) . filter_map ( |obligation| {
100
88
assert ! ( !obligation. has_escaping_bound_vars( ) ) ;
101
89
match obligation. predicate . kind ( ) . no_bound_vars ( ) {
102
- None => vec ! [ ] ,
90
+ None => None ,
103
91
Some ( pred) => match pred {
104
92
ty:: PredicateKind :: Trait ( ..)
105
93
| ty:: PredicateKind :: Subtype ( ..)
@@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>(
109
97
| ty:: PredicateKind :: ObjectSafe ( ..)
110
98
| ty:: PredicateKind :: ConstEvaluatable ( ..)
111
99
| ty:: PredicateKind :: ConstEquate ( ..)
112
- | ty:: PredicateKind :: TypeWellFormedFromEnv ( ..) => vec ! [ ] ,
100
+ | ty:: PredicateKind :: TypeWellFormedFromEnv ( ..) => None ,
113
101
ty:: PredicateKind :: WellFormed ( arg) => {
114
102
wf_args. push ( arg) ;
115
- vec ! [ ]
103
+ None
116
104
}
117
105
118
106
ty:: PredicateKind :: RegionOutlives ( ty:: OutlivesPredicate ( r_a, r_b) ) => {
119
- vec ! [ OutlivesBound :: RegionSubRegion ( r_b , r_a ) ]
107
+ Some ( ty :: OutlivesPredicate ( r_a . into ( ) , r_b ) )
120
108
}
121
109
122
110
ty:: PredicateKind :: TypeOutlives ( ty:: OutlivesPredicate ( ty_a, r_b) ) => {
123
- let ty_a = infcx. resolve_vars_if_possible ( ty_a) ;
124
- let mut components = smallvec ! [ ] ;
125
- push_outlives_components ( tcx, ty_a, & mut components) ;
126
- implied_bounds_from_components ( r_b, components)
111
+ Some ( ty:: OutlivesPredicate ( ty_a. into ( ) , r_b) )
127
112
}
128
113
} ,
129
114
}
@@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>(
133
118
// Ensure that those obligations that we had to solve
134
119
// get solved *here*.
135
120
match fulfill_cx. select_all_or_error ( infcx) . as_slice ( ) {
136
- [ ] => Ok ( implied_bounds ) ,
137
- _ => Err ( NoSolution ) ,
121
+ [ ] => ( ) ,
122
+ _ => return Err ( NoSolution ) ,
138
123
}
124
+
125
+ // We lazily compute the outlives components as
126
+ // `select_all_or_error` constrains inference variables.
127
+ let implied_bounds = outlives_bounds
128
+ . into_iter ( )
129
+ . flat_map ( |ty:: OutlivesPredicate ( a, r_b) | match a. unpack ( ) {
130
+ ty:: GenericArgKind :: Lifetime ( r_a) => vec ! [ OutlivesBound :: RegionSubRegion ( r_b, r_a) ] ,
131
+ ty:: GenericArgKind :: Type ( ty_a) => {
132
+ let ty_a = infcx. resolve_vars_if_possible ( ty_a) ;
133
+ let mut components = smallvec ! [ ] ;
134
+ push_outlives_components ( tcx, ty_a, & mut components) ;
135
+ implied_bounds_from_components ( r_b, components)
136
+ }
137
+ ty:: GenericArgKind :: Const ( _) => unreachable ! ( ) ,
138
+ } )
139
+ . collect ( ) ;
140
+
141
+ Ok ( implied_bounds)
139
142
}
140
143
141
144
/// When we have an implied bound that `T: 'a`, we can further break
0 commit comments