resolve all in scope trait aliases, then elaborate their bounds
This commit is contained in:
parent
a2b6734ea4
commit
3ccd35cd70
@ -1195,13 +1195,6 @@ impl<'a> ModuleData<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_trait_alias(&self) -> bool {
|
||||
match self.kind {
|
||||
ModuleKind::Def(Def::TraitAlias(_), _) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn nearest_item_scope(&'a self) -> Module<'a> {
|
||||
if self.is_trait() { self.parent.unwrap() } else { self }
|
||||
}
|
||||
@ -1359,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
|
||||
@ -2717,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);
|
||||
@ -4386,18 +4379,37 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
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);
|
||||
@ -4406,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?")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4843,7 +4857,6 @@ impl<'a> Resolver<'a> {
|
||||
let container = match parent.kind {
|
||||
ModuleKind::Def(Def::Mod(_), _) => "module",
|
||||
ModuleKind::Def(Def::Trait(_), _) => "trait",
|
||||
ModuleKind::Def(Def::TraitAlias(_), _) => "trait alias",
|
||||
ModuleKind::Block(..) => "block",
|
||||
_ => "enum",
|
||||
};
|
||||
@ -4872,7 +4885,6 @@ impl<'a> Resolver<'a> {
|
||||
(TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
|
||||
(TypeNS, Some(module)) if module.is_normal() => "module",
|
||||
(TypeNS, Some(module)) if module.is_trait() => "trait",
|
||||
(TypeNS, Some(module)) if module.is_trait_alias() => "trait alias",
|
||||
(TypeNS, _) => "type",
|
||||
};
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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) =
|
||||
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) =
|
||||
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);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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![]);
|
||||
|
@ -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(..) => {
|
||||
let def_id = self.map.local_def_id_from_hir_id(i.hir_id);
|
||||
self.traits.push(def_id);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) => {
|
||||
|
13
src/test/run-pass/traits/auxiliary/trait_alias.rs
Normal file
13
src/test/run-pass/traits/auxiliary/trait_alias.rs
Normal file
@ -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
src/test/run-pass/traits/trait-alias-import-cross-crate.rs
Normal file
14
src/test/run-pass/traits/trait-alias-import-cross-crate.rs
Normal file
@ -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.
|
||||
}
|
@ -14,10 +14,25 @@ mod inner {
|
||||
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();
|
||||
q.foo(); // From Bar.
|
||||
|
||||
u8::foo(); // From A.
|
||||
}
|
||||
|
24
src/test/ui/traits/trait-alias-ambiguous.rs
Normal file
24
src/test/ui/traits/trait-alias-ambiguous.rs
Normal file
@ -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
src/test/ui/traits/trait-alias-ambiguous.stderr
Normal file
20
src/test/ui/traits/trait-alias-ambiguous.stderr
Normal file
@ -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`.
|
Loading…
Reference in New Issue
Block a user