Skip to content

Commit 43d183d

Browse files
committed
Add supertrait item shadowing for type-level path resolution
1 parent 4f84d9f commit 43d183d

6 files changed

Lines changed: 160 additions & 7 deletions

File tree

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
405405

406406
pub(super) fn report_ambiguous_assoc_item(
407407
&self,
408-
bound1: ty::PolyTraitRef<'tcx>,
409-
bound2: ty::PolyTraitRef<'tcx>,
410-
matching_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
408+
matching_candidates: &[ty::PolyTraitRef<'tcx>],
411409
qself: AssocItemQSelf,
412410
assoc_tag: ty::AssocTag,
413411
assoc_ident: Ident,
@@ -439,7 +437,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
439437
// predicates!).
440438
// FIXME: Turn this into a structured, translatable & more actionable suggestion.
441439
let mut where_bounds = vec![];
442-
for bound in [bound1, bound2].into_iter().chain(matching_candidates) {
440+
for &bound in matching_candidates {
443441
let bound_id = bound.def_id();
444442
let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind(
445443
tcx,

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use std::{assert_matches, slice};
2424
use rustc_abi::FIRST_VARIANT;
2525
use rustc_ast::LitKind;
2626
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
27+
use rustc_data_structures::sso::SsoHashSet;
2728
use rustc_errors::codes::*;
2829
use rustc_errors::{
2930
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, StashKey,
@@ -1262,6 +1263,69 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12621263
)
12631264
}
12641265

1266+
/// When there are multiple traits which contain an identically named
1267+
/// associated item, this function eliminates any traits which are a
1268+
/// supertrait of another candidate trait.
1269+
///
1270+
/// This implements RFC #3624.
1271+
fn collapse_candidates_to_subtrait_pick(
1272+
&self,
1273+
matching_candidates: &[ty::PolyTraitRef<'tcx>],
1274+
) -> Option<ty::PolyTraitRef<'tcx>> {
1275+
if !self.tcx().features().supertrait_item_shadowing() {
1276+
return None;
1277+
}
1278+
1279+
let mut child_trait = matching_candidates[0];
1280+
let mut supertraits: SsoHashSet<_> =
1281+
traits::supertrait_def_ids(self.tcx(), child_trait.def_id()).collect();
1282+
1283+
let mut remaining_candidates: Vec<_> = matching_candidates[1..].iter().copied().collect();
1284+
while !remaining_candidates.is_empty() {
1285+
let mut made_progress = false;
1286+
let mut next_round = vec![];
1287+
1288+
for remaining_trait in remaining_candidates {
1289+
if supertraits.contains(&remaining_trait.def_id()) {
1290+
made_progress = true;
1291+
continue;
1292+
}
1293+
1294+
// This pick is not a supertrait of the `child_pick`.
1295+
// Check if it's a subtrait of the `child_pick`, instead.
1296+
// If it is, then it must have been a subtrait of every
1297+
// other pick we've eliminated at this point. It will
1298+
// take over at this point.
1299+
let remaining_trait_supertraits: SsoHashSet<_> =
1300+
traits::supertrait_def_ids(self.tcx(), remaining_trait.def_id()).collect();
1301+
if remaining_trait_supertraits.contains(&child_trait.def_id()) {
1302+
child_trait = remaining_trait;
1303+
supertraits = remaining_trait_supertraits;
1304+
made_progress = true;
1305+
continue;
1306+
}
1307+
1308+
// `child_pick` is not a supertrait of this pick.
1309+
// Don't bail here, since we may be comparing two supertraits
1310+
// of a common subtrait. These two supertraits won't be related
1311+
// at all, but we will pick them up next round when we find their
1312+
// child as we continue iterating in this round.
1313+
next_round.push(remaining_trait);
1314+
}
1315+
1316+
if made_progress {
1317+
// If we've made progress, iterate again.
1318+
remaining_candidates = next_round;
1319+
} else {
1320+
// Otherwise, we must have at least two candidates which
1321+
// are not related to each other at all.;
1322+
return None;
1323+
}
1324+
}
1325+
1326+
Some(child_trait)
1327+
}
1328+
12651329
/// Search for a single trait bound whose trait defines the associated item given by
12661330
/// `assoc_ident`.
12671331
///
@@ -1296,10 +1360,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12961360
};
12971361

12981362
if let Some(bound2) = matching_candidates.next() {
1363+
let all_matching_candidates: Vec<_> =
1364+
[bound1, bound2].into_iter().chain(matching_candidates).collect();
1365+
if let Some(bound) =
1366+
self.collapse_candidates_to_subtrait_pick(&all_matching_candidates)
1367+
{
1368+
return Ok(bound);
1369+
}
1370+
12991371
return Err(self.report_ambiguous_assoc_item(
1300-
bound1,
1301-
bound2,
1302-
matching_candidates,
1372+
&all_matching_candidates,
13031373
qself,
13041374
assoc_tag,
13051375
assoc_ident,
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ run-pass
2+
//@ check-run-results
3+
4+
#![feature(supertrait_item_shadowing)]
5+
#![feature(min_generic_const_args)]
6+
#![allow(dead_code)]
7+
8+
trait A {
9+
const CONST: i32;
10+
}
11+
impl<T> A for T {
12+
const CONST: i32 = 1;
13+
}
14+
15+
trait B: A {
16+
type const CONST: i32;
17+
}
18+
impl<T> B for T {
19+
type const CONST: i32 = 2;
20+
}
21+
22+
trait C: B {}
23+
impl<T> C for T {}
24+
25+
fn main() {
26+
println!("{}", i32::CONST);
27+
generic::<u32>();
28+
}
29+
30+
fn generic<T: C<CONST = 2>>() {
31+
println!("{}", T::CONST);
32+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2
2+
2
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//@ run-pass
2+
//@ check-run-results
3+
4+
#![feature(supertrait_item_shadowing)]
5+
#![allow(dead_code)]
6+
7+
use std::mem::size_of;
8+
9+
trait A {
10+
type T;
11+
}
12+
impl<T> A for T {
13+
type T = i8;
14+
}
15+
16+
trait B: A {
17+
type T;
18+
}
19+
impl<T> B for T {
20+
type T = i16;
21+
}
22+
23+
trait C: B {}
24+
impl<T> C for T {}
25+
26+
fn main() {
27+
generic::<u32>();
28+
generic2::<u32>();
29+
generic3::<u32>();
30+
generic4::<u32>();
31+
}
32+
33+
fn generic<U: B>() {
34+
println!("{}", size_of::<U::T>());
35+
}
36+
37+
fn generic2<U: A<T = i8>>() {
38+
println!("{}", size_of::<U::T>());
39+
}
40+
41+
fn generic3<U: B<T = i16>>() {
42+
println!("{}", size_of::<U::T>());
43+
}
44+
45+
fn generic4<U: C<T = i16>>() {
46+
println!("{}", size_of::<U::T>());
47+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2
2+
1
3+
2
4+
2

0 commit comments

Comments
 (0)