Rollup merge of #105846 - compiler-errors:issue-105838, r=jackh726

Account for return-position `impl Trait` in trait in `opt_suggest_box_span`

RPITITs are the only types where their opaque bounds might normalize to some other self type than the opaque type itself. To avoid needing to do normalization, let's just match on either alias kind.

Ideally, we'd just get rid of `opt_suggest_box_span`. It's kind of a wart on type-checking `if`/`match`. I've recently refactored this expression for being confusing/wrong, but moving it into the error path is pretty hard.

Fixes #105838
This commit is contained in:
Michael Goulet 2023-01-04 20:36:27 -08:00 committed by GitHub
commit f9ccbf084f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 3 deletions

View File

@ -526,7 +526,6 @@ pub(crate) fn opt_suggest_box_span(
None
}
})?;
let opaque_ty = self.tcx.mk_opaque(rpit_def_id, substs);
if !self.can_coerce(first_ty, expected) || !self.can_coerce(second_ty, expected) {
return None;
@ -540,13 +539,22 @@ pub(crate) fn opt_suggest_box_span(
{
let pred = pred.kind().rebind(match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
// FIXME(rpitit): This will need to be fixed when we move to associated types
assert!(matches!(
*trait_pred.trait_ref.self_ty().kind(),
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
if def_id == rpit_def_id && substs == substs
));
ty::PredicateKind::Clause(ty::Clause::Trait(
trait_pred.with_self_ty(self.tcx, ty),
))
}
ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
assert!(matches!(
*proj_pred.projection_ty.self_ty().kind(),
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
if def_id == rpit_def_id && substs == substs
));
proj_pred = proj_pred.with_self_ty(self.tcx, ty);
ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
}

View File

@ -0,0 +1,49 @@
// check-pass
#![feature(return_position_impl_trait_in_trait)]
//~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete
struct TestA {}
struct TestB {}
impl TestTrait for TestA {
type Output = ();
}
impl TestTrait for TestB {
type Output = ();
}
trait TestTrait {
type Output;
}
impl<A, B> TestTrait for GreeterOutput<A, B>
where
A: TestTrait<Output = ()>,
B: TestTrait<Output = ()>,
{
type Output = ();
}
enum GreeterOutput<A, B>
where
A: TestTrait<Output = ()>,
B: TestTrait<Output = ()>,
{
SayHello(A),
SayGoodbye(B),
}
trait Greeter {
fn test_func(&self, func: &str) -> impl TestTrait<Output = ()> {
match func {
"SayHello" => GreeterOutput::SayHello(TestA {}),
"SayGoodbye" => GreeterOutput::SayGoodbye(TestB {}),
_ => GreeterOutput::SayHello(TestA {}),
}
}
}
fn main() {
println!("Hello, world!");
}

View File

@ -0,0 +1,11 @@
warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/box-coerce-span-in-default.rs:3:12
|
LL | #![feature(return_position_impl_trait_in_trait)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted