auto merge of #19789 : nick29581/rust/assoc-ufcs2, r=nikomatsakis

Closes #18433
This commit is contained in:
bors 2014-12-17 08:13:07 +00:00
commit 4e8ba4955c
12 changed files with 244 additions and 26 deletions

View File

@ -443,6 +443,10 @@ impl tr for def::Def {
def::DefTrait(did) => def::DefTrait(did.tr(dcx)),
def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum),
def::DefAssociatedTy(did) => def::DefAssociatedTy(did.tr(dcx)),
def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did), ident) =>
def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did.tr(dcx)), ident),
def::DefAssociatedPath(def::TyParamProvenance::FromParam(did), ident) =>
def::DefAssociatedPath(def::TyParamProvenance::FromParam(did.tr(dcx)), ident),
def::DefPrimTy(p) => def::DefPrimTy(p),
def::DefTyParam(s, did, v) => def::DefTyParam(s, did.tr(dcx), v),
def::DefUse(did) => def::DefUse(did.tr(dcx)),

View File

@ -28,6 +28,10 @@ pub enum Def {
DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
DefTy(ast::DefId, bool /* is_enum */),
DefAssociatedTy(ast::DefId),
// A partially resolved path to an associated type `T::U` where `T` is a concrete
// type (indicated by the DefId) which implements a trait which has an associated
// type `U` (indicated by the Ident).
DefAssociatedPath(TyParamProvenance, ast::Ident),
DefTrait(ast::DefId),
DefPrimTy(ast::PrimTy),
DefTyParam(ParamSpace, ast::DefId, uint),
@ -60,6 +64,12 @@ pub enum MethodProvenance {
FromImpl(ast::DefId),
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum TyParamProvenance {
FromSelf(ast::DefId),
FromParam(ast::DefId),
}
impl MethodProvenance {
pub fn map<F>(self, f: F) -> MethodProvenance where
F: FnOnce(ast::DefId) -> ast::DefId,
@ -73,6 +83,17 @@ impl MethodProvenance {
impl Copy for MethodProvenance {}
impl TyParamProvenance {
pub fn def_id(&self) -> ast::DefId {
match *self {
TyParamProvenance::FromSelf(ref did) => did.clone(),
TyParamProvenance::FromParam(ref did) => did.clone(),
}
}
}
impl Copy for TyParamProvenance {}
impl Def {
pub fn def_id(&self) -> ast::DefId {
match *self {
@ -80,7 +101,9 @@ impl Def {
DefForeignMod(id) | DefStatic(id, _) |
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) |
DefTyParam(_, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
DefMethod(id, _, _) | DefConst(id) => {
DefMethod(id, _, _) | DefConst(id) |
DefAssociatedPath(TyParamProvenance::FromSelf(id), _) |
DefAssociatedPath(TyParamProvenance::FromParam(id), _) => {
id
}
DefLocal(id) |

View File

@ -595,7 +595,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) |
def::DefAssociatedTy(..) => {
def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
Ok(Rc::new(cmt_ {
id:id,
span:span,

View File

@ -2027,7 +2027,7 @@ impl<'a> Resolver<'a> {
is_public,
DUMMY_SP)
}
DefTy(..) | DefAssociatedTy(..) => {
DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => {
debug!("(building reduced graph for external \
crate) building type {}", final_ident);
@ -3361,8 +3361,7 @@ impl<'a> Resolver<'a> {
let module_path_len = module_path.len();
assert!(module_path_len > 0);
debug!("(resolving module path for import) processing `{}` rooted at \
`{}`",
debug!("(resolving module path for import) processing `{}` rooted at `{}`",
self.names_to_string(module_path),
self.module_to_string(&*module_));
@ -4960,14 +4959,10 @@ impl<'a> Resolver<'a> {
result_def =
Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
if path.segments
.iter()
.any(|s| s.parameters.has_lifetimes()) {
if path.segments[0].parameters.has_lifetimes() {
span_err!(self.session, path.span, E0157,
"lifetime parameters are not allowed on this type");
} else if path.segments
.iter()
.any(|s| !s.parameters.is_empty()) {
} else if !path.segments[0].parameters.is_empty() {
span_err!(self.session, path.span, E0153,
"type parameters are not allowed on this type");
}
@ -5309,6 +5304,34 @@ impl<'a> Resolver<'a> {
self.resolve_type(&*binding.ty);
}
// A special case for sugared associated type paths `T::A` where `T` is
// a type parameter and `A` is an associated type on some bound of `T`.
if namespace == TypeNS && path.segments.len() == 2 {
match self.resolve_identifier(path.segments[0].identifier,
TypeNS,
true,
path.span) {
Some((def, last_private)) => {
match def {
DefTyParam(_, did, _) => {
let def = DefAssociatedPath(TyParamProvenance::FromParam(did),
path.segments.last()
.unwrap().identifier);
return Some((def, last_private));
}
DefSelfTy(nid) => {
let def = DefAssociatedPath(TyParamProvenance::FromSelf(local_def(nid)),
path.segments.last()
.unwrap().identifier);
return Some((def, last_private));
}
_ => {}
}
}
_ => {}
}
}
if path.global {
return self.resolve_crate_relative_path(path, namespace);
}
@ -5561,8 +5584,7 @@ impl<'a> Resolver<'a> {
let search_result = match namespace {
ValueNS => {
let renamed = mtwt::resolve(ident);
self.search_ribs(self.value_ribs.as_slice(),
renamed, span)
self.search_ribs(self.value_ribs.as_slice(), renamed, span)
}
TypeNS => {
let name = ident.name;

View File

@ -221,6 +221,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
def::DefStruct(_) => Some(recorder::StructRef),
def::DefTy(..) |
def::DefAssociatedTy(..) |
def::DefAssociatedPath(..) |
def::DefTrait(_) => Some(recorder::TypeRef),
def::DefStatic(_, _) |
def::DefConst(_) |

View File

@ -205,7 +205,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
def::DefUse(..) | def::DefTyParamBinder(..) |
def::DefRegion(..) | def::DefLabel(..) | def::DefTyParam(..) |
def::DefSelfTy(..) => {
def::DefSelfTy(..) | def::DefAssociatedPath(..) => {
bcx.tcx().sess.span_bug(
ref_expr.span,
format!("cannot translate def {} \

View File

@ -74,6 +74,14 @@ pub trait AstConv<'tcx> {
fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx>;
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
/// Return an (optional) substitution to convert bound type parameters that
/// are in scope into free ones. This function should only return Some
/// within a fn body.
/// See ParameterEnvironment::free_substs for more information.
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
None
}
/// What type should we use when a type is omitted?
fn ty_infer(&self, span: Span) -> Ty<'tcx>;
@ -517,9 +525,9 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
}
/// Instantiates the path for the given trait reference, assuming that it's bound to a valid trait
/// type. Returns the def_id for the defining trait. Fails if the type is a type other than a trait
/// type.
/// Instantiates the path for the given trait reference, assuming that it's
/// bound to a valid trait type. Returns the def_id for the defining trait.
/// Fails if the type is a type other than a trait type.
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
rscope: &RS,
ast_trait_ref: &ast::TraitRef,
@ -846,13 +854,8 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
let trait_def = this.get_trait_def(trait_ref.def_id);
for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() {
if ty_param_def.name == qpath.item_name.name {
debug!("qpath_to_ty: corresponding ty_param_def={}", ty_param_def);
return trait_ref.substs.type_for_def(ty_param_def);
}
if let Some(ty) = find_assoc_ty(this, &*trait_ref, qpath.item_name) {
return ty;
}
this.tcx().sess.span_bug(ast_ty.span,
@ -860,6 +863,22 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
as a parameter for some reason")
}
fn find_assoc_ty<'tcx, AC>(this: &AC,
trait_ref: &ty::TraitRef<'tcx>,
type_name: ast::Ident)
-> Option<Ty<'tcx>>
where AC: AstConv<'tcx> {
let trait_def = this.get_trait_def(trait_ref.def_id);
for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() {
if ty_param_def.name == type_name.name {
return Some(trait_ref.substs.type_for_def(ty_param_def));
}
}
None
}
// Parses the programmer's textual representation of a type into our
// internal notion of a type.
pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
@ -1011,6 +1030,45 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
.get()).as_slice());
ty::mk_err()
}
def::DefAssociatedPath(typ, assoc_ident) => {
// FIXME(#19541): in both branches we should consider
// associated types in super-traits.
let (assoc_tys, tp_name): (Vec<_>, _) = match typ {
def::TyParamProvenance::FromParam(did) |
def::TyParamProvenance::FromSelf(did) => {
let ty_param_defs = tcx.ty_param_defs.borrow();
let tp_def = &(*ty_param_defs)[did.node];
let assoc_tys = tp_def.bounds.trait_bounds.iter()
.filter_map(|b| find_assoc_ty(this, &**b, assoc_ident))
.collect();
(assoc_tys, token::get_name(tp_def.name).to_string())
}
};
if assoc_tys.len() == 0 {
tcx.sess.span_err(ast_ty.span,
format!("associated type `{}` not \
found for type parameter `{}`",
token::get_ident(assoc_ident),
tp_name).as_slice());
return ty::mk_err()
}
if assoc_tys.len() > 1 {
tcx.sess.span_err(ast_ty.span,
format!("ambiguous associated type \
`{}` in bounds of `{}`",
token::get_ident(assoc_ident),
tp_name).as_slice());
}
let mut result_ty = assoc_tys[0];
if let Some(substs) = this.get_free_substs() {
result_ty = result_ty.subst(tcx, substs);
}
result_ty
}
_ => {
tcx.sess.span_fatal(ast_ty.span,
format!("found value name used \

View File

@ -1534,6 +1534,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
ty::lookup_trait_def(self.tcx(), id)
}
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
Some(&self.inh.param_env.free_substs)
}
fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
self.infcx().next_ty_var()
}
@ -4865,6 +4869,7 @@ pub fn polytype_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
def::DefTrait(_) |
def::DefTy(..) |
def::DefAssociatedTy(..) |
def::DefAssociatedPath(..) |
def::DefPrimTy(_) |
def::DefTyParam(..)=> {
fcx.ccx.tcx.sess.span_bug(sp, "expected value, found type");
@ -4973,6 +4978,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
def::DefTyParamBinder(..) |
def::DefTy(..) |
def::DefAssociatedTy(..) |
def::DefAssociatedPath(..) |
def::DefTrait(..) |
def::DefPrimTy(..) |
def::DefTyParam(..) => {

View File

@ -20,8 +20,6 @@ pub trait Foo {
fn foo2<I: Foo>(x: I) {
let _: A = x.boo(); //~ERROR use of undeclared
let _: I::A = x.boo(); //~ERROR failed to resolve
//~^ERROR use of undeclared type name `I::A`
}
pub fn main() {}

View File

@ -0,0 +1,26 @@
// Copyright 2014 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.
// Test that we have one and only one associated type per ref.
#![feature(associated_types)]
pub trait Foo {
type A;
}
pub trait Bar {
type A;
}
pub fn f1<T>(a: T, x: T::A) {} //~ERROR associated type `A` not found
pub fn f2<T: Foo + Bar>(a: T, x: T::A) {} //~ERROR ambiguous associated type `A`
pub fn main() {}

View File

@ -0,0 +1,34 @@
// Copyright 2014 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.
// Test type checking of uses of associated types via sugary paths.
#![feature(associated_types)]
pub trait Foo {
type A;
}
impl Foo for int {
type A = uint;
}
pub fn f1<T: Foo>(a: T, x: T::A) {}
pub fn f2<T: Foo>(a: T) -> T::A {
panic!();
}
pub fn main() {
f1(2i, 4i); //~ERROR the trait `Foo` is not implemented
f1(2u, 4u); //~ERROR the trait `Foo` is not implemented
f1(2u, 4i); //~ERROR the trait `Foo` is not implemented
let _: int = f2(2i); //~ERROR mismatched types: expected `int`, found `uint`
}

View File

@ -0,0 +1,46 @@
// Copyright 2014 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.
// Test paths to associated types using the type-parameter-only sugar.
#![feature(associated_types)]
pub trait Foo {
type A;
fn boo(&self) -> Self::A;
}
impl Foo for int {
type A = uint;
fn boo(&self) -> uint {
5
}
}
// Using a type via a function.
pub fn bar<T: Foo>(a: T, x: T::A) -> T::A {
let _: T::A = a.boo();
x
}
// Using a type via an impl.
trait C {
fn f();
}
struct B<X>;
impl<T: Foo> C for B<T> {
fn f() {
let x: T::A = panic!();
}
}
pub fn main() {
let z: uint = bar(2i, 4u);
}