auto merge of #19789 : nick29581/rust/assoc-ufcs2, r=nikomatsakis
Closes #18433
This commit is contained in:
commit
4e8ba4955c
@ -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)),
|
||||
|
@ -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) |
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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(_) |
|
||||
|
@ -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 {} \
|
||||
|
@ -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 \
|
||||
|
@ -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(..) => {
|
||||
|
@ -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() {}
|
||||
|
26
src/test/compile-fail/assoc-path-1.rs
Normal file
26
src/test/compile-fail/assoc-path-1.rs
Normal 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() {}
|
||||
|
34
src/test/compile-fail/assoc-path-2.rs
Normal file
34
src/test/compile-fail/assoc-path-2.rs
Normal 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`
|
||||
}
|
46
src/test/run-pass/assoc-sugar-path.rs
Normal file
46
src/test/run-pass/assoc-sugar-path.rs
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user