Implement RFC 3624 supertrait_item_shadowing

This commit is contained in:
Michael Goulet 2024-05-30 13:29:54 -04:00
parent 9fcc9cf4a2
commit 0c85044a5d
5 changed files with 142 additions and 4 deletions

View file

@ -633,6 +633,8 @@ declare_features! (
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
/// Allows string patterns to dereference values to match them.
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
/// Allows subtrait items to shadow supertrait items.
(unstable, supertrait_item_shadowing, "CURRENT_RUSTC_VERSION", Some(89151)),
/// Allows using `#[thread_local]` on `static` items.
(unstable, thread_local, "1.0.0", Some(29594)),
/// Allows defining `trait X = A + B;` alias items.

View file

@ -3,6 +3,7 @@ use std::cmp::max;
use std::ops::Deref;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sso::SsoHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::HirId;
@ -33,6 +34,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult,
};
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
use rustc_type_ir::elaborate::supertrait_def_ids;
use smallvec::{SmallVec, smallvec};
use tracing::{debug, instrument};
@ -1614,10 +1616,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
debug!("applicable_candidates: {:?}", applicable_candidates);
if applicable_candidates.len() > 1 {
if let Some(pick) =
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
{
return Some(Ok(pick));
if self.tcx.features().supertrait_item_shadowing() {
if let Some(pick) =
self.collapse_candidates_to_subtrait_pick(self_ty, &applicable_candidates)
{
return Some(Ok(pick));
}
} else {
if let Some(pick) =
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
{
return Some(Ok(pick));
}
}
}
@ -2084,6 +2094,52 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
})
}
/// Much like `collapse_candidates_to_trait_pick`, this method allows us to collapse
/// 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 implements RFC #3624.
fn collapse_candidates_to_subtrait_pick(
&self,
self_ty: Ty<'tcx>,
probes: &[(&Candidate<'tcx>, ProbeResult)],
) -> Option<Pick<'tcx>> {
let mut child_pick = probes[0].0;
let mut supertraits: SsoHashSet<_> =
supertrait_def_ids(self.tcx, child_pick.item.trait_container(self.tcx)?).collect();
// All other picks should be a supertrait of the `child_pick`.
// If it's not, then we update the `child_pick` and the `supertraits`
// list.
for (p, _) in &probes[1..] {
let p_container = p.item.trait_container(self.tcx)?;
if !supertraits.contains(&p_container) {
// This pick is not a supertrait of the `child_pick`.
// Check if it's a subtrait of the `child_pick`, which
// is sufficient to imply that all of the previous picks
// are also supertraits of this pick.
supertraits = supertrait_def_ids(self.tcx, p_container).collect();
if supertraits.contains(&child_pick.item.trait_container(self.tcx).unwrap()) {
child_pick = *p;
} else {
// `child_pick` is not a supertrait of this pick. Bail.
return None;
}
}
}
Some(Pick {
item: child_pick.item,
kind: TraitPick,
import_ids: child_pick.import_ids.clone(),
autoderefs: 0,
autoref_or_ptr_adjustment: None,
self_ty,
unstable_candidates: vec![],
receiver_steps: None,
})
}
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
/// candidate method where the method name may have been misspelled. Similarly to other
/// edit distance based suggestions, we provide at most one such suggestion.

View file

@ -1995,6 +1995,7 @@ symbols! {
sub_assign,
sub_with_overflow,
suggestion,
supertrait_item_shadowing,
surface_async_drop_in_place,
sym,
sync,

View file

@ -0,0 +1,22 @@
trait Sup {
fn method(&self) {}
}
trait Trait: Sup {
fn method(&self) {}
}
impl Sup for i32 {}
impl Trait for i32 {}
fn poly<T: Trait>(x: T) {
x.method();
//~^ ERROR multiple applicable items in scope
}
fn concrete() {
1.method();
//~^ ERROR multiple applicable items in scope
}
fn main() {}

View file

@ -0,0 +1,57 @@
error[E0034]: multiple applicable items in scope
--> $DIR/feature-gate-supertrait-item-shadowing.rs:13:7
|
LL | x.method();
| ^^^^^^ multiple `method` found
|
note: candidate #1 is defined in the trait `Sup`
--> $DIR/feature-gate-supertrait-item-shadowing.rs:2:5
|
LL | fn method(&self) {}
| ^^^^^^^^^^^^^^^^
note: candidate #2 is defined in the trait `Trait`
--> $DIR/feature-gate-supertrait-item-shadowing.rs:6:5
|
LL | fn method(&self) {}
| ^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL - x.method();
LL + Sup::method(&x);
|
help: disambiguate the method for candidate #2
|
LL - x.method();
LL + Trait::method(&x);
|
error[E0034]: multiple applicable items in scope
--> $DIR/feature-gate-supertrait-item-shadowing.rs:18:7
|
LL | 1.method();
| ^^^^^^ multiple `method` found
|
note: candidate #1 is defined in an impl of the trait `Sup` for the type `i32`
--> $DIR/feature-gate-supertrait-item-shadowing.rs:2:5
|
LL | fn method(&self) {}
| ^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `Trait` for the type `i32`
--> $DIR/feature-gate-supertrait-item-shadowing.rs:6:5
|
LL | fn method(&self) {}
| ^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL - 1.method();
LL + Sup::method(&1);
|
help: disambiguate the method for candidate #2
|
LL - 1.method();
LL + Trait::method(&1);
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0034`.