Skip to content

Commit 8adfde3

Browse files
ambiguous traits from globs are all in scope + lint this
1 parent 2a03c50 commit 8adfde3

File tree

7 files changed

+183
-89
lines changed

7 files changed

+183
-89
lines changed

compiler/rustc_hir/src/hir.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4555,6 +4555,8 @@ pub struct Upvar {
45554555
pub struct TraitCandidate {
45564556
pub def_id: DefId,
45574557
pub import_ids: SmallVec<[LocalDefId; 1]>,
4558+
// FIXME: explain why this is needed for now.
4559+
pub lint_ambiguous: bool,
45584560
}
45594561

45604562
#[derive(Copy, Clone, Debug, HashStable_Generic)]

compiler/rustc_hir_typeck/src/method/confirm.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::fmt::Debug;
12
use std::ops::Deref;
23

34
use rustc_hir as hir;
@@ -12,7 +13,7 @@ use rustc_hir_analysis::hir_ty_lowering::{
1213
use rustc_infer::infer::{
1314
BoundRegionConversionTime, DefineOpaqueTypes, InferOk, RegionVariableOrigin,
1415
};
15-
use rustc_lint::builtin::SUPERTRAIT_ITEM_SHADOWING_USAGE;
16+
use rustc_lint::builtin::{AMBIGUOUS_TRAIT_GLOB_IMPORTS, SUPERTRAIT_ITEM_SHADOWING_USAGE};
1617
use rustc_middle::traits::ObligationCauseCode;
1718
use rustc_middle::ty::adjustment::{
1819
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
@@ -149,6 +150,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
149150
// Lint when an item is shadowing a supertrait item.
150151
self.lint_shadowed_supertrait_items(pick, segment);
151152

153+
// Lint when a trait is ambiguously imported
154+
self.lint_ambiguously_imported_trait(pick, segment);
155+
152156
// Add any trait/regions obligations specified on the method's type parameters.
153157
// We won't add these if we encountered an illegal sized bound, so that we can use
154158
// a custom error in that case.
@@ -322,7 +326,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
322326
})
323327
}
324328

325-
probe::TraitPick => {
329+
probe::TraitPick(_) => {
326330
let trait_def_id = pick.item.container_id(self.tcx);
327331

328332
// Make a trait reference `$0 : Trait<$1...$n>`
@@ -716,6 +720,26 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
716720
);
717721
}
718722

723+
fn lint_ambiguously_imported_trait(
724+
&self,
725+
pick: &probe::Pick<'_>,
726+
segment: &hir::PathSegment<'tcx>,
727+
) {
728+
if let probe::PickKind::TraitPick(true) = pick.kind {
729+
} else {
730+
return;
731+
};
732+
let trait_name = self.tcx.item_name(pick.item.container_id(self.tcx));
733+
let import_span = self.tcx.hir_span_if_local(pick.import_ids[0].to_def_id()).unwrap();
734+
735+
self.tcx.node_lint(AMBIGUOUS_TRAIT_GLOB_IMPORTS, segment.hir_id, |diag| {
736+
diag.primary_message(format!("Usage of ambiguously imported trait `{trait_name}`"))
737+
.span(segment.ident.span)
738+
.span_label(import_span, format!("`{trait_name}`imported ambiguously here"))
739+
.help(format!("Import `{trait_name}` explicitly"));
740+
});
741+
}
742+
719743
fn upcast(
720744
&mut self,
721745
source_trait_ref: ty::PolyTraitRef<'tcx>,

compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ pub(crate) struct Candidate<'tcx> {
106106
pub(crate) enum CandidateKind<'tcx> {
107107
InherentImplCandidate { impl_def_id: DefId, receiver_steps: usize },
108108
ObjectCandidate(ty::PolyTraitRef<'tcx>),
109-
TraitCandidate(ty::PolyTraitRef<'tcx>),
109+
TraitCandidate(ty::PolyTraitRef<'tcx>, bool /* lint_ambiguous */),
110110
WhereClauseCandidate(ty::PolyTraitRef<'tcx>),
111111
}
112112

@@ -235,7 +235,10 @@ pub(crate) struct Pick<'tcx> {
235235
pub(crate) enum PickKind<'tcx> {
236236
InherentImplPick,
237237
ObjectPick,
238-
TraitPick,
238+
TraitPick(
239+
// Is Ambiguously Imported
240+
bool,
241+
),
239242
WhereClausePick(
240243
// Trait
241244
ty::PolyTraitRef<'tcx>,
@@ -560,7 +563,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
560563
probe_cx.push_candidate(
561564
Candidate {
562565
item,
563-
kind: CandidateKind::TraitCandidate(ty::Binder::dummy(trait_ref)),
566+
kind: CandidateKind::TraitCandidate(
567+
ty::Binder::dummy(trait_ref),
568+
false,
569+
),
564570
import_ids: smallvec![],
565571
},
566572
false,
@@ -1018,6 +1024,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10181024
self.assemble_extension_candidates_for_trait(
10191025
&trait_candidate.import_ids,
10201026
trait_did,
1027+
trait_candidate.lint_ambiguous,
10211028
);
10221029
}
10231030
}
@@ -1029,7 +1036,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10291036
let mut duplicates = FxHashSet::default();
10301037
for trait_info in suggest::all_traits(self.tcx) {
10311038
if duplicates.insert(trait_info.def_id) {
1032-
self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id);
1039+
self.assemble_extension_candidates_for_trait(
1040+
&smallvec![],
1041+
trait_info.def_id,
1042+
false,
1043+
);
10331044
}
10341045
}
10351046
}
@@ -1055,6 +1066,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10551066
&mut self,
10561067
import_ids: &SmallVec<[LocalDefId; 1]>,
10571068
trait_def_id: DefId,
1069+
lint_ambiguous: bool,
10581070
) {
10591071
let trait_args = self.fresh_args_for_item(self.span, trait_def_id);
10601072
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> {
10761088
Candidate {
10771089
item,
10781090
import_ids: import_ids.clone(),
1079-
kind: TraitCandidate(bound_trait_ref),
1091+
kind: TraitCandidate(bound_trait_ref, lint_ambiguous),
10801092
},
10811093
false,
10821094
);
@@ -1099,7 +1111,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10991111
Candidate {
11001112
item,
11011113
import_ids: import_ids.clone(),
1102-
kind: TraitCandidate(ty::Binder::dummy(trait_ref)),
1114+
kind: TraitCandidate(ty::Binder::dummy(trait_ref), lint_ambiguous),
11031115
},
11041116
false,
11051117
);
@@ -1842,7 +1854,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18421854
ObjectCandidate(_) | WhereClauseCandidate(_) => {
18431855
CandidateSource::Trait(candidate.item.container_id(self.tcx))
18441856
}
1845-
TraitCandidate(trait_ref) => self.probe(|_| {
1857+
TraitCandidate(trait_ref, _) => self.probe(|_| {
18461858
let trait_ref = self.instantiate_binder_with_fresh_vars(
18471859
self.span,
18481860
BoundRegionConversionTime::FnCall,
@@ -1872,7 +1884,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18721884
fn candidate_source_from_pick(&self, pick: &Pick<'tcx>) -> CandidateSource {
18731885
match pick.kind {
18741886
InherentImplPick => CandidateSource::Impl(pick.item.container_id(self.tcx)),
1875-
ObjectPick | WhereClausePick(_) | TraitPick => {
1887+
ObjectPick | WhereClausePick(_) | TraitPick(_) => {
18761888
CandidateSource::Trait(pick.item.container_id(self.tcx))
18771889
}
18781890
}
@@ -1948,7 +1960,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
19481960
impl_bounds,
19491961
));
19501962
}
1951-
TraitCandidate(poly_trait_ref) => {
1963+
TraitCandidate(poly_trait_ref, _) => {
19521964
// Some trait methods are excluded for arrays before 2021.
19531965
// (`array.into_iter()` wants a slice iterator for compatibility.)
19541966
if let Some(method_name) = self.method_name {
@@ -2274,11 +2286,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
22742286
}
22752287
}
22762288

2289+
let lint_ambiguous = match probes[0].0.kind {
2290+
TraitCandidate(_, lint) => lint,
2291+
WhereClauseCandidate(_) => false,
2292+
InherentImplCandidate { .. } | ObjectCandidate(_) => {
2293+
unreachable!()
2294+
}
2295+
};
2296+
22772297
// FIXME: check the return type here somehow.
22782298
// If so, just use this trait and call it a day.
22792299
Some(Pick {
22802300
item: probes[0].0.item,
2281-
kind: TraitPick,
2301+
kind: TraitPick(lint_ambiguous),
22822302
import_ids: probes[0].0.import_ids.clone(),
22832303
autoderefs: 0,
22842304
autoref_or_ptr_adjustment: None,
@@ -2348,9 +2368,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
23482368
}
23492369
}
23502370

2371+
let lint_ambiguous = match probes[0].0.kind {
2372+
TraitCandidate(_, lint) => lint,
2373+
WhereClauseCandidate(_) => false,
2374+
InherentImplCandidate { .. } | ObjectCandidate(_) => {
2375+
unreachable!()
2376+
}
2377+
};
2378+
23512379
Some(Pick {
23522380
item: child_candidate.item,
2353-
kind: TraitPick,
2381+
kind: TraitPick(lint_ambiguous),
23542382
import_ids: child_candidate.import_ids.clone(),
23552383
autoderefs: 0,
23562384
autoref_or_ptr_adjustment: None,
@@ -2611,7 +2639,7 @@ impl<'tcx> Candidate<'tcx> {
26112639
kind: match self.kind {
26122640
InherentImplCandidate { .. } => InherentImplPick,
26132641
ObjectCandidate(_) => ObjectPick,
2614-
TraitCandidate(_) => TraitPick,
2642+
TraitCandidate(_, lint_ambiguous) => TraitPick(lint_ambiguous),
26152643
WhereClauseCandidate(trait_ref) => {
26162644
// Only trait derived from where-clauses should
26172645
// appear here, so they should not contain any

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ declare_lint_pass! {
2121
AMBIGUOUS_ASSOCIATED_ITEMS,
2222
AMBIGUOUS_GLOB_IMPORTS,
2323
AMBIGUOUS_GLOB_REEXPORTS,
24+
AMBIGUOUS_TRAIT_GLOB_IMPORTS,
2425
ARITHMETIC_OVERFLOW,
2526
ASM_SUB_REGISTER,
2627
BAD_ASM_STYLE,
@@ -4437,6 +4438,47 @@ declare_lint! {
44374438
};
44384439
}
44394440

4441+
declare_lint! {
4442+
/// The `ambiguous_trait_glob_imports` lint report traits that are imported ambiguously by glob imports,
4443+
/// but this wasn't done previously due to a rustc bug.
4444+
///
4445+
/// ### Example
4446+
///
4447+
/// ```rust,compile_fail
4448+
/// #![deny(ambiguous_trait_glob_imports)]
4449+
/// mod m1 {
4450+
/// pub trait Trait {
4451+
/// fn method1(&self) {}
4452+
/// }
4453+
/// impl Trait for u8 {}
4454+
/// }
4455+
/// mod m2 {
4456+
/// pub trait Trait {
4457+
/// fn method2(&self) {}
4458+
/// }
4459+
/// impl Trait for u8 {}
4460+
/// }
4461+
///
4462+
/// fn main() {
4463+
/// use m1::*;
4464+
/// use m2::*;
4465+
/// 0u8.method1();
4466+
/// 0u8.method2();
4467+
/// }
4468+
/// ```
4469+
///
4470+
/// {{produces}}
4471+
///
4472+
/// ### Explanation
4473+
///
4474+
/// Previous versions of Rust compile this wrong and actually report that `method2`
4475+
/// can't be found. Now both traits are imported but a warning is emitted that they are ambiguous.
4476+
///
4477+
pub AMBIGUOUS_TRAIT_GLOB_IMPORTS,
4478+
Warn,
4479+
"detects certain glob imports that import traits ambiguously and reports them.",
4480+
}
4481+
44404482
declare_lint! {
44414483
/// The `refining_impl_trait_reachable` lint detects `impl Trait` return
44424484
/// types in method signatures that are refined by a publically reachable

compiler/rustc_resolve/src/lib.rs

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -609,8 +609,18 @@ struct ModuleData<'ra> {
609609
globs: CmRefCell<Vec<Import<'ra>>>,
610610

611611
/// Used to memoize the traits in this module for faster searches through all traits in scope.
612-
traits:
613-
CmRefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>,
612+
traits: CmRefCell<
613+
Option<
614+
Box<
615+
[(
616+
Macros20NormalizedIdent,
617+
NameBinding<'ra>,
618+
Option<Module<'ra>>,
619+
bool, /* lint_ambiguous*/
620+
)],
621+
>,
622+
>,
623+
>,
614624

615625
/// Span of the module itself. Used for error reporting.
616626
span: Span,
@@ -702,12 +712,29 @@ impl<'ra> Module<'ra> {
702712
let mut traits = self.traits.borrow_mut(resolver.as_ref());
703713
if traits.is_none() {
704714
let mut collected_traits = Vec::new();
705-
self.for_each_child(resolver, |r, name, ns, binding| {
706-
if ns != TypeNS || binding.is_ambiguity_recursive() {
715+
self.for_each_child(resolver, |r, name, ns, mut binding| {
716+
if ns != TypeNS {
707717
return;
708718
}
709-
if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() {
710-
collected_traits.push((name, binding, r.as_ref().get_module(def_id)))
719+
let lint_ambiguous = binding.is_ambiguity_recursive();
720+
loop {
721+
// Add to collected_traits if it's a trait
722+
if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() {
723+
collected_traits.push((
724+
name,
725+
binding,
726+
r.as_ref().get_module(def_id),
727+
lint_ambiguous,
728+
));
729+
}
730+
731+
// Break if no ambiguity
732+
let Some((ambiguous_binding, AmbiguityKind::GlobVsGlob)) = binding.ambiguity
733+
else {
734+
break;
735+
};
736+
737+
binding = ambiguous_binding;
711738
}
712739
});
713740
*traits = Some(collected_traits.into_boxed_slice());
@@ -1893,7 +1920,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18931920
if let Some(module) = current_trait {
18941921
if self.trait_may_have_item(Some(module), assoc_item) {
18951922
let def_id = module.def_id();
1896-
found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] });
1923+
found_traits.push(TraitCandidate {
1924+
def_id,
1925+
import_ids: smallvec![],
1926+
lint_ambiguous: false,
1927+
});
18971928
}
18981929
}
18991930

@@ -1928,11 +1959,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
19281959
) {
19291960
module.ensure_traits(self);
19301961
let traits = module.traits.borrow();
1931-
for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() {
1962+
for &(trait_name, trait_binding, trait_module, lint_ambiguous) in
1963+
traits.as_ref().unwrap().iter()
1964+
{
19321965
if self.trait_may_have_item(trait_module, assoc_item) {
19331966
let def_id = trait_binding.res().def_id();
19341967
let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name.0);
1935-
found_traits.push(TraitCandidate { def_id, import_ids });
1968+
found_traits.push(TraitCandidate { def_id, import_ids, lint_ambiguous });
19361969
}
19371970
}
19381971
}

tests/ui/imports/ambiguous-trait-in-scope.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//@ check-pass
2+
13
mod m1 {
24
pub trait Trait {
35
fn method1(&self) {}
@@ -11,20 +13,20 @@ mod m2 {
1113
impl Trait for u8 {}
1214
}
1315

14-
fn test1() {
16+
pub fn test1() {
1517
// Create an ambiguous import for `Trait` in one order
1618
use m1::*;
1719
use m2::*;
18-
0u8.method1(); //~ ERROR no method named `method1` found for type `u8` in the current scope
19-
0u8.method2(); //~ ERROR no method named `method2` found for type `u8` in the current scope
20+
0u8.method1(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports]
21+
0u8.method2(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports]
2022
}
2123

2224
fn test2() {
2325
// Create an ambiguous import for `Trait` in another order
2426
use m2::*;
2527
use m1::*;
26-
0u8.method1(); //~ ERROR no method named `method1` found for type `u8` in the current scope
27-
0u8.method2(); //~ ERROR no method named `method2` found for type `u8` in the current scope
28+
0u8.method1(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports]
29+
0u8.method2(); //~ WARNING Usage of ambiguously imported trait `Trait` [ambiguous_trait_glob_imports]
2830
}
2931

3032
fn main() {}

0 commit comments

Comments
 (0)