Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolve: collect trait aliases along with traits #59166

Merged
merged 2 commits into from
Apr 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 41 additions & 18 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1352,7 +1352,7 @@ impl<'a> NameBinding<'a> {
}
}

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

// plain insert (no renaming, types are not currently hygienic....)
// Plain insert (no renaming, since types are not currently hygienic)
self_type_rib.bindings.insert(keywords::SelfUpper.ident(), self_def);
self.ribs[TypeNS].push(self_type_rib);
f(self);
Expand Down Expand Up @@ -4369,26 +4369,47 @@ impl<'a> Resolver<'a> {
let mut collected_traits = Vec::new();
module.for_each_child(|name, ns, binding| {
if ns != TypeNS { return }
if let Def::Trait(_) = binding.def() {
collected_traits.push((name, binding));
match binding.def() {
Def::Trait(_) |
Def::TraitAlias(_) => collected_traits.push((name, binding)),
_ => (),
}
});
*traits = Some(collected_traits.into_boxed_slice());
}

for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
let module = binding.module().unwrap();
let mut ident = ident;
if ident.span.glob_adjust(module.expansion, binding.span.ctxt().modern()).is_none() {
continue
}
if self.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
false,
module.span,
).is_ok() {
// Traits have pseudo-modules that can be used to search for the given ident.
if let Some(module) = binding.module() {
let mut ident = ident;
if ident.span.glob_adjust(
module.expansion,
binding.span.ctxt().modern(),
).is_none() {
continue
}
if self.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
false,
module.span,
).is_ok() {
let import_id = match binding.kind {
NameBindingKind::Import { directive, .. } => {
self.maybe_unused_trait_imports.insert(directive.id);
self.add_to_glob_map(&directive, trait_name);
Some(directive.id)
}
_ => None,
};
let trait_def_id = module.def_id().unwrap();
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
}
} else if let Def::TraitAlias(_) = binding.def() {
// For now, just treat all trait aliases as possible candidates, since we don't
// know if the ident is somewhere in the transitive bounds.

let import_id = match binding.kind {
NameBindingKind::Import { directive, .. } => {
self.maybe_unused_trait_imports.insert(directive.id);
Expand All @@ -4397,8 +4418,10 @@ impl<'a> Resolver<'a> {
}
_ => None,
};
let trait_def_id = module.def_id().unwrap();
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id: import_id });
let trait_def_id = binding.def().def_id();
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
} else {
bug!("candidate is not trait or trait alias?")
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_resolve/resolve_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {

self.populate_module_if_necessary(module);

if let Some(Def::Trait(_)) = module.def() {
if module.is_trait() {
self.session.span_err(directive.span, "items in traits are not importable.");
return;
} else if module.def_id() == directive.parent_scope.module.def_id() {
Expand Down
46 changes: 32 additions & 14 deletions src/librustc_typeck/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,20 +895,36 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
let trait_substs = self.fresh_item_substs(trait_def_id);
let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);

for item in self.impl_or_trait_item(trait_def_id) {
// Check whether `trait_def_id` defines a method with suitable name:
if !self.has_applicable_self(&item) {
debug!("method has inapplicable self");
self.record_static_candidate(TraitSource(trait_def_id));
continue;
}
if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, assume all super-traits are relevant.
let bounds = iter::once(trait_ref.to_poly_trait_ref());
self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);

let (xform_self_ty, xform_ret_ty) =
this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
this.push_candidate(Candidate {
xform_self_ty, xform_ret_ty, item, import_id,
kind: TraitCandidate(new_trait_ref),
}, true);
});
} else {
seanmonstar marked this conversation as resolved.
Show resolved Hide resolved
debug_assert!(self.tcx.is_trait(trait_def_id));
for item in self.impl_or_trait_item(trait_def_id) {
// Check whether `trait_def_id` defines a method with suitable name.
if !self.has_applicable_self(&item) {
debug!("method has inapplicable self");
self.record_static_candidate(TraitSource(trait_def_id));
continue;
}

let (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
self.push_candidate(Candidate {
xform_self_ty, xform_ret_ty, item, import_id,
kind: TraitCandidate(trait_ref),
}, false);
let (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
self.push_candidate(Candidate {
xform_self_ty, xform_ret_ty, item, import_id,
kind: TraitCandidate(trait_ref),
}, false);
}
}
Ok(())
}
Expand All @@ -929,7 +945,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
.filter(|&name| set.insert(name))
.collect();

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

debug!("pick: actual search failed, assemble diagnotics");

let static_candidates = mem::replace(&mut self.static_candidates, vec![]);
let private_candidate = self.private_candidate.take();
let unsatisfied_predicates = mem::replace(&mut self.unsatisfied_predicates, vec![]);
Expand Down
13 changes: 9 additions & 4 deletions src/librustc_typeck/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,9 +748,13 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId>

impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
fn visit_item(&mut self, i: &'v hir::Item) {
if let hir::ItemKind::Trait(..) = i.node {
let def_id = self.map.local_def_id_from_hir_id(i.hir_id);
self.traits.push(def_id);
match i.node {
hir::ItemKind::Trait(..) |
hir::ItemKind::TraitAlias(..) => {
seanmonstar marked this conversation as resolved.
Show resolved Hide resolved
let def_id = self.map.local_def_id_from_hir_id(i.hir_id);
self.traits.push(def_id);
}
_ => ()
}
}

Expand All @@ -772,7 +776,8 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId>
external_mods: &mut FxHashSet<DefId>,
def: Def) {
match def {
Def::Trait(def_id) => {
Def::Trait(def_id) |
Def::TraitAlias(def_id) => {
traits.push(def_id);
}
Def::Mod(def_id) => {
Expand Down
13 changes: 13 additions & 0 deletions src/test/run-pass/traits/auxiliary/trait_alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![feature(trait_alias)]

pub trait Hello {
fn hello(&self);
}

pub struct Hi;

impl Hello for Hi {
fn hello(&self) {}
}

pub trait Greet = Hello;
14 changes: 14 additions & 0 deletions src/test/run-pass/traits/trait-alias-import-cross-crate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// run-pass
// aux-build:trait_alias.rs

#![feature(trait_alias)]

extern crate trait_alias;

// Import only the alias, not the real trait.
use trait_alias::{Greet, Hi};

fn main() {
let hi = Hi;
hi.hello(); // From `Hello`, via `Greet` alias.
}
38 changes: 38 additions & 0 deletions src/test/run-pass/traits/trait-alias-import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#![feature(trait_alias)]

mod inner {
pub trait Foo {
fn foo(&self);
}

pub struct Qux;

impl Foo for Qux {
fn foo(&self) {}
}

pub trait Bar = Foo;
}

mod two {
pub trait A {
fn foo();
}

impl A for u8 {
fn foo() {}
}
}

// Import only the alias, not the `Foo` trait.
use inner::{Bar, Qux};

// Declaring an alias also brings in aliased methods.
trait Two = two::A;

fn main() {
let q = Qux;
q.foo(); // From Bar.

u8::foo(); // From A.
}
24 changes: 24 additions & 0 deletions src/test/ui/traits/trait-alias-ambiguous.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![feature(trait_alias)]

mod inner {
pub trait A { fn foo(&self); }
pub trait B { fn foo(&self); }

impl A for u8 {
fn foo(&self) {}
}
impl B for u8 {
fn foo(&self) {}
}

pub trait C = A + B;
}

use inner::C;

fn main() {
let t = 1u8;
t.foo(); //~ ERROR E0034

inner::A::foo(&t); // ok
}
20 changes: 20 additions & 0 deletions src/test/ui/traits/trait-alias-ambiguous.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0034]: multiple applicable items in scope
--> $DIR/trait-alias-ambiguous.rs:21:7
|
LL | t.foo();
| ^^^ multiple `foo` found
|
note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u8`
--> $DIR/trait-alias-ambiguous.rs:8:9
|
LL | fn foo(&self) {}
| ^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8`
--> $DIR/trait-alias-ambiguous.rs:11:9
|
LL | fn foo(&self) {}
| ^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0034`.