From d3841fbab621ed61a6915dccca7ef311d27e10fb Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 27 Nov 2023 22:36:39 -0300 Subject: [PATCH] Make type equality use bidirectional subtyping in invariant context --- .../rustc_hir_analysis/src/check/intrinsic.rs | 10 ++++-- compiler/rustc_infer/src/infer/equate.rs | 4 +-- .../src/infer/higher_ranked/mod.rs | 34 +++++++++++++++++++ .../issue-111404-1.rs | 4 +-- .../issue-111404-1.stderr | 18 ++++++---- .../coherence-fn-covariant-bound-vs-static.rs | 5 ++- ...erence-fn-covariant-bound-vs-static.stderr | 10 +++--- tests/ui/coherence/coherence-fn-inputs.rs | 5 ++- tests/ui/coherence/coherence-fn-inputs.stderr | 10 +++--- .../typeid-equality-by-subtyping.stderr | 9 ++++- .../hrtb-exists-forall-trait-covariant.rs | 3 +- .../hrtb-exists-forall-trait-covariant.stderr | 11 ++++++ tests/ui/lub-glb/old-lub-glb-hr-eq.rs | 3 +- tests/ui/lub-glb/old-lub-glb-hr-eq.stderr | 19 +++++++++++ .../member-constraints-in-root-universe.rs | 3 +- ...member-constraints-in-root-universe.stderr | 22 ++++++++++++ 16 files changed, 141 insertions(+), 29 deletions(-) create mode 100644 tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr create mode 100644 tests/ui/lub-glb/old-lub-glb-hr-eq.stderr create mode 100644 tests/ui/traits/new-solver/member-constraints-in-root-universe.stderr diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 7ea21b24fc821..8bcdd44ccbedd 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -138,6 +138,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let name_str = intrinsic_name.as_str(); let bound_vars = tcx.mk_bound_variable_kinds(&[ + ty::BoundVariableKind::Region(ty::BrAnon), ty::BoundVariableKind::Region(ty::BrAnon), ty::BoundVariableKind::Region(ty::BrEnv), ]); @@ -151,7 +152,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let env_region = ty::Region::new_bound( tcx, ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv }, + ty::BoundRegion { var: ty::BoundVar::from_u32(2), kind: ty::BrEnv }, ); let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]); (Ty::new_ref(tcx, env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) @@ -446,9 +447,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::raw_eq => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon }; - let param_ty = + let param_ty_lhs = + Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); + let br = ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon }; + let param_ty_rhs = Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); - (1, vec![param_ty; 2], tcx.types.bool) + (1, vec![param_ty_lhs, param_ty_rhs], tcx.types.bool) } sym::black_box => (1, vec![param(0)], param(0)), diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 5d929394eb04c..3d26c6fa59c8c 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -165,8 +165,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { } if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { - self.fields.higher_ranked_sub(a, b, self.a_is_expected)?; - self.fields.higher_ranked_sub(b, a, self.a_is_expected)?; + self.fields.higher_ranked_equate(a, b, self.a_is_expected)?; + self.fields.higher_ranked_equate(b, a, self.a_is_expected)?; } else { // Fast path for the common case. self.relate(a.skip_binder(), b.skip_binder())?; diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 510b1797d3c9b..2664ec7055c6f 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -57,6 +57,40 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // placeholders which **must not** be named afterwards. Ok(()) } + + #[instrument(skip(self), level = "debug")] + pub fn higher_ranked_equate( + &mut self, + sub: Binder<'tcx, T>, + sup: Binder<'tcx, T>, + sub_is_expected: bool, + ) -> RelateResult<'tcx, ()> + where + T: Relate<'tcx>, + { + let span = self.trace.cause.span; + // First, we instantiate each bound region in the supertype with a + // fresh placeholder region. Note that this automatically creates + // a new universe if needed. + let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup); + + // Next, we instantiate each bound region in the subtype + // with a fresh region variable. These region variables -- + // but no other preexisting region variables -- can name + // the placeholders. + let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); + + debug!("a_prime={:?}", sub_prime); + debug!("b_prime={:?}", sup_prime); + + // Compare types now that bound regions have been replaced. + let result = self.equate(sub_is_expected).relate(sub_prime, sup_prime)?; + + debug!("OK result={result:?}"); + // NOTE: returning the result here would be dangerous as it contains + // placeholders which **must not** be named afterwards. + Ok(()) + } } impl<'tcx> InferCtxt<'tcx> { diff --git a/tests/ui/associated-inherent-types/issue-111404-1.rs b/tests/ui/associated-inherent-types/issue-111404-1.rs index dd62e59f07d22..472666381ee28 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.rs +++ b/tests/ui/associated-inherent-types/issue-111404-1.rs @@ -8,7 +8,7 @@ impl<'a> Foo { } fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} -//~^ ERROR higher-ranked subtype error -//~| ERROR higher-ranked subtype error +//~^ ERROR mismatched types [E0308] +//~| ERROR mismatched types [E0308] fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-111404-1.stderr b/tests/ui/associated-inherent-types/issue-111404-1.stderr index cf4d4a5f19b12..5351f43a7ef81 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.stderr +++ b/tests/ui/associated-inherent-types/issue-111404-1.stderr @@ -1,16 +1,22 @@ -error: higher-ranked subtype error - --> $DIR/issue-111404-1.rs:10:1 +error[E0308]: mismatched types + --> $DIR/issue-111404-1.rs:10:11 | LL | fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected struct `Foo` + found struct `Foo fn(&'b ())>` -error: higher-ranked subtype error - --> $DIR/issue-111404-1.rs:10:1 +error[E0308]: mismatched types + --> $DIR/issue-111404-1.rs:10:11 | LL | fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | + = note: expected struct `Foo` + found struct `Foo fn(&'b ())>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.rs b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.rs index 99f805f7f0f63..b37d1639f9d34 100644 --- a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.rs +++ b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.rs @@ -1,3 +1,5 @@ +// check-pass + // Test that impls for these two types are considered ovelapping: // // * `for<'r> fn(fn(&'r u32))` @@ -15,7 +17,8 @@ trait Trait {} impl Trait for for<'r> fn(fn(&'r ())) {} impl<'a> Trait for fn(fn(&'a ())) {} -//~^ ERROR conflicting implementations +//~^ WARN conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))` [coherence_leak_check] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! // // Note in particular that we do NOT get a future-compatibility warning // here. This is because the new leak-check proposed in [MCP 295] does not diff --git a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr index 316da26b54d4a..ebe7366b9458b 100644 --- a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr +++ b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr @@ -1,13 +1,15 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))` - --> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1 +warning: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))` + --> $DIR/coherence-fn-covariant-bound-vs-static.rs:19:1 | LL | impl Trait for for<'r> fn(fn(&'r ())) {} | ------------------------------------- first implementation here LL | impl<'a> Trait for fn(fn(&'a ())) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))` | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56105 = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + = note: `#[warn(coherence_leak_check)]` on by default -error: aborting due to 1 previous error +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-fn-inputs.rs b/tests/ui/coherence/coherence-fn-inputs.rs index 3afec5c5459af..c351553c0adcd 100644 --- a/tests/ui/coherence/coherence-fn-inputs.rs +++ b/tests/ui/coherence/coherence-fn-inputs.rs @@ -1,3 +1,5 @@ +// check-pass + // Test that we consider these two types completely equal: // // * `for<'a, 'b> fn(&'a u32, &'b u32)` @@ -13,7 +15,8 @@ trait Trait {} impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {} impl Trait for for<'c> fn(&'c u32, &'c u32) { - //~^ ERROR conflicting implementations + //~^ WARN conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)` [coherence_leak_check] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! // // Note in particular that we do NOT get a future-compatibility warning // here. This is because the new leak-check proposed in [MCP 295] does not diff --git a/tests/ui/coherence/coherence-fn-inputs.stderr b/tests/ui/coherence/coherence-fn-inputs.stderr index 246ec5947b3e4..b00f1704f9481 100644 --- a/tests/ui/coherence/coherence-fn-inputs.stderr +++ b/tests/ui/coherence/coherence-fn-inputs.stderr @@ -1,13 +1,15 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)` - --> $DIR/coherence-fn-inputs.rs:15:1 +warning: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)` + --> $DIR/coherence-fn-inputs.rs:17:1 | LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {} | ----------------------------------------------- first implementation here LL | impl Trait for for<'c> fn(&'c u32, &'c u32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)` | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56105 = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + = note: `#[warn(coherence_leak_check)]` on by default -error: aborting due to 1 previous error +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr index 3bae93ccb83fb..77f93774f978b 100644 --- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr @@ -7,5 +7,12 @@ LL | WHAT_A_TYPE => 0, = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: aborting due to 1 previous error +error[E0277]: the trait bound `for<'a, 'b> fn(&'a (), &'b ()): WithAssoc` is not satisfied + --> $DIR/typeid-equality-by-subtyping.rs:44:51 + | +LL | fn unsound(x: >::Assoc) -> >::Assoc + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WithAssoc` is not implemented for `for<'a, 'b> fn(&'a (), &'b ())` + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs index f95496a6c3cc0..8dcccfc217be1 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs @@ -2,8 +2,6 @@ // // In particular, we test this pattern in trait solving, where it is not connected // to any part of the source code. -// -// check-pass trait Trait {} @@ -34,4 +32,5 @@ fn main() { // This is because we can use `'static`. foo::<()>(); + //~^ ERROR implementation of `Trait` is not general enough } diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr new file mode 100644 index 0000000000000..893f49ce8f5f0 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr @@ -0,0 +1,11 @@ +error: implementation of `Trait` is not general enough + --> $DIR/hrtb-exists-forall-trait-covariant.rs:34:5 + | +LL | foo::<()>(); + | ^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `()` must implement `Trait fn(fn(&'b u32))>` + = note: ...but it actually implements `Trait`, for some specific lifetime `'0` + +error: aborting due to 1 previous error + diff --git a/tests/ui/lub-glb/old-lub-glb-hr-eq.rs b/tests/ui/lub-glb/old-lub-glb-hr-eq.rs index fbf4aee02045d..df288793608d8 100644 --- a/tests/ui/lub-glb/old-lub-glb-hr-eq.rs +++ b/tests/ui/lub-glb/old-lub-glb-hr-eq.rs @@ -3,8 +3,6 @@ // error. However, now that we handle subtyping correctly, we no // longer get an error, because we recognize these two types as // equivalent! -// -// check-pass fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) { // The two types above are actually equivalent. With the older @@ -13,6 +11,7 @@ fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) { let z = match 22 { 0 => x, _ => y, + //~^ ERROR `match` arms have incompatible types [E0308] }; } diff --git a/tests/ui/lub-glb/old-lub-glb-hr-eq.stderr b/tests/ui/lub-glb/old-lub-glb-hr-eq.stderr new file mode 100644 index 0000000000000..e7c73a15d508b --- /dev/null +++ b/tests/ui/lub-glb/old-lub-glb-hr-eq.stderr @@ -0,0 +1,19 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/old-lub-glb-hr-eq.rs:13:14 + | +LL | let z = match 22 { + | _____________- +LL | | 0 => x, + | | - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8)` +LL | | _ => y, + | | ^ one type is more general than the other +LL | | +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8)` + found fn pointer `for<'a> fn(&'a u8, &'a u8)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/new-solver/member-constraints-in-root-universe.rs b/tests/ui/traits/new-solver/member-constraints-in-root-universe.rs index 97c4430586447..39d58dab97b7d 100644 --- a/tests/ui/traits/new-solver/member-constraints-in-root-universe.rs +++ b/tests/ui/traits/new-solver/member-constraints-in-root-universe.rs @@ -1,5 +1,4 @@ // compile-flags: -Ztrait-solver=next -// check-pass trait Trait { type Ty; @@ -11,6 +10,8 @@ impl Trait for for<'a> fn(&'a u8, &'a u8) { // argument is necessary to create universes before registering the hidden type. fn test<'a>(_: ::Ty) -> impl Sized { + //~^ ERROR the type ` fn(&'a u8, &'b u8) as Trait>::Ty` is not well-formed + //~| ERROR the size for values of type ` fn(&'a u8, &'b u8) as Trait>::Ty` cannot be known at compilation time [E0277] "hidden type is `&'?0 str` with '?0 member of ['static,]" } diff --git a/tests/ui/traits/new-solver/member-constraints-in-root-universe.stderr b/tests/ui/traits/new-solver/member-constraints-in-root-universe.stderr new file mode 100644 index 0000000000000..06f96c85df527 --- /dev/null +++ b/tests/ui/traits/new-solver/member-constraints-in-root-universe.stderr @@ -0,0 +1,22 @@ +error: the type ` fn(&'a u8, &'b u8) as Trait>::Ty` is not well-formed + --> $DIR/member-constraints-in-root-universe.rs:12:16 + | +LL | fn test<'a>(_: ::Ty) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type ` fn(&'a u8, &'b u8) as Trait>::Ty` cannot be known at compilation time + --> $DIR/member-constraints-in-root-universe.rs:12:13 + | +LL | fn test<'a>(_: ::Ty) -> impl Sized { + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for ` fn(&'a u8, &'b u8) as Trait>::Ty` + = help: unsized fn params are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn test<'a>(_: &::Ty) -> impl Sized { + | + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.