Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21348 from ChayimFriedman2/reenable-variance
fix: Reenable fixpoint variance
Chayim Refael Friedman 4 months ago
parent 96d0670 · parent 32028ab · commit 3364710
-rw-r--r--crates/hir-ty/src/tests/traits.rs24
-rw-r--r--crates/hir-ty/src/variance.rs79
-rw-r--r--crates/ide-completion/src/completions/dot.rs3
-rw-r--r--crates/ide/src/inlay_hints/bind_pat.rs12
4 files changed, 51 insertions, 67 deletions
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index a54c0a799d..38591f486e 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -851,7 +851,7 @@ struct S;
trait Trait<T> {}
impl Trait<&str> for S {}
-struct O<T>;
+struct O<T>(T);
impl<U, T: Trait<U>> O<T> {
fn foo(&self) -> U { loop {} }
}
@@ -1492,7 +1492,7 @@ fn dyn_trait_in_impl() {
trait Trait<T, U> {
fn foo(&self) -> (T, U);
}
-struct S<T, U> {}
+struct S<T, U>(T, U);
impl<T, U> S<T, U> {
fn bar(&self) -> &dyn Trait<T, U> { loop {} }
}
@@ -1506,16 +1506,16 @@ fn test(s: S<u32, i32>) {
}"#,
expect![[r#"
32..36 'self': &'? Self
- 102..106 'self': &'? S<T, U>
- 128..139 '{ loop {} }': &'? (dyn Trait<T, U> + 'static)
- 130..137 'loop {}': !
- 135..137 '{}': ()
- 175..179 'self': &'? Self
- 251..252 's': S<u32, i32>
- 267..289 '{ ...z(); }': ()
- 273..274 's': S<u32, i32>
- 273..280 's.bar()': &'? (dyn Trait<u32, i32> + 'static)
- 273..286 's.bar().baz()': (u32, i32)
+ 106..110 'self': &'? S<T, U>
+ 132..143 '{ loop {} }': &'? (dyn Trait<T, U> + 'static)
+ 134..141 'loop {}': !
+ 139..141 '{}': ()
+ 179..183 'self': &'? Self
+ 255..256 's': S<u32, i32>
+ 271..293 '{ ...z(); }': ()
+ 277..278 's': S<u32, i32>
+ 277..284 's.bar()': &'? (dyn Trait<u32, i32> + 'static)
+ 277..290 's.bar().baz()': (u32, i32)
"#]],
);
}
diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs
index 5b8122a0a5..e5cfe85573 100644
--- a/crates/hir-ty/src/variance.rs
+++ b/crates/hir-ty/src/variance.rs
@@ -36,9 +36,8 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Variances
#[salsa::tracked(
returns(ref),
- // cycle_fn = crate::variance::variances_of_cycle_fn,
- // cycle_initial = crate::variance::variances_of_cycle_initial,
- cycle_result = crate::variance::variances_of_cycle_initial,
+ 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);
@@ -64,35 +63,20 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance
if count == 0 {
return VariancesOf::empty(interner).store();
}
- 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;
- }
- }
+ let variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
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:
@@ -123,8 +107,7 @@ pub(crate) fn variances_of_cycle_initial(
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)).store()
+ VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Bivariant, count)).store()
}
struct Context<'db> {
@@ -484,8 +467,8 @@ struct Other<'a> {
}
"#,
expect![[r#"
- Hello['a: invariant]
- Other['a: invariant]
+ Hello['a: bivariant]
+ Other['a: bivariant]
"#]],
);
}
@@ -504,7 +487,7 @@ struct Foo<T: Trait> { //~ ERROR [T: o]
}
"#,
expect![[r#"
- Foo[T: invariant]
+ Foo[T: bivariant]
"#]],
);
}
@@ -586,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]
"#]],
);
}
@@ -708,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]
"#]],
);
@@ -737,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]
"#]],
);
}
@@ -855,7 +838,7 @@ struct S3<T>(S<T, T>);
"#,
expect![[r#"
S[T: covariant]
- S2[T: invariant]
+ S2[T: bivariant]
S3[T: covariant]
"#]],
);
@@ -868,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]
"#]],
);
}
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index 18cfa53f8e..18c1992afa 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -652,7 +652,7 @@ fn foo(u: U) { u.$0 }
fn test_method_completion_only_fitting_impls() {
check_no_kw(
r#"
-struct A<T> {}
+struct A<T>(T);
impl A<u32> {
fn the_method(&self) {}
}
@@ -662,6 +662,7 @@ impl A<i32> {
fn foo(a: A<u32>) { a.$0 }
"#,
expect![[r#"
+ fd 0 u32
me the_method() fn(&self)
"#]],
)
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index de207c7821..547004687c 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -339,14 +339,14 @@ fn main(a: SliceIter<'_, Container>) {
fn lt_hints() {
check_types(
r#"
-struct S<'lt>;
+struct S<'lt>(*mut &'lt ());
fn f<'a>() {
- let x = S::<'static>;
+ let x = S::<'static>(loop {});
//^ S<'static>
- let y = S::<'_>;
+ let y = S::<'_>(loop {});
//^ S<'_>
- let z = S::<'a>;
+ let z = S::<'a>(loop {});
//^ S<'a>
}
@@ -632,10 +632,10 @@ fn main() {
fn multi_dyn_trait_bounds() {
check_types(
r#"
-pub struct Vec<T> {}
+pub struct Vec<T>(*mut T);
impl<T> Vec<T> {
- pub fn new() -> Self { Vec {} }
+ pub fn new() -> Self { Vec(0 as *mut T) }
}
pub struct Box<T> {}