2
2
//! Do not call this query directory. See
3
3
//! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`].
4
4
5
- use rustc_infer:: infer:: canonical:: { self , Canonical } ;
5
+ use rustc_infer:: infer:: canonical;
6
6
use rustc_infer:: infer:: outlives:: components:: { push_outlives_components, Component } ;
7
7
use rustc_infer:: infer:: TyCtxtInferExt ;
8
8
use rustc_infer:: traits:: query:: OutlivesBound ;
9
9
use rustc_middle:: ty:: query:: Providers ;
10
10
use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitableExt } ;
11
- use rustc_span:: def_id:: CRATE_DEF_ID ;
12
- use rustc_span:: source_map:: DUMMY_SP ;
13
11
use rustc_trait_selection:: infer:: InferCtxtBuilderExt ;
14
12
use rustc_trait_selection:: traits:: query:: { CanonicalTyGoal , Fallible , NoSolution } ;
15
13
use rustc_trait_selection:: traits:: wf;
16
- use rustc_trait_selection:: traits:: ObligationCtxt ;
14
+ use rustc_trait_selection:: traits:: ObligationCause ;
17
15
use smallvec:: { smallvec, SmallVec } ;
18
16
19
17
pub ( crate ) fn provide ( p : & mut Providers ) {
@@ -23,79 +21,52 @@ pub(crate) fn provide(p: &mut Providers) {
23
21
fn implied_outlives_bounds < ' tcx > (
24
22
tcx : TyCtxt < ' tcx > ,
25
23
goal : CanonicalTyGoal < ' tcx > ,
26
- ) -> Result <
27
- & ' tcx Canonical < ' tcx , canonical:: QueryResponse < ' tcx , Vec < OutlivesBound < ' tcx > > > > ,
28
- NoSolution ,
29
- > {
24
+ ) -> Fallible < canonical:: CanonicalQueryResponse < ' tcx , Vec < OutlivesBound < ' tcx > > > > {
30
25
tcx. infer_ctxt ( ) . enter_canonical_trait_query ( & goal, |ocx, key| {
31
26
let ( param_env, ty) = key. into_parts ( ) ;
32
- compute_implied_outlives_bounds ( ocx, param_env, ty)
27
+
28
+ compute_implied_outlives_bounds ( tcx, param_env, ty, |ty| {
29
+ let ty = ocx. normalize ( & ObligationCause :: dummy ( ) , param_env, ty) ;
30
+ if !ocx. select_all_or_error ( ) . is_empty ( ) {
31
+ return Err ( NoSolution ) ;
32
+ }
33
+ let ty = ocx. infcx . resolve_vars_if_possible ( ty) ;
34
+ assert ! ( !ty. has_non_region_infer( ) ) ;
35
+ Ok ( ty)
36
+ } )
33
37
} )
34
38
}
35
39
40
+ /// For the sake of completeness, we should be careful when dealing with inference artifacts:
41
+ /// - This function shouldn't access an InferCtxt.
42
+ /// - `ty` must be fully resolved.
43
+ /// - `normalize_op` must return a fully resolved type.
36
44
fn compute_implied_outlives_bounds < ' tcx > (
37
- ocx : & ObligationCtxt < ' _ , ' tcx > ,
45
+ tcx : TyCtxt < ' tcx > ,
38
46
param_env : ty:: ParamEnv < ' tcx > ,
39
47
ty : Ty < ' tcx > ,
48
+ normalize_op : impl Fn ( Ty < ' tcx > ) -> Fallible < Ty < ' tcx > > ,
40
49
) -> Fallible < Vec < OutlivesBound < ' tcx > > > {
41
- let tcx = ocx. infcx . tcx ;
42
-
43
50
// Sometimes when we ask what it takes for T: WF, we get back that
44
51
// U: WF is required; in that case, we push U onto this stack and
45
52
// process it next. Because the resulting predicates aren't always
46
53
// guaranteed to be a subset of the original type, so we need to store the
47
54
// WF args we've computed in a set.
48
55
let mut checked_wf_args = rustc_data_structures:: fx:: FxHashSet :: default ( ) ;
49
- let mut wf_args = vec ! [ ty. into( ) ] ;
56
+ let mut wf_args = vec ! [ ty. into( ) , normalize_op ( ty ) ? . into ( ) ] ;
50
57
51
- let mut outlives_bounds: Vec < ty:: OutlivesPredicate < ty:: GenericArg < ' tcx > , ty:: Region < ' tcx > > > =
52
- vec ! [ ] ;
58
+ let mut outlives_bounds: Vec < OutlivesBound < ' tcx > > = vec ! [ ] ;
53
59
54
60
while let Some ( arg) = wf_args. pop ( ) {
55
61
if !checked_wf_args. insert ( arg) {
56
62
continue ;
57
63
}
58
64
59
- // Compute the obligations for `arg` to be well-formed. If `arg` is
60
- // an unresolved inference variable, just substituted an empty set
61
- // -- because the return type here is going to be things we *add*
62
- // to the environment, it's always ok for this set to be smaller
63
- // than the ultimate set. (Note: normally there won't be
64
- // unresolved inference variables here anyway, but there might be
65
- // during typeck under some circumstances.)
66
- //
67
- // FIXME(@lcnr): It's not really "always fine", having fewer implied
68
- // bounds can be backward incompatible, e.g. #101951 was caused by
69
- // us not dealing with inference vars in `TypeOutlives` predicates.
70
- let obligations = wf:: obligations ( ocx. infcx , param_env, CRATE_DEF_ID , 0 , arg, DUMMY_SP )
71
- . unwrap_or_default ( ) ;
72
-
73
- for obligation in obligations {
74
- debug ! ( ?obligation) ;
65
+ // From the full set of obligations, just filter down to the region relationships.
66
+ for obligation in wf:: unnormalized_obligations ( tcx, param_env, arg) {
75
67
assert ! ( !obligation. has_escaping_bound_vars( ) ) ;
76
-
77
- // While these predicates should all be implied by other parts of
78
- // the program, they are still relevant as they may constrain
79
- // inference variables, which is necessary to add the correct
80
- // implied bounds in some cases, mostly when dealing with projections.
81
- //
82
- // Another important point here: we only register `Projection`
83
- // predicates, since otherwise we might register outlives
84
- // predicates containing inference variables, and we don't
85
- // learn anything new from those.
86
- if obligation. predicate . has_non_region_infer ( ) {
87
- match obligation. predicate . kind ( ) . skip_binder ( ) {
88
- ty:: PredicateKind :: Clause ( ty:: Clause :: Projection ( ..) )
89
- | ty:: PredicateKind :: AliasEq ( ..) => {
90
- ocx. register_obligation ( obligation. clone ( ) ) ;
91
- }
92
- _ => { }
93
- }
94
- }
95
-
96
- let pred = match obligation. predicate . kind ( ) . no_bound_vars ( ) {
97
- None => continue ,
98
- Some ( pred) => pred,
68
+ let Some ( pred) = obligation. predicate . kind ( ) . no_bound_vars ( ) else {
69
+ continue ;
99
70
} ;
100
71
match pred {
101
72
ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( ..) )
@@ -114,48 +85,27 @@ fn compute_implied_outlives_bounds<'tcx>(
114
85
| ty:: PredicateKind :: TypeWellFormedFromEnv ( ..) => { }
115
86
116
87
// We need to search through *all* WellFormed predicates
117
- ty:: PredicateKind :: WellFormed ( arg) => {
118
- wf_args. push ( arg) ;
119
- }
88
+ ty:: PredicateKind :: WellFormed ( arg) => wf_args. push ( arg) ,
120
89
121
90
// We need to register region relationships
122
- ty:: PredicateKind :: Clause ( ty:: Clause :: RegionOutlives ( ty:: OutlivesPredicate (
123
- r_a,
124
- r_b,
125
- ) ) ) => outlives_bounds. push ( ty:: OutlivesPredicate ( r_a. into ( ) , r_b) ) ,
91
+ ty:: PredicateKind :: Clause ( ty:: Clause :: RegionOutlives (
92
+ ty:: OutlivesPredicate ( r_a, r_b) ,
93
+ ) ) => outlives_bounds. push ( OutlivesBound :: RegionSubRegion ( r_b, r_a) ) ,
126
94
127
95
ty:: PredicateKind :: Clause ( ty:: Clause :: TypeOutlives ( ty:: OutlivesPredicate (
128
96
ty_a,
129
97
r_b,
130
- ) ) ) => outlives_bounds. push ( ty:: OutlivesPredicate ( ty_a. into ( ) , r_b) ) ,
98
+ ) ) ) => {
99
+ let ty_a = normalize_op ( ty_a) ?;
100
+ let mut components = smallvec ! [ ] ;
101
+ push_outlives_components ( tcx, ty_a, & mut components) ;
102
+ outlives_bounds. extend ( implied_bounds_from_components ( r_b, components) )
103
+ }
131
104
}
132
105
}
133
106
}
134
107
135
- // This call to `select_all_or_error` is necessary to constrain inference variables, which we
136
- // use further down when computing the implied bounds.
137
- match ocx. select_all_or_error ( ) . as_slice ( ) {
138
- [ ] => ( ) ,
139
- _ => return Err ( NoSolution ) ,
140
- }
141
-
142
- // We lazily compute the outlives components as
143
- // `select_all_or_error` constrains inference variables.
144
- let implied_bounds = outlives_bounds
145
- . into_iter ( )
146
- . flat_map ( |ty:: OutlivesPredicate ( a, r_b) | match a. unpack ( ) {
147
- ty:: GenericArgKind :: Lifetime ( r_a) => vec ! [ OutlivesBound :: RegionSubRegion ( r_b, r_a) ] ,
148
- ty:: GenericArgKind :: Type ( ty_a) => {
149
- let ty_a = ocx. infcx . resolve_vars_if_possible ( ty_a) ;
150
- let mut components = smallvec ! [ ] ;
151
- push_outlives_components ( tcx, ty_a, & mut components) ;
152
- implied_bounds_from_components ( r_b, components)
153
- }
154
- ty:: GenericArgKind :: Const ( _) => unreachable ! ( ) ,
155
- } )
156
- . collect ( ) ;
157
-
158
- Ok ( implied_bounds)
108
+ Ok ( outlives_bounds)
159
109
}
160
110
161
111
/// When we have an implied bound that `T: 'a`, we can further break
@@ -165,28 +115,22 @@ fn compute_implied_outlives_bounds<'tcx>(
165
115
fn implied_bounds_from_components < ' tcx > (
166
116
sub_region : ty:: Region < ' tcx > ,
167
117
sup_components : SmallVec < [ Component < ' tcx > ; 4 ] > ,
168
- ) -> Vec < OutlivesBound < ' tcx > > {
169
- sup_components
170
- . into_iter ( )
171
- . filter_map ( |component| {
172
- match component {
173
- Component :: Region ( r) => Some ( OutlivesBound :: RegionSubRegion ( sub_region, r) ) ,
174
- Component :: Param ( p) => Some ( OutlivesBound :: RegionSubParam ( sub_region, p) ) ,
175
- Component :: Alias ( p) => Some ( OutlivesBound :: RegionSubAlias ( sub_region, p) ) ,
176
- Component :: EscapingAlias ( _) =>
177
- // If the projection has escaping regions, don't
178
- // try to infer any implied bounds even for its
179
- // free components. This is conservative, because
180
- // the caller will still have to prove that those
181
- // free components outlive `sub_region`. But the
182
- // idea is that the WAY that the caller proves
183
- // that may change in the future and we want to
184
- // give ourselves room to get smarter here.
185
- {
186
- None
187
- }
188
- Component :: UnresolvedInferenceVariable ( ..) => None ,
189
- }
190
- } )
191
- . collect ( )
118
+ ) -> impl Iterator < Item = OutlivesBound < ' tcx > > {
119
+ sup_components. into_iter ( ) . filter_map ( move |component| {
120
+ match component {
121
+ Component :: Region ( r) => Some ( OutlivesBound :: RegionSubRegion ( sub_region, r) ) ,
122
+ Component :: Param ( p) => Some ( OutlivesBound :: RegionSubParam ( sub_region, p) ) ,
123
+ Component :: Alias ( p) => Some ( OutlivesBound :: RegionSubAlias ( sub_region, p) ) ,
124
+ // If the projection has escaping regions, don't
125
+ // try to infer any implied bounds even for its
126
+ // free components. This is conservative, because
127
+ // the caller will still have to prove that those
128
+ // free components outlive `sub_region`. But the
129
+ // idea is that the WAY that the caller proves
130
+ // that may change in the future and we want to
131
+ // give ourselves room to get smarter here.
132
+ Component :: EscapingAlias ( _) => None ,
133
+ Component :: UnresolvedInferenceVariable ( ..) => bug ! ( "inference var in implied bounds" ) ,
134
+ }
135
+ } )
192
136
}
0 commit comments