Skip to content

Commit c4f2a62

Browse files
authored
Rollup merge of rust-lang#111860 - compiler-errors:issue-111838, r=WaffleLapkin
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 rust-lang#111838
2 parents 32c73c2 + 05c5caa commit c4f2a62

File tree

3 files changed

+42
-8
lines changed

3 files changed

+42
-8
lines changed

compiler/rustc_hir_typeck/src/method/confirm.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
471471
self_ty, method_self_ty, self.span, pick
472472
);
473473
let cause = self.cause(
474-
self.span,
474+
self.self_expr.span,
475475
ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
476476
assoc_item: pick.item,
477477
param_env: self.param_env,
@@ -482,13 +482,22 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
482482
Ok(InferOk { obligations, value: () }) => {
483483
self.register_predicates(obligations);
484484
}
485-
Err(_) => {
486-
span_bug!(
487-
self.span,
488-
"{} was a subtype of {} but now is not?",
489-
self_ty,
490-
method_self_ty
491-
);
485+
Err(terr) => {
486+
// FIXME(arbitrary_self_types): We probably should limit the
487+
// situations where this can occur by adding additional restrictions
488+
// to the feature, like the self type can't reference method substs.
489+
if self.tcx.features().arbitrary_self_types {
490+
self.err_ctxt()
491+
.report_mismatched_types(&cause, method_self_ty, self_ty, terr)
492+
.emit();
493+
} else {
494+
span_bug!(
495+
self.span,
496+
"{} was a subtype of {} but now is not?",
497+
self_ty,
498+
method_self_ty
499+
);
500+
}
492501
}
493502
}
494503
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(arbitrary_self_types)]
2+
3+
use std::ops::Deref;
4+
5+
struct Foo(u32);
6+
impl Foo {
7+
fn get<R: Deref<Target=Self>>(self: R) -> u32 {
8+
self.0
9+
}
10+
}
11+
12+
fn main() {
13+
let mut foo = Foo(1);
14+
foo.get::<&Foo>();
15+
//~^ ERROR mismatched types
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/arbitrary-self-from-method-substs.rs:14:5
3+
|
4+
LL | foo.get::<&Foo>();
5+
| ^^^ expected `&Foo`, found `Foo`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)