Skip to content

Commit 878c8a2

Browse files
committedFeb 29, 2024·
Auto merge of #118247 - spastorino:type-equality-subtyping, r=lcnr
change equate for binders to not rely on subtyping *summary by `@spastorino` and `@lcnr*` ### Context The following code: ```rust type One = for<'a> fn(&'a (), &'a ()); type Two = for<'a, 'b> fn(&'a (), &'b ()); mod my_api { use std::any::Any; use std::marker::PhantomData; pub struct Foo<T: 'static> { a: &'static dyn Any, _p: PhantomData<*mut T>, // invariant, the type of the `dyn Any` } impl<T: 'static> Foo<T> { pub fn deref(&self) -> &'static T { match self.a.downcast_ref::<T>() { None => unsafe { std::hint::unreachable_unchecked() }, Some(a) => a, } } pub fn new(a: T) -> Foo<T> { Foo::<T> { a: Box::leak(Box::new(a)), _p: PhantomData, } } } } use my_api::*; fn main() { let foo = Foo::<One>::new((|_, _| ()) as One); foo.deref(); let foo: Foo<Two> = foo; foo.deref(); } ``` has UB from hitting the `unreachable_unchecked`. This happens because `TypeId::of::<One>()` is not the same as `TypeId::of::<Two>()` despite them being considered the same types by the type checker. Currently the type checker considers binders to be equal if subtyping succeeds in both directions: `for<'a> T<'a> eq for<'b> U<'b>` holds if `for<'a> exists<'b> T<'b> <: T'<a> AND for<'b> exists<'a> T<'a> <: T<'b>` holds. This results in `for<'a> fn(&'a (), &'a ())` and `for<'a, 'b> fn(&'a (), &'b ())` being equal in the type system. `TypeId` is computed by looking at the *structure* of a type. Even though these types are semantically equal, they have a different *structure* resulting in them having different `TypeId`. This can break invariants of unsafe code at runtime and is unsound when happening at compile time, e.g. when using const generics. So as seen in `main`, we can assign a value of type `Foo::<One>` to a binding of type `Foo<Two>` given those are considered the same type but then when we call `deref`, it calls `downcast_ref` that relies on `TypeId` and we would hit the `None` arm as these have different `TypeId`s. As stated in #97156 (comment), this causes the API of existing crates to be unsound. ## What should we do about this The same type resulting in different `TypeId`s is a significant footgun, breaking a very reasonable assumptions by authors of unsafe code. It will also be unsound by itself once they are usable in generic contexts with const generics. There are two options going forward here: - change how the *structure* of a type is computed before relying on it. i.e. continue considering `for<'a> fn(&'a (), &'a ())` and `for<'a, 'b> fn(&'a (), &'b ())` to be equal, but normalize them to a common representation so that their `TypeId` are also the same. - change how the semantic equality of binders to match the way we compute the structure of types. i.e. `for<'a> fn(&'a (), &'a ())` and `for<'a, 'b> fn(&'a (), &'b ())` still have different `TypeId`s but are now also considered to not be semantically equal. --- Advantages of the first approach: - with the second approach some higher ranked types stop being equal, even though they are subtypes of each other General thoughts: - changing the approach in the future will be breaking - going from first to second may break ordinary type checking, as types which were previously equal are now distinct - going from second to first may break coherence, because previously disjoint impls overlap as the used types are now equal - both of these are quite unlikely. This PR did not result in any crater failures, so this should not matter too much Advantages of the second approach: - the soundness of the first approach requires more non-local reasoning. We have to make sure that changes to subtyping do not cause the representative computation to diverge from semantic equality - e.g. we intend to consider higher ranked implied bounds when subtyping to [fix] #25860, I don't know how this will interact and don't feel confident making any prediction here. - computing a representative type is non-trivial and soundness critical, therefore adding complexity to the "core type system" --- This PR goes with the second approach. A crater run did not result in any regressions. I am personally very hesitant about trying the first approach due to the above reasons. It feels like there are more unknowns when going that route. ### Changing the way we equate binders Relating bound variables from different depths already results in a universe error in equate. We therefore only need to make sure that there is 1-to-1 correspondence between bound variables when relating binders. This results in concrete types being structurally equal after anonymizing their bound variables. We implement this by instantiating one of the binder with placeholders and the other with inference variables and then equating the instantiated types. We do so in both directions. More formally, we change the typing rules as follows: ``` for<'r0, .., 'rn> exists<'l0, .., 'ln> LHS<'l0, .., 'ln> <: RHS<'r0, .., 'rn> for<'l0, .., 'ln> exists<'r0, .., 'rn> RHS<'r0, .., 'rn> <: LHS<'l0, .., 'ln> -------------------------------------------------------------------------- for<'l0, .., 'ln> LHS<'l0, .., 'ln> eq for<'r0, .., 'rn> RHS<'r0, .., 'rn> ``` to ``` for<'r0, .., 'rn> exists<'l0, .., 'ln> LHS<'l0, .., 'ln> eq RHS<'r0, .., 'rn> for<'l0, .., 'ln> exists<'r0, .., 'rn> RHS<'r0, .., 'rn> eq LHS<'l0, .., 'ln> -------------------------------------------------------------------------- for<'l0, .., 'ln> LHS<'l0, .., 'ln> eq for<'r0, .., 'rn> RHS<'r0, .., 'rn> ``` --- Fixes #97156 r? `@lcnr`
2 parents 1a1876c + 4a2e3bc commit 878c8a2

22 files changed

+319
-112
lines changed
 

‎compiler/rustc_borrowck/src/type_check/relate_tys.rs

+52-54
Original file line numberDiff line numberDiff line change
@@ -483,61 +483,59 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
483483
return Ok(ty::Binder::dummy(a));
484484
}
485485

486-
if self.ambient_covariance() {
487-
// Covariance, so we want `for<..> A <: for<..> B` --
488-
// therefore we compare any instantiation of A (i.e., A
489-
// instantiated with existentials) against every
490-
// instantiation of B (i.e., B instantiated with
491-
// universals).
492-
493-
// Reset the ambient variance to covariant. This is needed
494-
// to correctly handle cases like
495-
//
496-
// for<'a> fn(&'a u32, &'a u32) == for<'b, 'c> fn(&'b u32, &'c u32)
497-
//
498-
// Somewhat surprisingly, these two types are actually
499-
// **equal**, even though the one on the right looks more
500-
// polymorphic. The reason is due to subtyping. To see it,
501-
// consider that each function can call the other:
502-
//
503-
// - The left function can call the right with `'b` and
504-
// `'c` both equal to `'a`
505-
//
506-
// - The right function can call the left with `'a` set to
507-
// `{P}`, where P is the point in the CFG where the call
508-
// itself occurs. Note that `'b` and `'c` must both
509-
// include P. At the point, the call works because of
510-
// subtyping (i.e., `&'b u32 <: &{P} u32`).
511-
let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
512-
513-
// Note: the order here is important. Create the placeholders first, otherwise
514-
// we assign the wrong universe to the existential!
515-
self.enter_forall(b, |this, b| {
516-
let a = this.instantiate_binder_with_existentials(a);
517-
this.relate(a, b)
518-
})?;
519-
520-
self.ambient_variance = variance;
521-
}
486+
match self.ambient_variance {
487+
ty::Variance::Covariant => {
488+
// Covariance, so we want `for<..> A <: for<..> B` --
489+
// therefore we compare any instantiation of A (i.e., A
490+
// instantiated with existentials) against every
491+
// instantiation of B (i.e., B instantiated with
492+
// universals).
493+
494+
// Note: the order here is important. Create the placeholders first, otherwise
495+
// we assign the wrong universe to the existential!
496+
self.enter_forall(b, |this, b| {
497+
let a = this.instantiate_binder_with_existentials(a);
498+
this.relate(a, b)
499+
})?;
500+
}
522501

523-
if self.ambient_contravariance() {
524-
// Contravariance, so we want `for<..> A :> for<..> B`
525-
// -- therefore we compare every instantiation of A (i.e.,
526-
// A instantiated with universals) against any
527-
// instantiation of B (i.e., B instantiated with
528-
// existentials). Opposite of above.
529-
530-
// Reset ambient variance to contravariance. See the
531-
// covariant case above for an explanation.
532-
let variance =
533-
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
534-
535-
self.enter_forall(a, |this, a| {
536-
let b = this.instantiate_binder_with_existentials(b);
537-
this.relate(a, b)
538-
})?;
539-
540-
self.ambient_variance = variance;
502+
ty::Variance::Contravariant => {
503+
// Contravariance, so we want `for<..> A :> for<..> B` --
504+
// therefore we compare every instantiation of A (i.e., A
505+
// instantiated with universals) against any
506+
// instantiation of B (i.e., B instantiated with
507+
// existentials). Opposite of above.
508+
509+
// Note: the order here is important. Create the placeholders first, otherwise
510+
// we assign the wrong universe to the existential!
511+
self.enter_forall(a, |this, a| {
512+
let b = this.instantiate_binder_with_existentials(b);
513+
this.relate(a, b)
514+
})?;
515+
}
516+
517+
ty::Variance::Invariant => {
518+
// Invariant, so we want `for<..> A == for<..> B` --
519+
// therefore we want `exists<..> A == for<..> B` and
520+
// `exists<..> B == for<..> A`.
521+
//
522+
// See the comment in `fn Equate::binders` for more details.
523+
524+
// Note: the order here is important. Create the placeholders first, otherwise
525+
// we assign the wrong universe to the existential!
526+
self.enter_forall(b, |this, b| {
527+
let a = this.instantiate_binder_with_existentials(a);
528+
this.relate(a, b)
529+
})?;
530+
// Note: the order here is important. Create the placeholders first, otherwise
531+
// we assign the wrong universe to the existential!
532+
self.enter_forall(a, |this, a| {
533+
let b = this.instantiate_binder_with_existentials(b);
534+
this.relate(a, b)
535+
})?;
536+
}
537+
538+
ty::Variance::Bivariant => {}
541539
}
542540

543541
Ok(a)

‎compiler/rustc_hir_analysis/src/check/intrinsic.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ pub fn check_intrinsic_type(
168168
let name_str = intrinsic_name.as_str();
169169

170170
let bound_vars = tcx.mk_bound_variable_kinds(&[
171+
ty::BoundVariableKind::Region(ty::BrAnon),
171172
ty::BoundVariableKind::Region(ty::BrAnon),
172173
ty::BoundVariableKind::Region(ty::BrEnv),
173174
]);
@@ -181,7 +182,7 @@ pub fn check_intrinsic_type(
181182
let env_region = ty::Region::new_bound(
182183
tcx,
183184
ty::INNERMOST,
184-
ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv },
185+
ty::BoundRegion { var: ty::BoundVar::from_u32(2), kind: ty::BrEnv },
185186
);
186187
let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]);
187188
(Ty::new_ref(tcx, env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty)
@@ -493,9 +494,12 @@ pub fn check_intrinsic_type(
493494

494495
sym::raw_eq => {
495496
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
496-
let param_ty =
497+
let param_ty_lhs =
498+
Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));
499+
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon };
500+
let param_ty_rhs =
497501
Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));
498-
(1, 0, vec![param_ty; 2], tcx.types.bool)
502+
(1, 0, vec![param_ty_lhs, param_ty_rhs], tcx.types.bool)
499503
}
500504

501505
sym::black_box => (1, 0, vec![param(0)], param(0)),

‎compiler/rustc_infer/src/infer/relate/equate.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use super::combine::{CombineFields, ObligationEmittingRelation};
22
use super::StructurallyRelateAliases;
3+
use crate::infer::BoundRegionConversionTime::HigherRankedType;
34
use crate::infer::{DefineOpaqueTypes, SubregionOrigin};
45
use crate::traits::PredicateObligations;
56

67
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
78
use rustc_middle::ty::GenericArgsRef;
89
use rustc_middle::ty::TyVar;
9-
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
10+
use rustc_middle::ty::{self, Ty, TyCtxt};
1011

1112
use rustc_hir::def_id::DefId;
1213
use rustc_span::Span;
@@ -167,12 +168,34 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
167168
return Ok(a);
168169
}
169170

170-
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
171-
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
172-
self.fields.higher_ranked_sub(b, a, self.a_is_expected)?;
173-
} else {
171+
if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
174172
// Fast path for the common case.
175-
self.relate(a.skip_binder(), b.skip_binder())?;
173+
self.relate(a, b)?;
174+
} else {
175+
// When equating binders, we check that there is a 1-to-1
176+
// correspondence between the bound vars in both types.
177+
//
178+
// We do so by separately instantiating one of the binders with
179+
// placeholders and the other with inference variables and then
180+
// equating the instantiated types.
181+
//
182+
// We want `for<..> A == for<..> B` -- therefore we want
183+
// `exists<..> A == for<..> B` and `exists<..> B == for<..> A`.
184+
185+
let span = self.fields.trace.cause.span;
186+
let infcx = self.fields.infcx;
187+
188+
// Check if `exists<..> A == for<..> B`
189+
infcx.enter_forall(b, |b| {
190+
let a = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, a);
191+
self.relate(a, b)
192+
})?;
193+
194+
// Check if `exists<..> B == for<..> A`.
195+
infcx.enter_forall(a, |a| {
196+
let b = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, b);
197+
self.relate(a, b)
198+
})?;
176199
}
177200
Ok(a)
178201
}

‎tests/ui/associated-inherent-types/issue-111404-1.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ impl<'a> Foo<fn(&'a ())> {
88
}
99

1010
fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
11-
//~^ ERROR higher-ranked subtype error
11+
//~^ ERROR mismatched types [E0308]
12+
//~| ERROR mismatched types [E0308]
13+
//~| ERROR higher-ranked subtype error
1214
//~| ERROR higher-ranked subtype error
1315

1416
fn main() {}

‎tests/ui/associated-inherent-types/issue-111404-1.stderr

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-111404-1.rs:10:11
3+
|
4+
LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
6+
|
7+
= note: expected struct `Foo<fn(&())>`
8+
found struct `Foo<for<'b> fn(&'b ())>`
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/issue-111404-1.rs:10:11
12+
|
13+
LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
15+
|
16+
= note: expected struct `Foo<fn(&())>`
17+
found struct `Foo<for<'b> fn(&'b ())>`
18+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
19+
120
error: higher-ranked subtype error
221
--> $DIR/issue-111404-1.rs:10:1
322
|
@@ -12,5 +31,6 @@ LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
1231
|
1332
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
1433

15-
error: aborting due to 2 previous errors
34+
error: aborting due to 4 previous errors
1635

36+
For more information about this error, try `rustc --explain E0308`.

‎tests/ui/closure-expected-type/expect-fn-supply-fn.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@ fn expect_free_supply_bound() {
3030
// Here, we are given a function whose region is bound at closure level,
3131
// but we expect one bound in the argument. Error results.
3232
with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
33-
//~^ ERROR mismatched types
33+
//~^ ERROR mismatched types [E0308]
34+
//~| ERROR lifetime may not live long enough
3435
}
3536

3637
fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
3738
// Here, we are given a `fn(&u32)` but we expect a `fn(&'x
3839
// u32)`. In principle, this could be ok, but we demand equality.
3940
with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
40-
//~^ ERROR mismatched types
41+
//~^ ERROR mismatched types [E0308]
42+
//~| ERROR lifetime may not live long enough
4143
}
4244

4345
fn expect_bound_supply_free_from_closure() {

‎tests/ui/closure-expected-type/expect-fn-supply-fn.stderr

+21-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
1919
LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
2020
| ^ requires that `'x` must outlive `'static`
2121

22+
error: lifetime may not live long enough
23+
--> $DIR/expect-fn-supply-fn.rs:32:49
24+
|
25+
LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
26+
| ^
27+
| |
28+
| has type `fn(&'1 u32)`
29+
| requires that `'1` must outlive `'static`
30+
2231
error[E0308]: mismatched types
2332
--> $DIR/expect-fn-supply-fn.rs:32:49
2433
|
@@ -29,23 +38,32 @@ LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
2938
found fn pointer `for<'a> fn(&'a _)`
3039

3140
error[E0308]: mismatched types
32-
--> $DIR/expect-fn-supply-fn.rs:39:50
41+
--> $DIR/expect-fn-supply-fn.rs:40:50
3342
|
3443
LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
3544
| ^ one type is more general than the other
3645
|
3746
= note: expected fn pointer `for<'a> fn(&'a _)`
3847
found fn pointer `fn(&_)`
3948

49+
error: lifetime may not live long enough
50+
--> $DIR/expect-fn-supply-fn.rs:40:50
51+
|
52+
LL | fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
53+
| -- lifetime `'x` defined here
54+
...
55+
LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
56+
| ^ requires that `'x` must outlive `'static`
57+
4058
error[E0308]: mismatched types
41-
--> $DIR/expect-fn-supply-fn.rs:48:50
59+
--> $DIR/expect-fn-supply-fn.rs:50:50
4260
|
4361
LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
4462
| ^ one type is more general than the other
4563
|
4664
= note: expected fn pointer `for<'a> fn(&'a _)`
4765
found fn pointer `fn(&_)`
4866

49-
error: aborting due to 5 previous errors
67+
error: aborting due to 7 previous errors
5068

5169
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
// Test that impls for these two types are considered ovelapping:
1+
//@ check-pass
2+
3+
// These types were previously considered equal as they are subtypes of each other.
4+
// This has been changed in #118247 and we now consider them to be disjoint.
5+
//
6+
// In our test:
27
//
38
// * `for<'r> fn(fn(&'r u32))`
49
// * `fn(fn(&'a u32)` where `'a` is free
510
//
6-
// This is because, for `'a = 'static`, the two types overlap.
7-
// Effectively for them to be equal to you get:
11+
// These were considered equal as for `'a = 'static` subtyping succeeds in both
12+
// directions:
813
//
914
// * `for<'r> fn(fn(&'r u32)) <: fn(fn(&'static u32))`
1015
// * true if `exists<'r> { 'r: 'static }` (obviously true)
@@ -15,12 +20,7 @@ trait Trait {}
1520

1621
impl Trait for for<'r> fn(fn(&'r ())) {}
1722
impl<'a> Trait for fn(fn(&'a ())) {}
18-
//~^ ERROR conflicting implementations
19-
//
20-
// Note in particular that we do NOT get a future-compatibility warning
21-
// here. This is because the new leak-check proposed in [MCP 295] does not
22-
// "error" when these two types are equated.
23-
//
24-
// [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
23+
//~^ WARN conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))` [coherence_leak_check]
24+
//~| WARN the behavior may change in a future release
2525

2626
fn main() {}

‎tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`
2-
--> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
1+
warning: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`
2+
--> $DIR/coherence-fn-covariant-bound-vs-static.rs:22:1
33
|
44
LL | impl Trait for for<'r> fn(fn(&'r ())) {}
55
| ------------------------------------- first implementation here
66
LL | impl<'a> Trait for fn(fn(&'a ())) {}
77
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
88
|
9+
= warning: the behavior may change in a future release
10+
= note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
911
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
12+
= note: `#[warn(coherence_leak_check)]` on by default
1013

11-
error: aborting due to 1 previous error
14+
warning: 1 warning emitted
1215

13-
For more information about this error, try `rustc --explain E0119`.

‎tests/ui/coherence/coherence-fn-inputs.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
// Test that we consider these two types completely equal:
1+
//@ check-pass
2+
3+
// These types were previously considered equal as they are subtypes of each other.
4+
// This has been changed in #118247 and we now consider them to be disjoint.
25
//
36
// * `for<'a, 'b> fn(&'a u32, &'b u32)`
47
// * `for<'c> fn(&'c u32, &'c u32)`
58
//
6-
// For a long time we considered these to be distinct types. But in fact they
7-
// are equivalent, if you work through the implications of subtyping -- this is
8-
// because:
9+
// These types are subtypes of each other as:
910
//
1011
// * `'c` can be the intersection of `'a` and `'b` (and there is always an intersection)
1112
// * `'a` and `'b` can both be equal to `'c`
1213

1314
trait Trait {}
1415
impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
1516
impl Trait for for<'c> fn(&'c u32, &'c u32) {
16-
//~^ ERROR conflicting implementations
17+
//~^ WARN conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)` [coherence_leak_check]
18+
//~| WARN the behavior may change in a future release
1719
//
1820
// Note in particular that we do NOT get a future-compatibility warning
1921
// here. This is because the new leak-check proposed in [MCP 295] does not

‎tests/ui/coherence/coherence-fn-inputs.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`
2-
--> $DIR/coherence-fn-inputs.rs:15:1
1+
warning: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`
2+
--> $DIR/coherence-fn-inputs.rs:16:1
33
|
44
LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
55
| ----------------------------------------------- first implementation here
66
LL | impl Trait for for<'c> fn(&'c u32, &'c u32) {
77
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)`
88
|
9+
= warning: the behavior may change in a future release
10+
= note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
911
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
12+
= note: `#[warn(coherence_leak_check)]` on by default
1013

11-
error: aborting due to 1 previous error
14+
warning: 1 warning emitted
1215

13-
For more information about this error, try `rustc --explain E0119`.

‎tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr

+17-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,21 @@ LL | WHAT_A_TYPE => 0,
77
= note: the traits must be derived, manual `impl`s are not sufficient
88
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
99

10-
error: aborting due to 1 previous error
10+
error[E0277]: the trait bound `for<'a, 'b> fn(&'a (), &'b ()): WithAssoc<T>` is not satisfied
11+
--> $DIR/typeid-equality-by-subtyping.rs:44:51
12+
|
13+
LL | fn unsound<T>(x: <One as WithAssoc<T>>::Assoc) -> <Two as WithAssoc<T>>::Assoc
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WithAssoc<T>` is not implemented for `for<'a, 'b> fn(&'a (), &'b ())`
15+
16+
error[E0277]: the trait bound `for<'a, 'b> fn(&'a (), &'b ()): WithAssoc<T>` is not satisfied
17+
--> $DIR/typeid-equality-by-subtyping.rs:47:1
18+
|
19+
LL | / {
20+
LL | | let x: <Two as WithAssoc<T>>::Assoc = generic::<One, T>(x);
21+
LL | | x
22+
LL | | }
23+
| |_^ the trait `WithAssoc<T>` is not implemented for `for<'a, 'b> fn(&'a (), &'b ())`
24+
25+
error: aborting due to 3 previous errors
1126

27+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// A regression test for #97156
2+
3+
type One = for<'a> fn(&'a (), &'a ());
4+
type Two = for<'a, 'b> fn(&'a (), &'b ());
5+
6+
mod my_api {
7+
use std::any::Any;
8+
use std::marker::PhantomData;
9+
10+
pub struct Foo<T: 'static> {
11+
a: &'static dyn Any,
12+
_p: PhantomData<*mut T>, // invariant, the type of the `dyn Any`
13+
}
14+
15+
impl<T: 'static> Foo<T> {
16+
pub fn deref(&self) -> &'static T {
17+
match self.a.downcast_ref::<T>() {
18+
None => unsafe { std::hint::unreachable_unchecked() },
19+
Some(a) => a,
20+
}
21+
}
22+
23+
pub fn new(a: T) -> Foo<T> {
24+
Foo::<T> { a: Box::leak(Box::new(a)), _p: PhantomData }
25+
}
26+
}
27+
}
28+
29+
use my_api::*;
30+
31+
fn main() {
32+
let foo = Foo::<One>::new((|_, _| ()) as One);
33+
foo.deref();
34+
let foo: Foo<Two> = foo;
35+
//~^ ERROR mismatched types [E0308]
36+
//~| ERROR mismatched types [E0308]
37+
foo.deref();
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/higher-ranked-lifetime-equality.rs:34:25
3+
|
4+
LL | let foo: Foo<Two> = foo;
5+
| ^^^ one type is more general than the other
6+
|
7+
= note: expected struct `my_api::Foo<for<'a, 'b> fn(&'a (), &'b ())>`
8+
found struct `my_api::Foo<for<'a> fn(&'a (), &'a ())>`
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/higher-ranked-lifetime-equality.rs:34:25
12+
|
13+
LL | let foo: Foo<Two> = foo;
14+
| ^^^ one type is more general than the other
15+
|
16+
= note: expected struct `my_api::Foo<for<'a, 'b> fn(&'a (), &'b ())>`
17+
found struct `my_api::Foo<for<'a> fn(&'a (), &'a ())>`
18+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
19+
20+
error: aborting due to 2 previous errors
21+
22+
For more information about this error, try `rustc --explain E0308`.

‎tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
//
33
// In particular, we test this pattern in trait solving, where it is not connected
44
// to any part of the source code.
5-
//
6-
//@ check-pass
75

86
trait Trait<T> {}
97

@@ -21,17 +19,17 @@ fn main() {
2119
// - The impl provides the clause `forall<'a> { (): Trait<fn(fn(&'a u32))> }`
2220
// - We instantiate `'a` existentially to get `(): Trait<fn(fn(&?a u32))>`
2321
// - We unify `fn(fn(&?a u32))` with `for<'b> fn(fn(&'b u32))` -- this does a
24-
// "bidirectional" subtyping check, so we wind up with:
25-
// - `fn(fn(&?a u32)) <: for<'b> fn(fn(&'b u32))` :-
26-
// - `fn(&!b u32) <: fn(&?a u32)`
27-
// - `&?a u32 <: &!b u32`
28-
// - `?a: !'b` -- solveable if `?a` is inferred to `'static`
29-
// - `for<'b> fn(fn(&'b u32)) <: fn(fn(&?a u32))` :-
30-
// - `fn(&?a u32) <: fn(&?b u32)`
31-
// - `&?b u32 <: &?a u32`
32-
// - `?b: ?a` -- solveable if `?b` is inferred to `'static`
33-
// - So the subtyping check succeeds, somewhat surprisingly.
34-
// This is because we can use `'static`.
22+
// "bidirectional" equality check, so we wind up with:
23+
// - `fn(fn(&?a u32)) == for<'b> fn(fn(&'b u32))` :-
24+
// - `fn(&!b u32) == fn(&?a u32)`
25+
// - `&?a u32 == &!b u32`
26+
// - `?a == !b` -- error.
27+
// - `fn(fn(&?a u32)) == for<'b> fn(fn(&'b u32))` :-
28+
// - `fn(&?b u32) == fn(&?a u32)`
29+
// - `&?a u32 == &?b u32`
30+
// - `?a == ?b` -- OK.
31+
// - So the unification fails.
3532

3633
foo::<()>();
34+
//~^ ERROR implementation of `Trait` is not general enough
3735
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: implementation of `Trait` is not general enough
2+
--> $DIR/hrtb-exists-forall-trait-covariant.rs:33:5
3+
|
4+
LL | foo::<()>();
5+
| ^^^^^^^^^^^ implementation of `Trait` is not general enough
6+
|
7+
= note: `()` must implement `Trait<for<'b> fn(fn(&'b u32))>`
8+
= note: ...but it actually implements `Trait<fn(fn(&'0 u32))>`, for some specific lifetime `'0`
9+
10+
error: aborting due to 1 previous error
11+

‎tests/ui/lub-glb/old-lub-glb-hr-eq.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
// error. However, now that we handle subtyping correctly, we no
44
// longer get an error, because we recognize these two types as
55
// equivalent!
6-
//
7-
//@ check-pass
86

97
fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
108
// 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)) {
1311
let z = match 22 {
1412
0 => x,
1513
_ => y,
14+
//~^ ERROR `match` arms have incompatible types [E0308]
1615
};
1716
}
1817

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: `match` arms have incompatible types
2+
--> $DIR/old-lub-glb-hr-eq.rs:13:14
3+
|
4+
LL | let z = match 22 {
5+
| _____________-
6+
LL | | 0 => x,
7+
| | - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8)`
8+
LL | | _ => y,
9+
| | ^ one type is more general than the other
10+
LL | |
11+
LL | | };
12+
| |_____- `match` arms have incompatible types
13+
|
14+
= note: expected fn pointer `for<'a, 'b> fn(&'a _, &'b _)`
15+
found fn pointer `for<'a> fn(&'a _, &'a _)`
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0308`.

‎tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// another -- effectively, the single lifetime `'a` is just inferred
77
// to be the intersection of the two distinct lifetimes.
88
//
9-
//@ check-pass
109
//@ compile-flags:-Zno-leak-check
1110

1211
use std::cell::Cell;
@@ -17,7 +16,9 @@ fn make_cell_aa() -> Cell<for<'a> fn(&'a u32, &'a u32)> {
1716

1817
fn aa_eq_ab() {
1918
let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa();
19+
//~^ ERROR mismatched types [E0308]
20+
//~| ERROR mismatched types [E0308]
2021
drop(a);
2122
}
2223

23-
fn main() { }
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/hr-fn-aau-eq-abu.rs:18:53
3+
|
4+
LL | let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa();
5+
| ^^^^^^^^^^^^^^ one type is more general than the other
6+
|
7+
= note: expected struct `Cell<for<'a, 'b> fn(&'a _, &'b _)>`
8+
found struct `Cell<for<'a> fn(&'a _, &'a _)>`
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/hr-fn-aau-eq-abu.rs:18:53
12+
|
13+
LL | let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa();
14+
| ^^^^^^^^^^^^^^ one type is more general than the other
15+
|
16+
= note: expected struct `Cell<for<'a, 'b> fn(&'a _, &'b _)>`
17+
found struct `Cell<for<'a> fn(&'a _, &'a _)>`
18+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
19+
20+
error: aborting due to 2 previous errors
21+
22+
For more information about this error, try `rustc --explain E0308`.

‎tests/ui/traits/next-solver/member-constraints-in-root-universe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//@ compile-flags: -Znext-solver
2-
//@ check-pass
32

43
trait Trait {
54
type Ty;
@@ -11,6 +10,7 @@ impl Trait for for<'a> fn(&'a u8, &'a u8) {
1110

1211
// argument is necessary to create universes before registering the hidden type.
1312
fn test<'a>(_: <fn(&u8, &u8) as Trait>::Ty) -> impl Sized {
13+
//~^ ERROR the type `<for<'a, 'b> fn(&'a u8, &'b u8) as Trait>::Ty` is not well-formed
1414
"hidden type is `&'?0 str` with '?0 member of ['static,]"
1515
}
1616

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: the type `<for<'a, 'b> fn(&'a u8, &'b u8) as Trait>::Ty` is not well-formed
2+
--> $DIR/member-constraints-in-root-universe.rs:12:16
3+
|
4+
LL | fn test<'a>(_: <fn(&u8, &u8) as Trait>::Ty) -> impl Sized {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+

0 commit comments

Comments
 (0)
Please sign in to comment.