Skip to content

Commit a2f3f0c

Browse files
authored
Rollup merge of rust-lang#59166 - seanmonstar:trait-alias-import, r=alexreg
resolve: collect trait aliases along with traits It seems trait aliases weren't being collected as `TraitCandidates` in resolve, this should change that. (I can't compile the full compiler locally, so relying on CI...) Fixes rust-lang#56485 r? @alexreg
2 parents e008e4f + 3ccd35c commit a2f3f0c

File tree

9 files changed

+192
-37
lines changed

9 files changed

+192
-37
lines changed

src/librustc_resolve/lib.rs

+41-18
Original file line numberDiff line numberDiff line change
@@ -1352,7 +1352,7 @@ impl<'a> NameBinding<'a> {
13521352
}
13531353
}
13541354

1355-
// We sometimes need to treat variants as `pub` for backwards compatibility
1355+
// We sometimes need to treat variants as `pub` for backwards compatibility.
13561356
fn pseudo_vis(&self) -> ty::Visibility {
13571357
if self.is_variant() && self.def().def_id().is_local() {
13581358
ty::Visibility::Public
@@ -2714,7 +2714,7 @@ impl<'a> Resolver<'a> {
27142714
{
27152715
let mut self_type_rib = Rib::new(NormalRibKind);
27162716

2717-
// plain insert (no renaming, types are not currently hygienic....)
2717+
// Plain insert (no renaming, since types are not currently hygienic)
27182718
self_type_rib.bindings.insert(keywords::SelfUpper.ident(), self_def);
27192719
self.ribs[TypeNS].push(self_type_rib);
27202720
f(self);
@@ -4438,26 +4438,47 @@ impl<'a> Resolver<'a> {
44384438
let mut collected_traits = Vec::new();
44394439
module.for_each_child(|name, ns, binding| {
44404440
if ns != TypeNS { return }
4441-
if let Def::Trait(_) = binding.def() {
4442-
collected_traits.push((name, binding));
4441+
match binding.def() {
4442+
Def::Trait(_) |
4443+
Def::TraitAlias(_) => collected_traits.push((name, binding)),
4444+
_ => (),
44434445
}
44444446
});
44454447
*traits = Some(collected_traits.into_boxed_slice());
44464448
}
44474449

44484450
for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
4449-
let module = binding.module().unwrap();
4450-
let mut ident = ident;
4451-
if ident.span.glob_adjust(module.expansion, binding.span.ctxt().modern()).is_none() {
4452-
continue
4453-
}
4454-
if self.resolve_ident_in_module_unadjusted(
4455-
ModuleOrUniformRoot::Module(module),
4456-
ident,
4457-
ns,
4458-
false,
4459-
module.span,
4460-
).is_ok() {
4451+
// Traits have pseudo-modules that can be used to search for the given ident.
4452+
if let Some(module) = binding.module() {
4453+
let mut ident = ident;
4454+
if ident.span.glob_adjust(
4455+
module.expansion,
4456+
binding.span.ctxt().modern(),
4457+
).is_none() {
4458+
continue
4459+
}
4460+
if self.resolve_ident_in_module_unadjusted(
4461+
ModuleOrUniformRoot::Module(module),
4462+
ident,
4463+
ns,
4464+
false,
4465+
module.span,
4466+
).is_ok() {
4467+
let import_id = match binding.kind {
4468+
NameBindingKind::Import { directive, .. } => {
4469+
self.maybe_unused_trait_imports.insert(directive.id);
4470+
self.add_to_glob_map(&directive, trait_name);
4471+
Some(directive.id)
4472+
}
4473+
_ => None,
4474+
};
4475+
let trait_def_id = module.def_id().unwrap();
4476+
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
4477+
}
4478+
} else if let Def::TraitAlias(_) = binding.def() {
4479+
// For now, just treat all trait aliases as possible candidates, since we don't
4480+
// know if the ident is somewhere in the transitive bounds.
4481+
44614482
let import_id = match binding.kind {
44624483
NameBindingKind::Import { directive, .. } => {
44634484
self.maybe_unused_trait_imports.insert(directive.id);
@@ -4466,8 +4487,10 @@ impl<'a> Resolver<'a> {
44664487
}
44674488
_ => None,
44684489
};
4469-
let trait_def_id = module.def_id().unwrap();
4470-
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id: import_id });
4490+
let trait_def_id = binding.def().def_id();
4491+
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
4492+
} else {
4493+
bug!("candidate is not trait or trait alias?")
44714494
}
44724495
}
44734496
}

src/librustc_resolve/resolve_imports.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
13341334

13351335
self.populate_module_if_necessary(module);
13361336

1337-
if let Some(Def::Trait(_)) = module.def() {
1337+
if module.is_trait() {
13381338
self.session.span_err(directive.span, "items in traits are not importable.");
13391339
return;
13401340
} else if module.def_id() == directive.parent_scope.module.def_id() {

src/librustc_typeck/check/method/probe.rs

+32-14
Original file line numberDiff line numberDiff line change
@@ -896,20 +896,36 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
896896
let trait_substs = self.fresh_item_substs(trait_def_id);
897897
let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
898898

899-
for item in self.impl_or_trait_item(trait_def_id) {
900-
// Check whether `trait_def_id` defines a method with suitable name:
901-
if !self.has_applicable_self(&item) {
902-
debug!("method has inapplicable self");
903-
self.record_static_candidate(TraitSource(trait_def_id));
904-
continue;
905-
}
899+
if self.tcx.is_trait_alias(trait_def_id) {
900+
// For trait aliases, assume all super-traits are relevant.
901+
let bounds = iter::once(trait_ref.to_poly_trait_ref());
902+
self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
903+
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
904+
905+
let (xform_self_ty, xform_ret_ty) =
906+
this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
907+
this.push_candidate(Candidate {
908+
xform_self_ty, xform_ret_ty, item, import_id,
909+
kind: TraitCandidate(new_trait_ref),
910+
}, true);
911+
});
912+
} else {
913+
debug_assert!(self.tcx.is_trait(trait_def_id));
914+
for item in self.impl_or_trait_item(trait_def_id) {
915+
// Check whether `trait_def_id` defines a method with suitable name.
916+
if !self.has_applicable_self(&item) {
917+
debug!("method has inapplicable self");
918+
self.record_static_candidate(TraitSource(trait_def_id));
919+
continue;
920+
}
906921

907-
let (xform_self_ty, xform_ret_ty) =
908-
self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
909-
self.push_candidate(Candidate {
910-
xform_self_ty, xform_ret_ty, item, import_id,
911-
kind: TraitCandidate(trait_ref),
912-
}, false);
922+
let (xform_self_ty, xform_ret_ty) =
923+
self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
924+
self.push_candidate(Candidate {
925+
xform_self_ty, xform_ret_ty, item, import_id,
926+
kind: TraitCandidate(trait_ref),
927+
}, false);
928+
}
913929
}
914930
Ok(())
915931
}
@@ -930,7 +946,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
930946
.filter(|&name| set.insert(name))
931947
.collect();
932948

933-
// sort them by the name so we have a stable result
949+
// Sort them by the name so we have a stable result.
934950
names.sort_by_cached_key(|n| n.as_str());
935951
names
936952
}
@@ -945,6 +961,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
945961
return r;
946962
}
947963

964+
debug!("pick: actual search failed, assemble diagnotics");
965+
948966
let static_candidates = mem::replace(&mut self.static_candidates, vec![]);
949967
let private_candidate = self.private_candidate.take();
950968
let unsatisfied_predicates = mem::replace(&mut self.unsatisfied_predicates, vec![]);

src/librustc_typeck/check/method/suggest.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -757,9 +757,13 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId>
757757

758758
impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
759759
fn visit_item(&mut self, i: &'v hir::Item) {
760-
if let hir::ItemKind::Trait(..) = i.node {
761-
let def_id = self.map.local_def_id_from_hir_id(i.hir_id);
762-
self.traits.push(def_id);
760+
match i.node {
761+
hir::ItemKind::Trait(..) |
762+
hir::ItemKind::TraitAlias(..) => {
763+
let def_id = self.map.local_def_id_from_hir_id(i.hir_id);
764+
self.traits.push(def_id);
765+
}
766+
_ => ()
763767
}
764768
}
765769

@@ -781,7 +785,8 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId>
781785
external_mods: &mut FxHashSet<DefId>,
782786
def: Def) {
783787
match def {
784-
Def::Trait(def_id) => {
788+
Def::Trait(def_id) |
789+
Def::TraitAlias(def_id) => {
785790
traits.push(def_id);
786791
}
787792
Def::Mod(def_id) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(trait_alias)]
2+
3+
pub trait Hello {
4+
fn hello(&self);
5+
}
6+
7+
pub struct Hi;
8+
9+
impl Hello for Hi {
10+
fn hello(&self) {}
11+
}
12+
13+
pub trait Greet = Hello;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-pass
2+
// aux-build:trait_alias.rs
3+
4+
#![feature(trait_alias)]
5+
6+
extern crate trait_alias;
7+
8+
// Import only the alias, not the real trait.
9+
use trait_alias::{Greet, Hi};
10+
11+
fn main() {
12+
let hi = Hi;
13+
hi.hello(); // From `Hello`, via `Greet` alias.
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#![feature(trait_alias)]
2+
3+
mod inner {
4+
pub trait Foo {
5+
fn foo(&self);
6+
}
7+
8+
pub struct Qux;
9+
10+
impl Foo for Qux {
11+
fn foo(&self) {}
12+
}
13+
14+
pub trait Bar = Foo;
15+
}
16+
17+
mod two {
18+
pub trait A {
19+
fn foo();
20+
}
21+
22+
impl A for u8 {
23+
fn foo() {}
24+
}
25+
}
26+
27+
// Import only the alias, not the `Foo` trait.
28+
use inner::{Bar, Qux};
29+
30+
// Declaring an alias also brings in aliased methods.
31+
trait Two = two::A;
32+
33+
fn main() {
34+
let q = Qux;
35+
q.foo(); // From Bar.
36+
37+
u8::foo(); // From A.
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(trait_alias)]
2+
3+
mod inner {
4+
pub trait A { fn foo(&self); }
5+
pub trait B { fn foo(&self); }
6+
7+
impl A for u8 {
8+
fn foo(&self) {}
9+
}
10+
impl B for u8 {
11+
fn foo(&self) {}
12+
}
13+
14+
pub trait C = A + B;
15+
}
16+
17+
use inner::C;
18+
19+
fn main() {
20+
let t = 1u8;
21+
t.foo(); //~ ERROR E0034
22+
23+
inner::A::foo(&t); // ok
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/trait-alias-ambiguous.rs:21:7
3+
|
4+
LL | t.foo();
5+
| ^^^ multiple `foo` found
6+
|
7+
note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u8`
8+
--> $DIR/trait-alias-ambiguous.rs:8:9
9+
|
10+
LL | fn foo(&self) {}
11+
| ^^^^^^^^^^^^^
12+
note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8`
13+
--> $DIR/trait-alias-ambiguous.rs:11:9
14+
|
15+
LL | fn foo(&self) {}
16+
| ^^^^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0034`.

0 commit comments

Comments
 (0)