diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1a216ebf117c6..e3daa6a794e1e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -618,6 +618,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 the use of `#[target_feature]` on safe functions. (unstable, target_feature_11, "1.45.0", Some(69098)), /// Allows using `#[thread_local]` on `static` items. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index be4004f5904cc..648725e4460b5 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -497,6 +497,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 diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index cd19993f93780..5354f1ba0954d 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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; @@ -377,7 +378,10 @@ 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_item_shadowed_by_supertrait(tcx, def_id); + let mut res = check_associated_item(tcx, def_id, span, method_sig); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { @@ -892,6 +896,45 @@ fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitI } } +fn check_item_shadowed_by_supertrait<'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>, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a0f365142baed..936baecf057e2 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -2,7 +2,8 @@ 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; @@ -1702,3 +1703,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, + }, +} diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 0f424a39840a3..a994b31aeb437 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -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 diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 052adaa69b2b9..de88cb6d0222f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -866,3 +866,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, + }, +} diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 880ee83c80a06..5acdc4d15a3c4 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -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> { @@ -143,6 +145,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Make sure nobody calls `drop()` explicitly. self.enforce_illegal_method_limitations(pick); + self.enforce_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 // a custom error in that case. @@ -665,6 +669,45 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } } + fn enforce_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>, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index b9d1f93bfb8e4..a2f1b103f3197 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -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, + + /// Candidates that were shadowed by supertraits. + pub shadowed_candidates: Vec, } #[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> { + 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![], } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9fc527a6a3ab3..c68eff3f64837 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -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, @@ -4966,6 +4968,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 + /// #![feature(supertrait_item_shadowing)] + /// #![deny(supertrait_item_shadowing_usage)] + /// + /// trait Upstream { + /// fn hello(&self) {} + /// } + /// impl Upstream for T {} + /// + /// trait Downstream: Upstream { + /// fn hello(&self) {} + /// } + /// impl 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_usage` lint detects when the + /// definition of an item that is provided by both a subtrait and + /// supertrait is shadowed, preferring the subtrait. + /// + /// ### Example + /// + /// ```rust + /// #![feature(supertrait_item_shadowing)] + /// #![deny(supertrait_item_shadowing_definition)] + /// + /// trait Upstream { + /// fn hello(&self) {} + /// } + /// impl Upstream for T {} + /// + /// trait Downstream: Upstream { + /// fn hello(&self) {} + /// } + /// impl 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. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f5ce5dbc9d66a..3e0861c437bc1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1978,6 +1978,7 @@ symbols! { sub_assign, sub_with_overflow, suggestion, + supertrait_item_shadowing, surface_async_drop_in_place, sym, sync, diff --git a/tests/ui/feature-gates/feature-gate-supertrait-item-shadowing.rs b/tests/ui/feature-gates/feature-gate-supertrait-item-shadowing.rs new file mode 100644 index 0000000000000..218d2eefeaff7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-supertrait-item-shadowing.rs @@ -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(x: T) { + x.method(); + //~^ ERROR multiple applicable items in scope +} + +fn concrete() { + 1.method(); + //~^ ERROR multiple applicable items in scope +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-supertrait-item-shadowing.stderr b/tests/ui/feature-gates/feature-gate-supertrait-item-shadowing.stderr new file mode 100644 index 0000000000000..6c01ec39cc247 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-supertrait-item-shadowing.stderr @@ -0,0 +1,53 @@ +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 | Sup::method(&x); + | ~~~~~~~~~~~~~~~ +help: disambiguate the method for candidate #2 + | +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 | Sup::method(&1); + | ~~~~~~~~~~~~~~~ +help: disambiguate the method for candidate #2 + | +LL | Trait::method(&1); + | ~~~~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/supertrait-shadowing/assoc-const.rs b/tests/ui/methods/supertrait-shadowing/assoc-const.rs new file mode 100644 index 0000000000000..a542ce7d326d1 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/assoc-const.rs @@ -0,0 +1,23 @@ +//@ run-pass +//@ check-run-results + +#![feature(supertrait_item_shadowing)] +#![allow(dead_code)] + +trait A { + const CONST: i32; +} +impl A for T { + const CONST: i32 = 1; +} + +trait B: A { + const CONST: i32; +} +impl B for T { + const CONST: i32 = 2; +} + +fn main() { + println!("{}", i32::CONST); +} diff --git a/tests/ui/methods/supertrait-shadowing/assoc-const.run.stdout b/tests/ui/methods/supertrait-shadowing/assoc-const.run.stdout new file mode 100644 index 0000000000000..0cfbf08886fca --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/assoc-const.run.stdout @@ -0,0 +1 @@ +2 diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor-2.rs b/tests/ui/methods/supertrait-shadowing/common-ancestor-2.rs new file mode 100644 index 0000000000000..cecf6dccf9d16 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor-2.rs @@ -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 A for T {} + +trait B { + fn hello(&self) { + println!("B"); + } +} +impl B for T {} + +trait C: A + B { + fn hello(&self) { + //~^ WARN trait item `hello` from `C` shadows identically named item + println!("C"); + } +} +impl C for T {} + +fn main() { + ().hello(); + //~^ WARN trait item `hello` from `C` shadows identically named item from supertrait +} diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor-2.run.stdout b/tests/ui/methods/supertrait-shadowing/common-ancestor-2.run.stdout new file mode 100644 index 0000000000000..3cc58df837521 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor-2.run.stdout @@ -0,0 +1 @@ +C diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor-2.stderr b/tests/ui/methods/supertrait-shadowing/common-ancestor-2.stderr new file mode 100644 index 0000000000000..934d5a0f7cfd3 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor-2.stderr @@ -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 + diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor-3.rs b/tests/ui/methods/supertrait-shadowing/common-ancestor-3.rs new file mode 100644 index 0000000000000..040fa9aab3987 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor-3.rs @@ -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 A for T {} + +trait B { + fn hello(&self) { + println!("B"); + } +} +impl B for T {} + +trait C: A + B { + fn hello(&self) { + //~^ WARN trait item `hello` from `C` shadows identically named item + println!("C"); + } +} +impl 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 D for T {} + +fn main() { + ().hello(); + //~^ WARN trait item `hello` from `D` shadows identically named item from supertrait +} diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor-3.run.stdout b/tests/ui/methods/supertrait-shadowing/common-ancestor-3.run.stdout new file mode 100644 index 0000000000000..178481050188c --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor-3.run.stdout @@ -0,0 +1 @@ +D diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor-3.stderr b/tests/ui/methods/supertrait-shadowing/common-ancestor-3.stderr new file mode 100644 index 0000000000000..28e44a2ff209a --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor-3.stderr @@ -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 + diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor.rs b/tests/ui/methods/supertrait-shadowing/common-ancestor.rs new file mode 100644 index 0000000000000..8e67c93536755 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor.rs @@ -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 A for T {} + +trait B: A { + fn hello(&self) { + //~^ WARN trait item `hello` from `B` shadows identically named item + println!("B"); + } +} +impl B for T {} + +fn main() { + ().hello(); + //~^ WARN trait item `hello` from `B` shadows identically named item from supertrait +} diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor.run.stdout b/tests/ui/methods/supertrait-shadowing/common-ancestor.run.stdout new file mode 100644 index 0000000000000..223b7836fb19f --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor.run.stdout @@ -0,0 +1 @@ +B diff --git a/tests/ui/methods/supertrait-shadowing/common-ancestor.stderr b/tests/ui/methods/supertrait-shadowing/common-ancestor.stderr new file mode 100644 index 0000000000000..f404fa6b53a35 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/common-ancestor.stderr @@ -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 + diff --git a/tests/ui/methods/supertrait-shadowing/definition-site.rs b/tests/ui/methods/supertrait-shadowing/definition-site.rs new file mode 100644 index 0000000000000..2768a6a6b2717 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/definition-site.rs @@ -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() {} diff --git a/tests/ui/methods/supertrait-shadowing/definition-site.stderr b/tests/ui/methods/supertrait-shadowing/definition-site.stderr new file mode 100644 index 0000000000000..f0bbf414a690c --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/definition-site.stderr @@ -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 + diff --git a/tests/ui/methods/supertrait-shadowing/false-subtrait-after-inference.rs b/tests/ui/methods/supertrait-shadowing/false-subtrait-after-inference.rs new file mode 100644 index 0000000000000..c3bc47e6740d8 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/false-subtrait-after-inference.rs @@ -0,0 +1,26 @@ +#![feature(supertrait_item_shadowing)] +#![warn(supertrait_item_shadowing_usage)] +#![warn(supertrait_item_shadowing_definition)] + +struct W(T); + +trait Upstream { + fn hello(&self) {} +} +impl Upstream for T {} + +trait Downstream: Upstream { + fn hello(&self) {} + //~^ WARN trait item `hello` from `Downstream` shadows identically named item +} +impl Downstream for W 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; +} diff --git a/tests/ui/methods/supertrait-shadowing/false-subtrait-after-inference.stderr b/tests/ui/methods/supertrait-shadowing/false-subtrait-after-inference.stderr new file mode 100644 index 0000000000000..47019ca7a320f --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/false-subtrait-after-inference.stderr @@ -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` to implement `Downstream` + --> $DIR/false-subtrait-after-inference.rs:16:9 + | +LL | impl Downstream for W 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`. diff --git a/tests/ui/methods/supertrait-shadowing/no-common-ancestor-2.rs b/tests/ui/methods/supertrait-shadowing/no-common-ancestor-2.rs new file mode 100644 index 0000000000000..2834ca31b7140 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/no-common-ancestor-2.rs @@ -0,0 +1,37 @@ +#![feature(supertrait_item_shadowing)] + +trait A { + fn hello(&self) { + println!("A"); + } +} +impl A for T {} + +trait B { + fn hello(&self) { + println!("B"); + } +} +impl B for T {} + +trait C: A + B { + fn hello(&self) { + println!("C"); + } +} +impl 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 D for T {} + +fn main() { + ().hello(); + //~^ ERROR multiple applicable items in scope +} diff --git a/tests/ui/methods/supertrait-shadowing/no-common-ancestor-2.stderr b/tests/ui/methods/supertrait-shadowing/no-common-ancestor-2.stderr new file mode 100644 index 0000000000000..8ac5e5b861763 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/no-common-ancestor-2.stderr @@ -0,0 +1,46 @@ +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 | A::hello(&()); + | ~~~~~~~~~~~~~ +help: disambiguate the method for candidate #2 + | +LL | B::hello(&()); + | ~~~~~~~~~~~~~ +help: disambiguate the method for candidate #3 + | +LL | C::hello(&()); + | ~~~~~~~~~~~~~ +help: disambiguate the method for candidate #4 + | +LL | D::hello(&()); + | ~~~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/supertrait-shadowing/no-common-ancestor.rs b/tests/ui/methods/supertrait-shadowing/no-common-ancestor.rs new file mode 100644 index 0000000000000..7323439d5884f --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/no-common-ancestor.rs @@ -0,0 +1,20 @@ +#![feature(supertrait_item_shadowing)] + +trait A { + fn hello(&self) { + println!("A"); + } +} +impl A for T {} + +trait B { + fn hello(&self) { + println!("B"); + } +} +impl B for T {} + +fn main() { + ().hello(); + //~^ ERROR multiple applicable items in scope +} diff --git a/tests/ui/methods/supertrait-shadowing/no-common-ancestor.stderr b/tests/ui/methods/supertrait-shadowing/no-common-ancestor.stderr new file mode 100644 index 0000000000000..c98b45335ea66 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/no-common-ancestor.stderr @@ -0,0 +1,28 @@ +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 | A::hello(&()); + | ~~~~~~~~~~~~~ +help: disambiguate the method for candidate #2 + | +LL | B::hello(&()); + | ~~~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/supertrait-shadowing/out-of-scope.rs b/tests/ui/methods/supertrait-shadowing/out-of-scope.rs new file mode 100644 index 0000000000000..bd263be59cc7d --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/out-of-scope.rs @@ -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 Subtrait for T {} +} + +trait Supertrait { + fn hello(&self) { + println!("supertrait"); + } +} +impl Supertrait for T {} + +fn main() { + ().hello(); +} diff --git a/tests/ui/methods/supertrait-shadowing/out-of-scope.run.stdout b/tests/ui/methods/supertrait-shadowing/out-of-scope.run.stdout new file mode 100644 index 0000000000000..1019e5f354346 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/out-of-scope.run.stdout @@ -0,0 +1 @@ +supertrait diff --git a/tests/ui/methods/supertrait-shadowing/trivially-false-subtrait.rs b/tests/ui/methods/supertrait-shadowing/trivially-false-subtrait.rs new file mode 100644 index 0000000000000..e44c7c18083d0 --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/trivially-false-subtrait.rs @@ -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); + +trait Upstream { + fn hello(&self) {} +} +impl Upstream for T {} + +trait Downstream: Upstream { + fn hello(&self) {} +} +impl Downstream for W where T: Foo {} + +trait Foo {} + +fn main() { + let x = W(1i32); + x.hello(); +} diff --git a/tests/ui/methods/supertrait-shadowing/type-dependent.rs b/tests/ui/methods/supertrait-shadowing/type-dependent.rs new file mode 100644 index 0000000000000..3af884fd52dcd --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/type-dependent.rs @@ -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 A for T {} + +trait B: A { + fn hello() { + println!("B"); + } +} +impl B for T {} + +fn foo() { + T::hello(); +} + +fn main() { + foo::<()>(); +} diff --git a/tests/ui/methods/supertrait-shadowing/type-dependent.run.stdout b/tests/ui/methods/supertrait-shadowing/type-dependent.run.stdout new file mode 100644 index 0000000000000..223b7836fb19f --- /dev/null +++ b/tests/ui/methods/supertrait-shadowing/type-dependent.run.stdout @@ -0,0 +1 @@ +B