Skip to content

Commit 2c43098

Browse files
Implement RFC 3624 supertrait_item_shadowing
1 parent 2d0ea79 commit 2c43098

File tree

5 files changed

+137
-4
lines changed

5 files changed

+137
-4
lines changed

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ declare_features! (
603603
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
604604
/// Allows string patterns to dereference values to match them.
605605
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
606+
/// Allows subtrait items to shadow supertrait items.
607+
(unstable, supertrait_item_shadowing, "CURRENT_RUSTC_VERSION", Some(89151)),
606608
/// Allows the use of `#[target_feature]` on safe functions.
607609
(unstable, target_feature_11, "1.45.0", Some(69098)),
608610
/// Allows using `#[thread_local]` on `static` items.

compiler/rustc_hir_typeck/src/method/probe.rs

+59-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::iter;
44
use std::ops::Deref;
55

66
use rustc_data_structures::fx::FxHashSet;
7+
use rustc_data_structures::sso::SsoHashSet;
78
use rustc_errors::Applicability;
89
use rustc_hir as hir;
910
use rustc_hir::HirId;
@@ -35,6 +36,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
3536
CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult,
3637
};
3738
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
39+
use rustc_type_ir::elaborate::supertrait_def_ids;
3840
use smallvec::{SmallVec, smallvec};
3941
use tracing::{debug, instrument};
4042

@@ -1315,10 +1317,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13151317
debug!("applicable_candidates: {:?}", applicable_candidates);
13161318

13171319
if applicable_candidates.len() > 1 {
1318-
if let Some(pick) =
1319-
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
1320-
{
1321-
return Some(Ok(pick));
1320+
if self.tcx.features().supertrait_item_shadowing {
1321+
if let Some(pick) =
1322+
self.collapse_candidates_to_subtrait_pick(self_ty, &applicable_candidates)
1323+
{
1324+
return Some(Ok(pick));
1325+
}
1326+
} else {
1327+
if let Some(pick) =
1328+
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
1329+
{
1330+
return Some(Ok(pick));
1331+
}
13221332
}
13231333
}
13241334

@@ -1751,6 +1761,51 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
17511761
})
17521762
}
17531763

1764+
/// Much like `collapse_candidates_to_trait_pick`, this method allows us to collapse
1765+
/// multiple conflicting picks if there is one pick whose trait container is a subtrait
1766+
/// of the trait containers of all of the other picks.
1767+
///
1768+
/// This implements RFC #3624.
1769+
fn collapse_candidates_to_subtrait_pick(
1770+
&self,
1771+
self_ty: Ty<'tcx>,
1772+
probes: &[(&Candidate<'tcx>, ProbeResult)],
1773+
) -> Option<Pick<'tcx>> {
1774+
let mut child_pick = probes[0].0;
1775+
let mut supertraits: SsoHashSet<_> =
1776+
supertrait_def_ids(self.tcx, child_pick.item.trait_container(self.tcx)?).collect();
1777+
1778+
// All other picks should be a supertrait of the `child_pick`.
1779+
// If it's not, then we update the `child_pick` and the `supertraits`
1780+
// list.
1781+
for (p, _) in &probes[1..] {
1782+
let p_container = p.item.trait_container(self.tcx)?;
1783+
if !supertraits.contains(&p_container) {
1784+
// This pick is not a supertrait of the `child_pick`.
1785+
// Check if it's a subtrait of the `child_pick`, which
1786+
// is sufficient to imply that all of the previous picks
1787+
// are also supertraits of this pick.
1788+
supertraits = supertrait_def_ids(self.tcx, p_container).collect();
1789+
if supertraits.contains(&child_pick.item.trait_container(self.tcx).unwrap()) {
1790+
child_pick = *p;
1791+
} else {
1792+
// `child_pick` is not a supertrait of this pick. Bail.
1793+
return None;
1794+
}
1795+
}
1796+
}
1797+
1798+
Some(Pick {
1799+
item: child_pick.item,
1800+
kind: TraitPick,
1801+
import_ids: child_pick.import_ids.clone(),
1802+
autoderefs: 0,
1803+
autoref_or_ptr_adjustment: None,
1804+
self_ty,
1805+
unstable_candidates: vec![],
1806+
})
1807+
}
1808+
17541809
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
17551810
/// candidate method where the method name may have been misspelled. Similarly to other
17561811
/// edit distance based suggestions, we provide at most one such suggestion.

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,7 @@ symbols! {
19321932
sub_assign,
19331933
sub_with_overflow,
19341934
suggestion,
1935+
supertrait_item_shadowing,
19351936
surface_async_drop_in_place,
19361937
sym,
19371938
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,53 @@
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 | Sup::method(&x);
20+
| ~~~~~~~~~~~~~~~
21+
help: disambiguate the method for candidate #2
22+
|
23+
LL | Trait::method(&x);
24+
| ~~~~~~~~~~~~~~~~~
25+
26+
error[E0034]: multiple applicable items in scope
27+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:18:7
28+
|
29+
LL | 1.method();
30+
| ^^^^^^ multiple `method` found
31+
|
32+
note: candidate #1 is defined in an impl of the trait `Sup` for the type `i32`
33+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:2:5
34+
|
35+
LL | fn method(&self) {}
36+
| ^^^^^^^^^^^^^^^^
37+
note: candidate #2 is defined in an impl of the trait `Trait` for the type `i32`
38+
--> $DIR/feature-gate-supertrait-item-shadowing.rs:6:5
39+
|
40+
LL | fn method(&self) {}
41+
| ^^^^^^^^^^^^^^^^
42+
help: disambiguate the method for candidate #1
43+
|
44+
LL | Sup::method(&1);
45+
| ~~~~~~~~~~~~~~~
46+
help: disambiguate the method for candidate #2
47+
|
48+
LL | Trait::method(&1);
49+
| ~~~~~~~~~~~~~~~~~
50+
51+
error: aborting due to 2 previous errors
52+
53+
For more information about this error, try `rustc --explain E0034`.

0 commit comments

Comments
 (0)