mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
Rollup merge of #114200 - compiler-errors:detect-tail-unsize-then-upcast, r=lcnr
Detect trait upcasting through struct tail unsizing in new solver select Oops, we were able to hide trait upcasting behind a parent unsize goal that evaluated to `Certainty::Yes`. Let's do rematching for `Certainty::Yes` unsize goals with `BuiltinImplSource::Misc` sources (corresponding to all of the other unsize rules) to make sure we end up selecting any nested goals which may be satisfied via `BuiltinImplSource::TraitUpcasting` or `::TupleUnsizing`. r? ``@lcnr``
This commit is contained in:
commit
c73e232d20
@ -100,10 +100,18 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
|
|||||||
rematch_impl(self, goal, def_id, nested_obligations)
|
rematch_impl(self, goal, def_id, nested_obligations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If an unsize goal is ambiguous, then we can manually rematch it to make
|
||||||
|
// selection progress for coercion during HIR typeck. If it is *not* ambiguous,
|
||||||
|
// but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals,
|
||||||
|
// and we need to rematch those to detect tuple unsizing and trait upcasting.
|
||||||
|
// FIXME: This will be wrong if we have param-env or where-clause bounds
|
||||||
|
// with the unsize goal -- we may need to mark those with different impl
|
||||||
|
// sources.
|
||||||
(Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
|
(Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
|
||||||
|
| (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc))
|
||||||
if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
|
if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
|
||||||
{
|
{
|
||||||
rematch_unsize(self, goal, nested_obligations, src)
|
rematch_unsize(self, goal, nested_obligations, src, certainty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Technically some builtin impls have nested obligations, but if
|
// Technically some builtin impls have nested obligations, but if
|
||||||
@ -217,6 +225,7 @@ fn rematch_unsize<'tcx>(
|
|||||||
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
||||||
mut nested: Vec<PredicateObligation<'tcx>>,
|
mut nested: Vec<PredicateObligation<'tcx>>,
|
||||||
source: BuiltinImplSource,
|
source: BuiltinImplSource,
|
||||||
|
certainty: Certainty,
|
||||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
|
let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
|
||||||
@ -227,6 +236,12 @@ fn rematch_unsize<'tcx>(
|
|||||||
&mut nested,
|
&mut nested,
|
||||||
);
|
);
|
||||||
match (a_ty.kind(), b_ty.kind()) {
|
match (a_ty.kind(), b_ty.kind()) {
|
||||||
|
// Stall any ambiguous upcasting goals, since we can't rematch those
|
||||||
|
(ty::Dynamic(_, _, ty::Dyn), ty::Dynamic(_, _, ty::Dyn)) => match certainty {
|
||||||
|
Certainty::Yes => Ok(Some(ImplSource::Builtin(source, nested))),
|
||||||
|
_ => Ok(None),
|
||||||
|
},
|
||||||
|
// `T` -> `dyn Trait` upcasting
|
||||||
(_, &ty::Dynamic(data, region, ty::Dyn)) => {
|
(_, &ty::Dynamic(data, region, ty::Dyn)) => {
|
||||||
// Check that the type implements all of the predicates of the def-id.
|
// Check that the type implements all of the predicates of the def-id.
|
||||||
// (i.e. the principal, all of the associated types match, and any auto traits)
|
// (i.e. the principal, all of the associated types match, and any auto traits)
|
||||||
@ -354,10 +369,10 @@ fn rematch_unsize<'tcx>(
|
|||||||
);
|
);
|
||||||
Ok(Some(ImplSource::Builtin(source, nested)))
|
Ok(Some(ImplSource::Builtin(source, nested)))
|
||||||
}
|
}
|
||||||
// FIXME: We *could* ICE here if either:
|
_ => {
|
||||||
// 1. the certainty is `Certainty::Yes`,
|
assert_ne!(certainty, Certainty::Yes);
|
||||||
// 2. we're in codegen (which should mean `Certainty::Yes`).
|
Ok(None)
|
||||||
_ => Ok(None),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
|
||||||
|
--> $DIR/upcast-through-struct-tail.rs:10:5
|
||||||
|
|
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
|
||||||
|
= help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
|
||||||
|
= note: required when coercing `Box<Wrapper<(dyn A + 'a)>>` into `Box<Wrapper<(dyn B + 'a)>>`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,13 @@
|
|||||||
|
error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
|
||||||
|
--> $DIR/upcast-through-struct-tail.rs:10:5
|
||||||
|
|
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
|
||||||
|
= help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
|
||||||
|
= note: required when coercing `Box<Wrapper<(dyn A + 'a)>>` into `Box<Wrapper<(dyn B + 'a)>>`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,14 @@
|
|||||||
|
// revisions: current next
|
||||||
|
//[next] compile-flags: -Ztrait-solver=next
|
||||||
|
|
||||||
|
struct Wrapper<T: ?Sized>(T);
|
||||||
|
|
||||||
|
trait A: B {}
|
||||||
|
trait B {}
|
||||||
|
|
||||||
|
fn test<'a>(x: Box<Wrapper<dyn A + 'a>>) -> Box<Wrapper<dyn B + 'a>> {
|
||||||
|
x
|
||||||
|
//~^ ERROR cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user