Skip to content

Commit 6561664

Browse files
committed
Path types to associated types with form T::A
Closes rust-lang#18433
1 parent 0669a43 commit 6561664

File tree

12 files changed

+244
-25
lines changed

12 files changed

+244
-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

+68-9
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ pub trait AstConv<'tcx> {
7373
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'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>>;
76+
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
77+
None
78+
}
7679

7780
/// What type should we use when a type is omitted?
7881
fn ty_infer(&self, span: Span) -> Ty<'tcx>;
@@ -517,9 +520,9 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
517520
}
518521

519522

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.
523+
/// Instantiates the path for the given trait reference, assuming that it's
524+
/// bound to a valid trait type. Returns the def_id for the defining trait.
525+
/// Fails if the type is a type other than a trait type.
523526
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
524527
rscope: &RS,
525528
ast_trait_ref: &ast::TraitRef,
@@ -846,18 +849,29 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
846849

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

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

851868
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);
869+
if ty_param_def.name == type_name.name {
870+
return Some(trait_ref.substs.type_for_def(ty_param_def));
855871
}
856872
}
857873

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

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

src/librustc_typeck/check/mod.rs

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

1538+
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
1539+
Some(&self.inh.param_env.free_substs)
1540+
}
1541+
15381542
fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
15391543
self.infcx().next_ty_var()
15401544
}
@@ -4866,6 +4870,7 @@ pub fn polytype_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
48664870
def::DefTrait(_) |
48674871
def::DefTy(..) |
48684872
def::DefAssociatedTy(..) |
4873+
def::DefAssociatedPath(..) |
48694874
def::DefPrimTy(_) |
48704875
def::DefTyParam(..)=> {
48714876
fcx.ccx.tcx.sess.span_bug(sp, "expected value, found type");
@@ -4974,6 +4979,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
49744979
def::DefTyParamBinder(..) |
49754980
def::DefTy(..) |
49764981
def::DefAssociatedTy(..) |
4982+
def::DefAssociatedPath(..) |
49774983
def::DefTrait(..) |
49784984
def::DefPrimTy(..) |
49794985
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)