@@ -39,19 +39,9 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Ar
3939 if count == 0 {
4040 return None ;
4141 }
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 ( ) ;
5143
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) )
5545}
5646
5747pub ( crate ) fn variances_of_cycle (
@@ -172,25 +162,14 @@ struct InferredIndex(usize);
172162
173163struct Context < ' db > {
174164 db : & ' db dyn HirDatabase ,
175- def : GenericDefId ,
176- has_trait_self : bool ,
177- len_self : usize ,
178- len_self_lifetimes : usize ,
179165 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 > ,
189167}
190168
191169impl 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 ( ) {
194173 GenericDefId :: AdtId ( adt) => {
195174 let db = self . db ;
196175 let mut add_constraints_from_variant = |variant| {
@@ -225,6 +204,26 @@ impl Context<'_> {
225204 }
226205 _ => { }
227206 }
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
228227 }
229228
230229 fn contravariant ( & mut self , variance : Variance ) -> Variance {
@@ -353,14 +352,8 @@ impl Context<'_> {
353352 // Chalk has no params, so use placeholders for now?
354353 TyKind :: Placeholder ( index) => {
355354 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) ;
364357 }
365358 TyKind :: Function ( f) => {
366359 self . add_constraints_from_sig ( f, variance) ;
@@ -396,7 +389,7 @@ impl Context<'_> {
396389 if args. is_empty ( ) {
397390 return ;
398391 }
399- if def_id == self . def {
392+ if def_id == self . generics . def ( ) {
400393 // HACK: Workaround for the trivial cycle salsa case (see
401394 // recursive_one_bivariant_more_non_bivariant_params test)
402395 let variance_i = variance. xform ( Variance :: Bivariant ) ;
@@ -463,18 +456,17 @@ impl Context<'_> {
463456 /// Adds constraints appropriate for a region appearing in a
464457 /// context with ambient variance `variance`
465458 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+ ) ;
466464 match region. data ( Interner ) {
467465 // FIXME: chalk has no params?
468466 LifetimeData :: Placeholder ( index) => {
469467 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) ;
478470 }
479471 LifetimeData :: Static => { }
480472
@@ -513,50 +505,15 @@ impl Context<'_> {
513505 }
514506 }
515507 }
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- }
541508
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) ;
560517 }
561518}
562519
0 commit comments