Skip to content

Commit 4e8ba49

Browse files
committed
auto merge of #19789 : nick29581/rust/assoc-ufcs2, r=nikomatsakis
Closes #18433
2 parents 4265e86 + 743d6a4 commit 4e8ba49

File tree

12 files changed

+243
-25
lines changed

12 files changed

+243
-25
lines changed

src/librustc/middle/astencode.rs

+4
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,10 @@ impl tr for def::Def {
443443
def::DefTrait(did) => def::DefTrait(did.tr(dcx)),
444444
def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum),
445445
def::DefAssociatedTy(did) => def::DefAssociatedTy(did.tr(dcx)),
446+
def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did), ident) =>
447+
def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did.tr(dcx)), ident),
448+
def::DefAssociatedPath(def::TyParamProvenance::FromParam(did), ident) =>
449+
def::DefAssociatedPath(def::TyParamProvenance::FromParam(did.tr(dcx)), ident),
446450
def::DefPrimTy(p) => def::DefPrimTy(p),
447451
def::DefTyParam(s, did, v) => def::DefTyParam(s, did.tr(dcx), v),
448452
def::DefUse(did) => def::DefUse(did.tr(dcx)),

src/librustc/middle/def.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ pub enum Def {
2828
DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
2929
DefTy(ast::DefId, bool /* is_enum */),
3030
DefAssociatedTy(ast::DefId),
31+
// A partially resolved path to an associated type `T::U` where `T` is a concrete
32+
// type (indicated by the DefId) which implements a trait which has an associated
33+
// type `U` (indicated by the Ident).
34+
DefAssociatedPath(TyParamProvenance, ast::Ident),
3135
DefTrait(ast::DefId),
3236
DefPrimTy(ast::PrimTy),
3337
DefTyParam(ParamSpace, ast::DefId, uint),
@@ -60,6 +64,12 @@ pub enum MethodProvenance {
6064
FromImpl(ast::DefId),
6165
}
6266

67+
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
68+
pub enum TyParamProvenance {
69+
FromSelf(ast::DefId),
70+
FromParam(ast::DefId),
71+
}
72+
6373
impl MethodProvenance {
6474
pub fn map<F>(self, f: F) -> MethodProvenance where
6575
F: FnOnce(ast::DefId) -> ast::DefId,
@@ -73,14 +83,27 @@ impl MethodProvenance {
7383

7484
impl Copy for MethodProvenance {}
7585

86+
impl TyParamProvenance {
87+
pub fn def_id(&self) -> ast::DefId {
88+
match *self {
89+
TyParamProvenance::FromSelf(ref did) => did.clone(),
90+
TyParamProvenance::FromParam(ref did) => did.clone(),
91+
}
92+
}
93+
}
94+
95+
impl Copy for TyParamProvenance {}
96+
7697
impl Def {
7798
pub fn def_id(&self) -> ast::DefId {
7899
match *self {
79100
DefFn(id, _) | DefStaticMethod(id, _) | DefMod(id) |
80101
DefForeignMod(id) | DefStatic(id, _) |
81102
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) |
82103
DefTyParam(_, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
83-
DefMethod(id, _, _) | DefConst(id) => {
104+
DefMethod(id, _, _) | DefConst(id) |
105+
DefAssociatedPath(TyParamProvenance::FromSelf(id), _) |
106+
DefAssociatedPath(TyParamProvenance::FromParam(id), _) => {
84107
id
85108
}
86109
DefLocal(id) |

src/librustc/middle/mem_categorization.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
595595
def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
596596
def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
597597
def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) |
598-
def::DefAssociatedTy(..) => {
598+
def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
599599
Ok(Rc::new(cmt_ {
600600
id:id,
601601
span:span,

src/librustc/middle/resolve.rs

+33-11
Original file line numberDiff line numberDiff line change
@@ -2027,7 +2027,7 @@ impl<'a> Resolver<'a> {
20272027
is_public,
20282028
DUMMY_SP)
20292029
}
2030-
DefTy(..) | DefAssociatedTy(..) => {
2030+
DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => {
20312031
debug!("(building reduced graph for external \
20322032
crate) building type {}", final_ident);
20332033

@@ -3361,8 +3361,7 @@ impl<'a> Resolver<'a> {
33613361
let module_path_len = module_path.len();
33623362
assert!(module_path_len > 0);
33633363

3364-
debug!("(resolving module path for import) processing `{}` rooted at \
3365-
`{}`",
3364+
debug!("(resolving module path for import) processing `{}` rooted at `{}`",
33663365
self.names_to_string(module_path),
33673366
self.module_to_string(&*module_));
33683367

@@ -4960,14 +4959,10 @@ impl<'a> Resolver<'a> {
49604959
result_def =
49614960
Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
49624961

4963-
if path.segments
4964-
.iter()
4965-
.any(|s| s.parameters.has_lifetimes()) {
4962+
if path.segments[0].parameters.has_lifetimes() {
49664963
span_err!(self.session, path.span, E0157,
49674964
"lifetime parameters are not allowed on this type");
4968-
} else if path.segments
4969-
.iter()
4970-
.any(|s| !s.parameters.is_empty()) {
4965+
} else if !path.segments[0].parameters.is_empty() {
49714966
span_err!(self.session, path.span, E0153,
49724967
"type parameters are not allowed on this type");
49734968
}
@@ -5309,6 +5304,34 @@ impl<'a> Resolver<'a> {
53095304
self.resolve_type(&*binding.ty);
53105305
}
53115306

5307+
// A special case for sugared associated type paths `T::A` where `T` is
5308+
// a type parameter and `A` is an associated type on some bound of `T`.
5309+
if namespace == TypeNS && path.segments.len() == 2 {
5310+
match self.resolve_identifier(path.segments[0].identifier,
5311+
TypeNS,
5312+
true,
5313+
path.span) {
5314+
Some((def, last_private)) => {
5315+
match def {
5316+
DefTyParam(_, did, _) => {
5317+
let def = DefAssociatedPath(TyParamProvenance::FromParam(did),
5318+
path.segments.last()
5319+
.unwrap().identifier);
5320+
return Some((def, last_private));
5321+
}
5322+
DefSelfTy(nid) => {
5323+
let def = DefAssociatedPath(TyParamProvenance::FromSelf(local_def(nid)),
5324+
path.segments.last()
5325+
.unwrap().identifier);
5326+
return Some((def, last_private));
5327+
}
5328+
_ => {}
5329+
}
5330+
}
5331+
_ => {}
5332+
}
5333+
}
5334+
53125335
if path.global {
53135336
return self.resolve_crate_relative_path(path, namespace);
53145337
}
@@ -5561,8 +5584,7 @@ impl<'a> Resolver<'a> {
55615584
let search_result = match namespace {
55625585
ValueNS => {
55635586
let renamed = mtwt::resolve(ident);
5564-
self.search_ribs(self.value_ribs.as_slice(),
5565-
renamed, span)
5587+
self.search_ribs(self.value_ribs.as_slice(), renamed, span)
55665588
}
55675589
TypeNS => {
55685590
let name = ident.name;

src/librustc_trans/save/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
221221
def::DefStruct(_) => Some(recorder::StructRef),
222222
def::DefTy(..) |
223223
def::DefAssociatedTy(..) |
224+
def::DefAssociatedPath(..) |
224225
def::DefTrait(_) => Some(recorder::TypeRef),
225226
def::DefStatic(_, _) |
226227
def::DefConst(_) |

src/librustc_trans/trans/callee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
205205
def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
206206
def::DefUse(..) | def::DefTyParamBinder(..) |
207207
def::DefRegion(..) | def::DefLabel(..) | def::DefTyParam(..) |
208-
def::DefSelfTy(..) => {
208+
def::DefSelfTy(..) | def::DefAssociatedPath(..) => {
209209
bcx.tcx().sess.span_bug(
210210
ref_expr.span,
211211
format!("cannot translate def {} \

src/librustc_typeck/astconv.rs

+67-9
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ pub trait AstConv<'tcx> {
7474
fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx>;
7575
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
7676

77+
/// Return an (optional) substitution to convert bound type parameters that
78+
/// are in scope into free ones. This function should only return Some
79+
/// within a fn body.
80+
/// See ParameterEnvironment::free_substs for more information.
81+
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
82+
None
83+
}
84+
7785
/// What type should we use when a type is omitted?
7886
fn ty_infer(&self, span: Span) -> Ty<'tcx>;
7987

@@ -517,9 +525,9 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
517525
}
518526

519527

520-
/// Instantiates the path for the given trait reference, assuming that it's bound to a valid trait
521-
/// type. Returns the def_id for the defining trait. Fails if the type is a type other than a trait
522-
/// type.
528+
/// Instantiates the path for the given trait reference, assuming that it's
529+
/// bound to a valid trait type. Returns the def_id for the defining trait.
530+
/// Fails if the type is a type other than a trait type.
523531
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
524532
rscope: &RS,
525533
ast_trait_ref: &ast::TraitRef,
@@ -846,18 +854,29 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
846854

847855
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
848856

857+
if let Some(ty) = find_assoc_ty(this, &*trait_ref, qpath.item_name) {
858+
return ty;
859+
}
860+
861+
this.tcx().sess.span_bug(ast_ty.span,
862+
"this associated type didn't get added \
863+
as a parameter for some reason")
864+
}
865+
866+
fn find_assoc_ty<'tcx, AC>(this: &AC,
867+
trait_ref: &ty::TraitRef<'tcx>,
868+
type_name: ast::Ident)
869+
-> Option<Ty<'tcx>>
870+
where AC: AstConv<'tcx> {
849871
let trait_def = this.get_trait_def(trait_ref.def_id);
850872

851873
for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() {
852-
if ty_param_def.name == qpath.item_name.name {
853-
debug!("qpath_to_ty: corresponding ty_param_def={}", ty_param_def);
854-
return trait_ref.substs.type_for_def(ty_param_def);
874+
if ty_param_def.name == type_name.name {
875+
return Some(trait_ref.substs.type_for_def(ty_param_def));
855876
}
856877
}
857878

858-
this.tcx().sess.span_bug(ast_ty.span,
859-
"this associated type didn't get added \
860-
as a parameter for some reason")
879+
None
861880
}
862881

863882
// Parses the programmer's textual representation of a type into our
@@ -1011,6 +1030,45 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
10111030
.get()).as_slice());
10121031
ty::mk_err()
10131032
}
1033+
def::DefAssociatedPath(typ, assoc_ident) => {
1034+
// FIXME(#19541): in both branches we should consider
1035+
// associated types in super-traits.
1036+
let (assoc_tys, tp_name): (Vec<_>, _) = match typ {
1037+
def::TyParamProvenance::FromParam(did) |
1038+
def::TyParamProvenance::FromSelf(did) => {
1039+
let ty_param_defs = tcx.ty_param_defs.borrow();
1040+
let tp_def = &(*ty_param_defs)[did.node];
1041+
let assoc_tys = tp_def.bounds.trait_bounds.iter()
1042+
.filter_map(|b| find_assoc_ty(this, &**b, assoc_ident))
1043+
.collect();
1044+
(assoc_tys, token::get_name(tp_def.name).to_string())
1045+
}
1046+
};
1047+
1048+
if assoc_tys.len() == 0 {
1049+
tcx.sess.span_err(ast_ty.span,
1050+
format!("associated type `{}` not \
1051+
found for type parameter `{}`",
1052+
token::get_ident(assoc_ident),
1053+
tp_name).as_slice());
1054+
return ty::mk_err()
1055+
}
1056+
1057+
if assoc_tys.len() > 1 {
1058+
tcx.sess.span_err(ast_ty.span,
1059+
format!("ambiguous associated type \
1060+
`{}` in bounds of `{}`",
1061+
token::get_ident(assoc_ident),
1062+
tp_name).as_slice());
1063+
}
1064+
1065+
let mut result_ty = assoc_tys[0];
1066+
if let Some(substs) = this.get_free_substs() {
1067+
result_ty = result_ty.subst(tcx, substs);
1068+
}
1069+
1070+
result_ty
1071+
}
10141072
_ => {
10151073
tcx.sess.span_fatal(ast_ty.span,
10161074
format!("found value name used \

src/librustc_typeck/check/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
15341534
ty::lookup_trait_def(self.tcx(), id)
15351535
}
15361536

1537+
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
1538+
Some(&self.inh.param_env.free_substs)
1539+
}
1540+
15371541
fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
15381542
self.infcx().next_ty_var()
15391543
}
@@ -4865,6 +4869,7 @@ pub fn polytype_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
48654869
def::DefTrait(_) |
48664870
def::DefTy(..) |
48674871
def::DefAssociatedTy(..) |
4872+
def::DefAssociatedPath(..) |
48684873
def::DefPrimTy(_) |
48694874
def::DefTyParam(..)=> {
48704875
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>,
49734978
def::DefTyParamBinder(..) |
49744979
def::DefTy(..) |
49754980
def::DefAssociatedTy(..) |
4981+
def::DefAssociatedPath(..) |
49764982
def::DefTrait(..) |
49774983
def::DefPrimTy(..) |
49784984
def::DefTyParam(..) => {

src/test/compile-fail/assoc-eq-1.rs

-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ pub trait Foo {
2020

2121
fn foo2<I: Foo>(x: I) {
2222
let _: A = x.boo(); //~ERROR use of undeclared
23-
let _: I::A = x.boo(); //~ERROR failed to resolve
24-
//~^ERROR use of undeclared type name `I::A`
2523
}
2624

2725
pub fn main() {}

src/test/compile-fail/assoc-path-1.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we have one and only one associated type per ref.
12+
13+
#![feature(associated_types)]
14+
15+
pub trait Foo {
16+
type A;
17+
}
18+
pub trait Bar {
19+
type A;
20+
}
21+
22+
pub fn f1<T>(a: T, x: T::A) {} //~ERROR associated type `A` not found
23+
pub fn f2<T: Foo + Bar>(a: T, x: T::A) {} //~ERROR ambiguous associated type `A`
24+
25+
pub fn main() {}
26+

src/test/compile-fail/assoc-path-2.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test type checking of uses of associated types via sugary paths.
12+
13+
#![feature(associated_types)]
14+
15+
pub trait Foo {
16+
type A;
17+
}
18+
19+
impl Foo for int {
20+
type A = uint;
21+
}
22+
23+
pub fn f1<T: Foo>(a: T, x: T::A) {}
24+
pub fn f2<T: Foo>(a: T) -> T::A {
25+
panic!();
26+
}
27+
28+
pub fn main() {
29+
f1(2i, 4i); //~ERROR the trait `Foo` is not implemented
30+
f1(2u, 4u); //~ERROR the trait `Foo` is not implemented
31+
f1(2u, 4i); //~ERROR the trait `Foo` is not implemented
32+
33+
let _: int = f2(2i); //~ERROR mismatched types: expected `int`, found `uint`
34+
}

0 commit comments

Comments
 (0)