Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/variance.rs')
| -rw-r--r-- | crates/hir-ty/src/variance.rs | 137 |
1 files changed, 67 insertions, 70 deletions
diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index b57bf03f24..e5cfe85573 100644 --- a/crates/hir-ty/src/variance.rs +++ b/crates/hir-ty/src/variance.rs @@ -17,7 +17,7 @@ use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId, signatures::Struct use rustc_ast_ir::Mutability; use rustc_type_ir::{ Variance, - inherent::{AdtDef, IntoKind, SliceLike}, + inherent::{AdtDef, IntoKind}, }; use stdx::never; @@ -25,63 +25,58 @@ use crate::{ db::HirDatabase, generics::{Generics, generics}, next_solver::{ - Const, ConstKind, DbInterner, ExistentialPredicate, GenericArg, GenericArgs, Region, - RegionKind, Term, Ty, TyKind, VariancesOf, + Const, ConstKind, DbInterner, ExistentialPredicate, GenericArgKind, GenericArgs, Region, + RegionKind, StoredVariancesOf, TermKind, Ty, TyKind, VariancesOf, }, }; pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> VariancesOf<'_> { + variances_of_query(db, def).as_ref() +} + +#[salsa::tracked( + returns(ref), + cycle_fn = crate::variance::variances_of_cycle_fn, + cycle_initial = crate::variance::variances_of_cycle_initial, +)] +fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariancesOf { tracing::debug!("variances_of(def={:?})", def); - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); match def { GenericDefId::FunctionId(_) => (), GenericDefId::AdtId(adt) => { if let AdtId::StructId(id) = adt { let flags = &db.struct_signature(id).flags; + let types = || crate::next_solver::default_types(db); if flags.contains(StructFlags::IS_UNSAFE_CELL) { - return VariancesOf::new_from_iter(interner, [Variance::Invariant]); + return types().one_invariant.store(); } else if flags.contains(StructFlags::IS_PHANTOM_DATA) { - return VariancesOf::new_from_iter(interner, [Variance::Covariant]); + return types().one_covariant.store(); } } } - _ => return VariancesOf::new_from_iter(interner, []), + _ => return VariancesOf::empty(interner).store(), } let generics = generics(db, def); let count = generics.len(); if count == 0 { - return VariancesOf::new_from_iter(interner, []); - } - let mut variances = - Context { generics, variances: vec![Variance::Bivariant; count], db }.solve(); - - // FIXME(next-solver): This is *not* the correct behavior. I don't know if it has an actual effect, - // since bivariance is prohibited in Rust, but rustc definitely does not fallback bivariance. - // So why do we do this? Because, with the new solver, the effects of bivariance are catastrophic: - // it leads to not relating types properly, and to very, very hard to debug bugs (speaking from experience). - // Furthermore, our variance infra is known to not handle cycles properly. Therefore, at least until we fix - // cycles, and perhaps forever at least for out tests, not allowing bivariance makes sense. - // Why specifically invariance? I don't have a strong reason, mainly that invariance is a stronger relationship - // (therefore, less room for mistakes) and that IMO incorrect covariance can be more problematic that incorrect - // bivariance, at least while we don't handle lifetimes anyway. - for variance in &mut variances { - if *variance == Variance::Bivariant { - *variance = Variance::Invariant; - } + return VariancesOf::empty(interner).store(); } + let variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve(); - VariancesOf::new_from_iter(interner, variances) + VariancesOf::new_from_slice(&variances).store() } -// pub(crate) fn variances_of_cycle_fn( -// _db: &dyn HirDatabase, -// _result: &Option<Arc<[Variance]>>, -// _count: u32, -// _def: GenericDefId, -// ) -> salsa::CycleRecoveryAction<Option<Arc<[Variance]>>> { -// salsa::CycleRecoveryAction::Iterate -// } +pub(crate) fn variances_of_cycle_fn( + _db: &dyn HirDatabase, + _: &salsa::Cycle<'_>, + _last_provisional_value: &StoredVariancesOf, + value: StoredVariancesOf, + _def: GenericDefId, +) -> StoredVariancesOf { + value +} fn glb(v1: Variance, v2: Variance) -> Variance { // Greatest lower bound of the variance lattice as defined in The Paper: @@ -105,14 +100,14 @@ fn glb(v1: Variance, v2: Variance) -> Variance { pub(crate) fn variances_of_cycle_initial( db: &dyn HirDatabase, + _: salsa::Id, def: GenericDefId, -) -> VariancesOf<'_> { - let interner = DbInterner::new_with(db, None, None); +) -> StoredVariancesOf { + let interner = DbInterner::new_no_crate(db); let generics = generics(db, def); let count = generics.len(); - // FIXME(next-solver): Returns `Invariance` and not `Bivariance` here, see the comment in the main query. - VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Invariant, count)) + VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Bivariant, count)).store() } struct Context<'db> { @@ -130,7 +125,7 @@ impl<'db> Context<'db> { let mut add_constraints_from_variant = |variant| { for (_, field) in db.field_types(variant).iter() { self.add_constraints_from_ty( - field.instantiate_identity(), + field.get().instantiate_identity(), Variance::Covariant, ); } @@ -232,11 +227,11 @@ impl<'db> Context<'db> { } ExistentialPredicate::Projection(projection) => { self.add_constraints_from_invariant_args(projection.args); - match projection.term { - Term::Ty(ty) => { + match projection.term.kind() { + TermKind::Ty(ty) => { self.add_constraints_from_ty(ty, Variance::Invariant) } - Term::Const(konst) => self.add_constraints_from_const(konst), + TermKind::Const(konst) => self.add_constraints_from_const(konst), } } ExistentialPredicate::AutoTrait(_) => {} @@ -266,12 +261,12 @@ impl<'db> Context<'db> { fn add_constraints_from_invariant_args(&mut self, args: GenericArgs<'db>) { for k in args.iter() { - match k { - GenericArg::Lifetime(lt) => { + match k.kind() { + GenericArgKind::Lifetime(lt) => { self.add_constraints_from_region(lt, Variance::Invariant) } - GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, Variance::Invariant), - GenericArg::Const(val) => self.add_constraints_from_const(val), + GenericArgKind::Type(ty) => self.add_constraints_from_ty(ty, Variance::Invariant), + GenericArgKind::Const(val) => self.add_constraints_from_const(val), } } } @@ -290,10 +285,12 @@ impl<'db> Context<'db> { let variances = self.db.variances_of(def_id); for (k, v) in args.iter().zip(variances) { - match k { - GenericArg::Lifetime(lt) => self.add_constraints_from_region(lt, variance.xform(v)), - GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, variance.xform(v)), - GenericArg::Const(val) => self.add_constraints_from_const(val), + match k.kind() { + GenericArgKind::Lifetime(lt) => { + self.add_constraints_from_region(lt, variance.xform(v)) + } + GenericArgKind::Type(ty) => self.add_constraints_from_ty(ty, variance.xform(v)), + GenericArgKind::Const(val) => self.add_constraints_from_const(val), } } } @@ -387,7 +384,7 @@ mod tests { AdtId, GenericDefId, ModuleDefId, hir::generics::GenericParamDataRef, src::HasSource, }; use itertools::Itertools; - use rustc_type_ir::{Variance, inherent::SliceLike}; + use rustc_type_ir::Variance; use stdx::format_to; use syntax::{AstNode, ast::HasName}; use test_fixture::WithFixture; @@ -470,8 +467,8 @@ struct Other<'a> { } "#, expect![[r#" - Hello['a: invariant] - Other['a: invariant] + Hello['a: bivariant] + Other['a: bivariant] "#]], ); } @@ -490,7 +487,7 @@ struct Foo<T: Trait> { //~ ERROR [T: o] } "#, expect![[r#" - Foo[T: invariant] + Foo[T: bivariant] "#]], ); } @@ -572,9 +569,9 @@ struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [U: *, T: +] get[Self: contravariant, T: covariant] get[Self: contravariant, T: contravariant] TestStruct[U: covariant, T: covariant] - TestEnum[U: invariant, T: covariant] - TestContraStruct[U: invariant, T: covariant] - TestBox[U: invariant, T: covariant] + TestEnum[U: bivariant, T: covariant] + TestContraStruct[U: bivariant, T: covariant] + TestBox[U: bivariant, T: covariant] "#]], ); } @@ -694,8 +691,8 @@ enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used trait SomeTrait<'a> { fn foo(&self); } // OK on traits. "#, expect![[r#" - SomeStruct['a: invariant] - SomeEnum['a: invariant] + SomeStruct['a: bivariant] + SomeEnum['a: bivariant] foo[Self: contravariant, 'a: invariant] "#]], ); @@ -723,14 +720,14 @@ struct DoubleNothing<T> { "#, expect![[r#" - SomeStruct[A: invariant] - SomeEnum[A: invariant] - ListCell[T: invariant] - SelfTyAlias[T: invariant] - WithBounds[T: invariant] - WithWhereBounds[T: invariant] - WithOutlivesBounds[T: invariant] - DoubleNothing[T: invariant] + SomeStruct[A: bivariant] + SomeEnum[A: bivariant] + ListCell[T: bivariant] + SelfTyAlias[T: bivariant] + WithBounds[T: bivariant] + WithWhereBounds[T: bivariant] + WithOutlivesBounds[T: bivariant] + DoubleNothing[T: bivariant] "#]], ); } @@ -841,7 +838,7 @@ struct S3<T>(S<T, T>); "#, expect![[r#" S[T: covariant] - S2[T: invariant] + S2[T: bivariant] S3[T: covariant] "#]], ); @@ -854,7 +851,7 @@ struct S3<T>(S<T, T>); struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V); "#, expect![[r#" - FixedPoint[T: invariant, U: invariant, V: invariant] + FixedPoint[T: covariant, U: covariant, V: covariant] "#]], ); } @@ -874,7 +871,7 @@ struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V); let mut defs: Vec<GenericDefId> = Vec::new(); let module = db.module_for_file_opt(file_id.file_id(&db)).unwrap(); let def_map = module.def_map(&db); - crate::tests::visit_module(&db, def_map, module.local_id, &mut |it| { + crate::tests::visit_module(&db, def_map, module, &mut |it| { defs.push(match it { ModuleDefId::FunctionId(it) => it.into(), ModuleDefId::AdtId(it) => it.into(), |