mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
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:
commit
3cb02729ab
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>,
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -1995,6 +1995,7 @@ symbols! {
|
||||
sub_assign,
|
||||
sub_with_overflow,
|
||||
suggestion,
|
||||
supertrait_item_shadowing,
|
||||
surface_async_drop_in_place,
|
||||
sym,
|
||||
sync,
|
||||
|
@ -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() {}
|
@ -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`.
|
23
tests/ui/methods/supertrait-shadowing/assoc-const.rs
Normal file
23
tests/ui/methods/supertrait-shadowing/assoc-const.rs
Normal 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);
|
||||
}
|
@ -0,0 +1 @@
|
||||
2
|
34
tests/ui/methods/supertrait-shadowing/common-ancestor-2.rs
Normal file
34
tests/ui/methods/supertrait-shadowing/common-ancestor-2.rs
Normal 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
|
||||
}
|
@ -0,0 +1 @@
|
||||
C
|
@ -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
|
||||
|
44
tests/ui/methods/supertrait-shadowing/common-ancestor-3.rs
Normal file
44
tests/ui/methods/supertrait-shadowing/common-ancestor-3.rs
Normal 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
|
||||
}
|
@ -0,0 +1 @@
|
||||
D
|
@ -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
|
||||
|
27
tests/ui/methods/supertrait-shadowing/common-ancestor.rs
Normal file
27
tests/ui/methods/supertrait-shadowing/common-ancestor.rs
Normal 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
|
||||
}
|
@ -0,0 +1 @@
|
||||
B
|
41
tests/ui/methods/supertrait-shadowing/common-ancestor.stderr
Normal file
41
tests/ui/methods/supertrait-shadowing/common-ancestor.stderr
Normal 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
|
||||
|
18
tests/ui/methods/supertrait-shadowing/definition-site.rs
Normal file
18
tests/ui/methods/supertrait-shadowing/definition-site.rs
Normal 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() {}
|
34
tests/ui/methods/supertrait-shadowing/definition-site.stderr
Normal file
34
tests/ui/methods/supertrait-shadowing/definition-site.stderr
Normal 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
|
||||
|
@ -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;
|
||||
}
|
@ -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`.
|
@ -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
|
||||
}
|
@ -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`.
|
20
tests/ui/methods/supertrait-shadowing/no-common-ancestor.rs
Normal file
20
tests/ui/methods/supertrait-shadowing/no-common-ancestor.rs
Normal 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
|
||||
}
|
@ -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`.
|
25
tests/ui/methods/supertrait-shadowing/out-of-scope.rs
Normal file
25
tests/ui/methods/supertrait-shadowing/out-of-scope.rs
Normal 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();
|
||||
}
|
@ -0,0 +1 @@
|
||||
supertrait
|
@ -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();
|
||||
}
|
29
tests/ui/methods/supertrait-shadowing/type-dependent.rs
Normal file
29
tests/ui/methods/supertrait-shadowing/type-dependent.rs
Normal 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::<()>();
|
||||
}
|
@ -0,0 +1 @@
|
||||
B
|
Loading…
Reference in New Issue
Block a user