Skip to content

Commit a269b31

Browse files
committed
Arbitrary self types v2: detect shadowing problems.
This builds on the previous commits by actually adding checks for cases where a new method shadows an older method.
1 parent 48e1df8 commit a269b31

9 files changed

+565
-4
lines changed

Diff for: compiler/rustc_hir_typeck/src/method/probe.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -1386,16 +1386,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13861386
// the shadowing, because the autoderef-based maths wouldn't line up.
13871387
// This is a niche case and we can live without generating an error
13881388
// in the case of such shadowing.
1389-
let _potentially_shadowed_pick = self.pick_autorefd_method(
1389+
let potentially_shadowed_pick = self.pick_autorefd_method(
13901390
step,
13911391
self_ty,
13921392
mutbl,
13931393
&mut pick_diag_hints,
13941394
Some(&pick_constraints),
13951395
);
1396-
1397-
// At the moment, this function does no checks. A future
1398-
// commit will fill out the body here.
1396+
// Look for actual pairs of shadower/shadowed which are
1397+
// the sort of shadowing case we want to avoid. Specifically...
1398+
if let Some(Ok(possible_shadowed)) = potentially_shadowed_pick.as_ref() {
1399+
let sources = [possible_shadower, possible_shadowed]
1400+
.into_iter()
1401+
.map(|p| self.candidate_source_from_pick(p))
1402+
.collect();
1403+
return Err(MethodError::Ambiguity(sources));
1404+
}
13991405
Ok(())
14001406
}
14011407

@@ -1771,6 +1777,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
17711777
}
17721778
}
17731779

1780+
fn candidate_source_from_pick(&self, pick: &Pick<'tcx>) -> CandidateSource {
1781+
match pick.kind {
1782+
InherentImplPick => CandidateSource::Impl(pick.item.container_id(self.tcx)),
1783+
ObjectPick | WhereClausePick(_) | TraitPick => {
1784+
CandidateSource::Trait(pick.item.container_id(self.tcx))
1785+
}
1786+
}
1787+
}
1788+
17741789
#[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)]
17751790
fn consider_probe(
17761791
&self,
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//@ run-pass
2+
3+
#![feature(arbitrary_self_types)]
4+
#![allow(dead_code)]
5+
6+
// With arbitrary self types v2, we show an error if there are
7+
// multiple contenders for a method call in an inner and outer type.
8+
// The goal is to avoid any possibility of confusion by a new
9+
// 'shadowing' method calling a 'shadowed' method.
10+
// However, there are niche circumstances where this
11+
// algorithm doesn't quite work, due to reborrows to get a different
12+
// lifetime. The test below explicitly tests those circumstances to ensure
13+
// the behavior is as expected, even if it's not 100% desirable. They're
14+
// very niche circumstances.
15+
16+
#[derive(Debug, PartialEq)]
17+
enum Callee {
18+
INNER,
19+
OUTER
20+
}
21+
22+
struct MyNonNull<T>(T);
23+
24+
impl<T> std::ops::Receiver for MyNonNull<T> {
25+
type Target = T;
26+
}
27+
28+
struct A;
29+
impl A {
30+
fn foo(self: MyNonNull<A>) -> Callee {
31+
Callee::INNER
32+
}
33+
34+
fn bar(self: &MyNonNull<A>) -> Callee {
35+
Callee::INNER
36+
}
37+
38+
fn baz(self: &&MyNonNull<A>) -> Callee {
39+
// note this is by DOUBLE reference
40+
Callee::INNER
41+
}
42+
}
43+
44+
impl<T> MyNonNull<T> {
45+
fn foo(&self) -> Callee{
46+
Callee::OUTER
47+
}
48+
49+
fn bar(&self) -> Callee{
50+
Callee::OUTER
51+
}
52+
53+
fn baz(&self) -> Callee{
54+
Callee::OUTER
55+
}
56+
}
57+
58+
fn main() {
59+
// The normal deshadowing case. Does not compile.
60+
// assert_eq!(MyNonNull(A).foo(), Callee::INNER);
61+
62+
// Similarly, does not compile.
63+
//assert_eq!(MyNonNull(A).bar(), Callee::INNER);
64+
65+
// The double-reference case.
66+
// We call the newly-added outer type method.
67+
// Not ideal but very niche so we accept it.
68+
assert_eq!(MyNonNull(A).baz(), Callee::OUTER);
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@ run-pass
2+
3+
#![feature(arbitrary_self_types)]
4+
#![feature(arbitrary_self_types_pointers)]
5+
6+
pub struct A;
7+
8+
impl A {
9+
pub fn f(self: *const MyNonNull<Self>) -> i32 { 1 }
10+
}
11+
12+
pub struct MyNonNull<T>(T);
13+
14+
impl<T> core::ops::Receiver for MyNonNull<T> {
15+
type Target = T;
16+
}
17+
18+
impl<T> MyNonNull<T> {
19+
// Imagine this a NEW method in B<T> shadowing an EXISTING
20+
// method in A.
21+
pub fn f(self: *mut Self) -> i32 {
22+
2
23+
}
24+
}
25+
26+
fn main() {
27+
let mut b = MyNonNull(A);
28+
let b = &mut b;
29+
let b = b as *mut MyNonNull<A>;
30+
// We actually allow the shadowing in the case of const vs mut raw
31+
// pointer receivers.
32+
assert_eq!(b.f(), 2);
33+
}

Diff for: tests/ui/self/arbitrary_self_types_unshadowing.rs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![feature(arbitrary_self_types)]
2+
3+
pub struct A;
4+
5+
// The receiver of the potentially shadowed method
6+
// precisely matches that of the shadower
7+
impl A {
8+
pub fn f(self: Wrapper<Self>) -> i32 { 1 }
9+
pub fn g(self: &Wrapper<Self>) -> i32 { 2 }
10+
pub fn h(self: &mut Wrapper<Self>) -> i32 { 3 }
11+
}
12+
13+
// The receiver of the potentially shadowed method is a reference
14+
pub struct B;
15+
16+
impl B {
17+
pub fn f(self: &Wrapper<Self>) -> i32 { 9 }
18+
}
19+
20+
// The receiver of the potentially shadowed method is a mut reference
21+
22+
pub struct C;
23+
24+
impl C {
25+
pub fn f(self: &mut Wrapper<Self>) -> i32 { 10 }
26+
pub fn g(self: &mut Wrapper<Self>) -> i32 { 11 }
27+
}
28+
29+
pub struct Wrapper<T>(T);
30+
31+
impl<T> core::ops::Receiver for Wrapper<T> {
32+
type Target = T;
33+
}
34+
35+
impl<T> Wrapper<T> {
36+
pub fn f(self) -> i32 { 5 }
37+
pub fn g(&self) -> i32 { 6 }
38+
pub fn h(&mut self) -> i32 { 7 }
39+
}
40+
41+
fn main() {
42+
assert_eq!(Wrapper(A).f(), 1);
43+
//~^ ERROR: multiple applicable items in scope
44+
assert_eq!(Wrapper(A).g(), 2);
45+
//~^ ERROR: multiple applicable items in scope
46+
assert_eq!(Wrapper(A).h(), 3);
47+
//~^ ERROR: multiple applicable items in scope
48+
let a = Wrapper(A);
49+
assert_eq!(Wrapper(B).f(), 9);
50+
//~^ ERROR: multiple applicable items in scope
51+
assert_eq!(Wrapper(C).f(), 10);
52+
//~^ ERROR: multiple applicable items in scope
53+
assert_eq!(Wrapper(C).g(), 11);
54+
//~^ ERROR: multiple applicable items in scope
55+
}
+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/arbitrary_self_types_unshadowing.rs:42:27
3+
|
4+
LL | assert_eq!(Wrapper(A).f(), 1);
5+
| ^ multiple `f` found
6+
|
7+
note: candidate #1 is defined in an impl for the type `A`
8+
--> $DIR/arbitrary_self_types_unshadowing.rs:8:5
9+
|
10+
LL | pub fn f(self: Wrapper<Self>) -> i32 { 1 }
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
note: candidate #2 is defined in an impl for the type `Wrapper<T>`
13+
--> $DIR/arbitrary_self_types_unshadowing.rs:36:5
14+
|
15+
LL | pub fn f(self) -> i32 { 5 }
16+
| ^^^^^^^^^^^^^^^^^^^^^
17+
18+
error[E0034]: multiple applicable items in scope
19+
--> $DIR/arbitrary_self_types_unshadowing.rs:44:27
20+
|
21+
LL | assert_eq!(Wrapper(A).g(), 2);
22+
| ^ multiple `g` found
23+
|
24+
note: candidate #1 is defined in an impl for the type `A`
25+
--> $DIR/arbitrary_self_types_unshadowing.rs:9:5
26+
|
27+
LL | pub fn g(self: &Wrapper<Self>) -> i32 { 2 }
28+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29+
note: candidate #2 is defined in an impl for the type `Wrapper<T>`
30+
--> $DIR/arbitrary_self_types_unshadowing.rs:37:5
31+
|
32+
LL | pub fn g(&self) -> i32 { 6 }
33+
| ^^^^^^^^^^^^^^^^^^^^^^
34+
35+
error[E0034]: multiple applicable items in scope
36+
--> $DIR/arbitrary_self_types_unshadowing.rs:46:27
37+
|
38+
LL | assert_eq!(Wrapper(A).h(), 3);
39+
| ^ multiple `h` found
40+
|
41+
note: candidate #1 is defined in an impl for the type `A`
42+
--> $DIR/arbitrary_self_types_unshadowing.rs:10:5
43+
|
44+
LL | pub fn h(self: &mut Wrapper<Self>) -> i32 { 3 }
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
46+
note: candidate #2 is defined in an impl for the type `Wrapper<T>`
47+
--> $DIR/arbitrary_self_types_unshadowing.rs:38:5
48+
|
49+
LL | pub fn h(&mut self) -> i32 { 7 }
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
51+
52+
error[E0034]: multiple applicable items in scope
53+
--> $DIR/arbitrary_self_types_unshadowing.rs:49:27
54+
|
55+
LL | assert_eq!(Wrapper(B).f(), 9);
56+
| ^ multiple `f` found
57+
|
58+
note: candidate #1 is defined in an impl for the type `B`
59+
--> $DIR/arbitrary_self_types_unshadowing.rs:17:5
60+
|
61+
LL | pub fn f(self: &Wrapper<Self>) -> i32 { 9 }
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63+
note: candidate #2 is defined in an impl for the type `Wrapper<T>`
64+
--> $DIR/arbitrary_self_types_unshadowing.rs:36:5
65+
|
66+
LL | pub fn f(self) -> i32 { 5 }
67+
| ^^^^^^^^^^^^^^^^^^^^^
68+
69+
error[E0034]: multiple applicable items in scope
70+
--> $DIR/arbitrary_self_types_unshadowing.rs:51:27
71+
|
72+
LL | assert_eq!(Wrapper(C).f(), 10);
73+
| ^ multiple `f` found
74+
|
75+
note: candidate #1 is defined in an impl for the type `C`
76+
--> $DIR/arbitrary_self_types_unshadowing.rs:25:5
77+
|
78+
LL | pub fn f(self: &mut Wrapper<Self>) -> i32 { 10 }
79+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
80+
note: candidate #2 is defined in an impl for the type `Wrapper<T>`
81+
--> $DIR/arbitrary_self_types_unshadowing.rs:36:5
82+
|
83+
LL | pub fn f(self) -> i32 { 5 }
84+
| ^^^^^^^^^^^^^^^^^^^^^
85+
86+
error[E0034]: multiple applicable items in scope
87+
--> $DIR/arbitrary_self_types_unshadowing.rs:53:27
88+
|
89+
LL | assert_eq!(Wrapper(C).g(), 11);
90+
| ^ multiple `g` found
91+
|
92+
note: candidate #1 is defined in an impl for the type `C`
93+
--> $DIR/arbitrary_self_types_unshadowing.rs:26:5
94+
|
95+
LL | pub fn g(self: &mut Wrapper<Self>) -> i32 { 11 }
96+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
97+
note: candidate #2 is defined in an impl for the type `Wrapper<T>`
98+
--> $DIR/arbitrary_self_types_unshadowing.rs:37:5
99+
|
100+
LL | pub fn g(&self) -> i32 { 6 }
101+
| ^^^^^^^^^^^^^^^^^^^^^^
102+
103+
error: aborting due to 6 previous errors
104+
105+
For more information about this error, try `rustc --explain E0034`.
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#![feature(arbitrary_self_types_pointers)]
2+
#![feature(arbitrary_self_types)]
3+
4+
pub struct A;
5+
6+
// The receiver of the potentially shadowed method
7+
// precisely matches that of the shadower
8+
impl A {
9+
pub fn f(self: Wrapper<Self>) -> i32 { 1 }
10+
pub fn g(self: &Wrapper<Self>) -> i32 { 2 }
11+
pub fn h(self: &mut Wrapper<Self>) -> i32 { 3 }
12+
pub fn i(self: *const Wrapper<Self>) -> i32 { 4 }
13+
}
14+
15+
// The receiver of the potentially shadowed method is a reference
16+
pub struct B;
17+
18+
impl B {
19+
pub fn f(self: &Wrapper<Self>) -> i32 { 9 }
20+
}
21+
22+
// The receiver of the potentially shadowed method is a mut reference
23+
24+
pub struct C;
25+
26+
impl C {
27+
pub fn f(self: &mut Wrapper<Self>) -> i32 { 10 }
28+
pub fn g(self: &mut Wrapper<Self>) -> i32 { 11 }
29+
}
30+
31+
pub struct Wrapper<T>(T);
32+
33+
impl<T> core::ops::Receiver for Wrapper<T> {
34+
type Target = T;
35+
}
36+
37+
impl<T> Wrapper<T> {
38+
pub fn f(self) -> i32 { 5 }
39+
pub fn g(&self) -> i32 { 6 }
40+
pub fn h(&mut self) -> i32 { 7 }
41+
pub fn i(self: *const Self) -> i32 { 8 }
42+
}
43+
44+
fn main() {
45+
assert_eq!(Wrapper(A).f(), 1);
46+
//~^ ERROR: multiple applicable items in scope
47+
assert_eq!(Wrapper(A).g(), 2);
48+
//~^ ERROR: multiple applicable items in scope
49+
assert_eq!(Wrapper(A).h(), 3);
50+
//~^ ERROR: multiple applicable items in scope
51+
let a = Wrapper(A);
52+
let a_ptr = &a as *const Wrapper<A>;
53+
assert_eq!(a_ptr.i(), 4);
54+
//~^ ERROR: multiple applicable items in scope
55+
assert_eq!(Wrapper(B).f(), 9);
56+
//~^ ERROR: multiple applicable items in scope
57+
assert_eq!(Wrapper(C).f(), 10);
58+
//~^ ERROR: multiple applicable items in scope
59+
assert_eq!(Wrapper(C).g(), 11);
60+
//~^ ERROR: multiple applicable items in scope
61+
}

0 commit comments

Comments
 (0)