Skip to content

Commit 62501e4

Browse files
committed
Receiver trait with target: Ignore post-Deref errs.
When probing for methods, we step forward through a chain of types. The first few of those steps can be reached by jumping through the chain of Derefs or the chain of Receivers. Later steps can only be reached by following the chain of Receivers. For instance, supposing A and B implement both Receiver and Deref, while C and D implement only Receiver: Type A<B<C<D<E>>>> Deref chain: A -> B -> C Receiver chain: A -> B -> C -> D -> E We report bad type errors from the end of the chain. Previously this 'receiver trait with target' code reported problems encountered at the end of the whole chain, but in fact we never morph the self type that far. So we now instead report errors encountered only at the end of the Deref chain. A test case is included which demonstrates the problem.
1 parent a3b1f37 commit 62501e4

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,10 +537,14 @@ fn method_autoderef_steps<'tcx>(
537537
.chain(std::iter::repeat(false));
538538

539539
let mut reached_raw_pointer = false;
540+
let mut final_ty_reachable_by_deref = None;
540541
let mut steps: Vec<_> = autoderef_via_receiver
541542
.by_ref()
542543
.zip(reachable_via_deref)
543544
.map(|((ty, d), reachable_via_deref)| {
545+
if reachable_via_deref {
546+
final_ty_reachable_by_deref = Some(ty);
547+
}
544548
let step = CandidateStep {
545549
self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty),
546550
autoderefs: d,
@@ -555,12 +559,15 @@ fn method_autoderef_steps<'tcx>(
555559
step
556560
})
557561
.collect();
558-
let final_ty = autoderef_via_receiver.final_ty(true);
562+
let final_ty =
563+
final_ty_reachable_by_deref.expect("Should be at least one type in any autoderef");
564+
let final_ty = infcx.resolve_vars_if_possible(final_ty);
559565
let opt_bad_ty = match final_ty.kind() {
560566
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
561567
reached_raw_pointer,
562568
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
563569
}),
570+
564571
ty::Array(elem_ty, _) => {
565572
let dereferences = steps.len() - 1;
566573
let reachable_via_deref =
@@ -584,6 +591,10 @@ fn method_autoderef_steps<'tcx>(
584591
_ => None,
585592
};
586593

594+
// FIXME - the previous section may emit an error if the final type reachable
595+
// by the Deref chain is ty::Infer(ty::TyVar(_)). We should consider emitting a warning
596+
// if the final type reachable by the Receiver chain is similarly problematic.
597+
587598
debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
588599

589600
MethodAutoderefStepsResult {

tests/ui/self/recursive-receiver.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// run-pass
2+
#![feature(receiver_trait)]
3+
4+
struct MyNonNull<T>(*const T);
5+
6+
impl<T> std::ops::Receiver for MyNonNull<T> {
7+
type Target = T;
8+
}
9+
10+
#[allow(dead_code)]
11+
impl<T> MyNonNull<T> {
12+
fn foo<U>(&self) -> *const U {
13+
self.cast().bar()
14+
}
15+
fn cast<U>(&self) -> MyNonNull<U> {
16+
MyNonNull(self.0 as *const U)
17+
}
18+
fn bar(&self) -> *const T {
19+
self.0
20+
}
21+
}
22+
23+
#[repr(transparent)]
24+
struct Foo(usize);
25+
#[repr(transparent)]
26+
struct Bar(usize);
27+
28+
fn main() {
29+
let a = Foo(3);
30+
let ptr = MyNonNull(&a);
31+
let _bar_ptr: *const Bar = ptr.foo();
32+
}

0 commit comments

Comments
 (0)