@@ -39,19 +39,9 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Ar
39
39
if count == 0 {
40
40
return None ;
41
41
}
42
- let mut ctxt = Context {
43
- def,
44
- has_trait_self : generics. parent_generics ( ) . map_or ( false , |it| it. has_trait_self ( ) ) ,
45
- len_self : generics. len_self ( ) ,
46
- len_self_lifetimes : generics. len_self_lifetimes ( ) ,
47
- generics,
48
- constraints : Vec :: new ( ) ,
49
- db,
50
- } ;
42
+ let variances = Context { generics, variances : vec ! [ Variance :: Bivariant ; count] , db } . solve ( ) ;
51
43
52
- ctxt. build_constraints_for_item ( ) ;
53
- let res = ctxt. solve ( ) ;
54
- res. is_empty ( ) . not ( ) . then ( || Arc :: from_iter ( res) )
44
+ variances. is_empty ( ) . not ( ) . then ( || Arc :: from_iter ( variances) )
55
45
}
56
46
57
47
pub ( crate ) fn variances_of_cycle (
@@ -172,25 +162,14 @@ struct InferredIndex(usize);
172
162
173
163
struct Context < ' db > {
174
164
db : & ' db dyn HirDatabase ,
175
- def : GenericDefId ,
176
- has_trait_self : bool ,
177
- len_self : usize ,
178
- len_self_lifetimes : usize ,
179
165
generics : Generics ,
180
- constraints : Vec < Constraint > ,
181
- }
182
-
183
- /// Declares that the variable `decl_id` appears in a location with
184
- /// variance `variance`.
185
- #[ derive( Clone ) ]
186
- struct Constraint {
187
- inferred : InferredIndex ,
188
- variance : Variance ,
166
+ variances : Vec < Variance > ,
189
167
}
190
168
191
169
impl Context < ' _ > {
192
- fn build_constraints_for_item ( & mut self ) {
193
- match self . def {
170
+ fn solve ( mut self ) -> Vec < Variance > {
171
+ tracing:: debug!( "solve(generics={:?})" , self . generics) ;
172
+ match self . generics . def ( ) {
194
173
GenericDefId :: AdtId ( adt) => {
195
174
let db = self . db ;
196
175
let mut add_constraints_from_variant = |variant| {
@@ -225,6 +204,26 @@ impl Context<'_> {
225
204
}
226
205
_ => { }
227
206
}
207
+ let mut variances = self . variances ;
208
+
209
+ // Const parameters are always invariant.
210
+ // Make all const parameters invariant.
211
+ for ( idx, param) in self . generics . iter_id ( ) . enumerate ( ) {
212
+ if let GenericParamId :: ConstParamId ( _) = param {
213
+ variances[ idx] = Variance :: Invariant ;
214
+ }
215
+ }
216
+
217
+ // Functions are permitted to have unused generic parameters: make those invariant.
218
+ if let GenericDefId :: FunctionId ( _) = self . generics . def ( ) {
219
+ for variance in & mut variances {
220
+ if * variance == Variance :: Bivariant {
221
+ * variance = Variance :: Invariant ;
222
+ }
223
+ }
224
+ }
225
+
226
+ variances
228
227
}
229
228
230
229
fn contravariant ( & mut self , variance : Variance ) -> Variance {
@@ -353,14 +352,8 @@ impl Context<'_> {
353
352
// Chalk has no params, so use placeholders for now?
354
353
TyKind :: Placeholder ( index) => {
355
354
let idx = crate :: from_placeholder_idx ( self . db , * index) ;
356
- let index = idx. local_id . into_raw ( ) . into_u32 ( ) as usize + self . len_self_lifetimes ;
357
- let inferred = if idx. parent == self . def {
358
- InferredIndex ( self . has_trait_self as usize + index)
359
- } else {
360
- InferredIndex ( self . len_self + index)
361
- } ;
362
- tracing:: debug!( "add_constraint(index={:?}, variance={:?})" , inferred, variance) ;
363
- self . constraints . push ( Constraint { inferred, variance } ) ;
355
+ let inferred = InferredIndex ( self . generics . type_or_const_param_idx ( idx) . unwrap ( ) ) ;
356
+ self . constrain ( inferred, variance) ;
364
357
}
365
358
TyKind :: Function ( f) => {
366
359
self . add_constraints_from_sig ( f, variance) ;
@@ -396,7 +389,7 @@ impl Context<'_> {
396
389
if args. is_empty ( ) {
397
390
return ;
398
391
}
399
- if def_id == self . def {
392
+ if def_id == self . generics . def ( ) {
400
393
// HACK: Workaround for the trivial cycle salsa case (see
401
394
// recursive_one_bivariant_more_non_bivariant_params test)
402
395
let variance_i = variance. xform ( Variance :: Bivariant ) ;
@@ -463,18 +456,17 @@ impl Context<'_> {
463
456
/// Adds constraints appropriate for a region appearing in a
464
457
/// context with ambient variance `variance`
465
458
fn add_constraints_from_region ( & mut self , region : & Lifetime , variance : Variance ) {
459
+ tracing:: debug!(
460
+ "add_constraints_from_region(region={:?}, variance={:?})" ,
461
+ region,
462
+ variance
463
+ ) ;
466
464
match region. data ( Interner ) {
467
465
// FIXME: chalk has no params?
468
466
LifetimeData :: Placeholder ( index) => {
469
467
let idx = crate :: lt_from_placeholder_idx ( self . db , * index) ;
470
- let index = idx. local_id . into_raw ( ) . into_u32 ( ) as usize ;
471
- let inferred = if idx. parent == self . def {
472
- InferredIndex ( index)
473
- } else {
474
- InferredIndex ( self . has_trait_self as usize + self . len_self + index)
475
- } ;
476
- tracing:: debug!( "add_constraint(index={:?}, variance={:?})" , inferred, variance) ;
477
- self . constraints . push ( Constraint { inferred, variance : variance. clone ( ) } ) ;
468
+ let inferred = InferredIndex ( self . generics . lifetime_idx ( idx) . unwrap ( ) ) ;
469
+ self . constrain ( inferred, variance) ;
478
470
}
479
471
LifetimeData :: Static => { }
480
472
@@ -513,50 +505,15 @@ impl Context<'_> {
513
505
}
514
506
}
515
507
}
516
- }
517
-
518
- impl Context < ' _ > {
519
- fn solve ( self ) -> Vec < Variance > {
520
- let mut solutions = vec ! [ Variance :: Bivariant ; self . generics. len( ) ] ;
521
- // Propagate constraints until a fixed point is reached. Note
522
- // that the maximum number of iterations is 2C where C is the
523
- // number of constraints (each variable can change values at most
524
- // twice). Since number of constraints is linear in size of the
525
- // input, so is the inference process.
526
- let mut changed = true ;
527
- while changed {
528
- changed = false ;
529
-
530
- for constraint in & self . constraints {
531
- let & Constraint { inferred, variance } = constraint;
532
- let InferredIndex ( inferred) = inferred;
533
- let old_value = solutions[ inferred] ;
534
- let new_value = variance. glb ( old_value) ;
535
- if old_value != new_value {
536
- solutions[ inferred] = new_value;
537
- changed = true ;
538
- }
539
- }
540
- }
541
508
542
- // Const parameters are always invariant.
543
- // Make all const parameters invariant.
544
- for ( idx, param) in self . generics . iter_id ( ) . enumerate ( ) {
545
- if let GenericParamId :: ConstParamId ( _) = param {
546
- solutions[ idx] = Variance :: Invariant ;
547
- }
548
- }
549
-
550
- // Functions are permitted to have unused generic parameters: make those invariant.
551
- if let GenericDefId :: FunctionId ( _) = self . def {
552
- for variance in & mut solutions {
553
- if * variance == Variance :: Bivariant {
554
- * variance = Variance :: Invariant ;
555
- }
556
- }
557
- }
558
-
559
- solutions
509
+ fn constrain ( & mut self , inferred : InferredIndex , variance : Variance ) {
510
+ tracing:: debug!(
511
+ "constrain(index={:?}, variance={:?}, to={:?})" ,
512
+ inferred,
513
+ self . variances[ inferred. 0 ] ,
514
+ variance
515
+ ) ;
516
+ self . variances [ inferred. 0 ] = self . variances [ inferred. 0 ] . glb ( variance) ;
560
517
}
561
518
}
562
519
0 commit comments