@@ -12,13 +12,6 @@ pub use rustc_middle::traits::query::OutlivesBound;
12
12
pub type BoundsCompat < ' a , ' tcx : ' a > = impl Iterator < Item = OutlivesBound < ' tcx > > + ' a ;
13
13
pub type Bounds < ' a , ' tcx : ' a > = impl Iterator < Item = OutlivesBound < ' tcx > > + ' a ;
14
14
pub trait InferCtxtExt < ' a , ' tcx > {
15
- fn implied_outlives_bounds_compat (
16
- & self ,
17
- param_env : ty:: ParamEnv < ' tcx > ,
18
- body_id : LocalDefId ,
19
- ty : Ty < ' tcx > ,
20
- ) -> Vec < OutlivesBound < ' tcx > > ;
21
-
22
15
fn implied_bounds_tys_compat (
23
16
& ' a self ,
24
17
param_env : ty:: ParamEnv < ' tcx > ,
@@ -29,130 +22,127 @@ pub trait InferCtxtExt<'a, 'tcx> {
29
22
fn implied_bounds_tys (
30
23
& ' a self ,
31
24
param_env : ty:: ParamEnv < ' tcx > ,
25
+ body_id : LocalDefId ,
32
26
tys : & ' a FxIndexSet < Ty < ' tcx > > ,
33
27
) -> Bounds < ' a , ' tcx > ;
34
28
}
35
29
36
- impl < ' a , ' tcx : ' a > InferCtxtExt < ' a , ' tcx > for InferCtxt < ' tcx > {
37
- /// Implied bounds are region relationships that we deduce
38
- /// automatically. The idea is that (e.g.) a caller must check that a
39
- /// function's argument types are well-formed immediately before
40
- /// calling that fn, and hence the *callee* can assume that its
41
- /// argument types are well-formed. This may imply certain relationships
42
- /// between generic parameters. For example:
43
- /// ```
44
- /// fn foo<T>(x: &T) {}
45
- /// ```
46
- /// can only be called with a `'a` and `T` such that `&'a T` is WF.
47
- /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
48
- ///
49
- /// # Parameters
50
- ///
51
- /// - `param_env`, the where-clauses in scope
52
- /// - `body_id`, the body-id to use when normalizing assoc types.
53
- /// Note that this may cause outlives obligations to be injected
54
- /// into the inference context with this body-id.
55
- /// - `ty`, the type that we are supposed to assume is WF.
56
- #[ instrument( level = "debug" , skip( self , param_env, body_id) , ret) ]
57
- fn implied_outlives_bounds_compat (
58
- & self ,
59
- param_env : ty:: ParamEnv < ' tcx > ,
60
- body_id : LocalDefId ,
61
- ty : Ty < ' tcx > ,
62
- ) -> Vec < OutlivesBound < ' tcx > > {
63
- let ty = self . resolve_vars_if_possible ( ty) ;
64
- let ty = OpportunisticRegionResolver :: new ( self ) . fold_ty ( ty) ;
65
-
66
- // We do not expect existential variables in implied bounds.
67
- // We may however encounter unconstrained lifetime variables
68
- // in very rare cases.
69
- //
70
- // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
71
- // an example.
72
- assert ! ( !ty. has_non_region_infer( ) ) ;
73
-
74
- let mut canonical_var_values = OriginalQueryValues :: default ( ) ;
75
- let canonical_ty =
76
- self . canonicalize_query_keep_static ( param_env. and ( ty) , & mut canonical_var_values) ;
77
- let Ok ( canonical_result) = self . tcx . implied_outlives_bounds_compat ( canonical_ty) else {
78
- return vec ! [ ] ;
79
- } ;
80
-
81
- let mut constraints = QueryRegionConstraints :: default ( ) ;
82
- let Ok ( InferOk { value : mut bounds, obligations } ) = self
83
- . instantiate_nll_query_response_and_region_obligations (
84
- & ObligationCause :: dummy ( ) ,
30
+ /// Implied bounds are region relationships that we deduce
31
+ /// automatically. The idea is that (e.g.) a caller must check that a
32
+ /// function's argument types are well-formed immediately before
33
+ /// calling that fn, and hence the *callee* can assume that its
34
+ /// argument types are well-formed. This may imply certain relationships
35
+ /// between generic parameters. For example:
36
+ /// ```
37
+ /// fn foo<T>(x: &T) {}
38
+ /// ```
39
+ /// can only be called with a `'a` and `T` such that `&'a T` is WF.
40
+ /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
41
+ ///
42
+ /// # Parameters
43
+ ///
44
+ /// - `param_env`, the where-clauses in scope
45
+ /// - `body_id`, the body-id to use when normalizing assoc types.
46
+ /// Note that this may cause outlives obligations to be injected
47
+ /// into the inference context with this body-id.
48
+ /// - `ty`, the type that we are supposed to assume is WF.
49
+ #[ instrument( level = "debug" , skip( infcx, param_env, body_id) , ret) ]
50
+ fn implied_outlives_bounds < ' a , ' tcx > (
51
+ infcx : & ' a InferCtxt < ' tcx > ,
52
+ param_env : ty:: ParamEnv < ' tcx > ,
53
+ body_id : LocalDefId ,
54
+ ty : Ty < ' tcx > ,
55
+ compat : bool ,
56
+ ) -> Vec < OutlivesBound < ' tcx > > {
57
+ let ty = infcx. resolve_vars_if_possible ( ty) ;
58
+ let ty = OpportunisticRegionResolver :: new ( infcx) . fold_ty ( ty) ;
59
+
60
+ // We do not expect existential variables in implied bounds.
61
+ // We may however encounter unconstrained lifetime variables
62
+ // in very rare cases.
63
+ //
64
+ // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
65
+ // an example.
66
+ assert ! ( !ty. has_non_region_infer( ) ) ;
67
+
68
+ let mut canonical_var_values = OriginalQueryValues :: default ( ) ;
69
+ let canonical_ty =
70
+ infcx. canonicalize_query_keep_static ( param_env. and ( ty) , & mut canonical_var_values) ;
71
+ let implied_bounds_result = if compat {
72
+ infcx. tcx . implied_outlives_bounds_compat ( canonical_ty)
73
+ } else {
74
+ infcx. tcx . implied_outlives_bounds ( canonical_ty)
75
+ } ;
76
+ let Ok ( canonical_result) = implied_bounds_result else {
77
+ return vec ! [ ] ;
78
+ } ;
79
+
80
+ let mut constraints = QueryRegionConstraints :: default ( ) ;
81
+ let Ok ( InferOk { value : mut bounds, obligations } ) = infcx
82
+ . instantiate_nll_query_response_and_region_obligations (
83
+ & ObligationCause :: dummy ( ) ,
84
+ param_env,
85
+ & canonical_var_values,
86
+ canonical_result,
87
+ & mut constraints,
88
+ )
89
+ else {
90
+ return vec ! [ ] ;
91
+ } ;
92
+ assert_eq ! ( & obligations, & [ ] ) ;
93
+
94
+ // Because of #109628, we may have unexpected placeholders. Ignore them!
95
+ // FIXME(#109628): panic in this case once the issue is fixed.
96
+ bounds. retain ( |bound| !bound. has_placeholders ( ) ) ;
97
+
98
+ if !constraints. is_empty ( ) {
99
+ let span = infcx. tcx . def_span ( body_id) ;
100
+
101
+ debug ! ( ?constraints) ;
102
+ if !constraints. member_constraints . is_empty ( ) {
103
+ span_bug ! ( span, "{:#?}" , constraints. member_constraints) ;
104
+ }
105
+
106
+ // Instantiation may have produced new inference variables and constraints on those
107
+ // variables. Process these constraints.
108
+ let ocx = ObligationCtxt :: new ( infcx) ;
109
+ let cause = ObligationCause :: misc ( span, body_id) ;
110
+ for & constraint in & constraints. outlives {
111
+ ocx. register_obligation ( infcx. query_outlives_constraint_to_obligation (
112
+ constraint,
113
+ cause. clone ( ) ,
85
114
param_env,
86
- & canonical_var_values,
87
- canonical_result,
88
- & mut constraints,
89
- )
90
- else {
91
- return vec ! [ ] ;
92
- } ;
93
- assert_eq ! ( & obligations, & [ ] ) ;
94
-
95
- // Because of #109628, we may have unexpected placeholders. Ignore them!
96
- // FIXME(#109628): panic in this case once the issue is fixed.
97
- bounds. retain ( |bound| !bound. has_placeholders ( ) ) ;
98
-
99
- if !constraints. is_empty ( ) {
100
- let span = self . tcx . def_span ( body_id) ;
101
-
102
- debug ! ( ?constraints) ;
103
- if !constraints. member_constraints . is_empty ( ) {
104
- span_bug ! ( span, "{:#?}" , constraints. member_constraints) ;
105
- }
106
-
107
- // Instantiation may have produced new inference variables and constraints on those
108
- // variables. Process these constraints.
109
- let ocx = ObligationCtxt :: new ( self ) ;
110
- let cause = ObligationCause :: misc ( span, body_id) ;
111
- for & constraint in & constraints. outlives {
112
- ocx. register_obligation ( self . query_outlives_constraint_to_obligation (
113
- constraint,
114
- cause. clone ( ) ,
115
- param_env,
116
- ) ) ;
117
- }
118
-
119
- let errors = ocx. select_all_or_error ( ) ;
120
- if !errors. is_empty ( ) {
121
- self . tcx . sess . span_delayed_bug (
122
- span,
123
- "implied_outlives_bounds_compat failed to solve obligations from instantiation" ,
124
- ) ;
125
- }
126
- } ;
127
-
128
- bounds
129
- }
115
+ ) ) ;
116
+ }
117
+
118
+ let errors = ocx. select_all_or_error ( ) ;
119
+ if !errors. is_empty ( ) {
120
+ infcx. tcx . sess . span_delayed_bug (
121
+ span,
122
+ "implied_outlives_bounds_compat failed to solve obligations from instantiation" ,
123
+ ) ;
124
+ }
125
+ } ;
126
+
127
+ bounds
128
+ }
130
129
130
+ impl < ' a , ' tcx : ' a > InferCtxtExt < ' a , ' tcx > for InferCtxt < ' tcx > {
131
131
fn implied_bounds_tys_compat (
132
132
& ' a self ,
133
133
param_env : ParamEnv < ' tcx > ,
134
134
body_id : LocalDefId ,
135
135
tys : & ' a FxIndexSet < Ty < ' tcx > > ,
136
136
) -> BoundsCompat < ' a , ' tcx > {
137
- tys. iter ( ) . flat_map ( move |ty| self . implied_outlives_bounds_compat ( param_env, body_id, * ty) )
137
+ tys. iter ( ) . flat_map ( move |ty| implied_outlives_bounds ( self , param_env, body_id, * ty, true ) )
138
138
}
139
139
140
140
fn implied_bounds_tys (
141
141
& ' a self ,
142
142
param_env : ParamEnv < ' tcx > ,
143
+ body_id : LocalDefId ,
143
144
tys : & ' a FxIndexSet < Ty < ' tcx > > ,
144
145
) -> Bounds < ' a , ' tcx > {
145
- tys. iter ( )
146
- . flat_map ( move |& ty| {
147
- let ty = self . resolve_vars_if_possible ( ty) ;
148
- let ty = OpportunisticRegionResolver :: new ( self ) . fold_ty ( ty) ;
149
-
150
- if ty. has_infer ( ) {
151
- return & [ ] as & [ OutlivesBound < ' _ > ] ;
152
- }
153
-
154
- self . tcx . implied_outlives_bounds ( param_env. and ( ty) ) . unwrap_or ( & [ ] )
155
- } )
156
- . copied ( )
146
+ tys. iter ( ) . flat_map ( move |ty| implied_outlives_bounds ( self , param_env, body_id, * ty, false ) )
157
147
}
158
148
}
0 commit comments