From 2a03c50e930fdded939ab7c86bc30e2e72ba9d9d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 22 Oct 2025 18:59:22 +0300 Subject: [PATCH 1/7] resolve: Do not consider traits from ambiguous imports to be in scope --- compiler/rustc_resolve/src/lib.rs | 2 +- tests/ui/imports/ambiguous-trait-in-scope.rs | 30 +++++++ .../imports/ambiguous-trait-in-scope.stderr | 83 +++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/ambiguous-trait-in-scope.rs create mode 100644 tests/ui/imports/ambiguous-trait-in-scope.stderr diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1636605b234f4..43e145c58ff66 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -703,7 +703,7 @@ impl<'ra> Module<'ra> { if traits.is_none() { let mut collected_traits = Vec::new(); self.for_each_child(resolver, |r, name, ns, binding| { - if ns != TypeNS { + if ns != TypeNS || binding.is_ambiguity_recursive() { return; } if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { diff --git a/tests/ui/imports/ambiguous-trait-in-scope.rs b/tests/ui/imports/ambiguous-trait-in-scope.rs new file mode 100644 index 0000000000000..ed51d88b82f0b --- /dev/null +++ b/tests/ui/imports/ambiguous-trait-in-scope.rs @@ -0,0 +1,30 @@ +mod m1 { + pub trait Trait { + fn method1(&self) {} + } + impl Trait for u8 {} +} +mod m2 { + pub trait Trait { + fn method2(&self) {} + } + impl Trait for u8 {} +} + +fn test1() { + // Create an ambiguous import for `Trait` in one order + use m1::*; + use m2::*; + 0u8.method1(); //~ ERROR no method named `method1` found for type `u8` in the current scope + 0u8.method2(); //~ ERROR no method named `method2` found for type `u8` in the current scope +} + +fn test2() { + // Create an ambiguous import for `Trait` in another order + use m2::*; + use m1::*; + 0u8.method1(); //~ ERROR no method named `method1` found for type `u8` in the current scope + 0u8.method2(); //~ ERROR no method named `method2` found for type `u8` in the current scope +} + +fn main() {} diff --git a/tests/ui/imports/ambiguous-trait-in-scope.stderr b/tests/ui/imports/ambiguous-trait-in-scope.stderr new file mode 100644 index 0000000000000..f41443270745e --- /dev/null +++ b/tests/ui/imports/ambiguous-trait-in-scope.stderr @@ -0,0 +1,83 @@ +error[E0599]: no method named `method1` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:18:9 + | +LL | fn method1(&self) {} + | ------- the method is available for `u8` here +... +LL | 0u8.method1(); + | ^^^^^^^ + | + = help: items from traits can only be used if the trait is in scope +help: trait `Trait` which provides `method1` is implemented but not in scope; perhaps you want to import it + | +LL + use m1::Trait; + | +help: there is a method `method2` with a similar name + | +LL - 0u8.method1(); +LL + 0u8.method2(); + | + +error[E0599]: no method named `method2` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:19:9 + | +LL | fn method2(&self) {} + | ------- the method is available for `u8` here +... +LL | 0u8.method2(); + | ^^^^^^^ + | + = help: items from traits can only be used if the trait is in scope +help: trait `Trait` which provides `method2` is implemented but not in scope; perhaps you want to import it + | +LL + use m2::Trait; + | +help: there is a method `method1` with a similar name + | +LL - 0u8.method2(); +LL + 0u8.method1(); + | + +error[E0599]: no method named `method1` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:26:9 + | +LL | fn method1(&self) {} + | ------- the method is available for `u8` here +... +LL | 0u8.method1(); + | ^^^^^^^ + | + = help: items from traits can only be used if the trait is in scope +help: trait `Trait` which provides `method1` is implemented but not in scope; perhaps you want to import it + | +LL + use m1::Trait; + | +help: there is a method `method2` with a similar name + | +LL - 0u8.method1(); +LL + 0u8.method2(); + | + +error[E0599]: no method named `method2` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:27:9 + | +LL | fn method2(&self) {} + | ------- the method is available for `u8` here +... +LL | 0u8.method2(); + | ^^^^^^^ + | + = help: items from traits can only be used if the trait is in scope +help: trait `Trait` which provides `method2` is implemented but not in scope; perhaps you want to import it + | +LL + use m2::Trait; + | +help: there is a method `method1` with a similar name + | +LL - 0u8.method2(); +LL + 0u8.method1(); + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. From 8adfde31f3210249f2ae67cd384ebdd7fdf28911 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Mon, 17 Nov 2025 10:16:39 +0100 Subject: [PATCH 2/7] ambiguous traits from globs are all in scope + lint this --- compiler/rustc_hir/src/hir.rs | 2 + .../rustc_hir_typeck/src/method/confirm.rs | 28 +++++- compiler/rustc_hir_typeck/src/method/probe.rs | 52 +++++++++--- compiler/rustc_lint_defs/src/builtin.rs | 42 +++++++++ compiler/rustc_resolve/src/lib.rs | 51 +++++++++-- tests/ui/imports/ambiguous-trait-in-scope.rs | 12 +-- .../imports/ambiguous-trait-in-scope.stderr | 85 ++++++------------- 7 files changed, 183 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 90bf82f15f819..eeff624b60554 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4555,6 +4555,8 @@ pub struct Upvar { pub struct TraitCandidate { pub def_id: DefId, pub import_ids: SmallVec<[LocalDefId; 1]>, + // FIXME: explain why this is needed for now. + pub lint_ambiguous: bool, } #[derive(Copy, Clone, Debug, HashStable_Generic)] diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index f7a0a55d5880d..f3883429a1f20 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::ops::Deref; use rustc_hir as hir; @@ -12,7 +13,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ use rustc_infer::infer::{ BoundRegionConversionTime, DefineOpaqueTypes, InferOk, RegionVariableOrigin, }; -use rustc_lint::builtin::SUPERTRAIT_ITEM_SHADOWING_USAGE; +use rustc_lint::builtin::{AMBIGUOUS_TRAIT_GLOB_IMPORTS, SUPERTRAIT_ITEM_SHADOWING_USAGE}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, @@ -149,6 +150,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Lint when an item is shadowing a supertrait item. self.lint_shadowed_supertrait_items(pick, segment); + // Lint when a trait is ambiguously imported + self.lint_ambiguously_imported_trait(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. @@ -322,7 +326,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }) } - probe::TraitPick => { + probe::TraitPick(_) => { let trait_def_id = pick.item.container_id(self.tcx); // Make a trait reference `$0 : Trait<$1...$n>` @@ -716,6 +720,26 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ); } + fn lint_ambiguously_imported_trait( + &self, + pick: &probe::Pick<'_>, + segment: &hir::PathSegment<'tcx>, + ) { + if let probe::PickKind::TraitPick(true) = pick.kind { + } else { + return; + }; + let trait_name = self.tcx.item_name(pick.item.container_id(self.tcx)); + let import_span = self.tcx.hir_span_if_local(pick.import_ids[0].to_def_id()).unwrap(); + + self.tcx.node_lint(AMBIGUOUS_TRAIT_GLOB_IMPORTS, segment.hir_id, |diag| { + diag.primary_message(format!("Usage of ambiguously imported trait `{trait_name}`")) + .span(segment.ident.span) + .span_label(import_span, format!("`{trait_name}`imported ambiguously here")) + .help(format!("Import `{trait_name}` explicitly")); + }); + } + 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 a3f6803c5dc2c..86e9b88682d79 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -106,7 +106,7 @@ pub(crate) struct Candidate<'tcx> { pub(crate) enum CandidateKind<'tcx> { InherentImplCandidate { impl_def_id: DefId, receiver_steps: usize }, ObjectCandidate(ty::PolyTraitRef<'tcx>), - TraitCandidate(ty::PolyTraitRef<'tcx>), + TraitCandidate(ty::PolyTraitRef<'tcx>, bool /* lint_ambiguous */), WhereClauseCandidate(ty::PolyTraitRef<'tcx>), } @@ -235,7 +235,10 @@ pub(crate) struct Pick<'tcx> { pub(crate) enum PickKind<'tcx> { InherentImplPick, ObjectPick, - TraitPick, + TraitPick( + // Is Ambiguously Imported + bool, + ), WhereClausePick( // Trait ty::PolyTraitRef<'tcx>, @@ -560,7 +563,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { probe_cx.push_candidate( Candidate { item, - kind: CandidateKind::TraitCandidate(ty::Binder::dummy(trait_ref)), + kind: CandidateKind::TraitCandidate( + ty::Binder::dummy(trait_ref), + false, + ), import_ids: smallvec![], }, false, @@ -1018,6 +1024,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.assemble_extension_candidates_for_trait( &trait_candidate.import_ids, trait_did, + trait_candidate.lint_ambiguous, ); } } @@ -1029,7 +1036,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let mut duplicates = FxHashSet::default(); for trait_info in suggest::all_traits(self.tcx) { if duplicates.insert(trait_info.def_id) { - self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id); + self.assemble_extension_candidates_for_trait( + &smallvec![], + trait_info.def_id, + false, + ); } } } @@ -1055,6 +1066,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &mut self, import_ids: &SmallVec<[LocalDefId; 1]>, trait_def_id: DefId, + lint_ambiguous: bool, ) { let trait_args = self.fresh_args_for_item(self.span, trait_def_id); let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, trait_args); @@ -1076,7 +1088,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Candidate { item, import_ids: import_ids.clone(), - kind: TraitCandidate(bound_trait_ref), + kind: TraitCandidate(bound_trait_ref, lint_ambiguous), }, false, ); @@ -1099,7 +1111,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Candidate { item, import_ids: import_ids.clone(), - kind: TraitCandidate(ty::Binder::dummy(trait_ref)), + kind: TraitCandidate(ty::Binder::dummy(trait_ref), lint_ambiguous), }, false, ); @@ -1842,7 +1854,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ObjectCandidate(_) | WhereClauseCandidate(_) => { CandidateSource::Trait(candidate.item.container_id(self.tcx)) } - TraitCandidate(trait_ref) => self.probe(|_| { + TraitCandidate(trait_ref, _) => self.probe(|_| { let trait_ref = self.instantiate_binder_with_fresh_vars( self.span, BoundRegionConversionTime::FnCall, @@ -1872,7 +1884,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn candidate_source_from_pick(&self, pick: &Pick<'tcx>) -> CandidateSource { match pick.kind { InherentImplPick => CandidateSource::Impl(pick.item.container_id(self.tcx)), - ObjectPick | WhereClausePick(_) | TraitPick => { + ObjectPick | WhereClausePick(_) | TraitPick(_) => { CandidateSource::Trait(pick.item.container_id(self.tcx)) } } @@ -1948,7 +1960,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { impl_bounds, )); } - TraitCandidate(poly_trait_ref) => { + TraitCandidate(poly_trait_ref, _) => { // Some trait methods are excluded for arrays before 2021. // (`array.into_iter()` wants a slice iterator for compatibility.) if let Some(method_name) = self.method_name { @@ -2274,11 +2286,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + let lint_ambiguous = match probes[0].0.kind { + TraitCandidate(_, lint) => lint, + WhereClauseCandidate(_) => false, + InherentImplCandidate { .. } | ObjectCandidate(_) => { + unreachable!() + } + }; + // FIXME: check the return type here somehow. // If so, just use this trait and call it a day. Some(Pick { item: probes[0].0.item, - kind: TraitPick, + kind: TraitPick(lint_ambiguous), import_ids: probes[0].0.import_ids.clone(), autoderefs: 0, autoref_or_ptr_adjustment: None, @@ -2348,9 +2368,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + let lint_ambiguous = match probes[0].0.kind { + TraitCandidate(_, lint) => lint, + WhereClauseCandidate(_) => false, + InherentImplCandidate { .. } | ObjectCandidate(_) => { + unreachable!() + } + }; + Some(Pick { item: child_candidate.item, - kind: TraitPick, + kind: TraitPick(lint_ambiguous), import_ids: child_candidate.import_ids.clone(), autoderefs: 0, autoref_or_ptr_adjustment: None, @@ -2611,7 +2639,7 @@ impl<'tcx> Candidate<'tcx> { kind: match self.kind { InherentImplCandidate { .. } => InherentImplPick, ObjectCandidate(_) => ObjectPick, - TraitCandidate(_) => TraitPick, + TraitCandidate(_, lint_ambiguous) => TraitPick(lint_ambiguous), WhereClauseCandidate(trait_ref) => { // Only trait derived from where-clauses should // appear here, so they should not contain any diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 1e965083d6699..de20b2f960715 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -21,6 +21,7 @@ declare_lint_pass! { AMBIGUOUS_ASSOCIATED_ITEMS, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_GLOB_REEXPORTS, + AMBIGUOUS_TRAIT_GLOB_IMPORTS, ARITHMETIC_OVERFLOW, ASM_SUB_REGISTER, BAD_ASM_STYLE, @@ -4437,6 +4438,47 @@ declare_lint! { }; } +declare_lint! { + /// The `ambiguous_trait_glob_imports` lint report traits that are imported ambiguously by glob imports, + /// but this wasn't done previously due to a rustc bug. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(ambiguous_trait_glob_imports)] + /// mod m1 { + /// pub trait Trait { + /// fn method1(&self) {} + /// } + /// impl Trait for u8 {} + /// } + /// mod m2 { + /// pub trait Trait { + /// fn method2(&self) {} + /// } + /// impl Trait for u8 {} + /// } + /// + /// fn main() { + /// use m1::*; + /// use m2::*; + /// 0u8.method1(); + /// 0u8.method2(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust compile this wrong and actually report that `method2` + /// can't be found. Now both traits are imported but a warning is emitted that they are ambiguous. + /// + pub AMBIGUOUS_TRAIT_GLOB_IMPORTS, + Warn, + "detects certain glob imports that import traits ambiguously and reports them.", +} + declare_lint! { /// The `refining_impl_trait_reachable` lint detects `impl Trait` return /// types in method signatures that are refined by a publically reachable diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 43e145c58ff66..e8c9b1a9518dc 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -609,8 +609,18 @@ struct ModuleData<'ra> { globs: CmRefCell>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: - CmRefCell, Option>)]>>>, + traits: CmRefCell< + Option< + Box< + [( + Macros20NormalizedIdent, + NameBinding<'ra>, + Option>, + bool, /* lint_ambiguous*/ + )], + >, + >, + >, /// Span of the module itself. Used for error reporting. span: Span, @@ -702,12 +712,29 @@ impl<'ra> Module<'ra> { let mut traits = self.traits.borrow_mut(resolver.as_ref()); if traits.is_none() { let mut collected_traits = Vec::new(); - self.for_each_child(resolver, |r, name, ns, binding| { - if ns != TypeNS || binding.is_ambiguity_recursive() { + self.for_each_child(resolver, |r, name, ns, mut binding| { + if ns != TypeNS { return; } - if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { - collected_traits.push((name, binding, r.as_ref().get_module(def_id))) + let lint_ambiguous = binding.is_ambiguity_recursive(); + loop { + // Add to collected_traits if it's a trait + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { + collected_traits.push(( + name, + binding, + r.as_ref().get_module(def_id), + lint_ambiguous, + )); + } + + // Break if no ambiguity + let Some((ambiguous_binding, AmbiguityKind::GlobVsGlob)) = binding.ambiguity + else { + break; + }; + + binding = ambiguous_binding; } }); *traits = Some(collected_traits.into_boxed_slice()); @@ -1893,7 +1920,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(module) = current_trait { if self.trait_may_have_item(Some(module), assoc_item) { let def_id = module.def_id(); - found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] }); + found_traits.push(TraitCandidate { + def_id, + import_ids: smallvec![], + lint_ambiguous: false, + }); } } @@ -1928,11 +1959,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { module.ensure_traits(self); let traits = module.traits.borrow(); - for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() { + for &(trait_name, trait_binding, trait_module, lint_ambiguous) in + traits.as_ref().unwrap().iter() + { if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name.0); - found_traits.push(TraitCandidate { def_id, import_ids }); + found_traits.push(TraitCandidate { def_id, import_ids, lint_ambiguous }); } } } diff --git a/tests/ui/imports/ambiguous-trait-in-scope.rs b/tests/ui/imports/ambiguous-trait-in-scope.rs index ed51d88b82f0b..f666ca2e2a306 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.rs +++ b/tests/ui/imports/ambiguous-trait-in-scope.rs @@ -1,3 +1,5 @@ +//@ check-pass + mod m1 { pub trait Trait { fn method1(&self) {} @@ -11,20 +13,20 @@ mod m2 { impl Trait for u8 {} } -fn test1() { +pub fn test1() { // Create an ambiguous import for `Trait` in one order use m1::*; use m2::*; - 0u8.method1(); //~ ERROR no method named `method1` found for type `u8` in the current scope - 0u8.method2(); //~ ERROR no method named `method2` found for type `u8` in the current scope + 0u8.method1(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports] + 0u8.method2(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports] } fn test2() { // Create an ambiguous import for `Trait` in another order use m2::*; use m1::*; - 0u8.method1(); //~ ERROR no method named `method1` found for type `u8` in the current scope - 0u8.method2(); //~ ERROR no method named `method2` found for type `u8` in the current scope + 0u8.method1(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports] + 0u8.method2(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports] } fn main() {} diff --git a/tests/ui/imports/ambiguous-trait-in-scope.stderr b/tests/ui/imports/ambiguous-trait-in-scope.stderr index f41443270745e..649c56431bf04 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.stderr +++ b/tests/ui/imports/ambiguous-trait-in-scope.stderr @@ -1,83 +1,46 @@ -error[E0599]: no method named `method1` found for type `u8` in the current scope - --> $DIR/ambiguous-trait-in-scope.rs:18:9 +warning: Usage of ambiguously imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:20:9 | -LL | fn method1(&self) {} - | ------- the method is available for `u8` here -... +LL | use m1::*; + | -- `Trait`imported ambiguously here +LL | use m2::*; LL | 0u8.method1(); | ^^^^^^^ | - = help: items from traits can only be used if the trait is in scope -help: trait `Trait` which provides `method1` is implemented but not in scope; perhaps you want to import it - | -LL + use m1::Trait; - | -help: there is a method `method2` with a similar name - | -LL - 0u8.method1(); -LL + 0u8.method2(); - | + = help: Import `Trait` explicitly + = note: `#[warn(ambiguous_trait_glob_imports)]` on by default -error[E0599]: no method named `method2` found for type `u8` in the current scope - --> $DIR/ambiguous-trait-in-scope.rs:19:9 +warning: Usage of ambiguously imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:21:9 | -LL | fn method2(&self) {} - | ------- the method is available for `u8` here -... +LL | use m2::*; + | -- `Trait`imported ambiguously here +LL | 0u8.method1(); LL | 0u8.method2(); | ^^^^^^^ | - = help: items from traits can only be used if the trait is in scope -help: trait `Trait` which provides `method2` is implemented but not in scope; perhaps you want to import it - | -LL + use m2::Trait; - | -help: there is a method `method1` with a similar name - | -LL - 0u8.method2(); -LL + 0u8.method1(); - | + = help: Import `Trait` explicitly -error[E0599]: no method named `method1` found for type `u8` in the current scope - --> $DIR/ambiguous-trait-in-scope.rs:26:9 +warning: Usage of ambiguously imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:28:9 | -LL | fn method1(&self) {} - | ------- the method is available for `u8` here -... +LL | use m1::*; + | -- `Trait`imported ambiguously here LL | 0u8.method1(); | ^^^^^^^ | - = help: items from traits can only be used if the trait is in scope -help: trait `Trait` which provides `method1` is implemented but not in scope; perhaps you want to import it - | -LL + use m1::Trait; - | -help: there is a method `method2` with a similar name - | -LL - 0u8.method1(); -LL + 0u8.method2(); - | + = help: Import `Trait` explicitly -error[E0599]: no method named `method2` found for type `u8` in the current scope - --> $DIR/ambiguous-trait-in-scope.rs:27:9 +warning: Usage of ambiguously imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:29:9 | -LL | fn method2(&self) {} - | ------- the method is available for `u8` here +LL | use m2::*; + | -- `Trait`imported ambiguously here ... LL | 0u8.method2(); | ^^^^^^^ | - = help: items from traits can only be used if the trait is in scope -help: trait `Trait` which provides `method2` is implemented but not in scope; perhaps you want to import it - | -LL + use m2::Trait; - | -help: there is a method `method1` with a similar name - | -LL - 0u8.method2(); -LL + 0u8.method1(); - | + = help: Import `Trait` explicitly -error: aborting due to 4 previous errors +warning: 4 warnings emitted -For more information about this error, try `rustc --explain E0599`. From c925e110892251a92bf328c5496791ec6be71dd2 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 18 Nov 2025 13:47:49 +0100 Subject: [PATCH 3/7] no lint for other candidates when creating TraitPick --- compiler/rustc_hir_typeck/src/method/probe.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 86e9b88682d79..c97f6ad206cc8 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2288,10 +2288,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let lint_ambiguous = match probes[0].0.kind { TraitCandidate(_, lint) => lint, - WhereClauseCandidate(_) => false, - InherentImplCandidate { .. } | ObjectCandidate(_) => { - unreachable!() - } + _ => false, }; // FIXME: check the return type here somehow. @@ -2370,10 +2367,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let lint_ambiguous = match probes[0].0.kind { TraitCandidate(_, lint) => lint, - WhereClauseCandidate(_) => false, - InherentImplCandidate { .. } | ObjectCandidate(_) => { - unreachable!() - } + _ => false, }; Some(Pick { From a619ad8ae3c923a2cfd97fc55c592e0ec89c24ab Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Wed, 19 Nov 2025 19:35:04 +0100 Subject: [PATCH 4/7] address review --- .../rustc_hir_typeck/src/method/confirm.rs | 6 +- compiler/rustc_lint_defs/src/builtin.rs | 24 ++++++-- compiler/rustc_resolve/src/lib.rs | 28 +++------ tests/ui/imports/ambiguous-trait-in-scope.rs | 12 ++-- .../imports/ambiguous-trait-in-scope.stderr | 58 +++++++++++++------ 5 files changed, 77 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index f3883429a1f20..6d0b7168db6b2 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -151,7 +151,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.lint_shadowed_supertrait_items(pick, segment); // Lint when a trait is ambiguously imported - self.lint_ambiguously_imported_trait(pick, segment); + self.lint_ambiguously_glob_imported_trait(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 @@ -720,7 +720,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ); } - fn lint_ambiguously_imported_trait( + fn lint_ambiguously_glob_imported_trait( &self, pick: &probe::Pick<'_>, segment: &hir::PathSegment<'tcx>, @@ -733,7 +733,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let import_span = self.tcx.hir_span_if_local(pick.import_ids[0].to_def_id()).unwrap(); self.tcx.node_lint(AMBIGUOUS_TRAIT_GLOB_IMPORTS, segment.hir_id, |diag| { - diag.primary_message(format!("Usage of ambiguously imported trait `{trait_name}`")) + diag.primary_message(format!("Use of ambiguously glob imported trait `{trait_name}`")) .span(segment.ident.span) .span_label(import_span, format!("`{trait_name}`imported ambiguously here")) .help(format!("Import `{trait_name}` explicitly")); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index de20b2f960715..fd7e3232eeac0 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4439,8 +4439,9 @@ declare_lint! { } declare_lint! { - /// The `ambiguous_trait_glob_imports` lint report traits that are imported ambiguously by glob imports, - /// but this wasn't done previously due to a rustc bug. + /// The `ambiguous_trait_glob_imports` lint reports uses of traits that are + /// imported ambiguously via glob imports. Previously, this was not enforced + /// due to a bug in rustc. /// /// ### Example /// @@ -4471,12 +4472,25 @@ declare_lint! { /// /// ### Explanation /// - /// Previous versions of Rust compile this wrong and actually report that `method2` - /// can't be found. Now both traits are imported but a warning is emitted that they are ambiguous. + /// When multiple traits with the same name are brought into scope through glob imports, + /// one trait becomes the "primary" one while the others are shadowed. Methods from the + /// shadowed traits (e.g. `method2`) become inaccessible, while methods from the "primary" + /// trait (e.g. `method1`) still resolve. Ideally, none of the ambiguous traits would be in scope, + /// but we have to allow this for now because of backwards compatibility. + /// This lint reports uses of these "primary" traits that are ambiguous. /// + /// This is a [future-incompatible] lint to transition this to a + /// hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints pub AMBIGUOUS_TRAIT_GLOB_IMPORTS, Warn, - "detects certain glob imports that import traits ambiguously and reports them.", + "detects usages of ambiguously glob imported traits", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseError, + reference: "issue #147992 ", + report_in_deps: false, + }; } declare_lint! { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e8c9b1a9518dc..078617855cc1b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -712,29 +712,17 @@ impl<'ra> Module<'ra> { let mut traits = self.traits.borrow_mut(resolver.as_ref()); if traits.is_none() { let mut collected_traits = Vec::new(); - self.for_each_child(resolver, |r, name, ns, mut binding| { + self.for_each_child(resolver, |r, name, ns, binding| { if ns != TypeNS { return; } - let lint_ambiguous = binding.is_ambiguity_recursive(); - loop { - // Add to collected_traits if it's a trait - if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { - collected_traits.push(( - name, - binding, - r.as_ref().get_module(def_id), - lint_ambiguous, - )); - } - - // Break if no ambiguity - let Some((ambiguous_binding, AmbiguityKind::GlobVsGlob)) = binding.ambiguity - else { - break; - }; - - binding = ambiguous_binding; + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { + collected_traits.push(( + name, + binding, + r.as_ref().get_module(def_id), + binding.is_ambiguity_recursive(), + )); } }); *traits = Some(collected_traits.into_boxed_slice()); diff --git a/tests/ui/imports/ambiguous-trait-in-scope.rs b/tests/ui/imports/ambiguous-trait-in-scope.rs index f666ca2e2a306..db33d8419c351 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.rs +++ b/tests/ui/imports/ambiguous-trait-in-scope.rs @@ -1,5 +1,3 @@ -//@ check-pass - mod m1 { pub trait Trait { fn method1(&self) {} @@ -17,16 +15,18 @@ pub fn test1() { // Create an ambiguous import for `Trait` in one order use m1::*; use m2::*; - 0u8.method1(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports] - 0u8.method2(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports] + 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_trait_glob_imports] + //~| WARNING: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } fn test2() { // Create an ambiguous import for `Trait` in another order use m2::*; use m1::*; - 0u8.method1(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports] - 0u8.method2(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports] + 0u8.method1(); //~ ERROR: no method named `method1` found for type `u8` in the current scope + 0u8.method2(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_trait_glob_imports] + //~| WARNING: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } fn main() {} diff --git a/tests/ui/imports/ambiguous-trait-in-scope.stderr b/tests/ui/imports/ambiguous-trait-in-scope.stderr index 649c56431bf04..2f610e30c92ec 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.stderr +++ b/tests/ui/imports/ambiguous-trait-in-scope.stderr @@ -1,5 +1,5 @@ -warning: Usage of ambiguously imported trait `Trait` - --> $DIR/ambiguous-trait-in-scope.rs:20:9 +warning: Use of ambiguously glob imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:18:9 | LL | use m1::*; | -- `Trait`imported ambiguously here @@ -7,32 +7,53 @@ LL | use m2::*; LL | 0u8.method1(); | ^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147992 = help: Import `Trait` explicitly - = note: `#[warn(ambiguous_trait_glob_imports)]` on by default + = note: `#[warn(ambiguous_trait_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -warning: Usage of ambiguously imported trait `Trait` - --> $DIR/ambiguous-trait-in-scope.rs:21:9 +error[E0599]: no method named `method2` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:20:9 | -LL | use m2::*; - | -- `Trait`imported ambiguously here -LL | 0u8.method1(); +LL | fn method2(&self) {} + | ------- the method is available for `u8` here +... LL | 0u8.method2(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: items from traits can only be used if the trait is in scope +help: trait `Trait` which provides `method2` is implemented but not in scope; perhaps you want to import it + | +LL + use m2::Trait; + | +help: there is a method `method1` with a similar name + | +LL - 0u8.method2(); +LL + 0u8.method1(); + | -warning: Usage of ambiguously imported trait `Trait` - --> $DIR/ambiguous-trait-in-scope.rs:28:9 +error[E0599]: no method named `method1` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:27:9 | -LL | use m1::*; - | -- `Trait`imported ambiguously here +LL | fn method1(&self) {} + | ------- the method is available for `u8` here +... LL | 0u8.method1(); | ^^^^^^^ | - = help: Import `Trait` explicitly + = help: items from traits can only be used if the trait is in scope +help: trait `Trait` which provides `method1` is implemented but not in scope; perhaps you want to import it + | +LL + use m1::Trait; + | +help: there is a method `method2` with a similar name + | +LL - 0u8.method1(); +LL + 0u8.method2(); + | -warning: Usage of ambiguously imported trait `Trait` - --> $DIR/ambiguous-trait-in-scope.rs:29:9 +warning: Use of ambiguously glob imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:28:9 | LL | use m2::*; | -- `Trait`imported ambiguously here @@ -40,7 +61,10 @@ LL | use m2::*; LL | 0u8.method2(); | ^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147992 = help: Import `Trait` explicitly -warning: 4 warnings emitted +error: aborting due to 2 previous errors; 2 warnings emitted +For more information about this error, try `rustc --explain E0599`. From 1df7adf42e5f267c41cfcc0b34c26c1ea0b41dfc Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Thu, 20 Nov 2025 14:39:04 +0100 Subject: [PATCH 5/7] address review --- compiler/rustc_hir/src/hir.rs | 5 ++++- compiler/rustc_hir_typeck/src/method/confirm.rs | 9 ++++----- compiler/rustc_lint_defs/src/builtin.rs | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index eeff624b60554..f3b6699f63727 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4555,7 +4555,10 @@ pub struct Upvar { pub struct TraitCandidate { pub def_id: DefId, pub import_ids: SmallVec<[LocalDefId; 1]>, - // FIXME: explain why this is needed for now. + // Indicates whether this trait candidate is ambiguously glob imported + // in it's scope. Related to the AMBIGUOUS_GLOB_IMPORTED_TRAIT lint. + // If this is set to true and the trait is used as a result of methdo lookup, this + // lint is thrown. pub lint_ambiguous: bool, } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 6d0b7168db6b2..0b5f8b3336a22 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -13,7 +13,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ use rustc_infer::infer::{ BoundRegionConversionTime, DefineOpaqueTypes, InferOk, RegionVariableOrigin, }; -use rustc_lint::builtin::{AMBIGUOUS_TRAIT_GLOB_IMPORTS, SUPERTRAIT_ITEM_SHADOWING_USAGE}; +use rustc_lint::builtin::{AMBIGUOUS_GLOB_IMPORTED_TRAIT, SUPERTRAIT_ITEM_SHADOWING_USAGE}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, @@ -725,14 +725,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { pick: &probe::Pick<'_>, segment: &hir::PathSegment<'tcx>, ) { - if let probe::PickKind::TraitPick(true) = pick.kind { - } else { + if pick.kind != probe::PickKind::TraitPick(true) { return; - }; + } let trait_name = self.tcx.item_name(pick.item.container_id(self.tcx)); let import_span = self.tcx.hir_span_if_local(pick.import_ids[0].to_def_id()).unwrap(); - self.tcx.node_lint(AMBIGUOUS_TRAIT_GLOB_IMPORTS, segment.hir_id, |diag| { + self.tcx.node_lint(AMBIGUOUS_GLOB_IMPORTED_TRAIT, segment.hir_id, |diag| { diag.primary_message(format!("Use of ambiguously glob imported trait `{trait_name}`")) .span(segment.ident.span) .span_label(import_span, format!("`{trait_name}`imported ambiguously here")) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index fd7e3232eeac0..6f15ea6651178 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -19,9 +19,9 @@ declare_lint_pass! { AARCH64_SOFTFLOAT_NEON, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_ASSOCIATED_ITEMS, + AMBIGUOUS_GLOB_IMPORTED_TRAIT, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_GLOB_REEXPORTS, - AMBIGUOUS_TRAIT_GLOB_IMPORTS, ARITHMETIC_OVERFLOW, ASM_SUB_REGISTER, BAD_ASM_STYLE, @@ -4483,7 +4483,7 @@ declare_lint! { /// hard error in the future. /// /// [future-incompatible]: ../index.md#future-incompatible-lints - pub AMBIGUOUS_TRAIT_GLOB_IMPORTS, + pub AMBIGUOUS_GLOB_IMPORTED_TRAIT, Warn, "detects usages of ambiguously glob imported traits", @future_incompatible = FutureIncompatibleInfo { From 6bada235506fb83a717804635e9c86a96c368557 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Thu, 20 Nov 2025 14:56:23 +0100 Subject: [PATCH 6/7] copy test from 148946 --- tests/ui/imports/ambiguous-trait-in-scope.rs | 61 +++++- .../imports/ambiguous-trait-in-scope.stderr | 175 +++++++++++++++--- .../auxiliary/ambiguous-trait-reexport.rs | 23 +++ 3 files changed, 228 insertions(+), 31 deletions(-) create mode 100644 tests/ui/imports/auxiliary/ambiguous-trait-reexport.rs diff --git a/tests/ui/imports/ambiguous-trait-in-scope.rs b/tests/ui/imports/ambiguous-trait-in-scope.rs index db33d8419c351..49121d4257107 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.rs +++ b/tests/ui/imports/ambiguous-trait-in-scope.rs @@ -1,3 +1,6 @@ +//@ edition:2018 +//@ aux-crate:external=ambiguous-trait-reexport.rs + mod m1 { pub trait Trait { fn method1(&self) {} @@ -10,13 +13,24 @@ mod m2 { } impl Trait for u8 {} } +mod m1_reexport { + pub use crate::m1::Trait; +} +mod m2_reexport { + pub use crate::m2::Trait; +} -pub fn test1() { +mod ambig_reexport { + pub use crate::m1::*; + pub use crate::m2::*; +} + +fn test1() { // Create an ambiguous import for `Trait` in one order use m1::*; use m2::*; - 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_trait_glob_imports] - //~| WARNING: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_trait] + //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } @@ -25,8 +39,45 @@ fn test2() { use m2::*; use m1::*; 0u8.method1(); //~ ERROR: no method named `method1` found for type `u8` in the current scope - 0u8.method2(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_trait_glob_imports] - //~| WARNING: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 0u8.method2(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_trait] + //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +} + +fn test_indirect_reexport() { + use m1_reexport::*; + use m2_reexport::*; + 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_trait] + //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope +} + +fn test_ambig_reexport() { + use ambig_reexport::*; + 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_trait] + //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope +} + +fn test_external() { + use external::m1::*; + use external::m2::*; + 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_trait] + //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope +} + +fn test_external_indirect_reexport() { + use external::m1_reexport::*; + use external::m2_reexport::*; + 0u8.method1(); //~ WARNING Use of ambiguously glob imported trait `Trait` [ambiguous_glob_imported_trait] + //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope +} + +fn test_external_ambig_reexport() { + use external::ambig_reexport::*; + 0u8.method1(); //~ ERROR: no method named `method1` found for type `u8` in the current scope + 0u8.method2(); //~ ERROR: no method named `method2` found for type `u8` in the current scope } fn main() {} diff --git a/tests/ui/imports/ambiguous-trait-in-scope.stderr b/tests/ui/imports/ambiguous-trait-in-scope.stderr index 2f610e30c92ec..d30c2530fce5e 100644 --- a/tests/ui/imports/ambiguous-trait-in-scope.stderr +++ b/tests/ui/imports/ambiguous-trait-in-scope.stderr @@ -1,5 +1,5 @@ warning: Use of ambiguously glob imported trait `Trait` - --> $DIR/ambiguous-trait-in-scope.rs:18:9 + --> $DIR/ambiguous-trait-in-scope.rs:32:9 | LL | use m1::*; | -- `Trait`imported ambiguously here @@ -10,50 +10,38 @@ LL | 0u8.method1(); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #147992 = help: Import `Trait` explicitly - = note: `#[warn(ambiguous_trait_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imported_trait)]` (part of `#[warn(future_incompatible)]`) on by default error[E0599]: no method named `method2` found for type `u8` in the current scope - --> $DIR/ambiguous-trait-in-scope.rs:20:9 + --> $DIR/ambiguous-trait-in-scope.rs:34:9 | -LL | fn method2(&self) {} - | ------- the method is available for `u8` here -... LL | 0u8.method2(); - | ^^^^^^^ + | ^^^^^^^ method not found in `u8` | = help: items from traits can only be used if the trait is in scope -help: trait `Trait` which provides `method2` is implemented but not in scope; perhaps you want to import it - | -LL + use m2::Trait; +help: the following traits which provide `method2` are implemented but not in scope; perhaps you want to import one of them | -help: there is a method `method1` with a similar name +LL + use ambiguous_trait_reexport::m2::Trait; | -LL - 0u8.method2(); -LL + 0u8.method1(); +LL + use crate::m2::Trait; | error[E0599]: no method named `method1` found for type `u8` in the current scope - --> $DIR/ambiguous-trait-in-scope.rs:27:9 + --> $DIR/ambiguous-trait-in-scope.rs:41:9 | -LL | fn method1(&self) {} - | ------- the method is available for `u8` here -... LL | 0u8.method1(); - | ^^^^^^^ + | ^^^^^^^ method not found in `u8` | = help: items from traits can only be used if the trait is in scope -help: trait `Trait` which provides `method1` is implemented but not in scope; perhaps you want to import it - | -LL + use m1::Trait; +help: the following traits which provide `method1` are implemented but not in scope; perhaps you want to import one of them | -help: there is a method `method2` with a similar name +LL + use ambiguous_trait_reexport::m1::Trait; | -LL - 0u8.method1(); -LL + 0u8.method2(); +LL + use crate::m1::Trait; | warning: Use of ambiguously glob imported trait `Trait` - --> $DIR/ambiguous-trait-in-scope.rs:28:9 + --> $DIR/ambiguous-trait-in-scope.rs:42:9 | LL | use m2::*; | -- `Trait`imported ambiguously here @@ -65,6 +53,141 @@ LL | 0u8.method2(); = note: for more information, see issue #147992 = help: Import `Trait` explicitly -error: aborting due to 2 previous errors; 2 warnings emitted +warning: Use of ambiguously glob imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:49:9 + | +LL | use m1_reexport::*; + | ----------- `Trait`imported ambiguously here +LL | use m2_reexport::*; +LL | 0u8.method1(); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147992 + = help: Import `Trait` explicitly + +error[E0599]: no method named `method2` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:51:9 + | +LL | 0u8.method2(); + | ^^^^^^^ method not found in `u8` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits which provide `method2` are implemented but not in scope; perhaps you want to import one of them + | +LL + use ambiguous_trait_reexport::m2::Trait; + | +LL + use crate::m2::Trait; + | + +warning: Use of ambiguously glob imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:56:9 + | +LL | use ambig_reexport::*; + | -------------- `Trait`imported ambiguously here +LL | 0u8.method1(); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147992 + = help: Import `Trait` explicitly + +error[E0599]: no method named `method2` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:58:9 + | +LL | 0u8.method2(); + | ^^^^^^^ method not found in `u8` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits which provide `method2` are implemented but not in scope; perhaps you want to import one of them + | +LL + use ambiguous_trait_reexport::m2::Trait; + | +LL + use crate::m2::Trait; + | + +warning: Use of ambiguously glob imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:64:9 + | +LL | use external::m1::*; + | ------------ `Trait`imported ambiguously here +LL | use external::m2::*; +LL | 0u8.method1(); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147992 + = help: Import `Trait` explicitly + +error[E0599]: no method named `method2` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:66:9 + | +LL | 0u8.method2(); + | ^^^^^^^ method not found in `u8` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits which provide `method2` are implemented but not in scope; perhaps you want to import one of them + | +LL + use ambiguous_trait_reexport::m2::Trait; + | +LL + use crate::m2::Trait; + | + +warning: Use of ambiguously glob imported trait `Trait` + --> $DIR/ambiguous-trait-in-scope.rs:72:9 + | +LL | use external::m1_reexport::*; + | --------------------- `Trait`imported ambiguously here +LL | use external::m2_reexport::*; +LL | 0u8.method1(); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147992 + = help: Import `Trait` explicitly + +error[E0599]: no method named `method2` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:74:9 + | +LL | 0u8.method2(); + | ^^^^^^^ method not found in `u8` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits which provide `method2` are implemented but not in scope; perhaps you want to import one of them + | +LL + use ambiguous_trait_reexport::m2::Trait; + | +LL + use crate::m2::Trait; + | + +error[E0599]: no method named `method1` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:79:9 + | +LL | 0u8.method1(); + | ^^^^^^^ method not found in `u8` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits which provide `method1` are implemented but not in scope; perhaps you want to import one of them + | +LL + use ambiguous_trait_reexport::m1::Trait; + | +LL + use crate::m1::Trait; + | + +error[E0599]: no method named `method2` found for type `u8` in the current scope + --> $DIR/ambiguous-trait-in-scope.rs:80:9 + | +LL | 0u8.method2(); + | ^^^^^^^ method not found in `u8` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits which provide `method2` are implemented but not in scope; perhaps you want to import one of them + | +LL + use ambiguous_trait_reexport::m2::Trait; + | +LL + use crate::m2::Trait; + | + +error: aborting due to 8 previous errors; 6 warnings emitted For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/imports/auxiliary/ambiguous-trait-reexport.rs b/tests/ui/imports/auxiliary/ambiguous-trait-reexport.rs new file mode 100644 index 0000000000000..77fb0c7d39348 --- /dev/null +++ b/tests/ui/imports/auxiliary/ambiguous-trait-reexport.rs @@ -0,0 +1,23 @@ +pub mod m1 { + pub trait Trait { + fn method1(&self) {} + } + impl Trait for u8 {} +} +pub mod m2 { + pub trait Trait { + fn method2(&self) {} + } + impl Trait for u8 {} +} +pub mod m1_reexport { + pub use crate::m1::Trait; +} +pub mod m2_reexport { + pub use crate::m2::Trait; +} + +pub mod ambig_reexport { + pub use crate::m1::*; + pub use crate::m2::*; +} From 72f96d9614a41f6c3bd98bf3befaa620ab9c19a6 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Thu, 20 Nov 2025 15:17:34 +0100 Subject: [PATCH 7/7] fix typo --- compiler/rustc_hir/src/hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f3b6699f63727..6b5a574e1b57d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4557,7 +4557,7 @@ pub struct TraitCandidate { pub import_ids: SmallVec<[LocalDefId; 1]>, // Indicates whether this trait candidate is ambiguously glob imported // in it's scope. Related to the AMBIGUOUS_GLOB_IMPORTED_TRAIT lint. - // If this is set to true and the trait is used as a result of methdo lookup, this + // If this is set to true and the trait is used as a result of method lookup, this // lint is thrown. pub lint_ambiguous: bool, }