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