Skip to content

Commit 47eaa3b

Browse files
Auto merge of #149058 - LorrensP-2158466:amb-trait-lint, r=<try>
FCW Lint when using an ambiguously glob imported trait
2 parents 568b117 + 07a8765 commit 47eaa3b

File tree

8 files changed

+446
-20
lines changed

8 files changed

+446
-20
lines changed

‎compiler/rustc_hir/src/hir.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4503,6 +4503,11 @@ pub struct Upvar {
45034503
pub struct TraitCandidate {
45044504
pub def_id: DefId,
45054505
pub import_ids: SmallVec<[LocalDefId; 1]>,
4506+
// Indicates whether this trait candidate is ambiguously glob imported
4507+
// in it's scope. Related to the AMBIGUOUS_GLOB_IMPORTED_TRAIT lint.
4508+
// If this is set to true and the trait is used as a result of method lookup, this
4509+
// lint is thrown.
4510+
pub lint_ambiguous: bool,
45064511
}
45074512

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

‎compiler/rustc_hir_typeck/src/method/confirm.rs‎

Lines changed: 25 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_GLOB_IMPORTED_TRAIT, 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_glob_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,25 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
716720
);
717721
}
718722

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

‎compiler/rustc_hir_typeck/src/method/probe.rs‎

Lines changed: 34 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,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
22742286
}
22752287
}
22762288

2289+
let lint_ambiguous = match probes[0].0.kind {
2290+
TraitCandidate(_, lint) => lint,
2291+
_ => false,
2292+
};
2293+
22772294
// FIXME: check the return type here somehow.
22782295
// If so, just use this trait and call it a day.
22792296
Some(Pick {
22802297
item: probes[0].0.item,
2281-
kind: TraitPick,
2298+
kind: TraitPick(lint_ambiguous),
22822299
import_ids: probes[0].0.import_ids.clone(),
22832300
autoderefs: 0,
22842301
autoref_or_ptr_adjustment: None,
@@ -2348,9 +2365,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
23482365
}
23492366
}
23502367

2368+
let lint_ambiguous = match probes[0].0.kind {
2369+
TraitCandidate(_, lint) => lint,
2370+
_ => false,
2371+
};
2372+
23512373
Some(Pick {
23522374
item: child_candidate.item,
2353-
kind: TraitPick,
2375+
kind: TraitPick(lint_ambiguous),
23542376
import_ids: child_candidate.import_ids.clone(),
23552377
autoderefs: 0,
23562378
autoref_or_ptr_adjustment: None,
@@ -2611,7 +2633,7 @@ impl<'tcx> Candidate<'tcx> {
26112633
kind: match self.kind {
26122634
InherentImplCandidate { .. } => InherentImplPick,
26132635
ObjectCandidate(_) => ObjectPick,
2614-
TraitCandidate(_) => TraitPick,
2636+
TraitCandidate(_, lint_ambiguous) => TraitPick(lint_ambiguous),
26152637
WhereClauseCandidate(trait_ref) => {
26162638
// Only trait derived from where-clauses should
26172639
// appear here, so they should not contain any

‎compiler/rustc_lint_defs/src/builtin.rs‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ declare_lint_pass! {
1919
AARCH64_SOFTFLOAT_NEON,
2020
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
2121
AMBIGUOUS_ASSOCIATED_ITEMS,
22+
AMBIGUOUS_GLOB_IMPORTED_TRAIT,
2223
AMBIGUOUS_GLOB_IMPORTS,
2324
AMBIGUOUS_GLOB_REEXPORTS,
2425
ARITHMETIC_OVERFLOW,
@@ -4488,6 +4489,61 @@ declare_lint! {
44884489
};
44894490
}
44904491

4492+
declare_lint! {
4493+
/// The `ambiguous_glob_imported_trait` lint reports uses of traits that are
4494+
/// imported ambiguously via glob imports. Previously, this was not enforced
4495+
/// due to a bug in rustc.
4496+
///
4497+
/// ### Example
4498+
///
4499+
/// ```rust,compile_fail
4500+
/// #![deny(ambiguous_glob_imported_trait)]
4501+
/// mod m1 {
4502+
/// pub trait Trait {
4503+
/// fn method1(&self) {}
4504+
/// }
4505+
/// impl Trait for u8 {}
4506+
/// }
4507+
/// mod m2 {
4508+
/// pub trait Trait {
4509+
/// fn method2(&self) {}
4510+
/// }
4511+
/// impl Trait for u8 {}
4512+
/// }
4513+
///
4514+
/// fn main() {
4515+
/// use m1::*;
4516+
/// use m2::*;
4517+
/// 0u8.method1();
4518+
/// 0u8.method2();
4519+
/// }
4520+
/// ```
4521+
///
4522+
/// {{produces}}
4523+
///
4524+
/// ### Explanation
4525+
///
4526+
/// When multiple traits with the same name are brought into scope through glob imports,
4527+
/// one trait becomes the "primary" one while the others are shadowed. Methods from the
4528+
/// shadowed traits (e.g. `method2`) become inaccessible, while methods from the "primary"
4529+
/// trait (e.g. `method1`) still resolve. Ideally, none of the ambiguous traits would be in scope,
4530+
/// but we have to allow this for now because of backwards compatibility.
4531+
/// This lint reports uses of these "primary" traits that are ambiguous.
4532+
///
4533+
/// This is a [future-incompatible] lint to transition this to a
4534+
/// hard error in the future.
4535+
///
4536+
/// [future-incompatible]: ../index.md#future-incompatible-lints
4537+
pub AMBIGUOUS_GLOB_IMPORTED_TRAIT,
4538+
Warn,
4539+
"detects usages of ambiguously glob imported traits",
4540+
@future_incompatible = FutureIncompatibleInfo {
4541+
reason: FutureIncompatibilityReason::FutureReleaseError,
4542+
reference: "issue #147992 <https://github.com/rust-lang/rust/issues/147992>",
4543+
report_in_deps: false,
4544+
};
4545+
}
4546+
44914547
declare_lint! {
44924548
/// The `refining_impl_trait_reachable` lint detects `impl Trait` return
44934549
/// types in method signatures that are refined by a publically reachable

‎compiler/rustc_resolve/src/lib.rs‎

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -608,8 +608,18 @@ struct ModuleData<'ra> {
608608
globs: CmRefCell<Vec<Import<'ra>>>,
609609

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

614624
/// Span of the module itself. Used for error reporting.
615625
span: Span,
@@ -706,7 +716,12 @@ impl<'ra> Module<'ra> {
706716
return;
707717
}
708718
if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() {
709-
collected_traits.push((name, binding, r.as_ref().get_module(def_id)))
719+
collected_traits.push((
720+
name,
721+
binding,
722+
r.as_ref().get_module(def_id),
723+
binding.is_ambiguity_recursive(),
724+
));
710725
}
711726
});
712727
*traits = Some(collected_traits.into_boxed_slice());
@@ -1891,7 +1906,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18911906
if let Some(module) = current_trait {
18921907
if self.trait_may_have_item(Some(module), assoc_item) {
18931908
let def_id = module.def_id();
1894-
found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] });
1909+
found_traits.push(TraitCandidate {
1910+
def_id,
1911+
import_ids: smallvec![],
1912+
lint_ambiguous: false,
1913+
});
18951914
}
18961915
}
18971916

@@ -1926,11 +1945,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
19261945
) {
19271946
module.ensure_traits(self);
19281947
let traits = module.traits.borrow();
1929-
for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() {
1948+
for &(trait_name, trait_binding, trait_module, lint_ambiguous) in
1949+
traits.as_ref().unwrap().iter()
1950+
{
19301951
if self.trait_may_have_item(trait_module, assoc_item) {
19311952
let def_id = trait_binding.res().def_id();
19321953
let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name.0);
1933-
found_traits.push(TraitCandidate { def_id, import_ids });
1954+
found_traits.push(TraitCandidate { def_id, import_ids, lint_ambiguous });
19341955
}
19351956
}
19361957
}

0 commit comments

Comments
 (0)