Skip to content

Commit 1cde4c7

Browse files
committed
Add supertrait item shadowing for type-level path resolution
1 parent f60a0f1 commit 1cde4c7

5 files changed

Lines changed: 148 additions & 1 deletion

File tree

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use std::slice;
2424
use rustc_ast::LitKind;
2525
use rustc_data_structures::assert_matches;
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, struct_span_code_err,
@@ -1176,6 +1177,69 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11761177
)
11771178
}
11781179

1180+
/// When there are multiple traits which contain an identically named
1181+
/// associated item, this function eliminates any traits which are a
1182+
/// supertrait of another candidate trait.
1183+
///
1184+
/// This implements RFC #3624.
1185+
fn collapse_candidates_to_subtrait_pick(
1186+
&self,
1187+
matching_candidates: &[ty::PolyTraitRef<'tcx>],
1188+
) -> Option<ty::PolyTraitRef<'tcx>> {
1189+
if !self.tcx().features().supertrait_item_shadowing() {
1190+
return None;
1191+
}
1192+
1193+
let mut child_trait = matching_candidates[0];
1194+
let mut supertraits: SsoHashSet<_> =
1195+
traits::supertrait_def_ids(self.tcx(), child_trait.def_id()).collect();
1196+
1197+
let mut remaining_candidates: Vec<_> = matching_candidates[1..].iter().copied().collect();
1198+
while !remaining_candidates.is_empty() {
1199+
let mut made_progress = false;
1200+
let mut next_round = vec![];
1201+
1202+
for remaining_trait in remaining_candidates {
1203+
if supertraits.contains(&remaining_trait.def_id()) {
1204+
made_progress = true;
1205+
continue;
1206+
}
1207+
1208+
// This pick is not a supertrait of the `child_pick`.
1209+
// Check if it's a subtrait of the `child_pick`, instead.
1210+
// If it is, then it must have been a subtrait of every
1211+
// other pick we've eliminated at this point. It will
1212+
// take over at this point.
1213+
let remaining_trait_supertraits: SsoHashSet<_> =
1214+
traits::supertrait_def_ids(self.tcx(), remaining_trait.def_id()).collect();
1215+
if remaining_trait_supertraits.contains(&child_trait.def_id()) {
1216+
child_trait = remaining_trait;
1217+
supertraits = remaining_trait_supertraits;
1218+
made_progress = true;
1219+
continue;
1220+
}
1221+
1222+
// `child_pick` is not a supertrait of this pick.
1223+
// Don't bail here, since we may be comparing two supertraits
1224+
// of a common subtrait. These two supertraits won't be related
1225+
// at all, but we will pick them up next round when we find their
1226+
// child as we continue iterating in this round.
1227+
next_round.push(remaining_trait);
1228+
}
1229+
1230+
if made_progress {
1231+
// If we've made progress, iterate again.
1232+
remaining_candidates = next_round;
1233+
} else {
1234+
// Otherwise, we must have at least two candidates which
1235+
// are not related to each other at all.;
1236+
return None;
1237+
}
1238+
}
1239+
1240+
Some(child_trait)
1241+
}
1242+
11791243
/// Search for a single trait bound whose trait defines the associated item given by
11801244
/// `assoc_ident`.
11811245
///
@@ -1215,6 +1279,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12151279
if let Some(bound2) = matching_candidates.next() {
12161280
debug!(?bound2);
12171281

1282+
// If the other matching candidates are all from supertraits of one
1283+
// trait, pick the subtrait.
1284+
let matching_candidates: Vec<_> =
1285+
[bound, bound2].into_iter().chain(matching_candidates).collect();
1286+
if let Some(bound) = self.collapse_candidates_to_subtrait_pick(&matching_candidates) {
1287+
return Ok(bound);
1288+
}
1289+
12181290
let assoc_kind_str = errors::assoc_tag_str(assoc_tag);
12191291
let qself_str = qself.to_string(tcx);
12201292
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
@@ -1238,7 +1310,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12381310
// predicates!).
12391311
// FIXME: Turn this into a structured, translatable & more actionable suggestion.
12401312
let mut where_bounds = vec![];
1241-
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
1313+
for bound in matching_candidates {
12421314
let bound_id = bound.def_id();
12431315
let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind(
12441316
tcx,
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//@ run-pass
2+
//@ check-run-results
3+
4+
#![feature(supertrait_item_shadowing)]
5+
#![feature(min_generic_const_args)]
6+
#![allow(dead_code, incomplete_features)]
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]
17+
const CONST: i32;
18+
}
19+
impl<T> B for T {
20+
#[type_const]
21+
const CONST: i32 = 2;
22+
}
23+
24+
trait C: B {}
25+
impl<T> C for T {}
26+
27+
fn main() {
28+
println!("{}", i32::CONST);
29+
generic::<u32>();
30+
}
31+
32+
fn generic<T: C<CONST = 2>>() {
33+
println!("{}", T::CONST);
34+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2
2+
2
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
}
30+
31+
fn generic<T: B>() {
32+
println!("{}", size_of::<T::T>());
33+
}
34+
35+
fn generic2<T: C<T = i16>>() {
36+
println!("{}", size_of::<T::T>());
37+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2
2+
2

0 commit comments

Comments
 (0)