Check namespaces when resolving associated items in typeck

This commit is contained in:
matthewjasper 2017-10-15 11:58:32 +01:00
parent cbf5d39cca
commit b522ee15ce
10 changed files with 127 additions and 25 deletions

View File

@ -18,6 +18,7 @@ use hir;
use hir::def::Def; use hir::def::Def;
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::resolve_lifetime as rl; use middle::resolve_lifetime as rl;
use namespace::Namespace;
use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits; use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
@ -827,8 +828,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let trait_did = bound.0.def_id; let trait_did = bound.0.def_id;
let (assoc_ident, def_scope) = tcx.adjust(assoc_name, trait_did, ref_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) let item = tcx.associated_items(trait_did).find(|i| {
.expect("missing associated type"); 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.projected_ty_from_poly_trait_ref(span, item.def_id, bound);
let ty = self.normalize_ty(span, ty); let ty = self.normalize_ty(span, ty);

View File

@ -13,6 +13,7 @@
use check::FnCtxt; use check::FnCtxt;
use hir::def::Def; use hir::def::Def;
use hir::def_id::DefId; use hir::def_id::DefId;
use namespace::Namespace;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::traits; use rustc::traits;
use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
@ -275,7 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Trait must have a method named `m_name` and it should not have // Trait must have a method named `m_name` and it should not have
// type parameters or early-bound regions. // type parameters or early-bound regions.
let tcx = self.tcx; 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 def_id = method_item.def_id;
let generics = tcx.generics_of(def_id); let generics = tcx.generics_of(def_id);
assert_eq!(generics.types.len(), 0); assert_eq!(generics.types.len(), 0);
@ -371,10 +372,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// Find item with name `item_name` defined in impl/trait `def_id` /// Find item with name `item_name` defined in impl/trait `def_id`
/// and return it, or `None`, if no such item was defined there. /// 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> { -> Option<ty::AssociatedItem> {
self.tcx.associated_items(def_id) 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))
} }
} }

View File

@ -16,6 +16,7 @@ use super::suggest;
use check::FnCtxt; use check::FnCtxt;
use hir::def_id::DefId; use hir::def_id::DefId;
use hir::def::Def; use hir::def::Def;
use namespace::Namespace;
use rustc::ty::subst::{Subst, Substs}; use rustc::ty::subst::{Subst, Substs};
use rustc::traits::{self, ObligationCause}; use rustc::traits::{self, ObligationCause};
use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
@ -1317,11 +1318,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
self.tcx.associated_items(def_id) self.tcx.associated_items(def_id)
.filter(|x| { .filter(|x| {
let dist = lev_distance(&*name.as_str(), &x.name.as_str()); 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() .collect()
} else { } 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 { } else {
self.tcx.associated_items(def_id).collect() self.tcx.associated_items(def_id).collect()

View File

@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
use hir::def::Def; use hir::def::Def;
use hir::def_id::{CRATE_DEF_INDEX, DefId}; use hir::def_id::{CRATE_DEF_INDEX, DefId};
use middle::lang_items::FnOnceTraitLangItem; use middle::lang_items::FnOnceTraitLangItem;
use namespace::Namespace;
use rustc::traits::{Obligation, SelectionContext}; use rustc::traits::{Obligation, SelectionContext};
use util::nodemap::FxHashSet; use util::nodemap::FxHashSet;
@ -92,12 +93,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
CandidateSource::ImplSource(impl_did) => { CandidateSource::ImplSource(impl_did) => {
// Provide the best span we can. Use the item, if local to crate, else // 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. // 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(|| { .or_else(|| {
self.associated_item( self.associated_item(
self.tcx.impl_trait_ref(impl_did).unwrap().def_id, self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
item_name,
item_name Namespace::Value,
) )
}).unwrap(); }).unwrap();
let note_span = self.tcx.hir.span_if_local(item.def_id).or_else(|| { let note_span = self.tcx.hir.span_if_local(item.def_id).or_else(|| {
@ -127,7 +128,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
} }
CandidateSource::TraitSource(trait_did) => { 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); let item_span = self.tcx.def_span(item.def_id);
span_note!(err, span_note!(err,
item_span, item_span,
@ -402,7 +405,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// implementing a trait would be legal but is rejected // implementing a trait would be legal but is rejected
// here). // here).
(type_is_local || info.def_id.is_local()) (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<_>>(); .collect::<Vec<_>>();

View File

@ -88,6 +88,7 @@ use astconv::AstConv;
use hir::def::{Def, CtorKind}; use hir::def::{Def, CtorKind};
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_back::slice::ref_slice; use rustc_back::slice::ref_slice;
use namespace::Namespace;
use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::middle::region; 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() { for impl_item in impl_items() {
let ty_impl_item = tcx.associated_item(tcx.hir.local_def_id(impl_item.id)); 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) 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 // Check that impl definition matches trait definition
if let Some(ty_trait_item) = ty_trait_item { if let Some(ty_trait_item) = ty_trait_item {

View File

@ -8,11 +8,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use namespace::Namespace;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir; use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::traits; 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>, pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
crate_num: CrateNum) { crate_num: CrateNum) {
@ -28,19 +29,10 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> {
impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId, fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId,
overlap: traits::OverlapResult) { overlap: traits::OverlapResult) {
#[derive(Copy, Clone, PartialEq)]
enum Namespace {
Type,
Value,
}
let name_and_namespace = |def_id| { let name_and_namespace = |def_id| {
let item = self.tcx.associated_item(def_id); let item = self.tcx.associated_item(def_id);
(item.name, match item.kind { (item.name, Namespace::from(item.kind))
ty::AssociatedKind::Type => Namespace::Type,
ty::AssociatedKind::Const |
ty::AssociatedKind::Method => Namespace::Value,
})
}; };
let impl_items1 = self.tcx.associated_item_def_ids(impl1); let impl_items1 = self.tcx.associated_item_def_ids(impl1);

View File

@ -123,6 +123,7 @@ mod constrained_type_params;
mod impl_wf_check; mod impl_wf_check;
mod coherence; mod coherence;
mod variance; mod variance;
mod namespace;
pub struct TypeAndSubsts<'tcx> { pub struct TypeAndSubsts<'tcx> {
substs: &'tcx Substs<'tcx>, substs: &'tcx Substs<'tcx>,

View File

@ -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,
}
}
}

View File

@ -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();
}

View File

@ -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() {}