Skip to content

Commit

Permalink
Rollup merge of #111860 - compiler-errors:issue-111838, r=WaffleLapkin
Browse files Browse the repository at this point in the history
Don't ICE if method receiver fails to unify with `arbitrary_self_types`

Consider:

```rust
struct Foo(u32);
impl Foo {
    fn get<R: Deref<Target=Self>>(self: R) -> u32 {
        self.0
    }
}

fn main() {
    let mut foo = Foo(1);
    foo.get::<&Foo>();
}
```

The problem here is that with `arbitrary_self_types`, we're allowed to have a method receiver that mentions generics from the method itself (`fn get<R: Deref<Target=Self>>(self: R)`). Since we don't actually take into account the user-written turbofish generics when doing method lookup (nor do we check that method predicates hold), method probing will happily infer `R = Foo` during the probe. When we later confirm the method, we do use the turbofish'd subst and instead now have that `R = &Foo`. This doesn't unify with the self type we chose during the probe, causing an ICE.

Getting this to work correctly will be difficult. Specifically, we'll need to actually pass in the turbofish generics for the method being probed for and check that the self type unifies considering those generics. This seems like a lot of work, and I'm not actually familiar with the restrictions originally called out for `#![feature(arbitrary_self_types)]`, but I think we should probably instead just deny having receivers that mention (type/const) generics that come from the method itself.

But I mostly just want to turn this ICE into an error, so I'll leave that up for later PRs.

Fixes #111838
  • Loading branch information
Dylan-DPC authored May 23, 2023
2 parents 32c73c2 + 05c5caa commit c4f2a62
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 8 deletions.
25 changes: 17 additions & 8 deletions compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self_ty, method_self_ty, self.span, pick
);
let cause = self.cause(
self.span,
self.self_expr.span,
ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
assoc_item: pick.item,
param_env: self.param_env,
Expand All @@ -482,13 +482,22 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
Err(_) => {
span_bug!(
self.span,
"{} was a subtype of {} but now is not?",
self_ty,
method_self_ty
);
Err(terr) => {
// FIXME(arbitrary_self_types): We probably should limit the
// situations where this can occur by adding additional restrictions
// to the feature, like the self type can't reference method substs.
if self.tcx.features().arbitrary_self_types {
self.err_ctxt()
.report_mismatched_types(&cause, method_self_ty, self_ty, terr)
.emit();
} else {
span_bug!(
self.span,
"{} was a subtype of {} but now is not?",
self_ty,
method_self_ty
);
}
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/self/arbitrary-self-from-method-substs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![feature(arbitrary_self_types)]

use std::ops::Deref;

struct Foo(u32);
impl Foo {
fn get<R: Deref<Target=Self>>(self: R) -> u32 {
self.0
}
}

fn main() {
let mut foo = Foo(1);
foo.get::<&Foo>();
//~^ ERROR mismatched types
}
9 changes: 9 additions & 0 deletions tests/ui/self/arbitrary-self-from-method-substs.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0308]: mismatched types
--> $DIR/arbitrary-self-from-method-substs.rs:14:5
|
LL | foo.get::<&Foo>();
| ^^^ expected `&Foo`, found `Foo`

error: aborting due to previous error

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

0 comments on commit c4f2a62

Please sign in to comment.