]> git.lizzy.rs Git - rust.git/commitdiff
Check namespaces when resolving associated items in typeck
authormatthewjasper <mjjasper1@gmail.com>
Sun, 15 Oct 2017 10:58:32 +0000 (11:58 +0100)
committermatthewjasper <mjjasper1@gmail.com>
Sun, 15 Oct 2017 10:58:32 +0000 (11:58 +0100)
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/coherence/inherent_impls_overlap.rs
src/librustc_typeck/lib.rs
src/librustc_typeck/namespace.rs [new file with mode: 0644]
src/test/run-pass/issue-35600.rs [new file with mode: 0644]
src/test/run-pass/issue-44247.rs [new file with mode: 0644]

index 6b7a5b3af9669935ee6e27d9b029f0e842941d9c..7c9497badfbea9925b6f3f450457e8d8bcbada11 100644 (file)
@@ -18,6 +18,7 @@
 use hir::def::Def;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
+use namespace::Namespace;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
@@ -827,8 +828,11 @@ pub fn associated_path_def_to_ty(&self,
 
         let trait_did = bound.0.def_id;
         let (assoc_ident, def_scope) = tcx.adjust(assoc_name, trait_did, ref_id);
-        let item = tcx.associated_items(trait_did).find(|i| i.name.to_ident() == assoc_ident)
-                                                  .expect("missing associated type");
+        let item = tcx.associated_items(trait_did).find(|i| {
+            Namespace::from(i.kind) == Namespace::Type &&
+            i.name.to_ident() == assoc_ident
+        })
+        .expect("missing associated type");
 
         let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, bound);
         let ty = self.normalize_ty(span, ty);
index 3ddeba9d44012b3735a30f5f5b810e3290a51ac3..d4eda13c6cd402c8655bd58ac34875e713247d37 100644 (file)
@@ -13,6 +13,7 @@
 use check::FnCtxt;
 use hir::def::Def;
 use hir::def_id::DefId;
+use namespace::Namespace;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
@@ -275,7 +276,7 @@ pub fn lookup_method_in_trait(&self,
         // Trait must have a method named `m_name` and it should not have
         // type parameters or early-bound regions.
         let tcx = self.tcx;
-        let method_item = self.associated_item(trait_def_id, m_name).unwrap();
+        let method_item = self.associated_item(trait_def_id, m_name, Namespace::Value).unwrap();
         let def_id = method_item.def_id;
         let generics = tcx.generics_of(def_id);
         assert_eq!(generics.types.len(), 0);
@@ -371,10 +372,10 @@ pub fn resolve_ufcs(&self,
 
     /// Find item with name `item_name` defined in impl/trait `def_id`
     /// and return it, or `None`, if no such item was defined there.
-    pub fn associated_item(&self, def_id: DefId, item_name: ast::Name)
+    pub fn associated_item(&self, def_id: DefId, item_name: ast::Name, ns: Namespace)
                            -> Option<ty::AssociatedItem> {
         self.tcx.associated_items(def_id)
-                .find(|item| self.tcx.hygienic_eq(item_name, item.name, def_id))
-
+                .find(|item| Namespace::from(item.kind) == ns &&
+                             self.tcx.hygienic_eq(item_name, item.name, def_id))
     }
 }
index a3b196f99d629ba7ed01368da62ea73f319f37e3..78941cb3a56868b2b1f96caabde6b6deac49ae12 100644 (file)
@@ -16,6 +16,7 @@
 use check::FnCtxt;
 use hir::def_id::DefId;
 use hir::def::Def;
+use namespace::Namespace;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
@@ -1317,11 +1318,14 @@ fn impl_or_trait_item(&self, def_id: DefId) -> Vec<ty::AssociatedItem> {
                 self.tcx.associated_items(def_id)
                     .filter(|x| {
                         let dist = lev_distance(&*name.as_str(), &x.name.as_str());
-                        dist > 0 && dist <= max_dist
+                        Namespace::from(x.kind) == Namespace::Value && dist > 0
+                        && dist <= max_dist
                     })
                     .collect()
             } else {
-                self.fcx.associated_item(def_id, name).map_or(Vec::new(), |x| vec![x])
+                self.fcx
+                    .associated_item(def_id, name, Namespace::Value)
+                    .map_or(Vec::new(), |x| vec![x])
             }
         } else {
             self.tcx.associated_items(def_id).collect()
index 90c5297b399859cdd140381552c0b98d05cb0650..23148406a111ecb62d6a3e953e71489a68d6c7e1 100644 (file)
@@ -17,6 +17,7 @@
 use hir::def::Def;
 use hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::lang_items::FnOnceTraitLangItem;
+use namespace::Namespace;
 use rustc::traits::{Obligation, SelectionContext};
 use util::nodemap::FxHashSet;
 
@@ -92,12 +93,12 @@ pub fn report_method_error(&self,
                     CandidateSource::ImplSource(impl_did) => {
                         // Provide the best span we can. Use the item, if local to crate, else
                         // the impl, if local to crate (item may be defaulted), else nothing.
-                        let item = self.associated_item(impl_did, item_name)
+                        let item = self.associated_item(impl_did, item_name, Namespace::Value)
                             .or_else(|| {
                                 self.associated_item(
                                     self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
-
-                                    item_name
+                                    item_name,
+                                    Namespace::Value,
                                 )
                             }).unwrap();
                         let note_span = self.tcx.hir.span_if_local(item.def_id).or_else(|| {
@@ -127,7 +128,9 @@ pub fn report_method_error(&self,
                         }
                     }
                     CandidateSource::TraitSource(trait_did) => {
-                        let item = self.associated_item(trait_did, item_name).unwrap();
+                        let item = self
+                            .associated_item(trait_did, item_name, Namespace::Value)
+                            .unwrap();
                         let item_span = self.tcx.def_span(item.def_id);
                         span_note!(err,
                                    item_span,
@@ -402,7 +405,7 @@ fn suggest_traits_to_import(&self,
                 // implementing a trait would be legal but is rejected
                 // here).
                 (type_is_local || info.def_id.is_local())
-                    && self.associated_item(info.def_id, item_name).is_some()
+                    && self.associated_item(info.def_id, item_name, Namespace::Value).is_some()
             })
             .collect::<Vec<_>>();
 
index 9c6a4abfbd7c0295c0d77fdf239537bf931bd519..8aaad11df3fed9f6197b618aead8f5677d541922 100644 (file)
@@ -88,6 +88,7 @@
 use hir::def::{Def, CtorKind};
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_back::slice::ref_slice;
+use namespace::Namespace;
 use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
@@ -1293,7 +1294,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     for impl_item in impl_items() {
         let ty_impl_item = tcx.associated_item(tcx.hir.local_def_id(impl_item.id));
         let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id)
-            .find(|ac| tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id));
+            .find(|ac| Namespace::from(&impl_item.node) == Namespace::from(ac.kind) &&
+                         tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id))
+            .or_else(|| {
+                // Not compatible, but needed for the error message
+                tcx.associated_items(impl_trait_ref.def_id)
+                   .find(|ac| tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id))
+            });
 
         // Check that impl definition matches trait definition
         if let Some(ty_trait_item) = ty_trait_item {
index 76dcfe36e4fcdc80e8d07763964cda2ffc575a2e..1355f711a4b14f5da51448743877b224d5c743e5 100644 (file)
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use namespace::Namespace;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::traits;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 
 pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                     crate_num: CrateNum) {
@@ -28,19 +29,10 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> {
 impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
     fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId,
                                        overlap: traits::OverlapResult) {
-        #[derive(Copy, Clone, PartialEq)]
-        enum Namespace {
-            Type,
-            Value,
-        }
 
         let name_and_namespace = |def_id| {
             let item = self.tcx.associated_item(def_id);
-            (item.name, match item.kind {
-                ty::AssociatedKind::Type => Namespace::Type,
-                ty::AssociatedKind::Const |
-                ty::AssociatedKind::Method => Namespace::Value,
-            })
+            (item.name, Namespace::from(item.kind))
         };
 
         let impl_items1 = self.tcx.associated_item_def_ids(impl1);
index 7a6ee73b9b9e9f1c14d6a8ac0f7028afa843d819..1c047ef98d831f643a1a5ee50899a8674c937c7d 100644 (file)
 mod impl_wf_check;
 mod coherence;
 mod variance;
+mod namespace;
 
 pub struct TypeAndSubsts<'tcx> {
     substs: &'tcx Substs<'tcx>,
diff --git a/src/librustc_typeck/namespace.rs b/src/librustc_typeck/namespace.rs
new file mode 100644 (file)
index 0000000..6f0e46b
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir;
+use rustc::ty;
+
+// Whether an item exists in the type or value namespace.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum Namespace {
+    Type,
+    Value,
+}
+
+impl From<ty::AssociatedKind> for Namespace {
+    fn from(a_kind: ty::AssociatedKind) -> Self {
+        match a_kind {
+            ty::AssociatedKind::Type => Namespace::Type,
+            ty::AssociatedKind::Const |
+            ty::AssociatedKind::Method => Namespace::Value,
+        }
+    }
+}
+
+impl<'a> From <&'a hir::ImplItemKind> for Namespace {
+    fn from(impl_kind: &'a hir::ImplItemKind) -> Self {
+        match *impl_kind {
+            hir::ImplItemKind::Type(..) => Namespace::Type,
+            hir::ImplItemKind::Const(..) |
+            hir::ImplItemKind::Method(..) => Namespace::Value,
+        }
+    }
+}
diff --git a/src/test/run-pass/issue-35600.rs b/src/test/run-pass/issue-35600.rs
new file mode 100644 (file)
index 0000000..88358ef
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo {
+    type bar;
+    fn bar();
+}
+
+impl Foo for () {
+    type bar = ();
+    fn bar() {}
+}
+
+fn main() {
+    let x: <() as Foo>::bar = ();
+    <()>::bar();
+}
diff --git a/src/test/run-pass/issue-44247.rs b/src/test/run-pass/issue-44247.rs
new file mode 100644 (file)
index 0000000..27b0aea
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait T {
+    type X;
+    const X: Self::X;
+}
+fn foo<X: T>() {
+    let _: X::X = X::X;
+}
+
+trait S {
+    const X: Self::X;
+    type X;
+}
+fn bar<X: S>() {
+    let _: X::X = X::X;
+}
+
+fn main() {}