17
17
//!
18
18
//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
19
19
20
- use rustc_middle:: ty:: relate:: RelateResult ;
21
- use rustc_middle:: ty:: { self , Ty , TyVar } ;
22
- use tracing:: instrument;
20
+ use rustc_middle:: traits:: solve:: Goal ;
21
+ use rustc_middle:: ty:: relate:: { Relate , RelateResult , TypeRelation } ;
22
+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TyVar , TypeVisitableExt } ;
23
+ use rustc_span:: Span ;
24
+ use tracing:: { debug, instrument} ;
23
25
24
- use super :: combine:: PredicateEmittingRelation ;
25
- use crate :: infer:: { DefineOpaqueTypes , InferCtxt } ;
26
+ use super :: StructurallyRelateAliases ;
27
+ use super :: combine:: { CombineFields , PredicateEmittingRelation } ;
28
+ use crate :: infer:: { DefineOpaqueTypes , InferCtxt , SubregionOrigin } ;
26
29
use crate :: traits:: ObligationCause ;
27
30
28
31
/// Trait for returning data about a lattice, and for abstracting
29
32
/// over the "direction" of the lattice operation (LUB/GLB).
30
33
///
31
34
/// GLB moves "down" the lattice (to smaller values); LUB moves
32
35
/// "up" the lattice (to bigger values).
33
- pub ( crate ) trait LatticeDir < ' f , ' tcx > : PredicateEmittingRelation < InferCtxt < ' tcx > > {
36
+ trait LatticeDir < ' f , ' tcx > : PredicateEmittingRelation < InferCtxt < ' tcx > > {
34
37
fn infcx ( & self ) -> & ' f InferCtxt < ' tcx > ;
35
38
36
39
fn cause ( & self ) -> & ObligationCause < ' tcx > ;
@@ -48,7 +51,7 @@ pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>
48
51
49
52
/// Relates two types using a given lattice.
50
53
#[ instrument( skip( this) , level = "debug" ) ]
51
- pub fn super_lattice_tys < ' a , ' tcx : ' a , L > (
54
+ fn super_lattice_tys < ' a , ' tcx : ' a , L > (
52
55
this : & mut L ,
53
56
a : Ty < ' tcx > ,
54
57
b : Ty < ' tcx > ,
@@ -113,3 +116,169 @@ where
113
116
_ => infcx. super_combine_tys ( this, a, b) ,
114
117
}
115
118
}
119
+
120
+ #[ derive( Clone , Copy ) ]
121
+ pub ( crate ) enum LatticeOpKind {
122
+ Glb ,
123
+ Lub ,
124
+ }
125
+
126
+ /// A greatest lower bound" (common subtype) or least upper bound (common supertype).
127
+ pub ( crate ) struct LatticeOp < ' combine , ' infcx , ' tcx > {
128
+ kind : LatticeOpKind ,
129
+ fields : & ' combine mut CombineFields < ' infcx , ' tcx > ,
130
+ }
131
+
132
+ impl < ' combine , ' infcx , ' tcx > LatticeOp < ' combine , ' infcx , ' tcx > {
133
+ pub ( crate ) fn new (
134
+ kind : LatticeOpKind ,
135
+ fields : & ' combine mut CombineFields < ' infcx , ' tcx > ,
136
+ ) -> LatticeOp < ' combine , ' infcx , ' tcx > {
137
+ LatticeOp { kind, fields }
138
+ }
139
+ }
140
+
141
+ impl < ' tcx > TypeRelation < TyCtxt < ' tcx > > for LatticeOp < ' _ , ' _ , ' tcx > {
142
+ fn cx ( & self ) -> TyCtxt < ' tcx > {
143
+ self . fields . tcx ( )
144
+ }
145
+
146
+ fn relate_with_variance < T : Relate < TyCtxt < ' tcx > > > (
147
+ & mut self ,
148
+ variance : ty:: Variance ,
149
+ _info : ty:: VarianceDiagInfo < TyCtxt < ' tcx > > ,
150
+ a : T ,
151
+ b : T ,
152
+ ) -> RelateResult < ' tcx , T > {
153
+ match variance {
154
+ ty:: Invariant => self . fields . equate ( StructurallyRelateAliases :: No ) . relate ( a, b) ,
155
+ ty:: Covariant => self . relate ( a, b) ,
156
+ // FIXME(#41044) -- not correct, need test
157
+ ty:: Bivariant => Ok ( a) ,
158
+ ty:: Contravariant => self . fields . lattice_op ( self . kind ) . relate ( a, b) ,
159
+ }
160
+ }
161
+
162
+ #[ instrument( skip( self ) , level = "trace" ) ]
163
+ fn tys ( & mut self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> RelateResult < ' tcx , Ty < ' tcx > > {
164
+ super_lattice_tys ( self , a, b)
165
+ }
166
+
167
+ #[ instrument( skip( self ) , level = "trace" ) ]
168
+ fn regions (
169
+ & mut self ,
170
+ a : ty:: Region < ' tcx > ,
171
+ b : ty:: Region < ' tcx > ,
172
+ ) -> RelateResult < ' tcx , ty:: Region < ' tcx > > {
173
+ let origin = SubregionOrigin :: Subtype ( Box :: new ( self . fields . trace . clone ( ) ) ) ;
174
+ let mut inner = self . fields . infcx . inner . borrow_mut ( ) ;
175
+ let mut constraints = inner. unwrap_region_constraints ( ) ;
176
+ Ok ( match self . kind {
177
+ // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
178
+ LatticeOpKind :: Glb => constraints. glb_regions ( self . cx ( ) , origin, a, b) ,
179
+
180
+ // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
181
+ LatticeOpKind :: Lub => constraints. lub_regions ( self . cx ( ) , origin, a, b) ,
182
+ } )
183
+ }
184
+
185
+ #[ instrument( skip( self ) , level = "trace" ) ]
186
+ fn consts (
187
+ & mut self ,
188
+ a : ty:: Const < ' tcx > ,
189
+ b : ty:: Const < ' tcx > ,
190
+ ) -> RelateResult < ' tcx , ty:: Const < ' tcx > > {
191
+ self . fields . infcx . super_combine_consts ( self , a, b)
192
+ }
193
+
194
+ fn binders < T > (
195
+ & mut self ,
196
+ a : ty:: Binder < ' tcx , T > ,
197
+ b : ty:: Binder < ' tcx , T > ,
198
+ ) -> RelateResult < ' tcx , ty:: Binder < ' tcx , T > >
199
+ where
200
+ T : Relate < TyCtxt < ' tcx > > ,
201
+ {
202
+ // GLB/LUB of a binder and itself is just itself
203
+ if a == b {
204
+ return Ok ( a) ;
205
+ }
206
+
207
+ debug ! ( "binders(a={:?}, b={:?})" , a, b) ;
208
+ if a. skip_binder ( ) . has_escaping_bound_vars ( ) || b. skip_binder ( ) . has_escaping_bound_vars ( ) {
209
+ // When higher-ranked types are involved, computing the GLB/LUB is
210
+ // very challenging, switch to invariance. This is obviously
211
+ // overly conservative but works ok in practice.
212
+ self . relate_with_variance ( ty:: Invariant , ty:: VarianceDiagInfo :: default ( ) , a, b) ?;
213
+ Ok ( a)
214
+ } else {
215
+ Ok ( ty:: Binder :: dummy ( self . relate ( a. skip_binder ( ) , b. skip_binder ( ) ) ?) )
216
+ }
217
+ }
218
+ }
219
+
220
+ impl < ' combine , ' infcx , ' tcx > LatticeDir < ' infcx , ' tcx > for LatticeOp < ' combine , ' infcx , ' tcx > {
221
+ fn infcx ( & self ) -> & ' infcx InferCtxt < ' tcx > {
222
+ self . fields . infcx
223
+ }
224
+
225
+ fn cause ( & self ) -> & ObligationCause < ' tcx > {
226
+ & self . fields . trace . cause
227
+ }
228
+
229
+ fn relate_bound ( & mut self , v : Ty < ' tcx > , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> RelateResult < ' tcx , ( ) > {
230
+ let mut sub = self . fields . sub ( ) ;
231
+ match self . kind {
232
+ LatticeOpKind :: Glb => {
233
+ sub. relate ( v, a) ?;
234
+ sub. relate ( v, b) ?;
235
+ }
236
+ LatticeOpKind :: Lub => {
237
+ sub. relate ( a, v) ?;
238
+ sub. relate ( b, v) ?;
239
+ }
240
+ }
241
+ Ok ( ( ) )
242
+ }
243
+
244
+ fn define_opaque_types ( & self ) -> DefineOpaqueTypes {
245
+ self . fields . define_opaque_types
246
+ }
247
+ }
248
+
249
+ impl < ' tcx > PredicateEmittingRelation < InferCtxt < ' tcx > > for LatticeOp < ' _ , ' _ , ' tcx > {
250
+ fn span ( & self ) -> Span {
251
+ self . fields . trace . span ( )
252
+ }
253
+
254
+ fn structurally_relate_aliases ( & self ) -> StructurallyRelateAliases {
255
+ StructurallyRelateAliases :: No
256
+ }
257
+
258
+ fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > {
259
+ self . fields . param_env
260
+ }
261
+
262
+ fn register_predicates (
263
+ & mut self ,
264
+ obligations : impl IntoIterator < Item : ty:: Upcast < TyCtxt < ' tcx > , ty:: Predicate < ' tcx > > > ,
265
+ ) {
266
+ self . fields . register_predicates ( obligations) ;
267
+ }
268
+
269
+ fn register_goals (
270
+ & mut self ,
271
+ obligations : impl IntoIterator < Item = Goal < ' tcx , ty:: Predicate < ' tcx > > > ,
272
+ ) {
273
+ self . fields . register_obligations ( obligations) ;
274
+ }
275
+
276
+ fn register_alias_relate_predicate ( & mut self , a : Ty < ' tcx > , b : Ty < ' tcx > ) {
277
+ self . register_predicates ( [ ty:: Binder :: dummy ( ty:: PredicateKind :: AliasRelate (
278
+ a. into ( ) ,
279
+ b. into ( ) ,
280
+ // FIXME(deferred_projection_equality): This isn't right, I think?
281
+ ty:: AliasRelationDirection :: Equate ,
282
+ ) ) ] ) ;
283
+ }
284
+ }
0 commit comments