Skip to content

Commit 388bc06

Browse files
Implement RFC 3624 supertrait_item_shadowing
1 parent a5cf8bb commit 388bc06

File tree

5 files changed

+137
-4
lines changed

5 files changed

+137
-4
lines changed

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,8 @@ declare_features! (
593593
(unstable, strict_provenance, "1.61.0", Some(95228)),
594594
/// Allows string patterns to dereference values to match them.
595595
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
596+
/// Allows subtrait items to shadow supertrait items.
597+
(unstable, supertrait_item_shadowing, "CURRENT_RUSTC_VERSION", Some(89151)),
596598
/// Allows the use of `#[target_feature]` on safe functions.
597599
(unstable, target_feature_11, "1.45.0", Some(69098)),
598600
/// Allows using `#[thread_local]` on `static` items.

compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 59 additions & 4 deletions
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::def::DefKind;
@@ -35,6 +36,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
3536
};
3637
use rustc_trait_selection::traits::query::CanonicalTyGoal;
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

@@ -1260,10 +1262,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12601262
debug!("applicable_candidates: {:?}", applicable_candidates);
12611263

12621264
if applicable_candidates.len() > 1 {
1263-
if let Some(pick) =
1264-
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
1265-
{
1266-
return Some(Ok(pick));
1265+
if self.tcx.features().supertrait_item_shadowing {
1266+
if let Some(pick) =
1267+
self.collapse_candidates_to_subtrait_pick(self_ty, &applicable_candidates)
1268+
{
1269+
return Some(Ok(pick));
1270+
}
1271+
} else {
1272+
if let Some(pick) =
1273+
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
1274+
{
1275+
return Some(Ok(pick));
1276+
}
12671277
}
12681278
}
12691279

@@ -1697,6 +1707,51 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
16971707
})
16981708
}
16991709

1710+
/// Much like `collapse_candidates_to_trait_pick`, this method allows us to collapse
1711+
/// multiple conflicting picks if there is one pick whose trait container is a subtrait
1712+
/// of the trait containers of all of the other picks.
1713+
///
1714+
/// This implements RFC #3624.
1715+
fn collapse_candidates_to_subtrait_pick(
1716+
&self,
1717+
self_ty: Ty<'tcx>,
1718+
probes: &[(&Candidate<'tcx>, ProbeResult)],
1719+
) -> Option<Pick<'tcx>> {
1720+
let mut child_pick = probes[0].0;
1721+
let mut supertraits: SsoHashSet<_> =
1722+
supertrait_def_ids(self.tcx, child_pick.item.trait_container(self.tcx)?).collect();
1723+
1724+
// All other picks should be a supertrait of the `child_pick`.
1725+
// If it's not, then we update the `child_pick` and the `supertraits`
1726+
// list.
1727+
for (p, _) in &probes[1..] {
1728+
let p_container = p.item.trait_container(self.tcx)?;
1729+
if !supertraits.contains(&p_container) {
1730+
// This pick is not a supertrait of the `child_pick`.
1731+
// Check if it's a subtrait of the `child_pick`, which
1732+
// is sufficient to imply that all of the previous picks
1733+
// are also supertraits of this pick.
1734+
supertraits = supertrait_def_ids(self.tcx, p_container).collect();
1735+
if supertraits.contains(&child_pick.item.trait_container(self.tcx).unwrap()) {
1736+
child_pick = *p;
1737+
} else {
1738+
// `child_pick` is not a supertrait of this pick. Bail.
1739+
return None;
1740+
}
1741+
}
1742+
}
1743+
1744+
Some(Pick {
1745+
item: child_pick.item,
1746+
kind: TraitPick,
1747+
import_ids: child_pick.import_ids.clone(),
1748+
autoderefs: 0,
1749+
autoref_or_ptr_adjustment: None,
1750+
self_ty,
1751+
unstable_candidates: vec![],
1752+
})
1753+
}
1754+
17001755
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
17011756
/// candidate method where the method name may have been misspelled. Similarly to other
17021757
/// edit distance based suggestions, we provide at most one such suggestion.

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,6 +1877,7 @@ symbols! {
18771877
sub_assign,
18781878
sub_with_overflow,
18791879
suggestion,
1880+
supertrait_item_shadowing,
18801881
surface_async_drop_in_place,
18811882
sym,
18821883
sync,
Lines changed: 22 additions & 0 deletions
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() {}
Lines changed: 53 additions & 0 deletions
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)