From b522ee15ce8b4cd419a4f26177694fe3200029be Mon Sep 17 00:00:00 2001 From: matthewjasper Date: Sun, 15 Oct 2017 11:58:32 +0100 Subject: [PATCH] Check namespaces when resolving associated items in typeck --- src/librustc_typeck/astconv.rs | 8 +++- src/librustc_typeck/check/method/mod.rs | 9 +++-- src/librustc_typeck/check/method/probe.rs | 8 +++- src/librustc_typeck/check/method/suggest.rs | 13 ++++--- src/librustc_typeck/check/mod.rs | 9 ++++- .../coherence/inherent_impls_overlap.rs | 14 ++----- src/librustc_typeck/lib.rs | 1 + src/librustc_typeck/namespace.rs | 39 +++++++++++++++++++ src/test/run-pass/issue-35600.rs | 24 ++++++++++++ src/test/run-pass/issue-44247.rs | 27 +++++++++++++ 10 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 src/librustc_typeck/namespace.rs create mode 100644 src/test/run-pass/issue-35600.rs create mode 100644 src/test/run-pass/issue-44247.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6b7a5b3af96..7c9497badfb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 3ddeba9d440..d4eda13c6cd 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -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 { 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)) } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a3b196f99d6..78941cb3a56 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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 { 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() diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 90c5297b399..23148406a11 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -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::>(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c6a4abfbd7..8aaad11df3f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 { diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 76dcfe36e4f..1355f711a4b 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -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); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 7a6ee73b9b9..1c047ef98d8 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -123,6 +123,7 @@ 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 index 00000000000..6f0e46b3afe --- /dev/null +++ b/src/librustc_typeck/namespace.rs @@ -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 or the MIT license +// , 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 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 index 00000000000..88358eff08d --- /dev/null +++ b/src/test/run-pass/issue-35600.rs @@ -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 or the MIT license +// , 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 index 00000000000..27b0aeaac55 --- /dev/null +++ b/src/test/run-pass/issue-44247.rs @@ -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 or the MIT license +// , 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() { + let _: X::X = X::X; +} + +trait S { + const X: Self::X; + type X; +} +fn bar() { + let _: X::X = X::X; +} + +fn main() {} -- 2.44.0