mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Rollup merge of #130866 - compiler-errors:dyn-instantiate-binder, r=lcnr
Allow instantiating object trait binder when upcasting This PR fixes two bugs (that probably need an FCP). ### We use equality rather than subtyping for upcasting dyn conversions This code should be valid: ```rust #![feature(trait_upcasting)] trait Foo: for<'h> Bar<'h> {} trait Bar<'a> {} fn foo(x: &dyn Foo) { let y: &dyn Bar<'static> = x; } ``` But instead: ``` error[E0308]: mismatched types --> src/lib.rs:7:32 | 7 | let y: &dyn Bar<'static> = x; | ^ one type is more general than the other | = note: expected existential trait ref `for<'h> Bar<'h>` found existential trait ref `Bar<'_>` ``` And so should this: ```rust #![feature(trait_upcasting)] fn foo(x: &dyn for<'h> Fn(&'h ())) { let y: &dyn FnOnce(&'static ()) = x; } ``` But instead: ``` error[E0308]: mismatched types --> src/lib.rs:4:39 | 4 | let y: &dyn FnOnce(&'static ()) = x; | ^ one type is more general than the other | = note: expected existential trait ref `for<'h> FnOnce<(&'h (),)>` found existential trait ref `FnOnce<(&(),)>` ``` Specifically, both of these fail because we use *equality* when comparing the supertrait to the *target* of the unsize goal. For the first example, since our supertrait is `for<'h> Bar<'h>` but our target is `Bar<'static>`, there's a higher-ranked type mismatch even though we *should* be able to instantiate that supertrait binder when upcasting. Similarly for the second example. ### New solver uses equality rather than subtyping for no-op (i.e. non-upcasting) dyn conversions This code should be valid in the new solver, like it is with the old solver: ```rust // -Znext-solver fn foo<'a>(x: &mut for<'h> dyn Fn(&'h ())) { let _: &mut dyn Fn(&'a ()) = x; } ``` But instead: ``` error: lifetime may not live long enough --> <source>:2:11 | 1 | fn foo<'a>(x: &mut dyn for<'h> Fn(&'h ())) { | -- lifetime `'a` defined here 2 | let _: &mut dyn Fn(&'a ()) = x; | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` | = note: requirement occurs because of a mutable reference to `dyn Fn(&())` ``` Specifically, this fails because we try to coerce `&mut dyn for<'h> Fn(&'h ())` to `&mut dyn Fn(&'a ())`, which registers an `dyn for<'h> Fn(&'h ()): dyn Fn(&'a ())` goal. This fails because the new solver uses *equating* rather than *subtyping* in `Unsize` goals. This is *mostly* not a problem... You may wonder why the same code passes on the new solver for immutable references: ``` // -Znext-solver fn foo<'a>(x: &dyn Fn(&())) { let _: &dyn Fn(&'a ()) = x; // works } ``` That's because in this case, we first try to coerce via `Unsize`, but due to the leak check the goal fails. Then, later in coercion, we fall back to a simple subtyping operation, which *does* work. Since `&T` is covariant over `T`, but `&mut T` is invariant, that's where the discrepancy between these two examples crops up. --- r? lcnr or reassign :D
This commit is contained in:
commit
4e510daed7
@ -92,12 +92,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
|
pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx>;
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> At<'a, 'tcx> {
|
impl<'a, 'tcx> At<'a, 'tcx> {
|
||||||
@ -116,7 +111,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
let mut fields = CombineFields::new(
|
let mut fields = CombineFields::new(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
ToTrace::to_trace(self.cause, expected, actual),
|
||||||
self.param_env,
|
self.param_env,
|
||||||
define_opaque_types,
|
define_opaque_types,
|
||||||
);
|
);
|
||||||
@ -136,7 +131,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
let mut fields = CombineFields::new(
|
let mut fields = CombineFields::new(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
ToTrace::to_trace(self.cause, expected, actual),
|
||||||
self.param_env,
|
self.param_env,
|
||||||
define_opaque_types,
|
define_opaque_types,
|
||||||
);
|
);
|
||||||
@ -154,12 +149,26 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
let mut fields = CombineFields::new(
|
self.eq_trace(
|
||||||
self.infcx,
|
|
||||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
|
||||||
self.param_env,
|
|
||||||
define_opaque_types,
|
define_opaque_types,
|
||||||
);
|
ToTrace::to_trace(self.cause, expected, actual),
|
||||||
|
expected,
|
||||||
|
actual,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes `expected == actual`.
|
||||||
|
pub fn eq_trace<T>(
|
||||||
|
self,
|
||||||
|
define_opaque_types: DefineOpaqueTypes,
|
||||||
|
trace: TypeTrace<'tcx>,
|
||||||
|
expected: T,
|
||||||
|
actual: T,
|
||||||
|
) -> InferResult<'tcx, ()>
|
||||||
|
where
|
||||||
|
T: Relate<TyCtxt<'tcx>>,
|
||||||
|
{
|
||||||
|
let mut fields = CombineFields::new(self.infcx, trace, self.param_env, define_opaque_types);
|
||||||
fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?;
|
fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?;
|
||||||
Ok(InferOk {
|
Ok(InferOk {
|
||||||
value: (),
|
value: (),
|
||||||
@ -192,7 +201,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
assert!(self.infcx.next_trait_solver());
|
assert!(self.infcx.next_trait_solver());
|
||||||
let mut fields = CombineFields::new(
|
let mut fields = CombineFields::new(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
ToTrace::to_trace(self.cause, expected, actual),
|
||||||
self.param_env,
|
self.param_env,
|
||||||
DefineOpaqueTypes::Yes,
|
DefineOpaqueTypes::Yes,
|
||||||
);
|
);
|
||||||
@ -284,7 +293,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
let mut fields = CombineFields::new(
|
let mut fields = CombineFields::new(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
ToTrace::to_trace(self.cause, expected, actual),
|
||||||
self.param_env,
|
self.param_env,
|
||||||
define_opaque_types,
|
define_opaque_types,
|
||||||
);
|
);
|
||||||
@ -306,7 +315,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
let mut fields = CombineFields::new(
|
let mut fields = CombineFields::new(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
ToTrace::to_trace(self.cause, true, expected, actual),
|
ToTrace::to_trace(self.cause, expected, actual),
|
||||||
self.param_env,
|
self.param_env,
|
||||||
define_opaque_types,
|
define_opaque_types,
|
||||||
);
|
);
|
||||||
@ -316,18 +325,13 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
|
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
|
||||||
ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b)
|
ToTrace::to_trace(cause, trait_ref_a, trait_ref_b)
|
||||||
}
|
}
|
||||||
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
|
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
|
||||||
ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b)
|
ToTrace::to_trace(cause, ty_a, ty_b)
|
||||||
}
|
}
|
||||||
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
|
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
|
||||||
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
|
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
|
||||||
@ -338,65 +342,45 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)),
|
values: ValuePairs::Regions(ExpectedFound::new(true, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: match (a.unpack(), b.unpack()) {
|
values: match (a.unpack(), b.unpack()) {
|
||||||
(GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
|
(GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
|
||||||
ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b))
|
ValuePairs::Regions(ExpectedFound::new(true, a, b))
|
||||||
}
|
}
|
||||||
(GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
|
(GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
|
||||||
ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
|
ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
|
||||||
}
|
}
|
||||||
(GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
|
(GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
|
||||||
ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
|
ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -419,72 +403,47 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)),
|
values: ValuePairs::Terms(ExpectedFound::new(true, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
|
values: ValuePairs::TraitRefs(ExpectedFound::new(true, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
values: ValuePairs::Aliases(ExpectedFound::new(true, a.into(), b.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)),
|
values: ValuePairs::Aliases(ExpectedFound::new(true, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::PolySigs(ExpectedFound::new(
|
values: ValuePairs::PolySigs(ExpectedFound::new(
|
||||||
a_is_expected,
|
true,
|
||||||
ty::Binder::dummy(a),
|
ty::Binder::dummy(a),
|
||||||
ty::Binder::dummy(b),
|
ty::Binder::dummy(b),
|
||||||
)),
|
)),
|
||||||
@ -493,43 +452,28 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)),
|
values: ValuePairs::PolySigs(ExpectedFound::new(true, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)),
|
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(true, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
a_is_expected: bool,
|
|
||||||
a: Self,
|
|
||||||
b: Self,
|
|
||||||
) -> TypeTrace<'tcx> {
|
|
||||||
TypeTrace {
|
TypeTrace {
|
||||||
cause: cause.clone(),
|
cause: cause.clone(),
|
||||||
values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)),
|
values: ValuePairs::ExistentialProjection(ExpectedFound::new(true, a, b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,10 +448,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.delegate.enter_forall(kind, |kind| {
|
self.enter_forall(kind, |ecx, kind| {
|
||||||
let goal = goal.with(self.cx(), ty::Binder::dummy(kind));
|
let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
|
||||||
self.add_goal(GoalSource::InstantiateHigherRanked, goal);
|
ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -840,12 +840,14 @@ where
|
|||||||
self.delegate.instantiate_binder_with_infer(value)
|
self.delegate.instantiate_binder_with_infer(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `enter_forall`, but takes `&mut self` and passes it back through the
|
||||||
|
/// callback since it can't be aliased during the call.
|
||||||
pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
|
pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
|
||||||
&self,
|
&mut self,
|
||||||
value: ty::Binder<I, T>,
|
value: ty::Binder<I, T>,
|
||||||
f: impl FnOnce(T) -> U,
|
f: impl FnOnce(&mut Self, T) -> U,
|
||||||
) -> U {
|
) -> U {
|
||||||
self.delegate.enter_forall(value, f)
|
self.delegate.enter_forall(value, |value| f(self, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||||
|
@ -895,10 +895,13 @@ where
|
|||||||
source_projection.item_def_id() == target_projection.item_def_id()
|
source_projection.item_def_id() == target_projection.item_def_id()
|
||||||
&& ecx
|
&& ecx
|
||||||
.probe(|_| ProbeKind::UpcastProjectionCompatibility)
|
.probe(|_| ProbeKind::UpcastProjectionCompatibility)
|
||||||
.enter(|ecx| -> Result<(), NoSolution> {
|
.enter(|ecx| -> Result<_, NoSolution> {
|
||||||
|
ecx.enter_forall(target_projection, |ecx, target_projection| {
|
||||||
|
let source_projection =
|
||||||
|
ecx.instantiate_binder_with_infer(source_projection);
|
||||||
ecx.eq(param_env, source_projection, target_projection)?;
|
ecx.eq(param_env, source_projection, target_projection)?;
|
||||||
let _ = ecx.try_evaluate_added_goals()?;
|
ecx.try_evaluate_added_goals()
|
||||||
Ok(())
|
})
|
||||||
})
|
})
|
||||||
.is_ok()
|
.is_ok()
|
||||||
};
|
};
|
||||||
@ -909,11 +912,14 @@ where
|
|||||||
// Check that a's supertrait (upcast_principal) is compatible
|
// Check that a's supertrait (upcast_principal) is compatible
|
||||||
// with the target (b_ty).
|
// with the target (b_ty).
|
||||||
ty::ExistentialPredicate::Trait(target_principal) => {
|
ty::ExistentialPredicate::Trait(target_principal) => {
|
||||||
ecx.eq(
|
let source_principal = upcast_principal.unwrap();
|
||||||
param_env,
|
let target_principal = bound.rebind(target_principal);
|
||||||
upcast_principal.unwrap(),
|
ecx.enter_forall(target_principal, |ecx, target_principal| {
|
||||||
bound.rebind(target_principal),
|
let source_principal =
|
||||||
)?;
|
ecx.instantiate_binder_with_infer(source_principal);
|
||||||
|
ecx.eq(param_env, source_principal, target_principal)?;
|
||||||
|
ecx.try_evaluate_added_goals()
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
// Check that b_ty's projection is satisfied by exactly one of
|
// Check that b_ty's projection is satisfied by exactly one of
|
||||||
// a_ty's projections. First, we look through the list to see if
|
// a_ty's projections. First, we look through the list to see if
|
||||||
@ -934,7 +940,12 @@ where
|
|||||||
Certainty::AMBIGUOUS,
|
Certainty::AMBIGUOUS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
ecx.enter_forall(target_projection, |ecx, target_projection| {
|
||||||
|
let source_projection =
|
||||||
|
ecx.instantiate_binder_with_infer(source_projection);
|
||||||
ecx.eq(param_env, source_projection, target_projection)?;
|
ecx.eq(param_env, source_projection, target_projection)?;
|
||||||
|
ecx.try_evaluate_added_goals()
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
// Check that b_ty's auto traits are present in a_ty's bounds.
|
// Check that b_ty's auto traits are present in a_ty's bounds.
|
||||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||||
@ -1187,17 +1198,15 @@ where
|
|||||||
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>,
|
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>,
|
||||||
) -> Result<Candidate<I>, NoSolution> {
|
) -> Result<Candidate<I>, NoSolution> {
|
||||||
self.probe_trait_candidate(source).enter(|ecx| {
|
self.probe_trait_candidate(source).enter(|ecx| {
|
||||||
ecx.add_goals(
|
let goals = constituent_tys(ecx, goal.predicate.self_ty())?
|
||||||
GoalSource::ImplWhereBound,
|
|
||||||
constituent_tys(ecx, goal.predicate.self_ty())?
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ty| {
|
.map(|ty| {
|
||||||
ecx.enter_forall(ty, |ty| {
|
ecx.enter_forall(ty, |ecx, ty| {
|
||||||
goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))
|
goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>();
|
||||||
);
|
ecx.add_goals(GoalSource::ImplWhereBound, goals);
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use rustc_hir::LangItem;
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
|
use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
|
||||||
use rustc_infer::infer::DefineOpaqueTypes;
|
use rustc_infer::infer::DefineOpaqueTypes;
|
||||||
|
use rustc_infer::infer::at::ToTrace;
|
||||||
use rustc_infer::infer::relate::TypeRelation;
|
use rustc_infer::infer::relate::TypeRelation;
|
||||||
use rustc_infer::traits::TraitObligation;
|
use rustc_infer::traits::TraitObligation;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
@ -44,7 +45,7 @@ use super::{
|
|||||||
TraitQueryMode, const_evaluatable, project, util, wf,
|
TraitQueryMode, const_evaluatable, project, util, wf,
|
||||||
};
|
};
|
||||||
use crate::error_reporting::InferCtxtErrorExt;
|
use crate::error_reporting::InferCtxtErrorExt;
|
||||||
use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
|
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
||||||
use crate::solve::InferCtxtSelectExt as _;
|
use crate::solve::InferCtxtSelectExt as _;
|
||||||
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
|
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
|
||||||
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
|
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
|
||||||
@ -2579,16 +2580,31 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
// Check that a_ty's supertrait (upcast_principal) is compatible
|
// Check that a_ty's supertrait (upcast_principal) is compatible
|
||||||
// with the target (b_ty).
|
// with the target (b_ty).
|
||||||
ty::ExistentialPredicate::Trait(target_principal) => {
|
ty::ExistentialPredicate::Trait(target_principal) => {
|
||||||
|
let hr_source_principal = upcast_principal.map_bound(|trait_ref| {
|
||||||
|
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||||
|
});
|
||||||
|
let hr_target_principal = bound.rebind(target_principal);
|
||||||
|
|
||||||
nested.extend(
|
nested.extend(
|
||||||
self.infcx
|
self.infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.enter_forall(hr_target_principal, |target_principal| {
|
||||||
.eq(
|
let source_principal =
|
||||||
|
self.infcx.instantiate_binder_with_fresh_vars(
|
||||||
|
obligation.cause.span,
|
||||||
|
HigherRankedType,
|
||||||
|
hr_source_principal,
|
||||||
|
);
|
||||||
|
self.infcx.at(&obligation.cause, obligation.param_env).eq_trace(
|
||||||
DefineOpaqueTypes::Yes,
|
DefineOpaqueTypes::Yes,
|
||||||
upcast_principal.map_bound(|trait_ref| {
|
ToTrace::to_trace(
|
||||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
&obligation.cause,
|
||||||
}),
|
hr_target_principal,
|
||||||
bound.rebind(target_principal),
|
hr_source_principal,
|
||||||
|
),
|
||||||
|
target_principal,
|
||||||
|
source_principal,
|
||||||
)
|
)
|
||||||
|
})
|
||||||
.map_err(|_| SelectionError::Unimplemented)?
|
.map_err(|_| SelectionError::Unimplemented)?
|
||||||
.into_obligations(),
|
.into_obligations(),
|
||||||
);
|
);
|
||||||
@ -2599,19 +2615,40 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
// return ambiguity. Otherwise, if exactly one matches, equate
|
// return ambiguity. Otherwise, if exactly one matches, equate
|
||||||
// it with b_ty's projection.
|
// it with b_ty's projection.
|
||||||
ty::ExistentialPredicate::Projection(target_projection) => {
|
ty::ExistentialPredicate::Projection(target_projection) => {
|
||||||
let target_projection = bound.rebind(target_projection);
|
let hr_target_projection = bound.rebind(target_projection);
|
||||||
|
|
||||||
let mut matching_projections =
|
let mut matching_projections =
|
||||||
a_data.projection_bounds().filter(|source_projection| {
|
a_data.projection_bounds().filter(|&hr_source_projection| {
|
||||||
// Eager normalization means that we can just use can_eq
|
// Eager normalization means that we can just use can_eq
|
||||||
// here instead of equating and processing obligations.
|
// here instead of equating and processing obligations.
|
||||||
source_projection.item_def_id() == target_projection.item_def_id()
|
hr_source_projection.item_def_id() == hr_target_projection.item_def_id()
|
||||||
&& self.infcx.can_eq(
|
&& self.infcx.probe(|_| {
|
||||||
obligation.param_env,
|
self.infcx
|
||||||
*source_projection,
|
.enter_forall(hr_target_projection, |target_projection| {
|
||||||
|
let source_projection =
|
||||||
|
self.infcx.instantiate_binder_with_fresh_vars(
|
||||||
|
obligation.cause.span,
|
||||||
|
HigherRankedType,
|
||||||
|
hr_source_projection,
|
||||||
|
);
|
||||||
|
self.infcx
|
||||||
|
.at(&obligation.cause, obligation.param_env)
|
||||||
|
.eq_trace(
|
||||||
|
DefineOpaqueTypes::Yes,
|
||||||
|
ToTrace::to_trace(
|
||||||
|
&obligation.cause,
|
||||||
|
hr_target_projection,
|
||||||
|
hr_source_projection,
|
||||||
|
),
|
||||||
target_projection,
|
target_projection,
|
||||||
|
source_projection,
|
||||||
)
|
)
|
||||||
|
})
|
||||||
|
.is_ok()
|
||||||
|
})
|
||||||
});
|
});
|
||||||
let Some(source_projection) = matching_projections.next() else {
|
|
||||||
|
let Some(hr_source_projection) = matching_projections.next() else {
|
||||||
return Err(SelectionError::Unimplemented);
|
return Err(SelectionError::Unimplemented);
|
||||||
};
|
};
|
||||||
if matching_projections.next().is_some() {
|
if matching_projections.next().is_some() {
|
||||||
@ -2619,8 +2656,24 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
nested.extend(
|
nested.extend(
|
||||||
self.infcx
|
self.infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.enter_forall(hr_target_projection, |target_projection| {
|
||||||
.eq(DefineOpaqueTypes::Yes, source_projection, target_projection)
|
let source_projection =
|
||||||
|
self.infcx.instantiate_binder_with_fresh_vars(
|
||||||
|
obligation.cause.span,
|
||||||
|
HigherRankedType,
|
||||||
|
hr_source_projection,
|
||||||
|
);
|
||||||
|
self.infcx.at(&obligation.cause, obligation.param_env).eq_trace(
|
||||||
|
DefineOpaqueTypes::Yes,
|
||||||
|
ToTrace::to_trace(
|
||||||
|
&obligation.cause,
|
||||||
|
hr_target_projection,
|
||||||
|
hr_source_projection,
|
||||||
|
),
|
||||||
|
target_projection,
|
||||||
|
source_projection,
|
||||||
|
)
|
||||||
|
})
|
||||||
.map_err(|_| SelectionError::Unimplemented)?
|
.map_err(|_| SelectionError::Unimplemented)?
|
||||||
.into_obligations(),
|
.into_obligations(),
|
||||||
);
|
);
|
||||||
|
27
tests/ui/coercion/sub-principals.rs
Normal file
27
tests/ui/coercion/sub-principals.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//@ check-pass
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// Verify that the unsize goal can cast a higher-ranked trait goal to
|
||||||
|
// a non-higer-ranked instantiation.
|
||||||
|
|
||||||
|
#![feature(unsize)]
|
||||||
|
|
||||||
|
use std::marker::Unsize;
|
||||||
|
|
||||||
|
fn test<T: ?Sized, U: ?Sized>()
|
||||||
|
where
|
||||||
|
T: Unsize<U>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
test::<dyn for<'a> Fn(&'a ()) -> &'a (), dyn Fn(&'static ()) -> &'static ()>();
|
||||||
|
|
||||||
|
trait Foo<'a, 'b> {}
|
||||||
|
test::<dyn for<'a, 'b> Foo<'a, 'b>, dyn for<'a> Foo<'a, 'a>>();
|
||||||
|
|
||||||
|
trait Bar<'a> {}
|
||||||
|
test::<dyn for<'a> Bar<'a>, dyn Bar<'_>>();
|
||||||
|
}
|
@ -1,22 +0,0 @@
|
|||||||
error[E0308]: mismatched types
|
|
||||||
--> $DIR/higher-ranked-upcasting-ok.rs:17:5
|
|
||||||
|
|
|
||||||
LL | x
|
|
||||||
| ^ one type is more general than the other
|
|
||||||
|
|
|
||||||
= note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
|
|
||||||
found existential trait ref `for<'a> Supertrait<'a, 'a>`
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
|
||||||
--> $DIR/higher-ranked-upcasting-ok.rs:17:5
|
|
||||||
|
|
|
||||||
LL | x
|
|
||||||
| ^ one type is more general than the other
|
|
||||||
|
|
|
||||||
= note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
|
|
||||||
found existential trait ref `for<'a> Supertrait<'a, 'a>`
|
|
||||||
= 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`.
|
|
@ -1,14 +0,0 @@
|
|||||||
error[E0308]: mismatched types
|
|
||||||
--> $DIR/higher-ranked-upcasting-ok.rs:17:5
|
|
||||||
|
|
|
||||||
LL | fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
|
|
||||||
| ------------------------------- expected `&dyn for<'a> Supertrait<'a, 'a>` because of return type
|
|
||||||
LL | x
|
|
||||||
| ^ expected trait `Supertrait`, found trait `Subtrait`
|
|
||||||
|
|
|
||||||
= note: expected reference `&dyn for<'a> Supertrait<'a, 'a>`
|
|
||||||
found reference `&dyn for<'a, 'b> Subtrait<'a, 'b>`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -1,19 +1,21 @@
|
|||||||
//@ revisions: current next
|
//@ revisions: current next
|
||||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
//@[next] compile-flags: -Znext-solver
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
// We should be able to instantiate a binder during trait upcasting.
|
// We should be able to instantiate a binder during trait upcasting.
|
||||||
// This test could be `check-pass`, but we should make sure that we
|
// This test could be `check-pass`, but we should make sure that we
|
||||||
// do so in both trait solvers.
|
// do so in both trait solvers.
|
||||||
#![feature(trait_upcasting)]
|
|
||||||
#![crate_type = "rlib"]
|
|
||||||
trait Supertrait<'a, 'b> {}
|
|
||||||
|
|
||||||
|
#![feature(trait_upcasting)]
|
||||||
|
|
||||||
|
trait Supertrait<'a, 'b> {}
|
||||||
trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
|
trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
|
||||||
|
|
||||||
impl<'a> Supertrait<'a, 'a> for () {}
|
impl<'a> Supertrait<'a, 'a> for () {}
|
||||||
impl<'a> Subtrait<'a, 'a> for () {}
|
impl<'a> Subtrait<'a, 'a> for () {}
|
||||||
fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
|
fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
|
||||||
x //~ ERROR mismatched types
|
x
|
||||||
//[current]~^ ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
@ -4,8 +4,8 @@ error[E0308]: mismatched types
|
|||||||
LL | x
|
LL | x
|
||||||
| ^ one type is more general than the other
|
| ^ one type is more general than the other
|
||||||
|
|
|
|
||||||
= note: expected existential trait ref `for<'a> Supertrait<'a, 'a>`
|
= note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
|
||||||
found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
|
found existential trait ref `for<'a> Supertrait<'a, 'a>`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/higher-ranked-upcasting-ub.rs:22:5
|
--> $DIR/higher-ranked-upcasting-ub.rs:22:5
|
||||||
@ -13,8 +13,8 @@ error[E0308]: mismatched types
|
|||||||
LL | x
|
LL | x
|
||||||
| ^ one type is more general than the other
|
| ^ one type is more general than the other
|
||||||
|
|
|
|
||||||
= note: expected existential trait ref `for<'a> Supertrait<'a, 'a>`
|
= note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
|
||||||
found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
|
found existential trait ref `for<'a> Supertrait<'a, 'a>`
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
26
tests/ui/traits/trait-upcasting/sub.rs
Normal file
26
tests/ui/traits/trait-upcasting/sub.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//@ check-pass
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// Verify that the unsize goal can cast a higher-ranked trait goal to
|
||||||
|
// a non-higer-ranked instantiation.
|
||||||
|
|
||||||
|
#![feature(unsize)]
|
||||||
|
|
||||||
|
use std::marker::Unsize;
|
||||||
|
|
||||||
|
fn test<T: ?Sized, U: ?Sized>()
|
||||||
|
where
|
||||||
|
T: Unsize<U>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
test::<dyn for<'a> Fn(&'a ()) -> &'a (), dyn FnOnce(&'static ()) -> &'static ()>();
|
||||||
|
|
||||||
|
trait Foo: for<'a> Bar<'a> {}
|
||||||
|
trait Bar<'a> {}
|
||||||
|
test::<dyn Foo, dyn Bar<'static>>();
|
||||||
|
test::<dyn Foo, dyn Bar<'_>>();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user