Skip to content

Commit

Permalink
Auto merge of #45297 - matthewjasper:associated-item-namespaces, r=pe…
Browse files Browse the repository at this point in the history
…trochenkov

Check namespaces when resolving associated items in typeck

Closes #35600
Closes #44247
Fixes a "cannot move a value of type..." error in the same case as #44247 but with the associated items swapped.
  • Loading branch information
bors committed Oct 16, 2017
2 parents fdec805 + b522ee1 commit abe7c87
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 25 deletions.
8 changes: 6 additions & 2 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 5 additions & 4 deletions src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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))
}
}
8 changes: 6 additions & 2 deletions src/librustc_typeck/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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()
Expand Down
13 changes: 8 additions & 5 deletions src/librustc_typeck/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(|| {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<_>>();

Expand Down
9 changes: 8 additions & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
14 changes: 3 additions & 11 deletions src/librustc_typeck/coherence/inherent_impls_overlap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
39 changes: 39 additions & 0 deletions src/librustc_typeck/namespace.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 24 additions & 0 deletions src/test/run-pass/issue-35600.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 27 additions & 0 deletions src/test/run-pass/issue-44247.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit abe7c87

Please sign in to comment.