Skip to content

Commit

Permalink
Rollup merge of rust-lang#59166 - seanmonstar:trait-alias-import, r=a…
Browse files Browse the repository at this point in the history
…lexreg

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
  • Loading branch information
Centril authored Apr 2, 2019
2 parents e008e4f + 3ccd35c commit a2f3f0c
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 37 deletions.
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 @@ -2714,7 +2714,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 @@ -4438,26 +4438,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 @@ -4466,8 +4487,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 @@ -1334,7 +1334,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 @@ -896,20 +896,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 {
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 @@ -930,7 +946,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 @@ -945,6 +961,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 @@ -757,9 +757,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(..) => {
let def_id = self.map.local_def_id_from_hir_id(i.hir_id);
self.traits.push(def_id);
}
_ => ()
}
}

Expand All @@ -781,7 +785,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`.

0 comments on commit a2f3f0c

Please sign in to comment.