about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSean McArthur <sean@seanmonstar.com>2019-03-15 14:55:04 -0700
committerSean McArthur <sean@seanmonstar.com>2019-04-01 11:23:40 -0700
commit3ccd35cd70eed139de411f9533d406c498ed4d62 (patch)
treed82c8e581f1d0edfaf56bd5c4b4de6ef1cce7679
parenta2b6734ea40dcd53e1bdad6d8dc3e31c0fec929a (diff)
downloadrust-3ccd35cd70eed139de411f9533d406c498ed4d62.tar.gz
rust-3ccd35cd70eed139de411f9533d406c498ed4d62.zip
resolve all in scope trait aliases, then elaborate their bounds
-rw-r--r--src/librustc_resolve/lib.rs62
-rw-r--r--src/librustc_resolve/resolve_imports.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs46
-rw-r--r--src/librustc_typeck/check/method/suggest.rs13
-rw-r--r--src/test/run-pass/traits/auxiliary/trait_alias.rs13
-rw-r--r--src/test/run-pass/traits/trait-alias-import-cross-crate.rs14
-rw-r--r--src/test/run-pass/traits/trait-alias-import.rs17
-rw-r--r--src/test/ui/traits/trait-alias-ambiguous.rs24
-rw-r--r--src/test/ui/traits/trait-alias-ambiguous.stderr20
9 files changed, 166 insertions, 45 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index e50cda602c2..fdfb21a605f 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -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",
         };
 
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 9daffd522bf..05597de2735 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -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()  {
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 1f0ab3abb28..48fa26e5882 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -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 {
+            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(())
     }
@@ -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![]);
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index f933e61b8c6..b49614eedb1 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -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) => {
diff --git a/src/test/run-pass/traits/auxiliary/trait_alias.rs b/src/test/run-pass/traits/auxiliary/trait_alias.rs
new file mode 100644
index 00000000000..9e412215512
--- /dev/null
+++ b/src/test/run-pass/traits/auxiliary/trait_alias.rs
@@ -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;
diff --git a/src/test/run-pass/traits/trait-alias-import-cross-crate.rs b/src/test/run-pass/traits/trait-alias-import-cross-crate.rs
new file mode 100644
index 00000000000..975542ab49b
--- /dev/null
+++ b/src/test/run-pass/traits/trait-alias-import-cross-crate.rs
@@ -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.
+}
diff --git a/src/test/run-pass/traits/trait-alias-import.rs b/src/test/run-pass/traits/trait-alias-import.rs
index 9def1f0d480..7d63320b9aa 100644
--- a/src/test/run-pass/traits/trait-alias-import.rs
+++ b/src/test/run-pass/traits/trait-alias-import.rs
@@ -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.
 }
diff --git a/src/test/ui/traits/trait-alias-ambiguous.rs b/src/test/ui/traits/trait-alias-ambiguous.rs
new file mode 100644
index 00000000000..28409e0c662
--- /dev/null
+++ b/src/test/ui/traits/trait-alias-ambiguous.rs
@@ -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
+}
diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr
new file mode 100644
index 00000000000..b7443269b88
--- /dev/null
+++ b/src/test/ui/traits/trait-alias-ambiguous.stderr
@@ -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`.