Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

pub(super) fn report_ambiguous_assoc_item(
&self,
bound1: ty::PolyTraitRef<'tcx>,
bound2: ty::PolyTraitRef<'tcx>,
matching_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
matching_candidates: &[ty::PolyTraitRef<'tcx>],
qself: AssocItemQSelf,
assoc_tag: ty::AssocTag,
assoc_ident: Ident,
Expand Down Expand Up @@ -439,7 +437,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// predicates!).
// FIXME: Turn this into a structured, translatable & more actionable suggestion.
let mut where_bounds = vec![];
for bound in [bound1, bound2].into_iter().chain(matching_candidates) {
for &bound in matching_candidates {
let bound_id = bound.def_id();
let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind(
tcx,
Expand Down
80 changes: 77 additions & 3 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use std::{assert_matches, slice};
use rustc_abi::FIRST_VARIANT;
use rustc_ast::LitKind;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::sso::SsoHashSet;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, StashKey,
Expand Down Expand Up @@ -1262,6 +1263,74 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
}

/// When there are multiple traits which contain an identically named
/// associated item, this function eliminates any traits which are a
/// supertrait of another candidate trait.
///
/// This is the type-level analogue of
/// `rustc_hir_typeck::method::probe::ProbeContext::collapse_candidates_to_subtrait_pick`;
/// keep both implementations in sync.
///
/// This implements RFC #3624.
fn collapse_candidates_to_subtrait_pick(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think docs here and for collapse_candidates_to_subtrait_pick in method::probe should link to each other to help ensure they are kept up to date.

It's kind of unfortunate we can't have some shared code here.

&self,
matching_candidates: &[ty::PolyTraitRef<'tcx>],
) -> Option<ty::PolyTraitRef<'tcx>> {
if !self.tcx().features().supertrait_item_shadowing() {
return None;
}

let mut child_trait = matching_candidates[0];
let mut supertraits: SsoHashSet<_> =
traits::supertrait_def_ids(self.tcx(), child_trait.def_id()).collect();

let mut remaining_candidates: Vec<_> = matching_candidates[1..].iter().copied().collect();
while !remaining_candidates.is_empty() {
let mut made_progress = false;
let mut next_round = vec![];

for remaining_trait in remaining_candidates {
if supertraits.contains(&remaining_trait.def_id()) {
made_progress = true;
continue;
}

// This candidate is not a supertrait of the `child_trait`.
// Check if it's a subtrait of the `child_trait`, instead.
// If it is, then it must have been a subtrait of every
// other pick we've eliminated at this point. It will
// take over at this point.
let remaining_trait_supertraits: SsoHashSet<_> =
traits::supertrait_def_ids(self.tcx(), remaining_trait.def_id()).collect();
if remaining_trait_supertraits.contains(&child_trait.def_id()) {
child_trait = remaining_trait;
supertraits = remaining_trait_supertraits;
made_progress = true;
continue;
}

// Neither `child_trait` or the current candidate are
// supertraits of each other.
// Don't bail here, since we may be comparing two supertraits
// of a common subtrait. These two supertraits won't be related
// at all, but we will pick them up next round when we find their
// child as we continue iterating in this round.
next_round.push(remaining_trait);
}

if made_progress {
// If we've made progress, iterate again.
remaining_candidates = next_round;
} else {
// Otherwise, we must have at least two candidates which
// are not related to each other at all.
return None;
}
}

Some(child_trait)
}

/// Search for a single trait bound whose trait defines the associated item given by
/// `assoc_ident`.
///
Expand Down Expand Up @@ -1296,10 +1365,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};

if let Some(bound2) = matching_candidates.next() {
let all_matching_candidates: Vec<_> =
[bound1, bound2].into_iter().chain(matching_candidates).collect();
if let Some(bound) = self.collapse_candidates_to_subtrait_pick(&all_matching_candidates)
{
return Ok(bound);
}

return Err(self.report_ambiguous_assoc_item(
bound1,
bound2,
matching_candidates,
&all_matching_candidates,
qself,
assoc_tag,
assoc_ident,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2359,6 +2359,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// multiple conflicting picks if there is one pick whose trait container is a subtrait
/// of the trait containers of all of the other picks.
///
/// This is the method-probe analogue of
/// `rustc_hir_analysis::hir_ty_lowering::HirTyLowerer::collapse_candidates_to_subtrait_pick`;
/// keep both implementations in sync.
///
/// This implements RFC #3624.
fn collapse_candidates_to_subtrait_pick(
&self,
Expand Down
4 changes: 4 additions & 0 deletions tests/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,10 @@ Generic collection of tests for suggestions, when no more specific directories a

**FIXME**: Some overlap with `tests/ui/did_you_mean/`, that directory should probably be moved under here.

## `tests/ui/supertrait-shadowing/`

Tests for supertrait item shadowing (RFC 3624).

## `tests/ui/svh/`: Strict Version Hash

Tests on the *Strict Version Hash* (SVH, also known as the "crate hash").
Expand Down
22 changes: 0 additions & 22 deletions tests/ui/methods/supertrait-shadowing/assoc-const.rs

This file was deleted.

33 changes: 0 additions & 33 deletions tests/ui/methods/supertrait-shadowing/common-ancestor-2.rs

This file was deleted.

43 changes: 0 additions & 43 deletions tests/ui/methods/supertrait-shadowing/common-ancestor-3.rs

This file was deleted.

68 changes: 0 additions & 68 deletions tests/ui/methods/supertrait-shadowing/common-ancestor-3.stderr

This file was deleted.

26 changes: 0 additions & 26 deletions tests/ui/methods/supertrait-shadowing/common-ancestor.rs

This file was deleted.

18 changes: 0 additions & 18 deletions tests/ui/methods/supertrait-shadowing/definition-site.rs

This file was deleted.

34 changes: 0 additions & 34 deletions tests/ui/methods/supertrait-shadowing/definition-site.stderr

This file was deleted.

Loading
Loading