Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21348 from ChayimFriedman2/reenable-variance
fix: Reenable fixpoint variance
| -rw-r--r-- | crates/hir-ty/src/tests/traits.rs | 24 | ||||
| -rw-r--r-- | crates/hir-ty/src/variance.rs | 79 | ||||
| -rw-r--r-- | crates/ide-completion/src/completions/dot.rs | 3 | ||||
| -rw-r--r-- | crates/ide/src/inlay_hints/bind_pat.rs | 12 |
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> {} |