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.rs137
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(),