Auto merge of #125782 - compiler-errors:supertrait-item-shadowing, r=BoxyUwU

Implement RFC 3624 `supertrait_item_shadowing` (v2)

Implements RFC 3624 and the associated lint in the RFC.

Implements:
* Shadowing algorithm
* Lint for call-site shadowing (allow by default, gated)
* Lint for definition-site shadowing (allow by default, gated)

Tracking:
- https://github.com/rust-lang/rust/issues/89151

cc `@Amanieu` and https://github.com/rust-lang/rfcs/pull/3624 and #89151
This commit is contained in:
bors 2025-02-13 08:52:01 +00:00
commit 3cb02729ab
36 changed files with 1071 additions and 3 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

@ -506,6 +506,12 @@ hir_analysis_specialization_trait = implementing `rustc_specialization_trait` tr
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
hir_analysis_supertrait_item_multiple_shadowee = items from several supertraits are shadowed: {$traits}
hir_analysis_supertrait_item_shadowee = item from `{$supertrait}` is shadowed by a subtrait item
hir_analysis_supertrait_item_shadowing = trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait
hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
.note = this item must mention the opaque type in its signature in order to be able to register hidden types

View File

@ -12,6 +12,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{AmbigArg, ItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_lint_defs::builtin::SUPERTRAIT_ITEM_SHADOWING_DEFINITION;
use rustc_macros::LintDiagnostic;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::query::Providers;
@ -388,7 +389,12 @@ fn check_trait_item<'tcx>(
hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span),
_ => (None, trait_item.span),
};
check_dyn_incompatible_self_trait_by_name(tcx, trait_item);
// Check that an item definition in a subtrait is shadowing a supertrait item.
lint_item_shadowing_supertrait_item(tcx, def_id);
let mut res = check_associated_item(tcx, def_id, span, method_sig);
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) {
@ -898,6 +904,45 @@ fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitI
}
}
fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_id: LocalDefId) {
let item_name = tcx.item_name(trait_item_def_id.to_def_id());
let trait_def_id = tcx.local_parent(trait_item_def_id);
let shadowed: Vec<_> = traits::supertrait_def_ids(tcx, trait_def_id.to_def_id())
.skip(1)
.flat_map(|supertrait_def_id| {
tcx.associated_items(supertrait_def_id).filter_by_name_unhygienic(item_name)
})
.collect();
if !shadowed.is_empty() {
let shadowee = if let [shadowed] = shadowed[..] {
errors::SupertraitItemShadowee::Labeled {
span: tcx.def_span(shadowed.def_id),
supertrait: tcx.item_name(shadowed.trait_container(tcx).unwrap()),
}
} else {
let (traits, spans): (Vec<_>, Vec<_>) = shadowed
.iter()
.map(|item| {
(tcx.item_name(item.trait_container(tcx).unwrap()), tcx.def_span(item.def_id))
})
.unzip();
errors::SupertraitItemShadowee::Several { traits: traits.into(), spans: spans.into() }
};
tcx.emit_node_span_lint(
SUPERTRAIT_ITEM_SHADOWING_DEFINITION,
tcx.local_def_id_to_hir_id(trait_item_def_id),
tcx.def_span(trait_item_def_id),
errors::SupertraitItemShadowing {
item: item_name,
subtrait: tcx.item_name(trait_def_id.to_def_id()),
shadowee,
},
);
}
}
fn check_impl_item<'tcx>(
tcx: TyCtxt<'tcx>,
impl_item: &'tcx hir::ImplItem<'tcx>,

View File

@ -3,7 +3,8 @@
use rustc_abi::ExternAbi;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan,
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
MultiSpan,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
@ -1733,3 +1734,28 @@ pub(crate) struct RegisterTypeUnstable<'a> {
pub span: Span,
pub ty: Ty<'a>,
}
#[derive(LintDiagnostic)]
#[diag(hir_analysis_supertrait_item_shadowing)]
pub(crate) struct SupertraitItemShadowing {
pub item: Symbol,
pub subtrait: Symbol,
#[subdiagnostic]
pub shadowee: SupertraitItemShadowee,
}
#[derive(Subdiagnostic)]
pub(crate) enum SupertraitItemShadowee {
#[note(hir_analysis_supertrait_item_shadowee)]
Labeled {
#[primary_span]
span: Span,
supertrait: Symbol,
},
#[note(hir_analysis_supertrait_item_multiple_shadowee)]
Several {
#[primary_span]
spans: MultiSpan,
traits: DiagSymbolList,
},
}

View File

@ -192,6 +192,14 @@ hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `
hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead
hir_typeck_supertrait_item_multiple_shadowee = items from several supertraits are shadowed: {$traits}
hir_typeck_supertrait_item_shadowee = item from `{$supertrait}` is shadowed by a subtrait item
hir_typeck_supertrait_item_shadower = item from `{$subtrait}` shadows a supertrait item
hir_typeck_supertrait_item_shadowing = trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait
hir_typeck_trivial_cast = trivial {$numeric ->
[true] numeric cast
*[false] cast

View File

@ -868,3 +868,38 @@ pub(crate) struct ReplaceCommaWithSemicolon {
pub comma_span: Span,
pub descr: &'static str,
}
#[derive(LintDiagnostic)]
#[diag(hir_typeck_supertrait_item_shadowing)]
pub(crate) struct SupertraitItemShadowing {
pub item: Symbol,
pub subtrait: Symbol,
#[subdiagnostic]
pub shadower: SupertraitItemShadower,
#[subdiagnostic]
pub shadowee: SupertraitItemShadowee,
}
#[derive(Subdiagnostic)]
#[note(hir_typeck_supertrait_item_shadower)]
pub(crate) struct SupertraitItemShadower {
pub subtrait: Symbol,
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
pub(crate) enum SupertraitItemShadowee {
#[note(hir_typeck_supertrait_item_shadowee)]
Labeled {
#[primary_span]
span: Span,
supertrait: Symbol,
},
#[note(hir_typeck_supertrait_item_multiple_shadowee)]
Several {
#[primary_span]
spans: MultiSpan,
traits: DiagSymbolList,
},
}

View File

@ -10,6 +10,7 @@ use rustc_hir_analysis::hir_ty_lowering::{
FeedConstTy, GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
use rustc_lint::builtin::SUPERTRAIT_ITEM_SHADOWING_USAGE;
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
@ -24,6 +25,7 @@ use rustc_trait_selection::traits;
use tracing::debug;
use super::{MethodCallee, probe};
use crate::errors::{SupertraitItemShadowee, SupertraitItemShadower, SupertraitItemShadowing};
use crate::{FnCtxt, callee};
struct ConfirmContext<'a, 'tcx> {
@ -141,7 +143,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let method_sig = ty::Binder::dummy(method_sig);
// Make sure nobody calls `drop()` explicitly.
self.enforce_illegal_method_limitations(pick);
self.check_for_illegal_method_calls(pick);
// Lint when an item is shadowing a supertrait item.
self.lint_shadowed_supertrait_items(pick, segment);
// Add any trait/regions obligations specified on the method's type parameters.
// We won't add these if we encountered an illegal sized bound, so that we can use
@ -656,7 +661,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
})
}
fn enforce_illegal_method_limitations(&self, pick: &probe::Pick<'_>) {
fn check_for_illegal_method_calls(&self, pick: &probe::Pick<'_>) {
// Disallow calls to the method `drop` defined in the `Drop` trait.
if let Some(trait_def_id) = pick.item.trait_container(self.tcx) {
if let Err(e) = callee::check_legal_trait_for_method_call(
@ -672,6 +677,45 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
}
}
fn lint_shadowed_supertrait_items(
&self,
pick: &probe::Pick<'_>,
segment: &hir::PathSegment<'tcx>,
) {
if pick.shadowed_candidates.is_empty() {
return;
}
let shadower_span = self.tcx.def_span(pick.item.def_id);
let subtrait = self.tcx.item_name(pick.item.trait_container(self.tcx).unwrap());
let shadower = SupertraitItemShadower { span: shadower_span, subtrait };
let shadowee = if let [shadowee] = &pick.shadowed_candidates[..] {
let shadowee_span = self.tcx.def_span(shadowee.def_id);
let supertrait = self.tcx.item_name(shadowee.trait_container(self.tcx).unwrap());
SupertraitItemShadowee::Labeled { span: shadowee_span, supertrait }
} else {
let (traits, spans): (Vec<_>, Vec<_>) = pick
.shadowed_candidates
.iter()
.map(|item| {
(
self.tcx.item_name(item.trait_container(self.tcx).unwrap()),
self.tcx.def_span(item.def_id),
)
})
.unzip();
SupertraitItemShadowee::Several { traits: traits.into(), spans: spans.into() }
};
self.tcx.emit_node_span_lint(
SUPERTRAIT_ITEM_SHADOWING_USAGE,
segment.hir_id,
segment.ident.span,
SupertraitItemShadowing { shadower, shadowee, item: segment.ident.name, subtrait },
);
}
fn upcast(
&mut self,
source_trait_ref: ty::PolyTraitRef<'tcx>,

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};
@ -224,6 +226,9 @@ pub(crate) struct Pick<'tcx> {
/// to identify this method. Used only for deshadowing errors.
/// Only applies for inherent impls.
pub receiver_steps: Option<usize>,
/// Candidates that were shadowed by supertraits.
pub shadowed_candidates: Vec<ty::AssocItem>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -1634,6 +1639,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
if applicable_candidates.len() > 1 {
// We collapse to a subtrait pick *after* filtering unstable candidates
// to make sure we don't prefer a unstable subtrait method over a stable
// supertrait method.
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));
}
}
let sources = candidates.iter().map(|p| self.candidate_source(p, self_ty)).collect();
return Some(Err(MethodError::Ambiguity(sources)));
}
@ -1672,6 +1688,7 @@ impl<'tcx> Pick<'tcx> {
self_ty,
unstable_candidates: _,
receiver_steps: _,
shadowed_candidates: _,
} = *self;
self_ty != other.self_ty || def_id != other.item.def_id
}
@ -2081,6 +2098,83 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self_ty,
unstable_candidates: vec![],
receiver_steps: None,
shadowed_candidates: vec![],
})
}
/// 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_candidate = probes[0].0;
let mut child_trait = child_candidate.item.trait_container(self.tcx)?;
let mut supertraits: SsoHashSet<_> = supertrait_def_ids(self.tcx, child_trait).collect();
let mut remaining_candidates: Vec<_> = probes[1..].iter().map(|&(p, _)| p).collect();
while !remaining_candidates.is_empty() {
let mut made_progress = false;
let mut next_round = vec![];
for remaining_candidate in remaining_candidates {
let remaining_trait = remaining_candidate.item.trait_container(self.tcx)?;
if supertraits.contains(&remaining_trait) {
made_progress = true;
continue;
}
// This pick is not a supertrait of the `child_pick`.
// Check if it's a subtrait of the `child_pick`, 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<_> =
supertrait_def_ids(self.tcx, remaining_trait).collect();
if remaining_trait_supertraits.contains(&child_trait) {
child_candidate = remaining_candidate;
child_trait = remaining_trait;
supertraits = remaining_trait_supertraits;
made_progress = true;
continue;
}
// `child_pick` is not a supertrait of this pick.
// 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_candidate);
}
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(Pick {
item: child_candidate.item,
kind: TraitPick,
import_ids: child_candidate.import_ids.clone(),
autoderefs: 0,
autoref_or_ptr_adjustment: None,
self_ty,
unstable_candidates: vec![],
shadowed_candidates: probes
.iter()
.map(|(c, _)| c.item)
.filter(|item| item.def_id != child_candidate.item.def_id)
.collect(),
receiver_steps: None,
})
}
@ -2378,6 +2472,7 @@ impl<'tcx> Candidate<'tcx> {
InherentImplCandidate { receiver_steps, .. } => Some(receiver_steps),
_ => None,
},
shadowed_candidates: vec![],
}
}
}

View File

@ -101,6 +101,8 @@ declare_lint_pass! {
SINGLE_USE_LIFETIMES,
SOFT_UNSTABLE,
STABLE_FEATURES,
SUPERTRAIT_ITEM_SHADOWING_DEFINITION,
SUPERTRAIT_ITEM_SHADOWING_USAGE,
TAIL_EXPR_DROP_ORDER,
TEST_UNSTABLE_LINT,
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
@ -4916,6 +4918,87 @@ declare_lint! {
};
}
declare_lint! {
/// The `supertrait_item_shadowing_usage` lint detects when the
/// usage of an item that is provided by both a subtrait and supertrait
/// is shadowed, preferring the subtrait.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![feature(supertrait_item_shadowing)]
/// #![deny(supertrait_item_shadowing_usage)]
///
/// trait Upstream {
/// fn hello(&self) {}
/// }
/// impl<T> Upstream for T {}
///
/// trait Downstream: Upstream {
/// fn hello(&self) {}
/// }
/// impl<T> Downstream for T {}
///
/// struct MyType;
/// MyType.hello();
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// RFC 3624 specified a heuristic in which a supertrait item would be
/// shadowed by a subtrait item when ambiguity occurs during item
/// selection. In order to mitigate side-effects of this happening
/// silently, this lint detects these cases when users want to deny them
/// or fix the call sites.
pub SUPERTRAIT_ITEM_SHADOWING_USAGE,
// FIXME(supertrait_item_shadowing): It is not decided if this should
// warn by default at the call site.
Allow,
"detects when a supertrait item is shadowed by a subtrait item",
@feature_gate = supertrait_item_shadowing;
}
declare_lint! {
/// The `supertrait_item_shadowing_definition` lint detects when the
/// definition of an item that is provided by both a subtrait and
/// supertrait is shadowed, preferring the subtrait.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![feature(supertrait_item_shadowing)]
/// #![deny(supertrait_item_shadowing_definition)]
///
/// trait Upstream {
/// fn hello(&self) {}
/// }
/// impl<T> Upstream for T {}
///
/// trait Downstream: Upstream {
/// fn hello(&self) {}
/// }
/// impl<T> Downstream for T {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// RFC 3624 specified a heuristic in which a supertrait item would be
/// shadowed by a subtrait item when ambiguity occurs during item
/// selection. In order to mitigate side-effects of this happening
/// silently, this lint detects these cases when users want to deny them
/// or fix their trait definitions.
pub SUPERTRAIT_ITEM_SHADOWING_DEFINITION,
// FIXME(supertrait_item_shadowing): It is not decided if this should
// warn by default at the usage site.
Allow,
"detects when a supertrait item is shadowed by a subtrait item",
@feature_gate = supertrait_item_shadowing;
}
declare_lint! {
/// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer
/// transmute in const functions and associated constants.

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`.

View File

@ -0,0 +1,23 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![allow(dead_code)]
trait A {
const CONST: i32;
}
impl<T> A for T {
const CONST: i32 = 1;
}
trait B: A {
const CONST: i32;
}
impl<T> B for T {
const CONST: i32 = 2;
}
fn main() {
println!("{}", i32::CONST);
}

View File

@ -0,0 +1 @@
2

View File

@ -0,0 +1,34 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![warn(supertrait_item_shadowing_usage)]
#![warn(supertrait_item_shadowing_definition)]
#![allow(dead_code)]
trait A {
fn hello(&self) {
println!("A");
}
}
impl<T> A for T {}
trait B {
fn hello(&self) {
println!("B");
}
}
impl<T> B for T {}
trait C: A + B {
fn hello(&self) {
//~^ WARN trait item `hello` from `C` shadows identically named item
println!("C");
}
}
impl<T> C for T {}
fn main() {
().hello();
//~^ WARN trait item `hello` from `C` shadows identically named item from supertrait
}

View File

@ -0,0 +1,47 @@
warning: trait item `hello` from `C` shadows identically named item from supertrait
--> $DIR/common-ancestor-2.rs:24:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
|
note: items from several supertraits are shadowed: `B` and `A`
--> $DIR/common-ancestor-2.rs:10:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor-2.rs:6:9
|
LL | #![warn(supertrait_item_shadowing_definition)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: trait item `hello` from `C` shadows identically named item from supertrait
--> $DIR/common-ancestor-2.rs:32:8
|
LL | ().hello();
| ^^^^^
|
note: item from `C` shadows a supertrait item
--> $DIR/common-ancestor-2.rs:24:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: items from several supertraits are shadowed: `A` and `B`
--> $DIR/common-ancestor-2.rs:10:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor-2.rs:5:9
|
LL | #![warn(supertrait_item_shadowing_usage)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: 2 warnings emitted

View File

@ -0,0 +1,44 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![warn(supertrait_item_shadowing_usage)]
#![warn(supertrait_item_shadowing_definition)]
#![allow(dead_code)]
trait A {
fn hello(&self) {
println!("A");
}
}
impl<T> A for T {}
trait B {
fn hello(&self) {
println!("B");
}
}
impl<T> B for T {}
trait C: A + B {
fn hello(&self) {
//~^ WARN trait item `hello` from `C` shadows identically named item
println!("C");
}
}
impl<T> C for T {}
// `D` extends `C` which extends `B` and `A`
trait D: C {
fn hello(&self) {
//~^ WARN trait item `hello` from `D` shadows identically named item
println!("D");
}
}
impl<T> D for T {}
fn main() {
().hello();
//~^ WARN trait item `hello` from `D` shadows identically named item from supertrait
}

View File

@ -0,0 +1,68 @@
warning: trait item `hello` from `C` shadows identically named item from supertrait
--> $DIR/common-ancestor-3.rs:24:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
|
note: items from several supertraits are shadowed: `B` and `A`
--> $DIR/common-ancestor-3.rs:10:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor-3.rs:6:9
|
LL | #![warn(supertrait_item_shadowing_definition)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: trait item `hello` from `D` shadows identically named item from supertrait
--> $DIR/common-ancestor-3.rs:34:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
|
note: items from several supertraits are shadowed: `C`, `B`, and `A`
--> $DIR/common-ancestor-3.rs:10:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
warning: trait item `hello` from `D` shadows identically named item from supertrait
--> $DIR/common-ancestor-3.rs:42:8
|
LL | ().hello();
| ^^^^^
|
note: item from `D` shadows a supertrait item
--> $DIR/common-ancestor-3.rs:34:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: items from several supertraits are shadowed: `A`, `B`, and `C`
--> $DIR/common-ancestor-3.rs:10:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
...
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor-3.rs:5:9
|
LL | #![warn(supertrait_item_shadowing_usage)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: 3 warnings emitted

View File

@ -0,0 +1,27 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![warn(supertrait_item_shadowing_usage)]
#![warn(supertrait_item_shadowing_definition)]
#![allow(dead_code)]
trait A {
fn hello(&self) {
println!("A");
}
}
impl<T> A for T {}
trait B: A {
fn hello(&self) {
//~^ WARN trait item `hello` from `B` shadows identically named item
println!("B");
}
}
impl<T> B for T {}
fn main() {
().hello();
//~^ WARN trait item `hello` from `B` shadows identically named item from supertrait
}

View File

@ -0,0 +1,41 @@
warning: trait item `hello` from `B` shadows identically named item from supertrait
--> $DIR/common-ancestor.rs:17:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
|
note: item from `A` is shadowed by a subtrait item
--> $DIR/common-ancestor.rs:10:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor.rs:6:9
|
LL | #![warn(supertrait_item_shadowing_definition)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: trait item `hello` from `B` shadows identically named item from supertrait
--> $DIR/common-ancestor.rs:25:8
|
LL | ().hello();
| ^^^^^
|
note: item from `B` shadows a supertrait item
--> $DIR/common-ancestor.rs:17:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: item from `A` is shadowed by a subtrait item
--> $DIR/common-ancestor.rs:10:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/common-ancestor.rs:5:9
|
LL | #![warn(supertrait_item_shadowing_usage)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: 2 warnings emitted

View File

@ -0,0 +1,18 @@
#![feature(supertrait_item_shadowing)]
#![deny(supertrait_item_shadowing_definition)]
trait SuperSuper {
fn method();
}
trait Super: SuperSuper {
fn method();
//~^ ERROR trait item `method` from `Super` shadows identically named item
}
trait Sub: Super {
fn method();
//~^ ERROR trait item `method` from `Sub` shadows identically named item
}
fn main() {}

View File

@ -0,0 +1,34 @@
error: trait item `method` from `Super` shadows identically named item from supertrait
--> $DIR/definition-site.rs:9:5
|
LL | fn method();
| ^^^^^^^^^^^^
|
note: item from `SuperSuper` is shadowed by a subtrait item
--> $DIR/definition-site.rs:5:5
|
LL | fn method();
| ^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/definition-site.rs:2:9
|
LL | #![deny(supertrait_item_shadowing_definition)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait item `method` from `Sub` shadows identically named item from supertrait
--> $DIR/definition-site.rs:14:5
|
LL | fn method();
| ^^^^^^^^^^^^
|
note: items from several supertraits are shadowed: `Super` and `SuperSuper`
--> $DIR/definition-site.rs:5:5
|
LL | fn method();
| ^^^^^^^^^^^^
...
LL | fn method();
| ^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,26 @@
#![feature(supertrait_item_shadowing)]
#![warn(supertrait_item_shadowing_usage)]
#![warn(supertrait_item_shadowing_definition)]
struct W<T>(T);
trait Upstream {
fn hello(&self) {}
}
impl<T> Upstream for T {}
trait Downstream: Upstream {
fn hello(&self) {}
//~^ WARN trait item `hello` from `Downstream` shadows identically named item
}
impl<T> Downstream for W<T> where T: Foo {}
trait Foo {}
fn main() {
let x = W(Default::default());
x.hello();
//~^ ERROR the trait bound `i32: Foo` is not satisfied
//~| WARN trait item `hello` from `Downstream` shadows identically named item from supertrait
let _: i32 = x.0;
}

View File

@ -0,0 +1,59 @@
warning: trait item `hello` from `Downstream` shadows identically named item from supertrait
--> $DIR/false-subtrait-after-inference.rs:13:5
|
LL | fn hello(&self) {}
| ^^^^^^^^^^^^^^^
|
note: item from `Upstream` is shadowed by a subtrait item
--> $DIR/false-subtrait-after-inference.rs:8:5
|
LL | fn hello(&self) {}
| ^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/false-subtrait-after-inference.rs:3:9
|
LL | #![warn(supertrait_item_shadowing_definition)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: trait item `hello` from `Downstream` shadows identically named item from supertrait
--> $DIR/false-subtrait-after-inference.rs:22:7
|
LL | x.hello();
| ^^^^^
|
note: item from `Downstream` shadows a supertrait item
--> $DIR/false-subtrait-after-inference.rs:13:5
|
LL | fn hello(&self) {}
| ^^^^^^^^^^^^^^^
note: item from `Upstream` is shadowed by a subtrait item
--> $DIR/false-subtrait-after-inference.rs:8:5
|
LL | fn hello(&self) {}
| ^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/false-subtrait-after-inference.rs:2:9
|
LL | #![warn(supertrait_item_shadowing_usage)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/false-subtrait-after-inference.rs:22:7
|
LL | x.hello();
| ^^^^^ the trait `Foo` is not implemented for `i32`
|
help: this trait has no implementations, consider adding one
--> $DIR/false-subtrait-after-inference.rs:18:1
|
LL | trait Foo {}
| ^^^^^^^^^
note: required for `W<i32>` to implement `Downstream`
--> $DIR/false-subtrait-after-inference.rs:16:9
|
LL | impl<T> Downstream for W<T> where T: Foo {}
| ^^^^^^^^^^ ^^^^ --- unsatisfied trait bound introduced here
error: aborting due to 1 previous error; 2 warnings emitted
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,37 @@
#![feature(supertrait_item_shadowing)]
trait A {
fn hello(&self) {
println!("A");
}
}
impl<T> A for T {}
trait B {
fn hello(&self) {
println!("B");
}
}
impl<T> B for T {}
trait C: A + B {
fn hello(&self) {
println!("C");
}
}
impl<T> C for T {}
// Since `D` is not a subtrait of `C`,
// we have no obvious lower bound.
trait D: B {
fn hello(&self) {
println!("D");
}
}
impl<T> D for T {}
fn main() {
().hello();
//~^ ERROR multiple applicable items in scope
}

View File

@ -0,0 +1,50 @@
error[E0034]: multiple applicable items in scope
--> $DIR/no-common-ancestor-2.rs:35:8
|
LL | ().hello();
| ^^^^^ multiple `hello` found
|
note: candidate #1 is defined in an impl of the trait `A` for the type `T`
--> $DIR/no-common-ancestor-2.rs:4:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `B` for the type `T`
--> $DIR/no-common-ancestor-2.rs:11:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: candidate #3 is defined in an impl of the trait `C` for the type `T`
--> $DIR/no-common-ancestor-2.rs:18:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: candidate #4 is defined in an impl of the trait `D` for the type `T`
--> $DIR/no-common-ancestor-2.rs:28:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL - ().hello();
LL + A::hello(&());
|
help: disambiguate the method for candidate #2
|
LL - ().hello();
LL + B::hello(&());
|
help: disambiguate the method for candidate #3
|
LL - ().hello();
LL + C::hello(&());
|
help: disambiguate the method for candidate #4
|
LL - ().hello();
LL + D::hello(&());
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0034`.

View File

@ -0,0 +1,20 @@
#![feature(supertrait_item_shadowing)]
trait A {
fn hello(&self) {
println!("A");
}
}
impl<T> A for T {}
trait B {
fn hello(&self) {
println!("B");
}
}
impl<T> B for T {}
fn main() {
().hello();
//~^ ERROR multiple applicable items in scope
}

View File

@ -0,0 +1,30 @@
error[E0034]: multiple applicable items in scope
--> $DIR/no-common-ancestor.rs:18:8
|
LL | ().hello();
| ^^^^^ multiple `hello` found
|
note: candidate #1 is defined in an impl of the trait `A` for the type `T`
--> $DIR/no-common-ancestor.rs:4:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `B` for the type `T`
--> $DIR/no-common-ancestor.rs:11:5
|
LL | fn hello(&self) {
| ^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL - ().hello();
LL + A::hello(&());
|
help: disambiguate the method for candidate #2
|
LL - ().hello();
LL + B::hello(&());
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0034`.

View File

@ -0,0 +1,25 @@
//@ run-pass
//@ check-run-results
#![feature(supertrait_item_shadowing)]
#![allow(dead_code)]
mod out_of_scope {
pub trait Subtrait: super::Supertrait {
fn hello(&self) {
println!("subtrait");
}
}
impl<T> Subtrait for T {}
}
trait Supertrait {
fn hello(&self) {
println!("supertrait");
}
}
impl<T> Supertrait for T {}
fn main() {
().hello();
}

View File

@ -0,0 +1 @@
supertrait

View File

@ -0,0 +1,26 @@
//@ check-pass
// Make sure we don't prefer a subtrait that we would've otherwise eliminated
// in `consider_probe` during method probing.
#![feature(supertrait_item_shadowing)]
#![allow(dead_code)]
struct W<T>(T);
trait Upstream {
fn hello(&self) {}
}
impl<T> Upstream for T {}
trait Downstream: Upstream {
fn hello(&self) {}
}
impl<T> Downstream for W<T> where T: Foo {}
trait Foo {}
fn main() {
let x = W(1i32);
x.hello();
}

View File

@ -0,0 +1,29 @@
//@ run-pass
//@ check-run-results
// Makes sure we can shadow with type-dependent method syntax.
#![feature(supertrait_item_shadowing)]
#![allow(dead_code)]
trait A {
fn hello() {
println!("A");
}
}
impl<T> A for T {}
trait B: A {
fn hello() {
println!("B");
}
}
impl<T> B for T {}
fn foo<T>() {
T::hello();
}
fn main() {
foo::<()>();
}

View File

@ -0,0 +1 @@
B