Skip to content

Commit 0c85044

Browse files
Implement RFC 3624 supertrait_item_shadowing
1 parent 9fcc9cf commit 0c85044

File tree

5 files changed

+142
-4
lines changed

5 files changed

+142
-4
lines changed

Diff for: compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,8 @@ declare_features! (
633633
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
634634
/// Allows string patterns to dereference values to match them.
635635
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
636+
/// Allows subtrait items to shadow supertrait items.
637+
(unstable, supertrait_item_shadowing, "CURRENT_RUSTC_VERSION", Some(89151)),
636638
/// Allows using `#[thread_local]` on `static` items.
637639
(unstable, thread_local, "1.0.0", Some(29594)),
638640
/// Allows defining `trait X = A + B;` alias items.

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

+60-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::cmp::max;
33
use std::ops::Deref;
44

55
use rustc_data_structures::fx::FxHashSet;
6+
use rustc_data_structures::sso::SsoHashSet;
67
use rustc_errors::Applicability;
78
use rustc_hir as hir;
89
use rustc_hir::HirId;
@@ -33,6 +34,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
3334
CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult,
3435
};
3536
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
37+
use rustc_type_ir::elaborate::supertrait_def_ids;
3638
use smallvec::{SmallVec, smallvec};
3739
use tracing::{debug, instrument};
3840

@@ -1614,10 +1616,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
16141616
debug!("applicable_candidates: {:?}", applicable_candidates);
16151617

16161618
if applicable_candidates.len() > 1 {
1617-
if let Some(pick) =
1618-
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
1619-
{
1620-
return Some(Ok(pick));
1619+
if self.tcx.features().supertrait_item_shadowing() {
1620+
if let Some(pick) =
1621+
self.collapse_candidates_to_subtrait_pick(self_ty, &applicable_candidates)
1622+
{
1623+
return Some(Ok(pick));
1624+
}
1625+
} else {
1626+
if let Some(pick) =
1627+
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
1628+
{
1629+
return Some(Ok(pick));
1630+
}
16211631
}
16221632
}
16231633

@@ -2084,6 +2094,52 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
20842094
})
20852095
}
20862096

2097+
/// Much like `collapse_candidates_to_trait_pick`, this method allows us to collapse
2098+
/// multiple conflicting picks if there is one pick whose trait container is a subtrait
2099+
/// of the trait containers of all of the other picks.
2100+
///
2101+
/// This implements RFC #3624.
2102+
fn collapse_candidates_to_subtrait_pick(
2103+
&self,
2104+
self_ty: Ty<'tcx>,
2105+
probes: &[(&Candidate<'tcx>, ProbeResult)],
2106+
) -> Option<Pick<'tcx>> {
2107+
let mut child_pick = probes[0].0;
2108+
let mut supertraits: SsoHashSet<_> =
2109+
supertrait_def_ids(self.tcx, child_pick.item.trait_container(self.tcx)?).collect();
2110+
2111+
// All other picks should be a supertrait of the `child_pick`.
2112+
// If it's not, then we update the `child_pick` and the `supertraits`
2113+
// list.
2114+
for (p, _) in &probes[1..] {
2115+
let p_container = p.item.trait_container(self.tcx)?;
2116+
if !supertraits.contains(&p_container) {
2117+
// This pick is not a supertrait of the `child_pick`.
2118+
// Check if it's a subtrait of the `child_pick`, which
2119+
// is sufficient to imply that all of the previous picks
2120+
// are also supertraits of this pick.
2121+
supertraits = supertrait_def_ids(self.tcx, p_container).collect();
2122+
if supertraits.contains(&child_pick.item.trait_container(self.tcx).unwrap()) {
2123+
child_pick = *p;
2124+
} else {
2125+
// `child_pick` is not a supertrait of this pick. Bail.
2126+
return None;
2127+
}
2128+
}
2129+
}
2130+
2131+
Some(Pick {
2132+
item: child_pick.item,
2133+
kind: TraitPick,
2134+
import_ids: child_pick.import_ids.clone(),
2135+
autoderefs: 0,
2136+
autoref_or_ptr_adjustment: None,
2137+
self_ty,
2138+
unstable_candidates: vec![],
2139+
receiver_steps: None,
2140+
})
2141+
}
2142+
20872143
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
20882144
/// candidate method where the method name may have been misspelled. Similarly to other
20892145
/// edit distance based suggestions, we provide at most one such suggestion.

Diff for: compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1995,6 +1995,7 @@ symbols! {
19951995
sub_assign,
19961996
sub_with_overflow,
19971997
suggestion,
1998+
supertrait_item_shadowing,
19981999
surface_async_drop_in_place,
19992000
sym,
20002001
sync,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
trait Sup {
2+
fn method(&self) {}
3+
}
4+
5+
trait Trait: Sup {
6+
fn method(&self) {}
7+
}
8+
9+
impl Sup for i32 {}
10+
impl Trait for i32 {}
11+
12+
fn poly<T: Trait>(x: T) {
13+
x.method();
14+
//~^ ERROR multiple applicable items in scope
15+
}
16+
17+
fn concrete() {
18+
1.method();
19+
//~^ ERROR multiple applicable items in scope
20+
}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:13:7
3+
|
4+
LL | x.method();
5+
| ^^^^^^ multiple `method` found
6+
|
7+
note: candidate #1 is defined in the trait `Sup`
8+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:2:5
9+
|
10+
LL | fn method(&self) {}
11+
| ^^^^^^^^^^^^^^^^
12+
note: candidate #2 is defined in the trait `Trait`
13+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:6:5
14+
|
15+
LL | fn method(&self) {}
16+
| ^^^^^^^^^^^^^^^^
17+
help: disambiguate the method for candidate #1
18+
|
19+
LL - x.method();
20+
LL + Sup::method(&x);
21+
|
22+
help: disambiguate the method for candidate #2
23+
|
24+
LL - x.method();
25+
LL + Trait::method(&x);
26+
|
27+
28+
error[E0034]: multiple applicable items in scope
29+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:18:7
30+
|
31+
LL | 1.method();
32+
| ^^^^^^ multiple `method` found
33+
|
34+
note: candidate #1 is defined in an impl of the trait `Sup` for the type `i32`
35+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:2:5
36+
|
37+
LL | fn method(&self) {}
38+
| ^^^^^^^^^^^^^^^^
39+
note: candidate #2 is defined in an impl of the trait `Trait` for the type `i32`
40+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:6:5
41+
|
42+
LL | fn method(&self) {}
43+
| ^^^^^^^^^^^^^^^^
44+
help: disambiguate the method for candidate #1
45+
|
46+
LL - 1.method();
47+
LL + Sup::method(&1);
48+
|
49+
help: disambiguate the method for candidate #2
50+
|
51+
LL - 1.method();
52+
LL + Trait::method(&1);
53+
|
54+
55+
error: aborting due to 2 previous errors
56+
57+
For more information about this error, try `rustc --explain E0034`.

0 commit comments

Comments
 (0)