Check namespaces when resolving associated items in typeck
This commit is contained in:
parent
cbf5d39cca
commit
b522ee15ce
@ -18,6 +18,7 @@ use hir;
|
||||
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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
|
||||
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);
|
||||
|
@ -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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
/// 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))
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ use super::suggest;
|
||||
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 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
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()
|
||||
|
@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
|
||||
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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// 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<_>>();
|
||||
|
||||
|
@ -88,6 +88,7 @@ use astconv::AstConv;
|
||||
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 {
|
||||
|
@ -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);
|
||||
|
@ -123,6 +123,7 @@ mod constrained_type_params;
|
||||
mod impl_wf_check;
|
||||
mod coherence;
|
||||
mod variance;
|
||||
mod namespace;
|
||||
|
||||
pub struct TypeAndSubsts<'tcx> {
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
|
39
src/librustc_typeck/namespace.rs
Normal file
39
src/librustc_typeck/namespace.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
24
src/test/run-pass/issue-35600.rs
Normal file
24
src/test/run-pass/issue-35600.rs
Normal 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();
|
||||
}
|
27
src/test/run-pass/issue-44247.rs
Normal file
27
src/test/run-pass/issue-44247.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user