Skip to content

Commit 3ccd35c

Browse files
committed
resolve all in scope trait aliases, then elaborate their bounds
1 parent a2b6734 commit 3ccd35c

File tree

9 files changed

+166
-45
lines changed

9 files changed

+166
-45
lines changed

src/librustc_resolve/lib.rs

+37-25
Original file line numberDiff line numberDiff line change
@@ -1195,13 +1195,6 @@ impl<'a> ModuleData<'a> {
11951195
}
11961196
}
11971197

1198-
fn is_trait_alias(&self) -> bool {
1199-
match self.kind {
1200-
ModuleKind::Def(Def::TraitAlias(_), _) => true,
1201-
_ => false,
1202-
}
1203-
}
1204-
12051198
fn nearest_item_scope(&'a self) -> Module<'a> {
12061199
if self.is_trait() { self.parent.unwrap() } else { self }
12071200
}
@@ -1359,7 +1352,7 @@ impl<'a> NameBinding<'a> {
13591352
}
13601353
}
13611354

1362-
// We sometimes need to treat variants as `pub` for backwards compatibility
1355+
// We sometimes need to treat variants as `pub` for backwards compatibility.
13631356
fn pseudo_vis(&self) -> ty::Visibility {
13641357
if self.is_variant() && self.def().def_id().is_local() {
13651358
ty::Visibility::Public
@@ -2717,7 +2710,7 @@ impl<'a> Resolver<'a> {
27172710
{
27182711
let mut self_type_rib = Rib::new(NormalRibKind);
27192712

2720-
// plain insert (no renaming, types are not currently hygienic....)
2713+
// Plain insert (no renaming, since types are not currently hygienic)
27212714
self_type_rib.bindings.insert(keywords::SelfUpper.ident(), self_def);
27222715
self.ribs[TypeNS].push(self_type_rib);
27232716
f(self);
@@ -4386,18 +4379,37 @@ impl<'a> Resolver<'a> {
43864379
}
43874380

43884381
for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
4389-
let module = binding.module().unwrap();
4390-
let mut ident = ident;
4391-
if ident.span.glob_adjust(module.expansion, binding.span.ctxt().modern()).is_none() {
4392-
continue
4393-
}
4394-
if self.resolve_ident_in_module_unadjusted(
4395-
ModuleOrUniformRoot::Module(module),
4396-
ident,
4397-
ns,
4398-
false,
4399-
module.span,
4400-
).is_ok() {
4382+
// Traits have pseudo-modules that can be used to search for the given ident.
4383+
if let Some(module) = binding.module() {
4384+
let mut ident = ident;
4385+
if ident.span.glob_adjust(
4386+
module.expansion,
4387+
binding.span.ctxt().modern(),
4388+
).is_none() {
4389+
continue
4390+
}
4391+
if self.resolve_ident_in_module_unadjusted(
4392+
ModuleOrUniformRoot::Module(module),
4393+
ident,
4394+
ns,
4395+
false,
4396+
module.span,
4397+
).is_ok() {
4398+
let import_id = match binding.kind {
4399+
NameBindingKind::Import { directive, .. } => {
4400+
self.maybe_unused_trait_imports.insert(directive.id);
4401+
self.add_to_glob_map(&directive, trait_name);
4402+
Some(directive.id)
4403+
}
4404+
_ => None,
4405+
};
4406+
let trait_def_id = module.def_id().unwrap();
4407+
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
4408+
}
4409+
} else if let Def::TraitAlias(_) = binding.def() {
4410+
// For now, just treat all trait aliases as possible candidates, since we don't
4411+
// know if the ident is somewhere in the transitive bounds.
4412+
44014413
let import_id = match binding.kind {
44024414
NameBindingKind::Import { directive, .. } => {
44034415
self.maybe_unused_trait_imports.insert(directive.id);
@@ -4406,8 +4418,10 @@ impl<'a> Resolver<'a> {
44064418
}
44074419
_ => None,
44084420
};
4409-
let trait_def_id = module.def_id().unwrap();
4410-
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id: import_id });
4421+
let trait_def_id = binding.def().def_id();
4422+
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
4423+
} else {
4424+
bug!("candidate is not trait or trait alias?")
44114425
}
44124426
}
44134427
}
@@ -4843,7 +4857,6 @@ impl<'a> Resolver<'a> {
48434857
let container = match parent.kind {
48444858
ModuleKind::Def(Def::Mod(_), _) => "module",
48454859
ModuleKind::Def(Def::Trait(_), _) => "trait",
4846-
ModuleKind::Def(Def::TraitAlias(_), _) => "trait alias",
48474860
ModuleKind::Block(..) => "block",
48484861
_ => "enum",
48494862
};
@@ -4872,7 +4885,6 @@ impl<'a> Resolver<'a> {
48724885
(TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
48734886
(TypeNS, Some(module)) if module.is_normal() => "module",
48744887
(TypeNS, Some(module)) if module.is_trait() => "trait",
4875-
(TypeNS, Some(module)) if module.is_trait_alias() => "trait alias",
48764888
(TypeNS, _) => "type",
48774889
};
48784890

src/librustc_resolve/resolve_imports.rs

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

12461246
self.populate_module_if_necessary(module);
12471247

1248-
if let Some(Def::Trait(_)) = module.def() {
1248+
if module.is_trait() {
12491249
self.session.span_err(directive.span, "items in traits are not importable.");
12501250
return;
12511251
} 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
@@ -895,20 +895,36 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
895895
let trait_substs = self.fresh_item_substs(trait_def_id);
896896
let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
897897

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

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

932-
// sort them by the name so we have a stable result
948+
// Sort them by the name so we have a stable result.
933949
names.sort_by_cached_key(|n| n.as_str());
934950
names
935951
}
@@ -944,6 +960,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
944960
return r;
945961
}
946962

963+
debug!("pick: actual search failed, assemble diagnotics");
964+
947965
let static_candidates = mem::replace(&mut self.static_candidates, vec![]);
948966
let private_candidate = self.private_candidate.take();
949967
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
@@ -748,9 +748,13 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId>
748748

749749
impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
750750
fn visit_item(&mut self, i: &'v hir::Item) {
751-
if let hir::ItemKind::Trait(..) = i.node {
752-
let def_id = self.map.local_def_id_from_hir_id(i.hir_id);
753-
self.traits.push(def_id);
751+
match i.node {
752+
hir::ItemKind::Trait(..) |
753+
hir::ItemKind::TraitAlias(..) => {
754+
let def_id = self.map.local_def_id_from_hir_id(i.hir_id);
755+
self.traits.push(def_id);
756+
}
757+
_ => ()
754758
}
755759
}
756760

@@ -772,7 +776,8 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId>
772776
external_mods: &mut FxHashSet<DefId>,
773777
def: Def) {
774778
match def {
775-
Def::Trait(def_id) => {
779+
Def::Trait(def_id) |
780+
Def::TraitAlias(def_id) => {
776781
traits.push(def_id);
777782
}
778783
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+
}

src/test/run-pass/traits/trait-alias-import.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,25 @@ mod inner {
1414
pub trait Bar = Foo;
1515
}
1616

17+
mod two {
18+
pub trait A {
19+
fn foo();
20+
}
21+
22+
impl A for u8 {
23+
fn foo() {}
24+
}
25+
}
26+
1727
// Import only the alias, not the `Foo` trait.
1828
use inner::{Bar, Qux};
1929

30+
// Declaring an alias also brings in aliased methods.
31+
trait Two = two::A;
32+
2033
fn main() {
2134
let q = Qux;
22-
q.foo();
35+
q.foo(); // From Bar.
36+
37+
u8::foo(); // From A.
2338
}
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)