From 78a841810eb36e486ba68e6b9fa80e45d805cc4f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 5 Aug 2014 19:44:21 -0700 Subject: [PATCH] librustc: Implement associated types behind a feature gate. The implementation essentially desugars during type collection and AST type conversion time into the parameter scheme we have now. Only fully qualified names--e.g. `::Bar`--are supported. --- src/doc/rust.md | 2 + src/jemalloc | 2 +- src/librustc/lint/builtin.rs | 21 +- src/librustc/lint/context.rs | 21 + src/librustc/metadata/csearch.rs | 6 + src/librustc/metadata/decoder.rs | 27 +- src/librustc/metadata/encoder.rs | 170 ++- src/librustc/metadata/tydecode.rs | 5 + src/librustc/metadata/tyencode.rs | 2 + src/librustc/middle/astencode.rs | 21 +- src/librustc/middle/dead.rs | 8 +- src/librustc/middle/def.rs | 7 +- src/librustc/middle/expr_use_visitor.rs | 3 + src/librustc/middle/mem_categorization.rs | 7 +- src/librustc/middle/privacy.rs | 48 +- src/librustc/middle/reachable.rs | 6 +- src/librustc/middle/resolve.rs | 197 ++- src/librustc/middle/save/mod.rs | 55 +- src/librustc/middle/stability.rs | 13 +- src/librustc/middle/subst.rs | 15 +- src/librustc/middle/trans/base.rs | 19 +- src/librustc/middle/trans/callee.rs | 6 +- src/librustc/middle/trans/debuginfo.rs | 5 + src/librustc/middle/trans/inline.rs | 6 + src/librustc/middle/trans/meth.rs | 33 +- src/librustc/middle/trans/monomorphize.rs | 3 + src/librustc/middle/trans/reflect.rs | 1 + src/librustc/middle/ty.rs | 158 +- src/librustc/middle/ty_fold.rs | 1 + src/librustc/middle/typeck/astconv.rs | 216 ++- src/librustc/middle/typeck/check/method.rs | 18 +- src/librustc/middle/typeck/check/mod.rs | 114 +- src/librustc/middle/typeck/coherence/mod.rs | 6 +- src/librustc/middle/typeck/collect.rs | 1272 ++++++++++++++--- .../middle/typeck/infer/error_reporting.rs | 2 + src/librustc/middle/typeck/variance.rs | 1 + src/librustc/util/ppaux.rs | 8 +- src/librustdoc/clean/inline.rs | 4 + src/librustdoc/clean/mod.rs | 58 +- src/librustdoc/fold.rs | 6 + src/librustdoc/html/item_type.rs | 3 + src/librustdoc/html/render.rs | 1 + src/librustdoc/passes.rs | 3 + src/librustdoc/stability_summary.rs | 5 +- src/libsyntax/ast.rs | 34 + src/libsyntax/ast_map/blocks.rs | 3 + src/libsyntax/ast_map/mod.rs | 108 +- src/libsyntax/ast_util.rs | 57 + src/libsyntax/config.rs | 4 +- src/libsyntax/ext/tt/macro_rules.rs | 5 +- src/libsyntax/feature_gate.rs | 26 +- src/libsyntax/fold.rs | 135 +- src/libsyntax/parse/parser.rs | 244 ++-- src/libsyntax/print/pprust.rs | 42 +- src/libsyntax/visit.rs | 27 +- .../associated-types-feature-gate.rs | 33 + .../associated-types-in-ambiguous-context.rs | 39 + .../associated-types-in-wrong-context.rs | 32 + src/test/compile-fail/class-method-missing.rs | 2 +- src/test/compile-fail/issue-3344.rs | 2 +- .../compile-fail/missing-derivable-attr.rs | 2 +- .../associated-types-in-default-method.rs | 39 + src/test/run-pass/associated-types-in-fn.rs | 39 + .../associated-types-in-impl-generics.rs | 47 + .../associated-types-in-inherent-method.rs | 41 + src/test/run-pass/associated-types-simple.rs | 35 + src/test/run-pass/macro-method-issue-4621.rs | 2 +- 67 files changed, 3032 insertions(+), 551 deletions(-) create mode 100644 src/test/compile-fail/associated-types-feature-gate.rs create mode 100644 src/test/compile-fail/associated-types-in-ambiguous-context.rs create mode 100644 src/test/compile-fail/associated-types-in-wrong-context.rs create mode 100644 src/test/run-pass/associated-types-in-default-method.rs create mode 100644 src/test/run-pass/associated-types-in-fn.rs create mode 100644 src/test/run-pass/associated-types-in-impl-generics.rs create mode 100644 src/test/run-pass/associated-types-in-inherent-method.rs create mode 100644 src/test/run-pass/associated-types-simple.rs diff --git a/src/doc/rust.md b/src/doc/rust.md index 345b7615168f0..5028f224475a9 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -2557,6 +2557,8 @@ The currently implemented features of the reference compiler are: * `tuple_indexing` - Allows use of tuple indexing (expressions like `expr.0`) +* `associated_types` - Allows type aliases in traits. Experimental. + If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about #[feature] directives which enabled the new feature (because the directive is no longer necessary). However, if diff --git a/src/jemalloc b/src/jemalloc index 2dba541881fb8..aae04170ccbfe 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit 2dba541881fb8e35246d653bbe2e7c7088777a4a +Subproject commit aae04170ccbfeea620502106b581c3c216cd132a diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 836d355d55baa..473c3935769be 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -844,6 +844,17 @@ fn method_context(cx: &Context, m: &ast::Method) -> MethodContext { } } } + ty::TypeTraitItem(typedef) => { + match typedef.container { + ty::TraitContainer(..) => TraitDefaultImpl, + ty::ImplContainer(cid) => { + match ty::impl_trait_ref(cx.tcx, cid) { + Some(..) => TraitImpl, + None => PlainImpl + } + } + } + } } } } @@ -1511,13 +1522,9 @@ impl LintPass for Stability { method_num: index, .. }) => { - match ty::trait_item(cx.tcx, - trait_ref.def_id, - index) { - ty::MethodTraitItem(method) => { - method.def_id - } - } + ty::trait_item(cx.tcx, + trait_ref.def_id, + index).def_id() } } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index e39685705dfe0..51852a347d16e 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -25,6 +25,7 @@ //! for all lint attributes. use middle::privacy::ExportedItems; +use middle::subst; use middle::ty; use middle::typeck::astconv::AstConv; use middle::typeck::infer; @@ -491,6 +492,26 @@ impl<'a, 'tcx> AstConv<'tcx> for Context<'a, 'tcx>{ fn ty_infer(&self, _span: Span) -> ty::t { infer::new_infer_ctxt(self.tcx).next_ty_var() } + + fn associated_types_of_trait_are_valid(&self, _: ty::t, _: ast::DefId) + -> bool { + // FIXME(pcwalton): This is wrong. + true + } + + fn associated_type_binding(&self, + _: Span, + _: Option, + trait_id: ast::DefId, + associated_type_id: ast::DefId) + -> ty::t { + // FIXME(pcwalton): This is wrong. + let trait_def = self.get_trait_def(trait_id); + let index = ty::associated_type_parameter_index(self.tcx, + &*trait_def, + associated_type_id); + ty::mk_param(self.tcx, subst::TypeSpace, index, associated_type_id) + } } impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index c27f1d9ed1f53..c8ed926d6fe48 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -349,3 +349,9 @@ pub fn get_stability(cstore: &cstore::CStore, let cdata = cstore.get_crate_data(def.krate); decoder::get_stability(&*cdata, def.node) } + +pub fn is_associated_type(cstore: &cstore::CStore, def: ast::DefId) -> bool { + let cdata = cstore.get_crate_data(def.krate); + decoder::is_associated_type(&*cdata, def.node) +} + diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 748e59b75ed63..ac7f83cb385c2 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -23,7 +23,7 @@ use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::def; use middle::lang_items; -use middle::resolve::TraitItemKind; +use middle::resolve::{TraitItemKind, TypeTraitItemKind}; use middle::subst; use middle::ty::{ImplContainer, TraitContainer}; use middle::ty; @@ -167,6 +167,8 @@ fn item_visibility(item: rbml::Doc) -> ast::Visibility { } fn item_sort(item: rbml::Doc) -> char { + // NB(pcwalton): The default of 'r' here is relied upon in + // `is_associated_type` below. let mut ret = 'r'; reader::tagged_docs(item, tag_item_trait_item_sort, |doc| { ret = doc.as_str_slice().as_bytes()[0] as char; @@ -714,6 +716,7 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId) let def_id = item_def_id(doc, cdata); match item_sort(doc) { 'r' | 'p' => impl_items.push(ty::MethodTraitItemId(def_id)), + 't' => impl_items.push(ty::TypeTraitItemId(def_id)), _ => fail!("unknown impl item sort"), } true @@ -733,6 +736,7 @@ pub fn get_trait_item_name_and_kind(intr: Rc, let explicit_self = get_explicit_self(doc); (name, TraitItemKind::from_explicit_self_category(explicit_self)) } + 't' => (name, TypeTraitItemKind), c => { fail!("get_trait_item_name_and_kind(): unknown trait item kind \ in metadata: `{}`", c) @@ -758,13 +762,13 @@ pub fn get_impl_or_trait_item(intr: Rc, }; let name = item_name(&*intr, method_doc); + let vis = item_visibility(method_doc); match item_sort(method_doc) { 'r' | 'p' => { let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics); let fty = doc_method_fty(method_doc, tcx, cdata); - let vis = item_visibility(method_doc); let explicit_self = get_explicit_self(method_doc); let provided_source = get_provided_source(method_doc, cdata); @@ -777,6 +781,14 @@ pub fn get_impl_or_trait_item(intr: Rc, container, provided_source))) } + 't' => { + ty::TypeTraitItem(Rc::new(ty::AssociatedType { + ident: name, + vis: vis, + def_id: def_id, + container: container, + })) + } _ => fail!("unknown impl/trait item sort"), } } @@ -790,6 +802,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId) let def_id = item_def_id(mth, cdata); match item_sort(mth) { 'r' | 'p' => result.push(ty::MethodTraitItemId(def_id)), + 't' => result.push(ty::TypeTraitItemId(def_id)), _ => fail!("unknown trait item sort"), } true @@ -827,6 +840,7 @@ pub fn get_provided_trait_methods(intr: Rc, ty::MethodTraitItem(ref method) => { result.push((*method).clone()) } + ty::TypeTraitItem(_) => {} } } true @@ -1394,3 +1408,12 @@ fn doc_generics(base_doc: rbml::Doc, ty::Generics { types: types, regions: regions } } + +pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool { + let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items); + match maybe_find_item(id, items) { + None => false, + Some(item) => item_sort(item) == 't', + } +} + diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index c4f7c2db6a25f..d27a0d27c7b62 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -416,6 +416,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext, m.ident); } } + ty::TypeTraitItem(_) => {} } } } @@ -887,7 +888,44 @@ fn encode_info_for_method(ecx: &EncodeContext, } encode_method_argument_names(rbml_w, ast_method.pe_fn_decl()); } + Some(_) | None => {} + } + + rbml_w.end_tag(); +} + +fn encode_info_for_associated_type(ecx: &EncodeContext, + rbml_w: &mut Encoder, + associated_type: &ty::AssociatedType, + impl_path: PathElems, + parent_id: NodeId, + typedef_opt: Option>) { + debug!("encode_info_for_associated_type({},{})", + associated_type.def_id, + token::get_ident(associated_type.ident)); + + rbml_w.start_tag(tag_items_data_item); + + encode_def_id(rbml_w, associated_type.def_id); + encode_name(rbml_w, associated_type.ident.name); + encode_visibility(rbml_w, associated_type.vis); + encode_family(rbml_w, 'y'); + encode_parent_item(rbml_w, local_def(parent_id)); + encode_item_sort(rbml_w, 'r'); + + let stab = stability::lookup(ecx.tcx, associated_type.def_id); + encode_stability(rbml_w, stab); + + let elem = ast_map::PathName(associated_type.ident.name); + encode_path(rbml_w, impl_path.chain(Some(elem).move_iter())); + + match typedef_opt { None => {} + Some(typedef) => { + encode_attributes(rbml_w, typedef.attrs.as_slice()); + encode_type(ecx, rbml_w, ty::node_id_to_type(ecx.tcx, + typedef.id)); + } } rbml_w.end_tag(); @@ -1198,6 +1236,10 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_def_id(rbml_w, item_def_id); encode_item_sort(rbml_w, 'r'); } + ty::TypeTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 't'); + } } rbml_w.end_tag(); } @@ -1227,10 +1269,46 @@ fn encode_info_for_item(ecx: &EncodeContext, pos: rbml_w.writer.tell().unwrap(), }); - let ty::MethodTraitItem(method_type) = + let trait_item_type = ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()); - encode_info_for_method(ecx, rbml_w, &*method_type, path.clone(), - false, item.id, ast_item) + match (trait_item_type, ast_item) { + (ty::MethodTraitItem(ref method_type), + Some(&ast::MethodImplItem(_))) => { + encode_info_for_method(ecx, + rbml_w, + &**method_type, + path.clone(), + false, + item.id, + ast_item) + } + (ty::MethodTraitItem(ref method_type), _) => { + encode_info_for_method(ecx, + rbml_w, + &**method_type, + path.clone(), + false, + item.id, + None) + } + (ty::TypeTraitItem(ref associated_type), + Some(&ast::TypeImplItem(ref typedef))) => { + encode_info_for_associated_type(ecx, + rbml_w, + &**associated_type, + path.clone(), + item.id, + Some((*typedef).clone())) + } + (ty::TypeTraitItem(ref associated_type), _) => { + encode_info_for_associated_type(ecx, + rbml_w, + &**associated_type, + path.clone(), + item.id, + None) + } + } } } ItemTrait(_, _, _, ref ms) => { @@ -1253,6 +1331,10 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_def_id(rbml_w, method_def_id); encode_item_sort(rbml_w, 'r'); } + ty::TypeTraitItemId(type_def_id) => { + encode_def_id(rbml_w, type_def_id); + encode_item_sort(rbml_w, 't'); + } } rbml_w.end_tag(); @@ -1281,17 +1363,19 @@ fn encode_info_for_item(ecx: &EncodeContext, rbml_w.start_tag(tag_items_data_item); + encode_parent_item(rbml_w, def_id); + + let stab = stability::lookup(tcx, item_def_id.def_id()); + encode_stability(rbml_w, stab); + let trait_item_type = ty::impl_or_trait_item(tcx, item_def_id.def_id()); + let is_nonstatic_method; match trait_item_type { - ty::MethodTraitItem(method_ty) => { + ty::MethodTraitItem(method_ty) => { let method_def_id = item_def_id.def_id(); encode_method_ty_fields(ecx, rbml_w, &*method_ty); - encode_parent_item(rbml_w, def_id); - - let stab = stability::lookup(tcx, method_def_id); - encode_stability(rbml_w, stab); let elem = ast_map::PathName(method_ty.ident.name); encode_path(rbml_w, @@ -1315,33 +1399,53 @@ fn encode_info_for_item(ecx: &EncodeContext, } } - let trait_item = ms.get(i); - match *trait_item { - RequiredMethod(ref tm) => { - encode_attributes(rbml_w, tm.attrs.as_slice()); - encode_item_sort(rbml_w, 'r'); - encode_parent_sort(rbml_w, 't'); - encode_method_argument_names(rbml_w, &*tm.decl); - } + is_nonstatic_method = method_ty.explicit_self != + ty::StaticExplicitSelfCategory; + } + ty::TypeTraitItem(associated_type) => { + let elem = ast_map::PathName(associated_type.ident.name); + encode_path(rbml_w, + path.clone().chain(Some(elem).move_iter())); - ProvidedMethod(ref m) => { - encode_attributes(rbml_w, m.attrs.as_slice()); - // If this is a static method, we've already - // encoded this. - if method_ty.explicit_self != - ty::StaticExplicitSelfCategory { - // FIXME: I feel like there is something funny - // going on. - let pty = ty::lookup_item_type(tcx, method_def_id); - encode_bounds_and_type(rbml_w, ecx, &pty); - } - encode_item_sort(rbml_w, 'p'); - encode_parent_sort(rbml_w, 't'); - encode_inlined_item(ecx, rbml_w, - IITraitItemRef(def_id, trait_item)); - encode_method_argument_names(rbml_w, &*m.pe_fn_decl()); - } + encode_family(rbml_w, 'y'); + + is_nonstatic_method = false; + } + } + + encode_parent_sort(rbml_w, 't'); + + let trait_item = ms.get(i); + match ms.get(i) { + &RequiredMethod(ref tm) => { + encode_attributes(rbml_w, tm.attrs.as_slice()); + encode_item_sort(rbml_w, 'r'); + encode_method_argument_names(rbml_w, &*tm.decl); + } + + &ProvidedMethod(ref m) => { + encode_attributes(rbml_w, m.attrs.as_slice()); + // If this is a static method, we've already + // encoded this. + if is_nonstatic_method { + // FIXME: I feel like there is something funny + // going on. + let pty = ty::lookup_item_type(tcx, + item_def_id.def_id()); + encode_bounds_and_type(rbml_w, ecx, &pty); } + encode_item_sort(rbml_w, 'p'); + encode_inlined_item(ecx, + rbml_w, + IITraitItemRef(def_id, trait_item)); + encode_method_argument_names(rbml_w, + &*m.pe_fn_decl()); + } + + &TypeTraitItem(ref associated_type) => { + encode_attributes(rbml_w, + associated_type.attrs.as_slice()); + encode_item_sort(rbml_w, 't'); } } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 0e888b39b8516..d319559044c4c 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -630,6 +630,10 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef assert_eq!(next(st), '|'); let index = parse_uint(st); assert_eq!(next(st), '|'); + let associated_with = parse_opt(st, |st| { + parse_def(st, NominalType, |x,y| conv(x,y)) + }); + assert_eq!(next(st), '|'); let bounds = parse_bounds(st, |x,y| conv(x,y)); let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y))); @@ -638,6 +642,7 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef def_id: def_id, space: space, index: index, + associated_with: associated_with, bounds: bounds, default: default } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 3ef1d15cf5651..fd3e4fe6738c7 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -383,6 +383,8 @@ pub fn enc_type_param_def(w: &mut SeekableMemWriter, cx: &ctxt, v: &ty::TypePara mywrite!(w, "{}:{}|{}|{}|", token::get_ident(v.ident), (cx.ds)(v.def_id), v.space.to_uint(), v.index); + enc_opt(w, v.associated_with, |w, did| mywrite!(w, "{}", (cx.ds)(did))); + mywrite!(w, "|"); enc_bounds(w, cx, &v.bounds); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 880445ff38d32..399313ddd8ea9 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -83,7 +83,9 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext, e::IIForeignRef(i) => i.id, e::IITraitItemRef(_, &ast::ProvidedMethod(ref m)) => m.id, e::IITraitItemRef(_, &ast::RequiredMethod(ref m)) => m.id, - e::IIImplItemRef(_, &ast::MethodImplItem(ref m)) => m.id + e::IITraitItemRef(_, &ast::TypeTraitItem(ref ti)) => ti.id, + e::IIImplItemRef(_, &ast::MethodImplItem(ref m)) => m.id, + e::IIImplItemRef(_, &ast::TypeImplItem(ref ti)) => ti.id, }; debug!("> Encoding inlined item: {} ({})", ecx.tcx.map.path_to_string(id), @@ -155,12 +157,14 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, ast::IITraitItem(_, ref ti) => { match *ti { ast::ProvidedMethod(ref m) => m.pe_ident(), - ast::RequiredMethod(ref ty_m) => ty_m.ident + ast::RequiredMethod(ref ty_m) => ty_m.ident, + ast::TypeTraitItem(ref ti) => ti.ident, } }, ast::IIImplItem(_, ref m) => { match *m { - ast::MethodImplItem(ref m) => m.pe_ident() + ast::MethodImplItem(ref m) => m.pe_ident(), + ast::TypeImplItem(ref ti) => ti.ident, } } }; @@ -392,6 +396,12 @@ fn simplify_ast(ii: e::InlinedItemRef) -> ast::InlinedItem { ast::RequiredMethod( fold::noop_fold_type_method(ty_m.clone(), &mut fld)) } + ast::TypeTraitItem(ref associated_type) => { + ast::TypeTraitItem( + P(fold::noop_fold_associated_type( + (**associated_type).clone(), + &mut fld))) + } }) } e::IIImplItemRef(d, m) => { @@ -402,6 +412,10 @@ fn simplify_ast(ii: e::InlinedItemRef) -> ast::InlinedItem { .expect_one("noop_fold_method must produce \ exactly one method")) } + ast::TypeImplItem(ref td) => { + ast::TypeImplItem( + P(fold::noop_fold_typedef((**td).clone(), &mut fld))) + } }) } e::IIForeignRef(i) => { @@ -455,6 +469,7 @@ 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::DefPrimTy(p) => def::DefPrimTy(p), def::DefTyParam(s, did, v) => def::DefTyParam(s, did.tr(dcx), v), def::DefBinding(nid, bm) => def::DefBinding(dcx.tr_id(nid), bm), diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index a9c0b877d55b7..b75d61100ecd7 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -118,6 +118,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { ty::MethodTraitItem(method) => { self.check_def_id(method.def_id); } + ty::TypeTraitItem(typedef) => { + self.check_def_id(typedef.def_id); + } } } } @@ -226,6 +229,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { ast::MethodImplItem(ref method) => { visit::walk_block(self, method.pe_body()); } + ast::TypeImplItem(_) => {} } } ast_map::NodeForeignItem(foreign_item) => { @@ -341,6 +345,7 @@ impl<'v> Visitor<'v> for LifeSeeder { ast::MethodImplItem(ref method) => { self.worklist.push(method.id); } + ast::TypeImplItem(_) => {} } } } @@ -544,7 +549,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { ast::ProvidedMethod(ref method) => { visit::walk_block(self, &*method.pe_body()) } - ast::RequiredMethod(_) => () + ast::RequiredMethod(_) => {} + ast::TypeTraitItem(_) => {} } } } diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 70a9b6c533772..ae45d827def50 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -26,6 +26,7 @@ pub enum Def { DefLocal(ast::NodeId, ast::BindingMode), DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */), DefTy(ast::DefId, bool /* is_enum */), + DefAssociatedTy(ast::DefId), DefTrait(ast::DefId), DefPrimTy(ast::PrimTy), DefTyParam(ParamSpace, ast::DefId, uint), @@ -62,8 +63,9 @@ impl Def { match *self { DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | - DefVariant(_, id, _) | DefTy(id, _) | DefTyParam(_, id, _) | - DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => { + DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) | + DefTyParam(_, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | + DefMethod(id, _) => { id } DefArg(id, _) | @@ -90,3 +92,4 @@ impl Def { } } } + diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d6c11caefe84b..c8c5284022d99 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -134,6 +134,9 @@ impl OverloadedCallType { ty::MethodTraitItem(ref method_descriptor) => { (*method_descriptor).clone() } + ty::TypeTraitItem(_) => { + tcx.sess.bug("overloaded call method wasn't in method map") + } }; let impl_id = match method_descriptor.container { ty::TraitContainer(_) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 4f9cc9c080f9b..17d941b5958a7 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -319,7 +319,9 @@ impl MutabilityCategory { def::DefTy(..) | def::DefTrait(..) | def::DefPrimTy(..) | def::DefTyParam(..) | def::DefUse(..) | def::DefStruct(..) | def::DefTyParamBinder(..) | def::DefRegion(..) | def::DefLabel(..) | - def::DefMethod(..) => fail!("no MutabilityCategory for def: {}", *def), + def::DefMethod(..) | def::DefAssociatedTy(..) => { + fail!("no MutabilityCategory for def: {}", *def) + } def::DefStatic(_, false) => McImmutable, def::DefStatic(_, true) => McDeclared, @@ -533,7 +535,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) | def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) | def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) | - def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) => { + def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) | + def::DefAssociatedTy(..) => { Ok(Rc::new(cmt_ { id:id, span:span, diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 0eb684fe18e10..8aac96a5410a8 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -82,8 +82,13 @@ impl<'v> Visitor<'v> for ParentVisitor { ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => { for m in methods.iter() { match *m { - ast::ProvidedMethod(ref m) => self.parents.insert(m.id, item.id), - ast::RequiredMethod(ref m) => self.parents.insert(m.id, item.id), + ast::ProvidedMethod(ref m) => { + self.parents.insert(m.id, item.id); + } + ast::RequiredMethod(ref m) => { + self.parents.insert(m.id, item.id); + } + ast::TypeTraitItem(_) => {} }; } } @@ -272,6 +277,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.exported_items.insert(method.id); } } + ast::TypeImplItem(_) => {} } } } @@ -290,6 +296,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { debug!("required {}", m.id); self.exported_items.insert(m.id); } + ast::TypeTraitItem(ref t) => { + debug!("typedef {}", t.id); + self.exported_items.insert(t.id); + } } } } @@ -419,6 +429,31 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } } } + Some(&ty::TypeTraitItem(ref typedef)) => { + match typedef.container { + ty::TraitContainer(id) => { + debug!("privacy - recursing on trait {:?}", id); + self.def_privacy(id) + } + ty::ImplContainer(id) => { + match ty::impl_trait_ref(self.tcx, id) { + Some(t) => { + debug!("privacy - impl of trait {:?}", id); + self.def_privacy(t.def_id) + } + None => { + debug!("privacy - found a typedef {:?}", + typedef.vis); + if typedef.vis == ast::Public { + Allowable + } else { + ExternallyDenied + } + } + } + } + } + } None => { debug!("privacy - nope, not even a method"); ExternallyDenied @@ -469,6 +504,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { _ => m.pe_vis() } } + ast::TypeImplItem(_) => return Allowable, } } Some(ast_map::NodeTraitItem(_)) => { @@ -670,6 +706,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { ty::MethodTraitItem(method_type) => { method_type.provided_source.unwrap_or(method_id) } + ty::TypeTraitItem(_) => method_id, }; let string = token::get_ident(name); @@ -1110,6 +1147,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { ast::MethodImplItem(ref m) => { check_inherited(m.span, m.pe_vis(), ""); } + ast::TypeImplItem(_) => {} } } } @@ -1149,6 +1187,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { check_inherited(m.span, m.vis, "unnecessary visibility"); } + ast::TypeTraitItem(_) => {} } } } @@ -1184,6 +1223,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { ast::MethodImplItem(ref m) => { check_inherited(tcx, m.span, m.pe_vis()); } + ast::TypeImplItem(_) => {} } } } @@ -1211,6 +1251,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { ast::RequiredMethod(..) => {} ast::ProvidedMethod(ref m) => check_inherited(tcx, m.span, m.pe_vis()), + ast::TypeTraitItem(_) => {} } } } @@ -1351,6 +1392,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { ast::MethodImplItem(ref m) => { self.exported_items.contains(&m.id) } + ast::TypeImplItem(_) => false, } }); @@ -1367,6 +1409,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { ast::MethodImplItem(ref method) => { visit::walk_method_helper(self, &**method) } + ast::TypeImplItem(_) => {} } } } @@ -1401,6 +1444,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { visit::walk_method_helper(self, &**method); } } + ast::TypeImplItem(_) => {} } } if found_pub_static { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 630b65f527878..555a033a568d1 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -197,6 +197,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match *trait_method { ast::RequiredMethod(_) => false, ast::ProvidedMethod(_) => true, + ast::TypeTraitItem(_) => false, } } Some(ast_map::NodeImplItem(impl_item)) => { @@ -225,6 +226,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } } } + ast::TypeImplItem(_) => false, } } Some(_) => false, @@ -327,8 +329,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Keep going, nothing to get exported } ast::ProvidedMethod(ref method) => { - visit::walk_block(self, &*method.pe_body()) + visit::walk_block(self, &*method.pe_body()); } + ast::TypeTraitItem(_) => {} } } ast_map::NodeImplItem(impl_item) => { @@ -339,6 +342,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { visit::walk_block(self, method.pe_body()) } } + ast::TypeImplItem(_) => {} } } // Nothing to recurse on for these diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 861ac2ffe60d7..6fa33f4b5aa03 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -37,13 +37,15 @@ use syntax::ast::{RegionTyParamBound, StmtDecl, StructField}; use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound}; use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32}; use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt}; -use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyProc, TyRptr}; -use syntax::ast::{TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint}; -use syntax::ast::{UnboxedFnTyParamBound, UnnamedField, UnsafeFn, Variant}; -use syntax::ast::{ViewItem, ViewItemExternCrate, ViewItemUse, ViewPathGlob}; -use syntax::ast::{ViewPathList, ViewPathSimple, Visibility}; +use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyProc, TyQPath}; +use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint}; +use syntax::ast::{TypeImplItem, UnboxedFnTyParamBound, UnnamedField}; +use syntax::ast::{UnsafeFn, Variant, ViewItem, ViewItemExternCrate}; +use syntax::ast::{ViewItemUse, ViewPathGlob, ViewPathList, ViewPathSimple}; +use syntax::ast::{Visibility}; use syntax::ast; use syntax::ast_util::{PostExpansionMethod, local_def, walk_pat}; +use syntax::ast_util; use syntax::attr::AttrMetaMethods; use syntax::ext::mtwt; use syntax::parse::token::special_names; @@ -313,6 +315,7 @@ enum ModulePrefixResult { pub enum TraitItemKind { NonstaticMethodTraitItemKind, StaticMethodTraitItemKind, + TypeTraitItemKind, } impl TraitItemKind { @@ -1393,6 +1396,24 @@ impl<'a> Resolver<'a> { method.span, is_public); } + TypeImplItem(ref typedef) => { + // Add the typedef to the module. + let ident = typedef.ident; + let typedef_name_bindings = + self.add_child( + ident, + new_parent.clone(), + ForbidDuplicateTypesAndModules, + typedef.span); + let def = DefAssociatedTy(local_def( + typedef.id)); + let is_public = typedef.vis == + ast::Public; + typedef_name_bindings.define_type( + def, + typedef.span, + is_public); + } } } } @@ -1432,42 +1453,66 @@ impl<'a> Resolver<'a> { // Add the names of all the methods to the trait info. for method in methods.iter() { - let (m_id, m_ident, m_fn_style, m_self, m_span) = match *method { - ast::RequiredMethod(ref m) => { - (m.id, m.ident, m.fn_style, &m.explicit_self, m.span) - } - ast::ProvidedMethod(ref m) => { - (m.id, m.pe_ident(), m.pe_fn_style(), m.pe_explicit_self(), m.span) - } - }; + let (ident, kind) = match *method { + ast::RequiredMethod(_) | + ast::ProvidedMethod(_) => { + let ty_m = + ast_util::trait_item_to_ty_method(method); + + let ident = ty_m.ident; + + // Add it as a name in the trait module. + let (def, static_flag) = match ty_m.explicit_self + .node { + SelfStatic => { + // Static methods become + // `def_static_method`s. + (DefStaticMethod( + local_def(ty_m.id), + FromTrait(local_def(item.id)), + ty_m.fn_style), + StaticMethodTraitItemKind) + } + _ => { + // Non-static methods become + // `def_method`s. + (DefMethod(local_def(ty_m.id), + Some(local_def(item.id))), + NonstaticMethodTraitItemKind) + } + }; - // Add it as a name in the trait module. - let (def, static_flag) = match m_self.node { - SelfStatic => { - // Static methods become `def_static_method`s. - (DefStaticMethod(local_def(m_id), - FromTrait(local_def(item.id)), - m_fn_style), - StaticMethodTraitItemKind) + let method_name_bindings = + self.add_child(ident, + module_parent.clone(), + ForbidDuplicateTypesAndValues, + ty_m.span); + method_name_bindings.define_value(def, + ty_m.span, + true); + + (ident, static_flag) } - _ => { - // Non-static methods become `def_method`s. - (DefMethod(local_def(m_id), - Some(local_def(item.id))), - NonstaticMethodTraitItemKind) + ast::TypeTraitItem(ref associated_type) => { + let def = DefAssociatedTy(local_def( + associated_type.id)); + + let name_bindings = + self.add_child(associated_type.ident, + module_parent.clone(), + ForbidDuplicateTypesAndValues, + associated_type.span); + name_bindings.define_type(def, + associated_type.span, + true); + + (associated_type.ident, TypeTraitItemKind) } }; - let method_name_bindings = - self.add_child(m_ident, - module_parent.clone(), - ForbidDuplicateValues, - m_span); - method_name_bindings.define_value(def, m_span, true); - self.trait_item_map .borrow_mut() - .insert((m_ident.name, def_id), static_flag); + .insert((ident.name, def_id), kind); } name_bindings.define_type(DefTrait(def_id), sp, is_public); @@ -1823,7 +1868,7 @@ impl<'a> Resolver<'a> { is_public, DUMMY_SP) } - DefTy(..) => { + DefTy(..) | DefAssociatedTy(..) => { debug!("(building reduced graph for external \ crate) building type {}", final_ident); @@ -4065,6 +4110,9 @@ impl<'a> Resolver<'a> { ProvidedMethod(m.id)), &**m) } + ast::TypeTraitItem(_) => { + visit::walk_trait_item(this, method); + } } } }); @@ -4509,6 +4557,14 @@ impl<'a> Resolver<'a> { ProvidedMethod(method.id)), &**method); } + TypeImplItem(ref typedef) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(typedef.ident, + typedef.span); + + this.resolve_type(&*typedef.typ); + } } } }); @@ -4745,9 +4801,73 @@ impl<'a> Resolver<'a> { }); } + TyQPath(ref qpath) => { + self.resolve_type(&*qpath.for_type); + + let current_module = self.current_module.clone(); + let module_path_idents: Vec<_> = + qpath.trait_name + .segments + .iter() + .map(|ps| ps.identifier) + .collect(); + match self.resolve_module_path( + current_module, + module_path_idents.as_slice(), + UseLexicalScope, + qpath.trait_name.span, + PathSearch) { + Success((ref module, _)) if module.kind.get() == + TraitModuleKind => { + match self.resolve_definition_of_name_in_module( + (*module).clone(), + qpath.item_name.name, + TypeNS) { + ChildNameDefinition(def, lp) | + ImportNameDefinition(def, lp) => { + match def { + DefAssociatedTy(trait_type_id) => { + let def = DefAssociatedTy( + trait_type_id); + self.record_def(ty.id, (def, lp)); + } + _ => { + self.resolve_error( + ty.span, + "not an associated type"); + } + } + } + NoNameDefinition => { + self.resolve_error(ty.span, + "unresolved associated \ + type"); + } + } + } + Success(..) => self.resolve_error(ty.span, "not a trait"), + Indeterminate => { + self.session.span_bug(ty.span, + "indeterminate result when \ + resolving associated type") + } + Failed(error) => { + let (span, help) = match error { + Some((span, msg)) => (span, format!("; {}", msg)), + None => (ty.span, String::new()), + }; + self.resolve_error(span, + format!("unresolved trait: {}", + help).as_slice()) + } + } + } + TyClosure(ref c) | TyProc(ref c) => { - self.resolve_type_parameter_bounds(ty.id, &c.bounds, - TraitBoundingTypeParameter); + self.resolve_type_parameter_bounds( + ty.id, + &c.bounds, + TraitBoundingTypeParameter); visit::walk_ty(self, ty); } @@ -5210,8 +5330,9 @@ impl<'a> Resolver<'a> { Some(def_id) => { match self.trait_item_map.borrow().find(&(ident.name, def_id)) { Some(&StaticMethodTraitItemKind) => (), + Some(&TypeTraitItemKind) => (), None => (), - _ => { + Some(&NonstaticMethodTraitItemKind) => { debug!("containing module was a trait or impl \ and name was a method -> not resolved"); return None; diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index 37ba3b75f8917..cab83f4cda244 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -227,6 +227,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefForeignMod(_) => Some(recorder::ModRef), def::DefStruct(_) => Some(recorder::StructRef), def::DefTy(..) | + def::DefAssociatedTy(..) | def::DefTrait(_) => Some(recorder::TypeRef), def::DefStatic(_, _) | def::DefBinding(_, _) | @@ -355,11 +356,12 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { ty::MethodTraitItemId(def_id) => { method.id != 0 && def_id.node == 0 } + ty::TypeTraitItemId(_) => false, } }); let decl_id = match decl_id { None => None, - Some(ty::MethodTraitItemId(def_id)) => Some(def_id), + Some(id) => Some(id.def_id()), }; let sub_span = self.span.sub_span_after_keyword(method.span, keywords::Fn); @@ -646,6 +648,9 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { ast::MethodImplItem(ref method) => { visit::walk_method_helper(self, &**method) } + ast::TypeImplItem(ref typedef) => { + visit::walk_ty(self, &*typedef.typ) + } } } } @@ -764,12 +769,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def_id) .iter() .find(|mr| { - match **mr { - ty::MethodTraitItem(ref mr) => { - mr.ident.name == ti.ident() - .name - } - } + mr.ident().name == ti.ident().name }) .unwrap() .def_id()) @@ -782,18 +782,13 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { Some(impl_items.get(&def_id) .iter() .find(|mr| { - match **mr { - ty::MethodTraitItemId(mr) => { - ty::impl_or_trait_item( - &self.analysis - .ty_cx, - mr).ident() - .name == - ti.ident().name - } - } - }).unwrap() - .def_id()) + ty::impl_or_trait_item( + &self.analysis.ty_cx, + mr.def_id()).ident().name == + ti.ident().name + }) + .unwrap() + .def_id()) } } } else { @@ -894,7 +889,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { match ty::trait_item_of_item(&self.analysis.ty_cx, def_id) { None => None, - Some(ty::MethodTraitItemId(decl_id)) => Some(decl_id), + Some(decl_id) => Some(decl_id.def_id()), }; // This incantation is required if the method referenced is a @@ -905,6 +900,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { ty::MethodTraitItem(method) => { method.provided_source.unwrap_or(def_id) } + ty::TypeTraitItem(_) => def_id, }; (Some(def_id), decl_id) } @@ -913,23 +909,15 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { let trait_item = ty::trait_item(&self.analysis.ty_cx, mp.trait_ref.def_id, mp.method_num); - match trait_item { - ty::MethodTraitItem(method) => { - (None, Some(method.def_id)) - } - } - }, + (None, Some(trait_item.def_id())) + } typeck::MethodObject(ref mo) => { // method invoked on a trait instance let trait_item = ty::trait_item(&self.analysis.ty_cx, mo.trait_ref.def_id, mo.method_num); - match trait_item { - ty::MethodTraitItem(method) => { - (None, Some(method.def_id)) - } - } - }, + (None, Some(trait_item.def_id())) + } }; let sub_span = self.span.sub_span_for_meth_name(ex.span); self.fmt.meth_call_str(ex.span, @@ -1139,7 +1127,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { qualname, method_type.id); } - ast::ProvidedMethod(ref method) => self.process_method(&**method) + ast::ProvidedMethod(ref method) => self.process_method(&**method), + ast::TypeTraitItem(_) => {} } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index eb736ae8a7666..ef169264650f4 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -16,8 +16,9 @@ use syntax::codemap::Span; use syntax::{attr, visit}; use syntax::ast; use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant}; -use syntax::ast::{Item, RequiredMethod, ProvidedMethod, TraitItem, TypeMethod, Method}; -use syntax::ast::{Generics, StructDef, StructField, Ident}; +use syntax::ast::{Item, RequiredMethod, ProvidedMethod, TraitItem}; +use syntax::ast::{TypeMethod, Method, Generics, StructDef, StructField}; +use syntax::ast::{Ident, TypeTraitItem}; use syntax::ast_util::is_local; use syntax::attr::Stability; use syntax::visit::{FnKind, FkMethod, Visitor}; @@ -79,9 +80,13 @@ impl<'v> Visitor<'v> for Annotator { RequiredMethod(TypeMethod {id, ref attrs, ..}) => (id, attrs), // work around lack of pattern matching for @ types - ProvidedMethod(ref method) => match **method { - Method {id, ref attrs, ..} => (id, attrs) + ProvidedMethod(ref method) => { + match **method { + Method {attrs: ref attrs, id: id, ..} => (id, attrs), + } } + + TypeTraitItem(ref typedef) => (typedef.id, &typedef.attrs), }; self.annotate(id, attrs, |v| visit::walk_trait_item(v, t)); } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 4b35024ecb05f..9583dcf560e94 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -630,7 +630,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { let t1 = match ty::get(t).sty { ty::ty_param(p) => { - check(self, p, t, self.substs.types.opt_get(p.space, p.idx)) + check(self, + p, + t, + self.substs.types.opt_get(p.space, p.idx), + p.space, + p.idx) } _ => { ty_fold::super_fold_ty(self, t) @@ -648,7 +653,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { fn check(this: &SubstFolder, p: ty::ParamTy, source_ty: ty::t, - opt_ty: Option<&ty::t>) + opt_ty: Option<&ty::t>, + space: ParamSpace, + index: uint) -> ty::t { match opt_ty { Some(t) => *t, @@ -656,10 +663,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { let span = this.span.unwrap_or(DUMMY_SP); this.tcx().sess.span_bug( span, - format!("Type parameter `{}` ({}) out of range \ + format!("Type parameter `{}` ({}/{}/{}) out of range \ when substituting (root type={})", p.repr(this.tcx()), source_ty.repr(this.tcx()), + space, + index, this.root_ty.repr(this.tcx())).as_slice()); } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index a0cb8810289fa..a814c9d624cfa 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1375,6 +1375,10 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool { tcx.sess.bug("unexpected variant: required trait method \ in has_nested_returns") } + ast::TypeTraitItem(_) => { + tcx.sess.bug("unexpected variant: type trait item in \ + has_nested_returns") + } } } Some(ast_map::NodeImplItem(ii)) => { @@ -1391,6 +1395,10 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool { ast::MethMac(_) => tcx.sess.bug("unexpanded macro") } } + ast::TypeImplItem(_) => { + tcx.sess.bug("unexpected variant: type impl item in \ + has_nested_returns") + } } } Some(ast_map::NodeExpr(e)) => { @@ -2779,9 +2787,9 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { ast_map::NodeTraitItem(trait_method) => { debug!("get_item_val(): processing a NodeTraitItem"); match *trait_method { - ast::RequiredMethod(_) => { - ccx.sess().bug("unexpected variant: required trait method in \ - get_item_val()"); + ast::RequiredMethod(_) | ast::TypeTraitItem(_) => { + ccx.sess().bug("unexpected variant: required trait \ + method in get_item_val()"); } ast::ProvidedMethod(ref m) => { register_method(ccx, id, &**m) @@ -2792,6 +2800,11 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { ast_map::NodeImplItem(ii) => { match *ii { ast::MethodImplItem(ref m) => register_method(ccx, id, &**m), + ast::TypeImplItem(ref typedef) => { + ccx.sess().span_bug(typedef.span, + "unexpected variant: required impl \ + method in get_item_val()") + } } } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index ef98a73430264..c54a446c455c7 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -203,7 +203,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) datum_callee(bcx, ref_expr) } def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) | - def::DefTy(..) | def::DefPrimTy(..) | + def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) | def::DefUse(..) | def::DefTyParamBinder(..) | def::DefRegion(..) | def::DefLabel(..) | def::DefTyParam(..) | def::DefSelfTy(..) | def::DefMethod(..) => { @@ -458,6 +458,10 @@ pub fn trans_fn_ref_with_substs( (true, source_id, new_substs) } + ty::TypeTraitItem(_) => { + bcx.tcx().sess.bug("trans_fn_ref_with_vtables() tried \ + to translate an associated type?!") + } } } }; diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index a600baba5540c..359da14d57eaf 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -1153,6 +1153,11 @@ pub fn create_function_debug_context(cx: &CrateContext, method.span, true) } + ast::TypeImplItem(ref typedef) => { + cx.sess().span_bug(typedef.span, + "create_function_debug_context() \ + called on associated type?!") + } } } ast_map::NodeExpr(ref expr) => { diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index e1e728fbea018..e5c8d4d0ab343 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -156,6 +156,9 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) // don't. local_def(mth.id) } + ast::TypeTraitItem(_) => { + ccx.sess().bug("found TypeTraitItem IITraitItem") + } } } csearch::found(&ast::IIImplItem(impl_did, ref impl_item)) => { @@ -185,6 +188,9 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) } local_def(mth.id) } + ast::TypeImplItem(_) => { + ccx.sess().bug("found TypeImplItem IIImplItem") + } } } }; diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 27216d067b999..f127638774591 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -71,6 +71,7 @@ pub fn trans_impl(ccx: &CrateContext, ast::MethodImplItem(ref method) => { visit::walk_method_helper(&mut v, &**method); } + ast::TypeImplItem(_) => {} } } return; @@ -100,6 +101,7 @@ pub fn trans_impl(ccx: &CrateContext, }; visit::walk_method_helper(&mut v, &**method); } + ast::TypeImplItem(_) => {} } } } @@ -183,7 +185,11 @@ pub fn trans_static_method_callee(bcx: Block, ast_map::NodeTraitItem(method) => { let ident = match *method { ast::RequiredMethod(ref m) => m.ident, - ast::ProvidedMethod(ref m) => m.pe_ident() + ast::ProvidedMethod(ref m) => m.pe_ident(), + ast::TypeTraitItem(_) => { + bcx.tcx().sess.bug("trans_static_method_callee() on \ + an associated type?!") + } }; ident.name } @@ -294,14 +300,10 @@ fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name) .expect("could not find impl while translating"); let meth_did = impl_items.iter() .find(|&did| { - match *did { - ty::MethodTraitItemId(did) => { - ty::impl_or_trait_item(ccx.tcx(), - did).ident() - .name == - name - } - } + ty::impl_or_trait_item(ccx.tcx(), + did.def_id()).ident() + .name == + name }).expect("could not find method while \ translating"); @@ -323,6 +325,10 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let impl_did = vtable_impl.impl_def_id; let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) { ty::MethodTraitItem(method) => method.ident, + ty::TypeTraitItem(_) => { + bcx.tcx().sess.bug("can't monomorphize an associated \ + type") + } }; let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name); @@ -693,7 +699,7 @@ fn emit_vtable_methods(bcx: Block, ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trt_id); let trait_item_def_ids = ty::trait_item_def_ids(tcx, trt_id); - trait_item_def_ids.iter().map(|method_def_id| { + trait_item_def_ids.iter().flat_map(|method_def_id| { let method_def_id = method_def_id.def_id(); let ident = ty::impl_or_trait_item(tcx, method_def_id).ident(); // The substitutions we have are on the impl, so we grab @@ -710,7 +716,7 @@ fn emit_vtable_methods(bcx: Block, debug!("(making impl vtable) method has self or type \ params: {}", token::get_ident(ident)); - C_null(Type::nil(ccx).ptr_to()) + Some(C_null(Type::nil(ccx).ptr_to())).move_iter() } else { let mut fn_ref = trans_fn_ref_with_substs( bcx, @@ -724,9 +730,12 @@ fn emit_vtable_methods(bcx: Block, m_id, substs.clone()); } - fn_ref + Some(fn_ref).move_iter() } } + ty::TypeTraitItem(_) => { + None.move_iter() + } } }).collect() } diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 00e9d9f0e39b6..d2bbbdfad0ef6 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -231,6 +231,9 @@ pub fn monomorphic_fn(ccx: &CrateContext, } d } + ast::TypeImplItem(_) => { + ccx.sess().bug("can't monomorphize an associated type") + } } } ast_map::NodeTraitItem(method) => { diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 214726edd778d..03550299fbdf5 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -92,6 +92,7 @@ impl<'a, 'blk, 'tcx> Reflector<'a, 'blk, 'tcx> { format!("couldn't find visit method for {}", ty_name).as_slice()); let method = match self.visitor_items[mth_idx] { ty::MethodTraitItem(ref method) => (*method).clone(), + ty::TypeTraitItem(_) => return, }; let mth_ty = ty::mk_bare_fn(tcx, method.fty.clone()); debug!("Emit call visit method: visit_{}: {}", ty_name, ty_to_string(tcx, mth_ty)); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 09912b5458352..897bc4517f4e1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -97,30 +97,37 @@ impl ImplOrTraitItemContainer { #[deriving(Clone)] pub enum ImplOrTraitItem { MethodTraitItem(Rc), + TypeTraitItem(Rc), } impl ImplOrTraitItem { fn id(&self) -> ImplOrTraitItemId { match *self { MethodTraitItem(ref method) => MethodTraitItemId(method.def_id), + TypeTraitItem(ref associated_type) => { + TypeTraitItemId(associated_type.def_id) + } } } pub fn def_id(&self) -> ast::DefId { match *self { MethodTraitItem(ref method) => method.def_id, + TypeTraitItem(ref associated_type) => associated_type.def_id, } } pub fn ident(&self) -> ast::Ident { match *self { MethodTraitItem(ref method) => method.ident, + TypeTraitItem(ref associated_type) => associated_type.ident, } } pub fn container(&self) -> ImplOrTraitItemContainer { match *self { MethodTraitItem(ref method) => method.container, + TypeTraitItem(ref associated_type) => associated_type.container, } } } @@ -128,12 +135,14 @@ impl ImplOrTraitItem { #[deriving(Clone)] pub enum ImplOrTraitItemId { MethodTraitItemId(ast::DefId), + TypeTraitItemId(ast::DefId), } impl ImplOrTraitItemId { pub fn def_id(&self) -> ast::DefId { match *self { MethodTraitItemId(def_id) => def_id, + TypeTraitItemId(def_id) => def_id, } } } @@ -182,6 +191,14 @@ impl Method { } } +#[deriving(Clone)] +pub struct AssociatedType { + pub ident: ast::Ident, + pub vis: ast::Visibility, + pub def_id: ast::DefId, + pub container: ImplOrTraitItemContainer, +} + #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct mt { pub ty: t, @@ -556,6 +573,13 @@ pub struct ctxt<'tcx> { /// Maps closures to their capture clauses. pub capture_modes: RefCell, + + /// Maps def IDs to true if and only if they're associated types. + pub associated_types: RefCell>, + + /// Maps def IDs of traits to information about their associated types. + pub trait_associated_types: + RefCell>>>, } pub enum tbox_flag { @@ -1179,6 +1203,7 @@ pub struct TypeParameterDef { pub def_id: ast::DefId, pub space: subst::ParamSpace, pub index: uint, + pub associated_with: Option, pub bounds: ParamBounds, pub default: Option, } @@ -1238,7 +1263,7 @@ pub struct ParameterEnvironment { /// the "outer" view of a type or method to the "inner" view. /// In general, this means converting from bound parameters to /// free parameters. Since we currently represent bound/free type - /// parameters in the same way, this only has an affect on regions. + /// parameters in the same way, this only has an effect on regions. pub free_substs: Substs, /// Bounds on the various type parameters @@ -1275,8 +1300,19 @@ impl ParameterEnvironment { method_generics, method.pe_body().id) } + TypeTraitItem(_) => { + cx.sess + .bug("ParameterEnvironment::from_item(): \ + can't create a parameter environment \ + for type trait items") + } } } + ast::TypeImplItem(_) => { + cx.sess.bug("ParameterEnvironment::from_item(): \ + can't create a parameter environment \ + for type impl items") + } } } Some(ast_map::NodeTraitItem(trait_method)) => { @@ -1299,8 +1335,19 @@ impl ParameterEnvironment { method_generics, method.pe_body().id) } + TypeTraitItem(_) => { + cx.sess + .bug("ParameterEnvironment::from_item(): \ + can't create a parameter environment \ + for type trait items") + } } } + ast::TypeTraitItem(_) => { + cx.sess.bug("ParameterEnvironment::from_item(): \ + can't create a parameter environment \ + for type trait items") + } } } Some(ast_map::NodeItem(item)) => { @@ -1476,6 +1523,8 @@ pub fn mk_ctxt<'tcx>(s: Session, transmute_restrictions: RefCell::new(Vec::new()), stability: RefCell::new(stability), capture_modes: RefCell::new(capture_modes), + associated_types: RefCell::new(DefIdMap::new()), + trait_associated_types: RefCell::new(DefIdMap::new()), } } @@ -1894,6 +1943,10 @@ impl ParamTy { pub fn to_ty(self, tcx: &ty::ctxt) -> ty::t { ty::mk_param(tcx, self.space, self.idx, self.def_id) } + + pub fn is_self(&self) -> bool { + self.space == subst::SelfSpace && self.idx == 0 + } } impl ItemSubsts { @@ -3543,6 +3596,10 @@ pub fn method_call_type_param_defs<'tcx, T>(typer: &T, }) => { match ty::trait_item(typer.tcx(), trait_ref.def_id, n_mth) { ty::MethodTraitItem(method) => method.generics.types.clone(), + ty::TypeTraitItem(_) => { + typer.tcx().sess.bug("method_call_type_param_defs() \ + called on associated type") + } } } } @@ -4007,12 +4064,19 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec> { Some(ast_map::NodeItem(item)) => { match item.node { ItemTrait(_, _, _, ref ms) => { - ms.iter().filter_map(|m| match *m { - ast::RequiredMethod(_) => None, - ast::ProvidedMethod(ref m) => { - match impl_or_trait_item(cx, - ast_util::local_def(m.id)) { - MethodTraitItem(m) => Some(m), + let (_, p) = + ast_util::split_trait_methods(ms.as_slice()); + p.iter() + .map(|m| { + match impl_or_trait_item( + cx, + ast_util::local_def(m.id)) { + MethodTraitItem(m) => m, + TypeTraitItem(_) => { + cx.sess.bug("provided_trait_methods(): \ + split_trait_methods() put \ + associated types in the \ + provided method bucket?!") } } }).collect() @@ -4097,6 +4161,75 @@ pub fn impl_or_trait_item(cx: &ctxt, id: ast::DefId) -> ImplOrTraitItem { }) } +/// Returns true if the given ID refers to an associated type and false if it +/// refers to anything else. +pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool { + let result = match cx.associated_types.borrow_mut().find(&id) { + Some(result) => return *result, + None if id.krate == ast::LOCAL_CRATE => { + match cx.impl_or_trait_items.borrow().find(&id) { + Some(ref item) => { + match **item { + TypeTraitItem(_) => true, + MethodTraitItem(_) => false, + } + } + None => false, + } + } + None => { + csearch::is_associated_type(&cx.sess.cstore, id) + } + }; + + cx.associated_types.borrow_mut().insert(id, result); + result +} + +/// Returns the parameter index that the given associated type corresponds to. +pub fn associated_type_parameter_index(cx: &ctxt, + trait_def: &TraitDef, + associated_type_id: ast::DefId) + -> uint { + for type_parameter_def in trait_def.generics.types.iter() { + if type_parameter_def.def_id == associated_type_id { + return type_parameter_def.index + } + } + cx.sess.bug("couldn't find associated type parameter index") +} + +#[deriving(PartialEq, Eq)] +pub struct AssociatedTypeInfo { + pub def_id: ast::DefId, + pub index: uint, + pub ident: ast::Ident, +} + +impl PartialOrd for AssociatedTypeInfo { + fn partial_cmp(&self, other: &AssociatedTypeInfo) -> Option { + Some(self.index.cmp(&other.index)) + } +} + +impl Ord for AssociatedTypeInfo { + fn cmp(&self, other: &AssociatedTypeInfo) -> Ordering { + self.index.cmp(&other.index) + } +} + +/// Returns the associated types belonging to the given trait, in parameter +/// order. +pub fn associated_types_for_trait(cx: &ctxt, trait_id: ast::DefId) + -> Rc> { + cx.trait_associated_types + .borrow() + .find(&trait_id) + .expect("associated_types_for_trait(): trait not found, try calling \ + ensure_associated_types()") + .clone() +} + pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId) -> Rc> { lookup_locally_or_in_crate_store("trait_item_def_ids", @@ -4978,6 +5111,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, .insert(method_def_id, source); } } + TypeTraitItem(_) => {} } } @@ -5025,6 +5159,7 @@ pub fn populate_implementations_for_trait_if_necessary( .insert(method_def_id, source); } } + TypeTraitItem(_) => {} } } @@ -5108,9 +5243,7 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) Some(m) => m.clone(), None => return None, }; - let name = match impl_item { - MethodTraitItem(method) => method.ident.name, - }; + let name = impl_item.ident().name; match trait_of_item(tcx, def_id) { Some(trait_did) => { let trait_items = ty::trait_items(tcx, trait_did); @@ -5364,6 +5497,11 @@ pub fn construct_parameter_environment( space: subst::ParamSpace, defs: &[TypeParameterDef]) { for (i, def) in defs.iter().enumerate() { + debug!("construct_parameter_environment(): push_types_from_defs: \ + space={} def={} index={}", + space, + def.repr(tcx), + i); let ty = ty::mk_param(tcx, space, i, def.def_id); types.push(space, ty); } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 48fa6f823b0e5..3b08ccd5a7b2e 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -301,6 +301,7 @@ impl TypeFoldable for ty::TypeParameterDef { def_id: self.def_id, space: self.space, index: self.index, + associated_with: self.associated_with, bounds: self.bounds.fold_with(folder), default: self.default.fold_with(folder), } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 00678eb6380ca..8f60be8f7fbc0 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -70,14 +70,30 @@ use std::rc::Rc; use syntax::abi; use syntax::{ast, ast_util}; use syntax::codemap::Span; +use syntax::parse::token; pub trait AstConv<'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype; fn get_trait_def(&self, id: ast::DefId) -> Rc; - // what type should we use when a type is omitted? + /// What type should we use when a type is omitted? fn ty_infer(&self, span: Span) -> ty::t; + + /// Returns true if associated types from the given trait and type are + /// allowed to be used here and false otherwise. + fn associated_types_of_trait_are_valid(&self, + ty: ty::t, + trait_id: ast::DefId) + -> bool; + + /// Returns the binding of the given associated type for some type. + fn associated_type_binding(&self, + span: Span, + ty: Option, + trait_id: ast::DefId, + associated_type_id: ast::DefId) + -> ty::t; } pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) @@ -152,13 +168,16 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( r } -fn ast_path_substs<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, - rscope: &RS, - decl_generics: &ty::Generics, - self_ty: Option, - path: &ast::Path) -> Substs -{ +fn ast_path_substs<'tcx,AC,RS>( + this: &AC, + rscope: &RS, + decl_def_id: ast::DefId, + decl_generics: &ty::Generics, + self_ty: Option, + associated_ty: Option, + path: &ast::Path) + -> Substs + where AC: AstConv<'tcx>, RS: RegionScope { /*! * Given a path `path` that refers to an item `I` with the * declared generics `decl_generics`, returns an appropriate @@ -206,10 +225,17 @@ fn ast_path_substs<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( // Convert the type parameters supplied by the user. let ty_param_defs = decl_generics.types.get_slice(TypeSpace); let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).count(); - let formal_ty_param_count = ty_param_defs.len(); - let required_ty_param_count = ty_param_defs.iter() - .take_while(|x| x.default.is_none()) - .count(); + let formal_ty_param_count = + ty_param_defs.iter() + .take_while(|x| !ty::is_associated_type(tcx, x.def_id)) + .count(); + let required_ty_param_count = + ty_param_defs.iter() + .take_while(|x| { + x.default.is_none() && + !ty::is_associated_type(tcx, x.def_id) + }) + .count(); if supplied_ty_param_count < required_ty_param_count { let expected = if required_ty_param_count < formal_ty_param_count { "expected at least" @@ -242,9 +268,11 @@ fn ast_path_substs<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( "add #![feature(default_type_params)] to the crate attributes to enable"); } - let tps = path.segments.iter().flat_map(|s| s.types.iter()) - .map(|a_t| ast_ty_to_ty(this, rscope, &**a_t)) - .collect(); + let tps = path.segments + .iter() + .flat_map(|s| s.types.iter()) + .map(|a_t| ast_ty_to_ty(this, rscope, &**a_t)) + .collect(); let mut substs = Substs::new_type(tps, regions); @@ -263,24 +291,48 @@ fn ast_path_substs<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } for param in ty_param_defs.slice_from(supplied_ty_param_count).iter() { - let default = param.default.unwrap(); - let default = default.subst_spanned(tcx, &substs, Some(path.span)); - substs.types.push(TypeSpace, default); + match param.default { + Some(default) => { + // This is a default type parameter. + let default = default.subst_spanned(tcx, + &substs, + Some(path.span)); + substs.types.push(TypeSpace, default); + } + None => { + // This is an associated type. + substs.types.push( + TypeSpace, + this.associated_type_binding(path.span, + associated_ty, + decl_def_id, + param.def_id)) + } + } } substs } -pub fn ast_path_to_trait_ref<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, - rscope: &RS, - trait_def_id: ast::DefId, - self_ty: Option, - path: &ast::Path) -> Rc { +pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, + rscope: &RS, + trait_def_id: ast::DefId, + self_ty: Option, + associated_type: Option, + path: &ast::Path) + -> Rc + where AC: AstConv<'tcx>, + RS: RegionScope { let trait_def = this.get_trait_def(trait_def_id); Rc::new(ty::TraitRef { def_id: trait_def_id, - substs: ast_path_substs(this, rscope, &trait_def.generics, self_ty, path) + substs: ast_path_substs(this, + rscope, + trait_def_id, + &trait_def.generics, + self_ty, + associated_type, + path) }) } @@ -289,15 +341,20 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( rscope: &RS, did: ast::DefId, path: &ast::Path) - -> TypeAndSubsts -{ + -> TypeAndSubsts { let tcx = this.tcx(); let ty::Polytype { generics: generics, ty: decl_ty } = this.get_item_ty(did); - let substs = ast_path_substs(this, rscope, &generics, None, path); + let substs = ast_path_substs(this, + rscope, + did, + &generics, + None, + None, + path); let ty = decl_ty.subst(tcx, &substs); TypeAndSubsts { substs: substs, ty: ty } } @@ -333,7 +390,7 @@ pub fn ast_path_to_ty_relaxed<'tcx, AC: AstConv<'tcx>, Substs::new(VecPerParamSpace::params_from_type(type_params), VecPerParamSpace::params_from_type(region_params)) } else { - ast_path_substs(this, rscope, &generics, None, path) + ast_path_substs(this, rscope, did, &generics, None, None, path) }; let ty = decl_ty.subst(tcx, &substs); @@ -639,8 +696,12 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } } Some(&def::DefTrait(trait_def_id)) => { - let result = ast_path_to_trait_ref( - this, rscope, trait_def_id, None, path); + let result = ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + None, + path); let bounds = match *opt_bounds { None => { conv_existential_bounds(this, @@ -686,6 +747,52 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( constr(ast_ty_to_ty(this, rscope, a_seq_ty)) } +fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, + rscope: &RS, + trait_path: &ast::Path, + for_ast_type: &ast::Ty, + trait_type_id: ast::DefId, + span: Span) + -> ty::t + where AC: AstConv<'tcx>, RS: RegionScope { + // Find the trait that this associated type belongs to. + let trait_did = match ty::impl_or_trait_item(this.tcx(), + trait_type_id).container() { + ty::ImplContainer(_) => { + this.tcx().sess.span_bug(span, + "associated_ty_to_ty(): impl associated \ + types shouldn't go through this \ + function") + } + ty::TraitContainer(trait_id) => trait_id, + }; + + let for_type = ast_ty_to_ty(this, rscope, for_ast_type); + if !this.associated_types_of_trait_are_valid(for_type, trait_did) { + this.tcx().sess.span_err(span, + "this associated type is not \ + allowed in this context"); + return ty::mk_err() + } + + let trait_ref = ast_path_to_trait_ref(this, + rscope, + trait_did, + None, + Some(for_type), + trait_path); + let trait_def = this.get_trait_def(trait_did); + for type_parameter in trait_def.generics.types.iter() { + if type_parameter.def_id == trait_type_id { + return *trait_ref.substs.types.get(type_parameter.space, + type_parameter.index) + } + } + this.tcx().sess.span_bug(span, + "this associated type didn't get added \ + as a parameter for some reason") +} + // 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>( @@ -816,8 +923,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } match a_def { def::DefTrait(trait_def_id) => { - let result = ast_path_to_trait_ref( - this, rscope, trait_def_id, None, path); + let result = ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + None, + path); let empty_bounds: &[ast::TyParamBound] = &[]; let ast_bounds = match *bounds { Some(ref b) => b.as_slice(), @@ -856,6 +967,23 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( def::DefPrimTy(_) => { fail!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call"); } + def::DefAssociatedTy(trait_type_id) => { + let path_str = tcx.map.path_to_string( + tcx.map.get_parent(trait_type_id.node)); + tcx.sess.span_err(ast_ty.span, + format!("ambiguous associated \ + type; specify the type \ + using the syntax `::{}`", + path_str, + token::get_ident( + path.segments + .last() + .unwrap() + .identifier) + .get()).as_slice()); + ty::mk_err() + } _ => { tcx.sess.span_fatal(ast_ty.span, format!("found value name used \ @@ -864,6 +992,28 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } } } + ast::TyQPath(ref qpath) => { + match tcx.def_map.borrow().find(&ast_ty.id) { + None => { + tcx.sess.span_bug(ast_ty.span, + "unbound qualified path") + } + Some(&def::DefAssociatedTy(trait_type_id)) => { + associated_ty_to_ty(this, + rscope, + &qpath.trait_name, + &*qpath.for_type, + trait_type_id, + ast_ty.span) + } + Some(_) => { + tcx.sess.span_err(ast_ty.span, + "this qualified path does not name \ + an associated type"); + ty::mk_err() + } + } + } ast::TyFixedLengthVec(ref ty, ref e) => { match const_eval::eval_const_expr_partial(tcx, &**e) { Ok(ref r) => { diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index d3cae157d3b2c..5d2ce7b080eef 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -226,6 +226,7 @@ fn get_method_index(tcx: &ty::ctxt, for trait_item in trait_items.iter() { match *trait_item { ty::MethodTraitItem(_) => method_count += 1, + ty::TypeTraitItem(_) => {} } } true @@ -531,6 +532,11 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { .clone(); let method = match trait_item { ty::MethodTraitItem(method) => method, + ty::TypeTraitItem(_) => { + self.tcx().sess.bug( + "push_unboxed_closure_call_candidates_if_applicable(): \ + unexpected associated type in function trait") + } }; // Make sure it has the right name! @@ -730,11 +736,16 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { m.explicit_self != ty::StaticExplicitSelfCategory && m.ident.name == self.m_name } + ty::TypeTraitItem(_) => false, } }) { Some(pos) => { let method = match *trait_items.get(pos) { ty::MethodTraitItem(ref method) => (*method).clone(), + ty::TypeTraitItem(_) => { + tcx.sess.bug("typechecking associated type as \ + though it were a method") + } }; match mk_cand(self, @@ -812,7 +823,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { m.ident().name == self.m_name }) { Some(ty::MethodTraitItem(method)) => method, - None => { return; } // No method with the right name. + Some(ty::TypeTraitItem(_)) | None => { + // No method with the right name. + return + } }; // determine the `self` of the impl with fresh @@ -1575,7 +1589,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // If we're reporting statics, we want to report the trait // definition if possible, rather than an impl match ty::trait_item_of_item(self.tcx(), impl_did) { - None => { + None | Some(TypeTraitItemId(_)) => { debug!("(report candidate) No trait method \ found"); impl_did diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 2f5b6e1fa03ba..c8728d375f6a3 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -126,7 +126,7 @@ use std::mem::replace; use std::rc::Rc; use std::slice; use syntax::abi; -use syntax::ast::{ProvidedMethod, RequiredMethod}; +use syntax::ast::{ProvidedMethod, RequiredMethod, TypeTraitItem}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{local_def, PostExpansionMethod}; @@ -765,6 +765,9 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { ast::MethodImplItem(ref m) => { check_method_body(ccx, &impl_pty.generics, &**m); } + ast::TypeImplItem(_) => { + // Nothing to do here. + } } } @@ -793,6 +796,9 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { ProvidedMethod(ref m) => { check_method_body(ccx, &trait_def.generics, &**m); } + TypeTraitItem(_) => { + // Nothing to do. + } } } } @@ -898,6 +904,20 @@ fn check_impl_items_against_trait(ccx: &CrateCtxt, &**trait_method_ty, &impl_trait_ref.substs); } + _ => { + // This is span_bug as it should have already been + // caught in resolve. + tcx.sess + .span_bug(impl_method.span, + format!("item `{}` is of a \ + different kind from \ + its trait `{}`", + token::get_ident( + impl_item_ty.ident()), + pprust::path_to_string( + &ast_trait_ref.path)) + .as_slice()); + } } } None => { @@ -913,10 +933,57 @@ fn check_impl_items_against_trait(ccx: &CrateCtxt, } } } + ast::TypeImplItem(ref typedef) => { + let typedef_def_id = local_def(typedef.id); + let typedef_ty = ty::impl_or_trait_item(ccx.tcx, + typedef_def_id); + + // If this is an impl of an associated type, find the + // corresponding type definition in the trait. + let opt_associated_type = + trait_items.iter() + .find(|ti| { + ti.ident().name == typedef_ty.ident().name + }); + match opt_associated_type { + Some(associated_type) => { + match (associated_type, &typedef_ty) { + (&ty::TypeTraitItem(_), + &ty::TypeTraitItem(_)) => {} + _ => { + // This is `span_bug` as it should have + // already been caught in resolve. + tcx.sess + .span_bug(typedef.span, + format!("item `{}` is of a \ + different kind from \ + its trait `{}`", + token::get_ident( + typedef_ty.ident()), + pprust::path_to_string( + &ast_trait_ref.path)) + .as_slice()); + } + } + } + None => { + // This is `span_bug` as it should have already been + // caught in resolve. + tcx.sess.span_bug( + typedef.span, + format!( + "associated type `{}` is not a member of \ + trait `{}`", + token::get_ident(typedef_ty.ident()), + pprust::path_to_string( + &ast_trait_ref.path)).as_slice()); + } + } + } } } - // Check for missing methods from trait + // Check for missing items from trait let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id); let mut missing_methods = Vec::new(); @@ -929,6 +996,7 @@ fn check_impl_items_against_trait(ccx: &CrateCtxt, ast::MethodImplItem(ref m) => { m.pe_ident().name == trait_method.ident.name } + ast::TypeImplItem(_) => false, } }); let is_provided = @@ -940,12 +1008,27 @@ fn check_impl_items_against_trait(ccx: &CrateCtxt, token::get_ident(trait_method.ident))); } } + ty::TypeTraitItem(ref associated_type) => { + let is_implemented = impl_items.iter().any(|ii| { + match *ii { + ast::TypeImplItem(ref typedef) => { + typedef.ident.name == associated_type.ident.name + } + ast::MethodImplItem(_) => false, + } + }); + if !is_implemented { + missing_methods.push( + format!("`{}`", + token::get_ident(associated_type.ident))); + } + } } } if !missing_methods.is_empty() { span_err!(tcx.sess, impl_span, E0046, - "not all trait methods implemented, missing: {}", + "not all trait items implemented, missing: {}", missing_methods.connect(", ")); } } @@ -969,7 +1052,8 @@ fn compare_impl_method(tcx: &ty::ctxt, impl_m_body_id: ast::NodeId, trait_m: &ty::Method, trait_to_impl_substs: &subst::Substs) { - debug!("compare_impl_method()"); + debug!("compare_impl_method(trait_to_impl_substs={})", + trait_to_impl_substs.repr(tcx)); let infcx = infer::new_infer_ctxt(tcx); // Try to give more informative error messages about self typing @@ -1138,11 +1222,13 @@ fn compare_impl_method(tcx: &ty::ctxt, // FIXME(pcwalton): We could be laxer here regarding sub- and super- // traits, but I doubt that'll be wanted often, so meh. for impl_trait_bound in impl_param_def.bounds.trait_bounds.iter() { + debug!("compare_impl_method(): impl-trait-bound subst"); let impl_trait_bound = impl_trait_bound.subst(tcx, &impl_to_skol_substs); let mut ok = false; for trait_bound in trait_param_def.bounds.trait_bounds.iter() { + debug!("compare_impl_method(): trait-bound subst"); let trait_bound = trait_bound.subst(tcx, &trait_to_skol_substs); let infcx = infer::new_infer_ctxt(tcx); @@ -1185,6 +1271,9 @@ fn compare_impl_method(tcx: &ty::ctxt, // other words, anyone expecting to call a method with the type // from the trait, can safely call a method with the type from the // impl instead. + debug!("checking trait method for compatibility: impl ty {}, trait ty {}", + impl_fty.repr(tcx), + trait_fty.repr(tcx)); match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span), impl_fty, trait_fty) { Ok(()) => {} @@ -1513,6 +1602,21 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn ty_infer(&self, _span: Span) -> ty::t { self.infcx().next_ty_var() } + + fn associated_types_of_trait_are_valid(&self, _: ty::t, _: ast::DefId) + -> bool { + false + } + + fn associated_type_binding(&self, + span: Span, + _: Option, + _: ast::DefId, + _: ast::DefId) + -> ty::t { + self.tcx().sess.span_err(span, "unsupported associated type binding"); + ty::mk_err() + } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -4938,6 +5042,7 @@ pub fn polytype_for_def(fcx: &FnCtxt, } def::DefTrait(_) | def::DefTy(..) | + def::DefAssociatedTy(..) | def::DefPrimTy(_) | def::DefTyParam(..)=> { fcx.ccx.tcx.sess.span_bug(sp, "expected value, found type"); @@ -5048,6 +5153,7 @@ pub fn instantiate_path(fcx: &FnCtxt, def::DefVariant(..) | def::DefTyParamBinder(..) | def::DefTy(..) | + def::DefAssociatedTy(..) | def::DefTrait(..) | def::DefPrimTy(..) | def::DefTyParam(..) => { diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs index 76c5cab234f37..cef6e31b93704 100644 --- a/src/librustc/middle/typeck/coherence/mod.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -22,7 +22,7 @@ use middle::subst; use middle::subst::{Substs}; use middle::ty::get; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; -use middle::ty::{lookup_item_type}; +use middle::ty::{TypeTraitItemId, lookup_item_type}; use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open}; use middle::ty::{ty_param, Polytype, ty_ptr}; @@ -332,6 +332,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { MethodTraitItemId( local_def(ast_method.id)) } + ast::TypeImplItem(ref typedef) => { + TypeTraitItemId(local_def(typedef.id)) + } } }).collect(); @@ -393,6 +396,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { .insert(item_def_id.def_id(), source); } } + ty::TypeTraitItem(_) => {} } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index dedb860967c34..b7aa7656ae919 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -138,7 +138,13 @@ pub trait ToTy { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t; } -impl<'a, 'tcx> ToTy for CrateCtxt<'a, 'tcx> { +impl<'a,'tcx> ToTy for ImplCtxt<'a,'tcx> { + fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t { + ast_ty_to_ty(self, rs, ast_ty) + } +} + +impl<'a,'tcx> ToTy for CrateCtxt<'a,'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t { ast_ty_to_ty(self, rs, ast_ty) } @@ -158,6 +164,9 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { let abi = self.tcx.map.get_foreign_abi(id.node); ty_of_foreign_item(self, &*foreign_item, abi) } + Some(ast_map::NodeTraitItem(trait_item)) => { + ty_of_trait_item(self, &*trait_item) + } x => { self.tcx.sess.bug(format!("unexpected sort of node \ in get_item_ty(): {:?}", @@ -175,6 +184,22 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { "the type placeholder `_` is not allowed within types on item signatures."); ty::mk_err() } + + fn associated_types_of_trait_are_valid(&self, _: ty::t, _: ast::DefId) + -> bool { + false + } + + fn associated_type_binding(&self, + span: Span, + _: Option, + _: ast::DefId, + _: ast::DefId) + -> ty::t { + self.tcx().sess.span_err(span, "associated types may not be \ + referenced here"); + ty::mk_err() + } } pub fn get_enum_variant_types(ccx: &CrateCtxt, @@ -201,7 +226,10 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, ast::StructVariantKind(ref struct_def) => { let pty = Polytype { - generics: ty_generics_for_type(ccx, generics), + generics: ty_generics_for_type( + ccx, + generics, + DontCreateTypeParametersForAssociatedTypes), ty: enum_ty }; @@ -214,7 +242,10 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, }; let pty = Polytype { - generics: ty_generics_for_type(ccx, generics), + generics: ty_generics_for_type( + ccx, + generics, + DontCreateTypeParametersForAssociatedTypes), ty: result_ty }; @@ -244,6 +275,7 @@ fn collect_trait_methods(ccx: &CrateCtxt, ccx, trait_id, &trait_def.generics, + trait_items.as_slice(), &m.id, &m.ident, &m.explicit_self, @@ -257,6 +289,7 @@ fn collect_trait_methods(ccx: &CrateCtxt, ccx, trait_id, &trait_def.generics, + trait_items.as_slice(), &m.id, &m.pe_ident(), m.pe_explicit_self(), @@ -265,6 +298,12 @@ fn collect_trait_methods(ccx: &CrateCtxt, &m.pe_fn_style(), &*m.pe_fn_decl()) } + ast::TypeTraitItem(ref at) => { + tcx.sess.span_bug(at.span, + "there shouldn't \ + be a type trait \ + item here") + } }); if ty_method.explicit_self == @@ -277,6 +316,22 @@ fn collect_trait_methods(ccx: &CrateCtxt, .insert(ty_method.def_id, ty::MethodTraitItem(ty_method)); } + ast::TypeTraitItem(ref ast_associated_type) => { + let trait_did = local_def(trait_id); + let associated_type = ty::AssociatedType { + ident: ast_associated_type.ident, + vis: ast::Public, + def_id: local_def(ast_associated_type.id), + container: TraitContainer(trait_did), + }; + + let trait_item = ty::TypeTraitItem(Rc::new( + associated_type)); + tcx.impl_or_trait_items + .borrow_mut() + .insert(associated_type.def_id, + trait_item); + } } } @@ -293,6 +348,9 @@ fn collect_trait_methods(ccx: &CrateCtxt, ty::MethodTraitItemId(local_def( method.id)) } + ast::TypeTraitItem(ref typedef) => { + ty::TypeTraitItemId(local_def(typedef.id)) + } } }).collect()); @@ -314,9 +372,10 @@ fn collect_trait_methods(ccx: &CrateCtxt, ty: ty::mk_bare_fn(ccx.tcx, m.fty.clone()) }); } - fn ty_method_of_trait_method(this: &CrateCtxt, + fn ty_method_of_trait_method(ccx: &CrateCtxt, trait_id: ast::NodeId, trait_generics: &ty::Generics, + trait_items: &[ast::TraitItem], m_id: &ast::NodeId, m_ident: &ast::Ident, m_explicit_self: &ast::ExplicitSelf, @@ -325,20 +384,31 @@ fn collect_trait_methods(ccx: &CrateCtxt, m_fn_style: &ast::FnStyle, m_decl: &ast::FnDecl) -> ty::Method { - let trait_self_ty = ty::mk_self_type(this.tcx, local_def(trait_id)); - - let (fty, explicit_self_category) = - astconv::ty_of_method(this, + let ty_generics = + ty_generics_for_fn_or_method( + ccx, + m_generics, + (*trait_generics).clone(), + DontCreateTypeParametersForAssociatedTypes); + + let (fty, explicit_self_category) = { + let tmcx = TraitMethodCtxt { + ccx: ccx, + trait_id: local_def(trait_id), + trait_items: trait_items.as_slice(), + method_generics: &ty_generics, + }; + let trait_self_ty = ty::mk_self_type(tmcx.tcx(), + local_def(trait_id)); + astconv::ty_of_method(&tmcx, *m_id, *m_fn_style, trait_self_ty, m_explicit_self, m_decl, - m_abi); - let ty_generics = - ty_generics_for_fn_or_method(this, - m_generics, - (*trait_generics).clone()); + m_abi) + }; + ty::Method::new( *m_ident, ty_generics, @@ -386,12 +456,73 @@ pub fn convert_field(ccx: &CrateCtxt, } } -fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt, - container: ImplOrTraitItemContainer, - mut ms: I, - untransformed_rcvr_ty: ty::t, - rcvr_ty_generics: &ty::Generics, - rcvr_visibility: ast::Visibility) { +fn convert_associated_type(ccx: &CrateCtxt, + trait_def: &ty::TraitDef, + associated_type: &ast::AssociatedType) + -> ty::Polytype { + // Find the type parameter ID corresponding to this + // associated type. + let type_parameter_def = trait_def.generics + .types + .get_slice(subst::TypeSpace) + .iter() + .find(|def| { + def.def_id == local_def(associated_type.id) + }); + let type_parameter_def = match type_parameter_def { + Some(type_parameter_def) => type_parameter_def, + None => { + ccx.tcx().sess.span_bug(associated_type.span, + "`convert_associated_type()` didn't find \ + a type parameter ID corresponding to \ + this type") + } + }; + let param_type = ty::mk_param(ccx.tcx, + subst::TypeSpace, + type_parameter_def.index, + local_def(associated_type.id)); + ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.id), + Polytype { + generics: ty::Generics::empty(), + ty: param_type, + }); + write_ty_to_tcx(ccx.tcx, associated_type.id, param_type); + + let associated_type = Rc::new(ty::AssociatedType { + ident: associated_type.ident, + vis: ast::Public, + def_id: local_def(associated_type.id), + container: TraitContainer(trait_def.trait_ref.def_id), + }); + ccx.tcx + .impl_or_trait_items + .borrow_mut() + .insert(associated_type.def_id, + ty::TypeTraitItem(associated_type)); + + Polytype { + generics: ty::Generics::empty(), + ty: param_type, + } +} + +enum ConvertMethodContext<'a> { + /// Used when converting implementation methods. + ImplConvertMethodContext, + /// Used when converting method signatures. The def ID is the def ID of + /// the trait we're translating. + TraitConvertMethodContext(ast::DefId, &'a [ast::TraitItem]), +} + +fn convert_methods<'a,I>(ccx: &CrateCtxt, + convert_method_context: ConvertMethodContext, + container: ImplOrTraitItemContainer, + mut ms: I, + untransformed_rcvr_ty: ty::t, + rcvr_ty_generics: &ty::Generics, + rcvr_visibility: ast::Visibility) + where I: Iterator<&'a ast::Method> { debug!("convert_methods(untransformed_rcvr_ty={}, \ rcvr_ty_generics={})", untransformed_rcvr_ty.repr(ccx.tcx), @@ -400,11 +531,12 @@ fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt, let tcx = ccx.tcx; let mut seen_methods = HashSet::new(); for m in ms { - if !seen_methods.insert(m.pe_ident().repr(ccx.tcx)) { + if !seen_methods.insert(m.pe_ident().repr(tcx)) { tcx.sess.span_err(m.span, "duplicate method in trait impl"); } let mty = Rc::new(ty_of_method(ccx, + convert_method_context, container, m, untransformed_rcvr_ty, @@ -412,9 +544,9 @@ fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt, rcvr_visibility)); let fty = ty::mk_bare_fn(tcx, mty.fty.clone()); debug!("method {} (id {}) has type {}", - m.pe_ident().repr(ccx.tcx), + m.pe_ident().repr(tcx), m.id, - fty.repr(ccx.tcx)); + fty.repr(tcx)); tcx.tcache.borrow_mut().insert( local_def(m.id), Polytype { @@ -433,6 +565,7 @@ fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt, } fn ty_of_method(ccx: &CrateCtxt, + convert_method_context: ConvertMethodContext, container: ImplOrTraitItemContainer, m: &ast::Method, untransformed_rcvr_ty: ty::t, @@ -453,14 +586,43 @@ fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt, _ => m.pe_abi(), }; - let (fty, explicit_self_category) = - astconv::ty_of_method(ccx, - m.id, - m.pe_fn_style(), - untransformed_rcvr_ty, - m.pe_explicit_self(), - &*m.pe_fn_decl(), - real_abi); + let m_ty_generics = + ty_generics_for_fn_or_method( + ccx, + m.pe_generics(), + (*rcvr_ty_generics).clone(), + CreateTypeParametersForAssociatedTypes); + + let (fty, explicit_self_category) = match convert_method_context { + ImplConvertMethodContext => { + let imcx = ImplMethodCtxt { + ccx: ccx, + method_generics: &m_ty_generics, + }; + astconv::ty_of_method(&imcx, + m.id, + m.pe_fn_style(), + untransformed_rcvr_ty, + m.pe_explicit_self(), + &*m.pe_fn_decl(), + real_abi) + } + TraitConvertMethodContext(trait_id, trait_items) => { + let tmcx = TraitMethodCtxt { + ccx: ccx, + trait_id: trait_id, + trait_items: trait_items, + method_generics: &m_ty_generics, + }; + astconv::ty_of_method(&tmcx, + m.id, + m.pe_fn_style(), + untransformed_rcvr_ty, + m.pe_explicit_self(), + &*m.pe_fn_decl(), + real_abi) + } + }; // if the method specifies a visibility, use that, otherwise // inherit the visibility from the impl (so `foo` in `pub impl @@ -468,9 +630,6 @@ fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt, // foo(); }`). let method_vis = m.pe_vis().inherit_from(rcvr_visibility); - let m_ty_generics = - ty_generics_for_fn_or_method(ccx, m.pe_generics(), - (*rcvr_ty_generics).clone()); ty::Method::new(m.pe_ident(), m_ty_generics, fty, @@ -507,6 +666,404 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, } } +fn is_associated_type_valid_for_param(ty: ty::t, + trait_id: ast::DefId, + generics: &ty::Generics) + -> bool { + match ty::get(ty).sty { + ty::ty_param(param_ty) => { + let type_parameter = generics.types.get(param_ty.space, + param_ty.idx); + for trait_bound in type_parameter.bounds.trait_bounds.iter() { + if trait_bound.def_id == trait_id { + return true + } + } + } + _ => {} + } + + false +} + +fn find_associated_type_in_generics(tcx: &ty::ctxt, + span: Span, + ty: Option, + associated_type_id: ast::DefId, + generics: &ty::Generics) + -> ty::t { + let ty = match ty { + None => { + tcx.sess.span_bug(span, + "find_associated_type_in_generics(): no self \ + type") + } + Some(ty) => ty, + }; + + match ty::get(ty).sty { + ty::ty_param(ref param_ty) => { + /*let type_parameter = generics.types.get(param_ty.space, + param_ty.idx); + let param_id = type_parameter.def_id;*/ + let param_id = param_ty.def_id; + for type_parameter in generics.types.iter() { + if type_parameter.def_id == associated_type_id + && type_parameter.associated_with == Some(param_id) { + return ty::mk_param_from_def(tcx, type_parameter) + } + } + + tcx.sess.span_bug(span, + "find_associated_type_in_generics(): didn't \ + find associated type anywhere in the generics \ + list") + } + _ => { + tcx.sess.span_bug(span, + "find_associated_type_in_generics(): self type \ + is not a parameter") + + } + } +} + +fn type_is_self(ty: ty::t) -> bool { + match ty::get(ty).sty { + ty::ty_param(ref param_ty) if param_ty.is_self() => true, + _ => false, + } +} + +struct ImplCtxt<'a,'tcx:'a> { + ccx: &'a CrateCtxt<'a,'tcx>, + opt_trait_ref_id: Option, + impl_items: &'a [ast::ImplItem], + impl_generics: &'a ty::Generics, +} + +impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { + self.ccx.tcx + } + + fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype { + self.ccx.get_item_ty(id) + } + + fn get_trait_def(&self, id: ast::DefId) -> Rc { + self.ccx.get_trait_def(id) + } + + fn ty_infer(&self, span: Span) -> ty::t { + self.ccx.ty_infer(span) + } + + fn associated_types_of_trait_are_valid(&self, + ty: ty::t, + trait_id: ast::DefId) + -> bool { + // OK if the trait with the associated type is the trait we're + // implementing. + match self.opt_trait_ref_id { + Some(trait_ref_id) if trait_ref_id == trait_id => { + if type_is_self(ty) { + return true + } + } + Some(_) | None => {} + } + + // OK if the trait with the associated type is one of the traits in + // our bounds. + is_associated_type_valid_for_param(ty, trait_id, self.impl_generics) + } + + fn associated_type_binding(&self, + span: Span, + ty: Option, + trait_id: ast::DefId, + associated_type_id: ast::DefId) + -> ty::t { + ensure_associated_types(self, trait_id); + let associated_type_ids = ty::associated_types_for_trait(self.ccx.tcx, + trait_id); + match self.opt_trait_ref_id { + Some(trait_ref_id) if trait_ref_id == trait_id => { + // It's an associated type on the trait that we're + // implementing. + let associated_type_id = + associated_type_ids.iter() + .find(|id| { + id.def_id == associated_type_id + }) + .expect("associated_type_binding(): \ + expected associated type ID \ + in trait"); + let associated_type = + ty::impl_or_trait_item(self.ccx.tcx, + associated_type_id.def_id); + for impl_item in self.impl_items.iter() { + match *impl_item { + ast::MethodImplItem(_) => {} + ast::TypeImplItem(ref typedef) => { + if associated_type.ident().name == typedef.ident + .name { + return self.ccx.to_ty(&ExplicitRscope, + &*typedef.typ) + } + } + } + } + self.ccx + .tcx + .sess + .span_bug(span, + "ImplCtxt::associated_type_binding(): didn't \ + find associated type") + } + Some(_) | None => {} + } + + // OK then, it should be an associated type on one of the traits in + // our bounds. + find_associated_type_in_generics(self.ccx.tcx, + span, + ty, + associated_type_id, + self.impl_generics) + } +} + +struct FnCtxt<'a,'tcx:'a> { + ccx: &'a CrateCtxt<'a,'tcx>, + generics: &'a ty::Generics, +} + +impl<'a,'tcx> AstConv<'tcx> for FnCtxt<'a,'tcx> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { + self.ccx.tcx + } + + fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype { + self.ccx.get_item_ty(id) + } + + fn get_trait_def(&self, id: ast::DefId) -> Rc { + self.ccx.get_trait_def(id) + } + + fn ty_infer(&self, span: Span) -> ty::t { + self.ccx.ty_infer(span) + } + + fn associated_types_of_trait_are_valid(&self, + ty: ty::t, + trait_id: ast::DefId) + -> bool { + // OK if the trait with the associated type is one of the traits in + // our bounds. + is_associated_type_valid_for_param(ty, trait_id, self.generics) + } + + fn associated_type_binding(&self, + span: Span, + ty: Option, + _: ast::DefId, + associated_type_id: ast::DefId) + -> ty::t { + debug!("collect::FnCtxt::associated_type_binding()"); + + // The ID should map to an associated type on one of the traits in + // our bounds. + find_associated_type_in_generics(self.ccx.tcx, + span, + ty, + associated_type_id, + self.generics) + } +} + +struct ImplMethodCtxt<'a,'tcx:'a> { + ccx: &'a CrateCtxt<'a,'tcx>, + method_generics: &'a ty::Generics, +} + +impl<'a,'tcx> AstConv<'tcx> for ImplMethodCtxt<'a,'tcx> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { + self.ccx.tcx + } + + fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype { + self.ccx.get_item_ty(id) + } + + fn get_trait_def(&self, id: ast::DefId) -> Rc { + self.ccx.get_trait_def(id) + } + + fn ty_infer(&self, span: Span) -> ty::t { + self.ccx.ty_infer(span) + } + + fn associated_types_of_trait_are_valid(&self, + ty: ty::t, + trait_id: ast::DefId) + -> bool { + is_associated_type_valid_for_param(ty, trait_id, self.method_generics) + } + + fn associated_type_binding(&self, + span: Span, + ty: Option, + _: ast::DefId, + associated_type_id: ast::DefId) + -> ty::t { + debug!("collect::ImplMethodCtxt::associated_type_binding()"); + + // The ID should map to an associated type on one of the traits in + // our bounds. + find_associated_type_in_generics(self.ccx.tcx, + span, + ty, + associated_type_id, + self.method_generics) + } +} + +struct TraitMethodCtxt<'a,'tcx:'a> { + ccx: &'a CrateCtxt<'a,'tcx>, + trait_id: ast::DefId, + trait_items: &'a [ast::TraitItem], + method_generics: &'a ty::Generics, +} + +impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { + self.ccx.tcx + } + + fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype { + self.ccx.get_item_ty(id) + } + + fn get_trait_def(&self, id: ast::DefId) -> Rc { + self.ccx.get_trait_def(id) + } + + fn ty_infer(&self, span: Span) -> ty::t { + self.ccx.ty_infer(span) + } + + fn associated_types_of_trait_are_valid(&self, + ty: ty::t, + trait_id: ast::DefId) + -> bool { + // OK if the trait with the associated type is this trait. + if self.trait_id == trait_id && type_is_self(ty) { + return true + } + + // OK if the trait with the associated type is one of the traits in + // our bounds. + is_associated_type_valid_for_param(ty, trait_id, self.method_generics) + } + + fn associated_type_binding(&self, + span: Span, + ty: Option, + trait_id: ast::DefId, + associated_type_id: ast::DefId) + -> ty::t { + debug!("collect::TraitMethodCtxt::associated_type_binding()"); + + // If this is one of our own associated types, return it. + if trait_id == self.trait_id { + let mut index = 0; + for item in self.trait_items.iter() { + match *item { + ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} + ast::TypeTraitItem(ref item) => { + if local_def(item.id) == associated_type_id { + return ty::mk_param(self.tcx(), + subst::TypeSpace, + index, + associated_type_id) + } + index += 1; + } + } + } + self.ccx + .tcx + .sess + .span_bug(span, + "TraitMethodCtxt::associated_type_binding(): \ + didn't find associated type anywhere in the item \ + list") + } + + // The ID should map to an associated type on one of the traits in + // our bounds. + find_associated_type_in_generics(self.ccx.tcx, + span, + ty, + associated_type_id, + self.method_generics) + } +} + +struct GenericsCtxt<'a,AC:'a> { + chain: &'a AC, + associated_types_generics: &'a ty::Generics, +} + +impl<'a,'tcx,AC:AstConv<'tcx>> AstConv<'tcx> for GenericsCtxt<'a,AC> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { + self.chain.tcx() + } + + fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype { + self.chain.get_item_ty(id) + } + + fn get_trait_def(&self, id: ast::DefId) -> Rc { + self.chain.get_trait_def(id) + } + + fn ty_infer(&self, span: Span) -> ty::t { + self.chain.ty_infer(span) + } + + fn associated_types_of_trait_are_valid(&self, + ty: ty::t, + trait_id: ast::DefId) + -> bool { + // OK if the trait with the associated type is one of the traits in + // our bounds. + is_associated_type_valid_for_param(ty, + trait_id, + self.associated_types_generics) + } + + fn associated_type_binding(&self, + span: Span, + ty: Option, + _: ast::DefId, + associated_type_id: ast::DefId) + -> ty::t { + debug!("collect::GenericsCtxt::associated_type_binding()"); + + // The ID should map to an associated type on one of the traits in + // our bounds. + find_associated_type_in_generics(self.chain.tcx(), + span, + ty, + associated_type_id, + self.associated_types_generics) + } +} + pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id); @@ -525,14 +1082,22 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ref opt_trait_ref, ref selfty, ref impl_items) => { - let ty_generics = ty_generics_for_type(ccx, generics); + // Create generics from the generics specified in the impl head. + let ty_generics = ty_generics_for_type( + ccx, + generics, + CreateTypeParametersForAssociatedTypes); + let selfty = ccx.to_ty(&ExplicitRscope, &**selfty); write_ty_to_tcx(tcx, it.id, selfty); - tcx.tcache.borrow_mut().insert(local_def(it.id), - Polytype { - generics: ty_generics.clone(), - ty: selfty}); + tcx.tcache + .borrow_mut() + .insert(local_def(it.id), + Polytype { + generics: ty_generics.clone(), + ty: selfty, + }); // If there is a trait reference, treat the methods as always public. // This is to work around some incorrect behavior in privacy checking: @@ -545,6 +1110,20 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { it.vis }; + let icx = ImplCtxt { + ccx: ccx, + opt_trait_ref_id: match *opt_trait_ref { + None => None, + Some(ref ast_trait_ref) => { + Some(lookup_def_tcx(tcx, + ast_trait_ref.path.span, + ast_trait_ref.ref_id).def_id()) + } + }, + impl_items: impl_items.as_slice(), + impl_generics: &ty_generics, + }; + let mut methods = Vec::new(); for impl_item in impl_items.iter() { match *impl_item { @@ -555,10 +1134,33 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { method.pe_explicit_self()); methods.push(&**method); } + ast::TypeImplItem(ref typedef) => { + let typ = icx.to_ty(&ExplicitRscope, &*typedef.typ); + tcx.tcache + .borrow_mut() + .insert(local_def(typedef.id), + Polytype { + generics: ty::Generics::empty(), + ty: typ, + }); + write_ty_to_tcx(ccx.tcx, typedef.id, typ); + + let associated_type = Rc::new(ty::AssociatedType { + ident: typedef.ident, + vis: typedef.vis, + def_id: local_def(typedef.id), + container: ty::ImplContainer(local_def(it.id)), + }); + tcx.impl_or_trait_items + .borrow_mut() + .insert(local_def(typedef.id), + ty::TypeTraitItem(associated_type)); + } } } convert_methods(ccx, + ImplConvertMethodContext, ImplContainer(local_def(it.id)), methods.into_iter(), selfty, @@ -566,7 +1168,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { parent_visibility); for trait_ref in opt_trait_ref.iter() { - instantiate_trait_ref(ccx, trait_ref, selfty); + instantiate_trait_ref(&icx, trait_ref, selfty, None); } }, ast::ItemTrait(_, _, _, ref trait_methods) => { @@ -595,16 +1197,27 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { self_type, method.pe_explicit_self()) } + ast::TypeTraitItem(ref associated_type) => { + convert_associated_type(ccx, + &*trait_def, + &**associated_type); + } } } // Run convert_methods on the provided methods. - let untransformed_rcvr_ty = ty::mk_self_type(tcx, local_def(it.id)); + let untransformed_rcvr_ty = ty::mk_self_type(tcx, + local_def(it.id)); + let convert_method_context = + TraitConvertMethodContext(local_def(it.id), + trait_methods.as_slice()); convert_methods(ccx, + convert_method_context, TraitContainer(local_def(it.id)), trait_methods.iter().filter_map(|m| match *m { ast::RequiredMethod(_) => None, - ast::ProvidedMethod(ref m) => Some(&**m) + ast::ProvidedMethod(ref m) => Some(&**m), + ast::TypeTraitItem(_) => None, }), untransformed_rcvr_ty, &trait_def.generics, @@ -765,9 +1378,12 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) { ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), pty); } -pub fn instantiate_trait_ref(ccx: &CrateCtxt, - ast_trait_ref: &ast::TraitRef, - self_ty: ty::t) -> Rc { +pub fn instantiate_trait_ref<'tcx,AC>(this: &AC, + ast_trait_ref: &ast::TraitRef, + self_ty: ty::t, + associated_type: Option) + -> Rc + where AC: AstConv<'tcx> { /*! * 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 @@ -777,18 +1393,24 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt, // FIXME(#5121) -- distinguish early vs late lifetime params let rscope = ExplicitRscope; - match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) { + match lookup_def_tcx(this.tcx(), + ast_trait_ref.path.span, + ast_trait_ref.ref_id) { def::DefTrait(trait_did) => { let trait_ref = - astconv::ast_path_to_trait_ref( - ccx, &rscope, trait_did, Some(self_ty), &ast_trait_ref.path); + astconv::ast_path_to_trait_ref(this, + &rscope, + trait_did, + Some(self_ty), + associated_type, + &ast_trait_ref.path); - ccx.tcx.trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, - trait_ref.clone()); + this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, + trait_ref.clone()); trait_ref } _ => { - ccx.tcx.sess.span_fatal( + this.tcx().sess.span_fatal( ast_trait_ref.path.span, format!("`{}` is not a trait", path_to_string(&ast_trait_ref.path)).as_slice()); @@ -796,14 +1418,14 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt, } } -pub fn instantiate_unboxed_fn_ty(ccx: &CrateCtxt, - unboxed_function: &ast::UnboxedFnTy, - param_ty: ty::ParamTy) - -> Rc -{ +pub fn instantiate_unboxed_fn_ty<'tcx,AC>(this: &AC, + unboxed_function: &ast::UnboxedFnTy, + param_ty: ty::ParamTy) + -> Rc + where AC: AstConv<'tcx> { let rscope = ExplicitRscope; - let param_ty = param_ty.to_ty(ccx.tcx); - Rc::new(astconv::trait_ref_for_unboxed_function(ccx, + let param_ty = param_ty.to_ty(this.tcx()); + Rc::new(astconv::trait_ref_for_unboxed_function(this, &rscope, unboxed_function, Some(param_ty))) @@ -831,9 +1453,12 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { _ => {} } - let (generics, unbound, bounds) = match it.node { - ast::ItemTrait(ref generics, ref unbound, ref bounds, _) => { - (generics, unbound, bounds) + let (generics, unbound, bounds, items) = match it.node { + ast::ItemTrait(ref generics, + ref unbound, + ref supertraits, + ref items) => { + (generics, unbound, supertraits, items.as_slice()) } ref s => { tcx.sess.span_bug( @@ -842,12 +1467,13 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { } }; - let substs = mk_trait_substs(ccx, it.id, generics); + let substs = mk_trait_substs(ccx, it.id, generics, items); let ty_generics = ty_generics_for_trait(ccx, it.id, &substs, - generics); + generics, + items); let self_param_ty = ty::ParamTy::for_self(def_id); @@ -870,9 +1496,9 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { fn mk_trait_substs(ccx: &CrateCtxt, trait_id: ast::NodeId, - generics: &ast::Generics) - -> subst::Substs - { + generics: &ast::Generics, + items: &[ast::TraitItem]) + -> subst::Substs { // Creates a no-op substitution for the trait's type parameters. let regions = generics.lifetimes @@ -884,7 +1510,8 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { def.lifetime.name)) .collect(); - let types = + // Start with the generics in the type parameters... + let mut types: Vec<_> = generics.ty_params .iter() .enumerate() @@ -892,6 +1519,20 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { i, local_def(def.id))) .collect(); + // ...and add generics synthesized from the associated types. + for item in items.iter() { + match *item { + ast::TypeTraitItem(ref trait_item) => { + let index = types.len(); + types.push(ty::mk_param(ccx.tcx, + subst::TypeSpace, + index, + local_def(trait_item.id))) + } + ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} + } + } + let self_ty = ty::mk_param(ccx.tcx, subst::SelfSpace, 0, local_def(trait_id)); @@ -916,13 +1557,22 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) return pty; } ast::ItemFn(ref decl, fn_style, abi, ref generics, _) => { - let ty_generics = ty_generics_for_fn_or_method(ccx, generics, - ty::Generics::empty()); - let tofd = astconv::ty_of_bare_fn(ccx, - it.id, - fn_style, - abi, - &**decl); + let ty_generics = ty_generics_for_fn_or_method( + ccx, + generics, + ty::Generics::empty(), + CreateTypeParametersForAssociatedTypes); + let tofd = { + let fcx = FnCtxt { + ccx: ccx, + generics: &ty_generics, + }; + astconv::ty_of_bare_fn(&fcx, + it.id, + fn_style, + abi, + &**decl) + }; let pty = Polytype { generics: ty_generics, ty: ty::mk_bare_fn(ccx.tcx, tofd) @@ -930,7 +1580,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) debug!("type of {} (id {}) is {}", token::get_ident(it.ident), it.id, - ppaux::ty_to_string(tcx, pty.ty)); + pty.repr(tcx)); ccx.tcx.tcache.borrow_mut().insert(local_def(it.id), pty.clone()); return pty; @@ -944,7 +1594,10 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) let pty = { let ty = ccx.to_ty(&ExplicitRscope, &**t); Polytype { - generics: ty_generics_for_type(ccx, generics), + generics: ty_generics_for_type( + ccx, + generics, + DontCreateTypeParametersForAssociatedTypes), ty: ty } }; @@ -954,7 +1607,10 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) } ast::ItemEnum(_, ref generics) => { // Create a new generic polytype. - let ty_generics = ty_generics_for_type(ccx, generics); + let ty_generics = ty_generics_for_type( + ccx, + generics, + DontCreateTypeParametersForAssociatedTypes); let substs = mk_item_substs(ccx, &ty_generics); let t = ty::mk_enum(tcx, local_def(it.id), substs); let pty = Polytype { @@ -969,7 +1625,10 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) tcx.sess.span_bug(it.span, "invoked ty_of_item on trait"); } ast::ItemStruct(_, ref generics) => { - let ty_generics = ty_generics_for_type(ccx, generics); + let ty_generics = ty_generics_for_type( + ccx, + generics, + DontCreateTypeParametersForAssociatedTypes); let substs = mk_item_substs(ccx, &ty_generics); let t = ty::mk_struct(tcx, local_def(it.id), substs); let pty = Polytype { @@ -1006,30 +1665,88 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, } } +fn ty_of_trait_item(ccx: &CrateCtxt, trait_item: &ast::TraitItem) + -> ty::Polytype { + match *trait_item { + ast::RequiredMethod(ref m) => { + ccx.tcx.sess.span_bug(m.span, + "ty_of_trait_item() on required method") + } + ast::ProvidedMethod(ref m) => { + ccx.tcx.sess.span_bug(m.span, + "ty_of_trait_item() on provided method") + } + ast::TypeTraitItem(ref associated_type) => { + let parent = ccx.tcx.map.get_parent(associated_type.id); + let trait_def = match ccx.tcx.map.get(parent) { + ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item), + _ => { + ccx.tcx.sess.span_bug(associated_type.span, + "associated type's parent wasn't \ + an item?!") + } + }; + convert_associated_type(ccx, &*trait_def, &**associated_type) + } + } +} + fn ty_generics_for_type(ccx: &CrateCtxt, - generics: &ast::Generics) - -> ty::Generics -{ + generics: &ast::Generics, + create_type_parameters_for_associated_types: + CreateTypeParametersForAssociatedTypesFlag) + -> ty::Generics { ty_generics(ccx, subst::TypeSpace, generics.lifetimes.as_slice(), generics.ty_params.as_slice(), ty::Generics::empty(), - &generics.where_clause) + &generics.where_clause, + create_type_parameters_for_associated_types) } fn ty_generics_for_trait(ccx: &CrateCtxt, trait_id: ast::NodeId, substs: &subst::Substs, - generics: &ast::Generics) + generics: &ast::Generics, + items: &[ast::TraitItem]) -> ty::Generics { - let mut generics = ty_generics(ccx, - subst::TypeSpace, - generics.lifetimes.as_slice(), - generics.ty_params.as_slice(), - ty::Generics::empty(), - &generics.where_clause); + let mut generics = + ty_generics(ccx, + subst::TypeSpace, + generics.lifetimes.as_slice(), + generics.ty_params.as_slice(), + ty::Generics::empty(), + &generics.where_clause, + DontCreateTypeParametersForAssociatedTypes); + + // Add in type parameters for any associated types. + for item in items.iter() { + match *item { + ast::TypeTraitItem(ref associated_type) => { + let def = ty::TypeParameterDef { + space: subst::TypeSpace, + index: generics.types.len(subst::TypeSpace), + ident: associated_type.ident, + def_id: local_def(associated_type.id), + bounds: ty::ParamBounds { + builtin_bounds: ty::empty_builtin_bounds(), + trait_bounds: Vec::new(), + region_bounds: Vec::new(), + }, + associated_with: Some(local_def(trait_id)), + default: None, + }; + ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.id, + def.clone()); + generics.types.push(subst::TypeSpace, def); + } + ast::ProvidedMethod(_) | ast::RequiredMethod(_) => {} + } + } + // Add in the self type parameter. + // // Something of a hack: use the node id for the trait, also as // the node id for the Self type parameter. let param_id = trait_id; @@ -1048,6 +1765,7 @@ fn ty_generics_for_trait(ccx: &CrateCtxt, builtin_bounds: ty::empty_builtin_bounds(), trait_bounds: vec!(self_trait_ref), }, + associated_with: None, default: None }; @@ -1058,41 +1776,48 @@ fn ty_generics_for_trait(ccx: &CrateCtxt, generics } -fn ty_generics_for_fn_or_method(ccx: &CrateCtxt, - generics: &ast::Generics, - base_generics: ty::Generics) - -> ty::Generics { +fn ty_generics_for_fn_or_method<'tcx,AC>( + this: &AC, + generics: &ast::Generics, + base_generics: ty::Generics, + create_type_parameters_for_associated_types: + CreateTypeParametersForAssociatedTypesFlag) + -> ty::Generics + where AC: AstConv<'tcx> { let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); - ty_generics(ccx, + ty_generics(this, subst::FnSpace, early_lifetimes.as_slice(), generics.ty_params.as_slice(), base_generics, - &generics.where_clause) + &generics.where_clause, + create_type_parameters_for_associated_types) } // Add the Sized bound, unless the type parameter is marked as `Sized?`. -fn add_unsized_bound(ccx: &CrateCtxt, - unbound: &Option, - bounds: &mut ty::BuiltinBounds, - desc: &str, - span: Span) { - let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem); - +fn add_unsized_bound<'tcx,AC>(this: &AC, + unbound: &Option, + bounds: &mut ty::BuiltinBounds, + desc: &str, + span: Span) + where AC: AstConv<'tcx> { + let kind_id = this.tcx().lang_items.require(SizedTraitLangItem); match unbound { &Some(ast::TraitTyParamBound(ref tpb)) => { // FIXME(#8559) currently requires the unbound to be built-in. - let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb); + let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb); match kind_id { Ok(kind_id) if trait_def_id != kind_id => { - ccx.tcx.sess.span_warn(span, - format!("default bound relaxed \ - for a {}, but this does \ - nothing because the given \ - bound is not a default. \ - Only `Sized?` is supported.", - desc).as_slice()); - ty::try_add_builtin_trait(ccx.tcx, + this.tcx().sess.span_warn(span, + format!("default bound relaxed \ + for a {}, but this \ + does nothing because \ + the given bound is not \ + a default. \ + Only `Sized?` is \ + supported.", + desc).as_slice()); + ty::try_add_builtin_trait(this.tcx(), kind_id, bounds); } @@ -1100,28 +1825,104 @@ fn add_unsized_bound(ccx: &CrateCtxt, } } _ if kind_id.is_ok() => { - ty::try_add_builtin_trait(ccx.tcx, - kind_id.unwrap(), - bounds); + ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds); } // No lang item for Sized, so we can't add it as a bound. _ => {} } } -fn ty_generics(ccx: &CrateCtxt, - space: subst::ParamSpace, - lifetime_defs: &[ast::LifetimeDef], - types: &[ast::TyParam], - base_generics: ty::Generics, - where_clause: &ast::WhereClause) - -> ty::Generics -{ +#[deriving(Clone, PartialEq, Eq)] +enum CreateTypeParametersForAssociatedTypesFlag { + DontCreateTypeParametersForAssociatedTypes, + CreateTypeParametersForAssociatedTypes, +} + +fn ensure_associated_types<'tcx,AC>(this: &AC, trait_id: ast::DefId) + where AC: AstConv<'tcx> { + if this.tcx().trait_associated_types.borrow().contains_key(&trait_id) { + return + } + + if trait_id.krate == ast::LOCAL_CRATE { + match this.tcx().map.find(trait_id.node) { + Some(ast_map::NodeItem(item)) => { + match item.node { + ast::ItemTrait(_, _, _, ref trait_items) => { + let mut result = Vec::new(); + let mut index = 0; + for trait_item in trait_items.iter() { + match *trait_item { + ast::RequiredMethod(_) | + ast::ProvidedMethod(_) => {} + ast::TypeTraitItem(ref associated_type) => { + let info = ty::AssociatedTypeInfo { + def_id: local_def(associated_type.id), + index: index, + ident: associated_type.ident, + }; + result.push(info); + index += 1; + } + } + } + this.tcx() + .trait_associated_types + .borrow_mut() + .insert(trait_id, Rc::new(result)); + return + } + _ => { + this.tcx().sess.bug("ensure_associated_types() \ + called on non-trait") + } + } + } + _ => { + this.tcx().sess.bug("ensure_associated_types() called on \ + non-trait") + } + } + + } + + // Cross-crate case. + let mut result = Vec::new(); + let mut index = 0; + let trait_items = ty::trait_items(this.tcx(), trait_id); + for trait_item in trait_items.iter() { + match *trait_item { + ty::MethodTraitItem(_) => {} + ty::TypeTraitItem(ref associated_type) => { + let info = ty::AssociatedTypeInfo { + def_id: associated_type.def_id, + index: index, + ident: associated_type.ident + }; + result.push(info); + index += 1; + } + } + } + this.tcx().trait_associated_types.borrow_mut().insert(trait_id, + Rc::new(result)); +} + +fn ty_generics<'tcx,AC>(this: &AC, + space: subst::ParamSpace, + lifetime_defs: &[ast::LifetimeDef], + types: &[ast::TyParam], + base_generics: ty::Generics, + where_clause: &ast::WhereClause, + create_type_parameters_for_associated_types: + CreateTypeParametersForAssociatedTypesFlag) + -> ty::Generics + where AC: AstConv<'tcx> { let mut result = base_generics; for (i, l) in lifetime_defs.iter().enumerate() { let bounds = l.bounds.iter() - .map(|l| ast_region_to_region(ccx.tcx, l)) + .map(|l| ast_region_to_region(this.tcx(), l)) .collect(); let def = ty::RegionParameterDef { name: l.lifetime.name, space: space, @@ -1132,80 +1933,170 @@ fn ty_generics(ccx: &CrateCtxt, result.regions.push(space, def); } + assert!(result.types.is_empty_in(space)); + + // First, create the virtual type parameters for associated types if + // necessary. + let mut associated_types_generics = ty::Generics::empty(); + match create_type_parameters_for_associated_types { + DontCreateTypeParametersForAssociatedTypes => {} + CreateTypeParametersForAssociatedTypes => { + let mut index = 0; + for param in types.iter() { + for bound in param.bounds.iter() { + match *bound { + ast::TraitTyParamBound(ref trait_bound) => { + match lookup_def_tcx(this.tcx(), + trait_bound.path.span, + trait_bound.ref_id) { + def::DefTrait(trait_did) => { + ensure_associated_types(this, trait_did); + let associated_types = + ty::associated_types_for_trait( + this.tcx(), + trait_did); + for associated_type_info in + associated_types.iter() { + let associated_type_trait_item = + ty::impl_or_trait_item( + this.tcx(), + associated_type_info.def_id); + let def = ty::TypeParameterDef { + ident: associated_type_trait_item + .ident(), + def_id: + associated_type_info.def_id, + space: space, + index: types.len() + index, + bounds: ty::ParamBounds { + builtin_bounds: + ty::empty_builtin_bounds(), + trait_bounds: Vec::new(), + region_bounds: Vec::new(), + }, + associated_with: { + Some(local_def(param.id)) + }, + default: None, + }; + associated_types_generics.types + .push(space, + def); + index += 1; + } + } + _ => { + this.tcx().sess.span_bug(trait_bound.path + .span, + "not a trait?!") + } + } + } + _ => {} + } + } + } + } + } + + // Now create the real type parameters. + let gcx = GenericsCtxt { + chain: this, + associated_types_generics: &associated_types_generics, + }; for (i, param) in types.iter().enumerate() { - let def = get_or_create_type_parameter_def(ccx, + let def = get_or_create_type_parameter_def(&gcx, space, param, i, where_clause); - debug!("ty_generics: def for type param: {}", def.repr(ccx.tcx)); + debug!("ty_generics: def for type param: {}, {}", + def.repr(this.tcx()), + space); result.types.push(space, def); } + // Append the associated types to the result. + for associated_type_param in associated_types_generics.types + .get_slice(space) + .iter() { + assert!(result.types.get_slice(space).len() == + associated_type_param.index); + debug!("ty_generics: def for associated type: {}, {}", + associated_type_param.repr(this.tcx()), + space); + result.types.push(space, (*associated_type_param).clone()); + } + return result; - fn get_or_create_type_parameter_def(ccx: &CrateCtxt, + fn get_or_create_type_parameter_def<'tcx,AC>( + this: &AC, space: subst::ParamSpace, param: &ast::TyParam, index: uint, where_clause: &ast::WhereClause) - -> ty::TypeParameterDef { - match ccx.tcx.ty_param_defs.borrow().find(¶m.id) { + -> ty::TypeParameterDef + where AC: AstConv<'tcx> { + match this.tcx().ty_param_defs.borrow().find(¶m.id) { Some(d) => { return (*d).clone(); } None => { } } let param_ty = ty::ParamTy::new(space, index, local_def(param.id)); - let bounds = compute_bounds(ccx, + let bounds = compute_bounds(this, param.ident.name, param_ty, param.bounds.as_slice(), ¶m.unbound, param.span, where_clause); - let default = param.default.as_ref().map(|path| { - let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &**path); - let cur_idx = index; - - ty::walk_ty(ty, |t| { - match ty::get(t).sty { - ty::ty_param(p) => if p.idx > cur_idx { - span_err!(ccx.tcx.sess, path.span, E0128, - "type parameters with a default cannot use \ - forward declared identifiers"); - }, - _ => {} - } - }); + let default = match param.default { + None => None, + Some(ref path) => { + let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path); + let cur_idx = index; + + ty::walk_ty(ty, |t| { + match ty::get(t).sty { + ty::ty_param(p) => if p.idx > cur_idx { + span_err!(this.tcx().sess, path.span, E0128, + "type parameters with a default cannot use \ + forward declared identifiers"); + }, + _ => {} + } + }); - ty - }); + Some(ty) + } + }; let def = ty::TypeParameterDef { space: space, index: index, ident: param.ident, def_id: local_def(param.id), + associated_with: None, bounds: bounds, default: default }; - ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); + this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone()); def } } -fn compute_bounds( - ccx: &CrateCtxt, - name_of_bounded_thing: ast::Name, - param_ty: ty::ParamTy, - ast_bounds: &[ast::TyParamBound], - unbound: &Option, - span: Span, - where_clause: &ast::WhereClause) - -> ty::ParamBounds -{ +fn compute_bounds<'tcx,AC>(this: &AC, + name_of_bounded_thing: ast::Name, + param_ty: ty::ParamTy, + ast_bounds: &[ast::TyParamBound], + unbound: &Option, + span: Span, + where_clause: &ast::WhereClause) + -> ty::ParamBounds + where AC: AstConv<'tcx> { /*! * Translate the AST's notion of ty param bounds (which are an * enum consisting of a newtyped Ty or a region) to ty's @@ -1213,21 +2104,23 @@ fn compute_bounds( * traits, or the built-in trait (formerly known as kind): Send. */ - let mut param_bounds = conv_param_bounds(ccx, + let mut param_bounds = conv_param_bounds(this, span, param_ty, ast_bounds, where_clause); - add_unsized_bound(ccx, + add_unsized_bound(this, unbound, &mut param_bounds.builtin_bounds, "type parameter", span); - check_bounds_compatible(ccx.tcx, name_of_bounded_thing, - ¶m_bounds, span); + check_bounds_compatible(this.tcx(), + name_of_bounded_thing, + ¶m_bounds, + span); param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id)); @@ -1258,31 +2151,36 @@ fn check_bounds_compatible(tcx: &ty::ctxt, } } -fn conv_param_bounds(ccx: &CrateCtxt, - span: Span, - param_ty: ty::ParamTy, - ast_bounds: &[ast::TyParamBound], - where_clause: &ast::WhereClause) - -> ty::ParamBounds -{ +fn conv_param_bounds<'tcx,AC>(this: &AC, + span: Span, + param_ty: ty::ParamTy, + ast_bounds: &[ast::TyParamBound], + where_clause: &ast::WhereClause) + -> ty::ParamBounds + where AC: AstConv<'tcx> { let all_bounds = - merge_param_bounds(ccx, param_ty, ast_bounds, where_clause); + merge_param_bounds(this.tcx(), param_ty, ast_bounds, where_clause); let astconv::PartitionedBounds { builtin_bounds, trait_bounds, region_bounds, unboxed_fn_ty_bounds } = - astconv::partition_bounds(ccx.tcx, span, all_bounds.as_slice()); + astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice()); let unboxed_fn_ty_bounds = unboxed_fn_ty_bounds.into_iter() - .map(|b| instantiate_unboxed_fn_ty(ccx, b, param_ty)); + .map(|b| instantiate_unboxed_fn_ty(this, b, param_ty)); let trait_bounds: Vec> = trait_bounds.into_iter() - .map(|b| instantiate_trait_ref(ccx, b, param_ty.to_ty(ccx.tcx))) + .map(|b| { + instantiate_trait_ref(this, + b, + param_ty.to_ty(this.tcx()), + Some(param_ty.to_ty(this.tcx()))) + }) .chain(unboxed_fn_ty_bounds) .collect(); let region_bounds: Vec = region_bounds.move_iter() - .map(|r| ast_region_to_region(ccx.tcx, r)) + .map(|r| ast_region_to_region(this.tcx(), r)) .collect(); ty::ParamBounds { region_bounds: region_bounds, @@ -1291,12 +2189,11 @@ fn conv_param_bounds(ccx: &CrateCtxt, } } -fn merge_param_bounds<'a>(ccx: &CrateCtxt, +fn merge_param_bounds<'a>(tcx: &ty::ctxt, param_ty: ty::ParamTy, ast_bounds: &'a [ast::TyParamBound], where_clause: &'a ast::WhereClause) - -> Vec<&'a ast::TyParamBound> -{ + -> Vec<&'a ast::TyParamBound> { /*! * Merges the bounds declared on a type parameter with those * found from where clauses into a single list. @@ -1309,15 +2206,13 @@ fn merge_param_bounds<'a>(ccx: &CrateCtxt, } for predicate in where_clause.predicates.iter() { - let predicate_param_id = ccx.tcx - .def_map - .borrow() - .find(&predicate.id) - .expect("compute_bounds(): resolve \ - didn't resolve the type \ - parameter identifier in a \ - `where` clause") - .def_id(); + let predicate_param_id = + tcx.def_map + .borrow() + .find(&predicate.id) + .expect("compute_bounds(): resolve didn't resolve the type \ + parameter identifier in a `where` clause") + .def_id(); if param_ty.def_id != predicate_param_id { continue } @@ -1334,8 +2229,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, def_id: ast::DefId, ast_generics: &ast::Generics, abi: abi::Abi) - -> ty::Polytype { - + -> ty::Polytype { for i in decl.inputs.iter() { match (*i).pat.node { ast::PatIdent(_, _, _) => (), @@ -1347,9 +2241,11 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, } } - let ty_generics_for_fn_or_method = - ty_generics_for_fn_or_method(ccx, ast_generics, - ty::Generics::empty()); + let ty_generics_for_fn_or_method = ty_generics_for_fn_or_method( + ccx, + ast_generics, + ty::Generics::empty(), + DontCreateTypeParametersForAssociatedTypes); let rb = BindingRscope::new(def_id.node); let input_tys = decl.inputs .iter() diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index af670f25e5626..6ea80a59230ad 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -871,6 +871,7 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> { Some(&m.pe_explicit_self().node), m.span)) } + ast::TypeImplItem(_) => None, } }, _ => None @@ -1687,6 +1688,7 @@ fn lifetimes_in_scope(tcx: &ty::ctxt, taken.push_all(m.pe_generics().lifetimes.as_slice()); Some(m.id) } + ast::TypeImplItem(_) => None, } } _ => None diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 547fbce573bcc..a6edfcf80fdac 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -522,6 +522,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { self.add_constraints_from_sig(&method.fty.sig, self.covariant); } + ty::TypeTraitItem(_) => {} } } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index be4a1c95e5550..2083aa52bec6c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -603,9 +603,11 @@ impl Repr for def::Def { impl Repr for ty::TypeParameterDef { fn repr(&self, tcx: &ctxt) -> String { - format!("TypeParameterDef({}, {})", - self.def_id.repr(tcx), - self.bounds.repr(tcx)) + format!("TypeParameterDef({}, {}, {}/{})", + self.def_id, + self.bounds.repr(tcx), + self.space, + self.index) } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index ccb01ca620eb7..1a324e25472cf 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -316,6 +316,10 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, }; Some(item) } + ty::TypeTraitItem(_) => { + // FIXME(pcwalton): Implement. + None + } } }).collect(); return Some(clean::Item { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c03c56cd22312..9e05382fa556b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -17,7 +17,7 @@ use syntax::ast_util; use syntax::ast_util::PostExpansionMethod; use syntax::attr; use syntax::attr::{AttributeMethods, AttrMetaMethods}; -use syntax::codemap::Pos; +use syntax::codemap::{DUMMY_SP, Pos}; use syntax::parse::token::InternedString; use syntax::parse::token; use syntax::ptr::P; @@ -317,6 +317,7 @@ pub enum ItemEnum { ForeignStaticItem(Static), MacroItem(Macro), PrimitiveItem(Primitive), + AssociatedTypeItem, } #[deriving(Clone, Encodable, Decodable)] @@ -933,6 +934,7 @@ impl Clean for ast::TraitRef { pub enum TraitItem { RequiredMethod(Item), ProvidedMethod(Item), + TypeTraitItem(Item), } impl TraitItem { @@ -952,6 +954,7 @@ impl TraitItem { match *self { RequiredMethod(ref item) => item, ProvidedMethod(ref item) => item, + TypeTraitItem(ref item) => item, } } } @@ -961,6 +964,7 @@ impl Clean for ast::TraitItem { match self { &ast::RequiredMethod(ref t) => RequiredMethod(t.clean(cx)), &ast::ProvidedMethod(ref t) => ProvidedMethod(t.clean(cx)), + &ast::TypeTraitItem(ref t) => TypeTraitItem(t.clean(cx)), } } } @@ -968,12 +972,14 @@ impl Clean for ast::TraitItem { #[deriving(Clone, Encodable, Decodable)] pub enum ImplItem { MethodImplItem(Item), + TypeImplItem(Item), } impl Clean for ast::ImplItem { fn clean(&self, cx: &DocContext) -> ImplItem { match self { &ast::MethodImplItem(ref t) => MethodImplItem(t.clean(cx)), + &ast::TypeImplItem(ref t) => TypeImplItem(t.clean(cx)), } } } @@ -1028,6 +1034,7 @@ impl Clean for ty::ImplOrTraitItem { fn clean(&self, cx: &DocContext) -> Item { match *self { ty::MethodTraitItem(ref mti) => mti.clean(cx), + ty::TypeTraitItem(ref tti) => tti.clean(cx), } } } @@ -1743,6 +1750,7 @@ impl Clean for doctree::Impl { items: self.items.clean(cx).into_iter().map(|ti| { match ti { MethodImplItem(i) => i, + TypeImplItem(i) => i, } }).collect(), derived: detect_derived(self.attrs.as_slice()), @@ -2125,6 +2133,54 @@ impl Clean for attr::Stability { } } +impl Clean for ast::AssociatedType { + fn clean(&self, cx: &DocContext) -> Item { + Item { + source: self.span.clean(cx), + name: Some(self.ident.clean(cx)), + attrs: self.attrs.clean(cx), + inner: AssociatedTypeItem, + visibility: None, + def_id: ast_util::local_def(self.id), + stability: None, + } + } +} + +impl Clean for ty::AssociatedType { + fn clean(&self, cx: &DocContext) -> Item { + Item { + source: DUMMY_SP.clean(cx), + name: Some(self.ident.clean(cx)), + attrs: Vec::new(), + inner: AssociatedTypeItem, + visibility: None, + def_id: self.def_id, + stability: None, + } + } +} + +impl Clean for ast::Typedef { + fn clean(&self, cx: &DocContext) -> Item { + Item { + source: self.span.clean(cx), + name: Some(self.ident.clean(cx)), + attrs: self.attrs.clean(cx), + inner: TypedefItem(Typedef { + type_: self.typ.clean(cx), + generics: Generics { + lifetimes: Vec::new(), + type_params: Vec::new(), + }, + }), + visibility: None, + def_id: ast_util::local_def(self.id), + stability: None, + } + } +} + fn lang_struct(cx: &DocContext, did: Option, t: ty::t, name: &str, fallback: fn(Box) -> Type) -> Type { diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 66e93de995ee8..54e9c29e11df0 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -55,6 +55,12 @@ pub trait DocFolder { None => return None, } }, + TypeTraitItem(it) => { + match this.fold_item(it) { + Some(x) => return Some(TypeTraitItem(x)), + None => return None, + } + } } } let mut foo = Vec::new(); swap(&mut foo, &mut i.items); diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 6e240b0d8d4a6..e18ab0bd14f59 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -38,6 +38,7 @@ pub enum ItemType { ForeignStatic = 14, Macro = 15, Primitive = 16, + AssociatedType = 17, } impl ItemType { @@ -60,6 +61,7 @@ impl ItemType { ForeignStatic => "ffs", Macro => "macro", Primitive => "primitive", + AssociatedType => "associatedtype", } } } @@ -95,6 +97,7 @@ pub fn shortty(item: &clean::Item) -> ItemType { clean::ForeignStaticItem(..) => ForeignStatic, clean::MacroItem(..) => Macro, clean::PrimitiveItem(..) => Primitive, + clean::AssociatedTypeItem => AssociatedType, } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a0c4283711e68..2107854c52b95 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1512,6 +1512,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, clean::ForeignStaticItem(..) => ("ffi-statics", "Foreign Statics"), clean::MacroItem(..) => ("macros", "Macros"), clean::PrimitiveItem(..) => ("primitives", "Primitive Types"), + clean::AssociatedTypeItem(..) => ("associated-types", "Associated Types"), }; try!(write!(w, "

\ diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index eeccc3303ebfe..33337594b4c67 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -175,6 +175,9 @@ impl<'a> fold::DocFolder for Stripper<'a> { // Primitives are never stripped clean::PrimitiveItem(..) => {} + + // Associated types are never stripped + clean::AssociatedTypeItem(..) => {} } let fastreturn = match i.inner { diff --git a/src/librustdoc/stability_summary.rs b/src/librustdoc/stability_summary.rs index 11d00fa20a418..02dc4e9bdb622 100644 --- a/src/librustdoc/stability_summary.rs +++ b/src/librustdoc/stability_summary.rs @@ -22,7 +22,7 @@ use syntax::ast::Public; use clean::{Crate, Item, ModuleItem, Module, StructItem, Struct, EnumItem, Enum}; use clean::{ImplItem, Impl, Trait, TraitItem, ProvidedMethod, RequiredMethod}; -use clean::{ViewItemItem, PrimitiveItem}; +use clean::{TypeTraitItem, ViewItemItem, PrimitiveItem}; #[deriving(Zero, Encodable, Decodable, PartialEq, Eq)] /// The counts for each stability level. @@ -131,7 +131,8 @@ fn summarize_item(item: &Item) -> (Counts, Option) { fn extract_item<'a>(trait_item: &'a TraitItem) -> &'a Item { match *trait_item { ProvidedMethod(ref item) | - RequiredMethod(ref item) => item + RequiredMethod(ref item) | + TypeTraitItem(ref item) => item } } let subcounts = trait_items.iter() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5546f868ba08d..eac158e664c26 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -555,6 +555,18 @@ pub enum Expr_ { ExprParen(P) } +/// A "qualified path": +/// +/// as SomeTrait>::SomeAssociatedItem +/// ^~~~~ ^~~~~~~~~ ^~~~~~~~~~~~~~~~~~ +/// for_type trait_name item_name +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct QPath { + pub for_type: P, + pub trait_name: Path, + pub item_name: Ident, +} + #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum CaptureClause { CaptureByValue, @@ -766,11 +778,31 @@ pub struct TypeMethod { pub enum TraitItem { RequiredMethod(TypeMethod), ProvidedMethod(P), + TypeTraitItem(P), } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum ImplItem { MethodImplItem(P), + TypeImplItem(P), +} + +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct AssociatedType { + pub id: NodeId, + pub span: Span, + pub ident: Ident, + pub attrs: Vec, +} + +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct Typedef { + pub id: NodeId, + pub span: Span, + pub ident: Ident, + pub vis: Visibility, + pub attrs: Vec, + pub typ: P, } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] @@ -917,6 +949,8 @@ pub enum Ty_ { TyUnboxedFn(P), TyTup(Vec> ), TyPath(Path, Option, NodeId), // for #7264; see above + /// A "qualified path", e.g. ` as SomeTrait>::SomeType` + TyQPath(P), /// No-op; kept solely so that we can pretty-print faithfully TyParen(P), TyTypeof(P), diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 1400e494917f1..8280f34615fc2 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -207,6 +207,9 @@ impl<'a> FnLikeNode<'a> { ast_map::NodeImplItem(ii) => { match *ii { ast::MethodImplItem(ref m) => method(&**m), + ast::TypeImplItem(_) => { + fail!("impl method FnLikeNode that is not fn-like") + } } } ast_map::NodeExpr(e) => match e.node { diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index ed0b8700bf374..a5458461a8b25 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -11,11 +11,11 @@ use abi; use ast::*; use ast_util; -use ast_util::PostExpansionMethod; use codemap::{DUMMY_SP, Span, Spanned}; use fold::Folder; use parse::token; use print::pprust; +use ptr::P; use visit::{mod, Visitor}; use arena::TypedArena; @@ -391,16 +391,20 @@ impl<'ast> Map<'ast> { } } } + TypeImplItem(ref t) => PathName(t.ident.name), } }, NodeTraitItem(tm) => match *tm { RequiredMethod(ref m) => PathName(m.ident.name), - ProvidedMethod(ref m) => match m.node { - MethDecl(ident, _, _, _, _, _, _, _) => { - PathName(ident.name) + ProvidedMethod(ref m) => { + match m.node { + MethDecl(ident, _, _, _, _, _, _, _) => { + PathName(ident.name) + } + MethMac(_) => fail!("no path elem for {:?}", node), } - MethMac(_) => fail!("no path elem for {:?}", node), } + TypeTraitItem(ref m) => PathName(m.ident.name), }, NodeVariant(v) => PathName(v.node.name.name), _ => fail!("no path elem for {:?}", node) @@ -459,11 +463,13 @@ impl<'ast> Map<'ast> { NodeForeignItem(fi) => Some(fi.attrs.as_slice()), NodeTraitItem(ref tm) => match **tm { RequiredMethod(ref type_m) => Some(type_m.attrs.as_slice()), - ProvidedMethod(ref m) => Some(m.attrs.as_slice()) + ProvidedMethod(ref m) => Some(m.attrs.as_slice()), + TypeTraitItem(ref typ) => Some(typ.attrs.as_slice()), }, NodeImplItem(ref ii) => { match **ii { MethodImplItem(ref m) => Some(m.attrs.as_slice()), + TypeImplItem(ref t) => Some(t.attrs.as_slice()), } } NodeVariant(ref v) => Some(v.node.attrs.as_slice()), @@ -503,11 +509,13 @@ impl<'ast> Map<'ast> { match *trait_method { RequiredMethod(ref type_method) => type_method.span, ProvidedMethod(ref method) => method.span, + TypeTraitItem(ref typedef) => typedef.span, } } Some(NodeImplItem(ref impl_item)) => { match **impl_item { MethodImplItem(ref method) => method.span, + TypeImplItem(ref typedef) => typedef.span, } } Some(NodeVariant(variant)) => variant.span, @@ -633,6 +641,7 @@ impl Named for TraitItem { match *self { RequiredMethod(ref tm) => tm.ident.name, ProvidedMethod(ref m) => m.name(), + TypeTraitItem(ref at) => at.ident.name, } } } @@ -640,6 +649,7 @@ impl Named for ImplItem { fn name(&self) -> Name { match *self { MethodImplItem(ref m) => m.name(), + TypeImplItem(ref td) => td.ident.name, } } } @@ -712,10 +722,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { match i.node { ItemImpl(_, _, _, ref impl_items) => { for impl_item in impl_items.iter() { - let id = match *impl_item { - MethodImplItem(ref m) => m.id - }; - self.insert(id, NodeImplItem(impl_item)); + match *impl_item { + MethodImplItem(ref m) => { + self.insert(m.id, NodeImplItem(impl_item)); + } + TypeImplItem(ref t) => { + self.insert(t.id, NodeImplItem(impl_item)); + } + } } } ItemEnum(ref enum_definition, _) => { @@ -737,13 +751,28 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { None => {} } } - ItemTrait(_, _, _, ref methods) => { - for tm in methods.iter() { - let id = match *tm { - RequiredMethod(ref m) => m.id, - ProvidedMethod(ref m) => m.id - }; - self.insert(id, NodeTraitItem(tm)); + ItemTrait(_, _, ref bounds, ref trait_items) => { + for b in bounds.iter() { + match *b { + TraitTyParamBound(ref t) => { + self.insert(t.ref_id, NodeItem(i)); + } + _ => {} + } + } + + for tm in trait_items.iter() { + match *tm { + RequiredMethod(ref m) => { + self.insert(m.id, NodeTraitItem(tm)); + } + ProvidedMethod(ref m) => { + self.insert(m.id, NodeTraitItem(tm)); + } + TypeTraitItem(ref typ) => { + self.insert(typ.id, NodeTraitItem(tm)); + } + } } } _ => {} @@ -892,6 +921,11 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, IITraitItem(fld.fold_ops.new_def_id(d), RequiredMethod(fld.fold_type_method(ty_m))) } + TypeTraitItem(at) => { + IITraitItem( + fld.fold_ops.new_def_id(d), + TypeTraitItem(P(fld.fold_associated_type((*at).clone())))) + } }, IIImplItem(d, m) => match m { MethodImplItem(m) => { @@ -899,6 +933,10 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, MethodImplItem(fld.fold_method(m) .expect_one("expected one method"))) } + TypeImplItem(t) => { + IIImplItem(fld.fold_ops.new_def_id(d), + TypeImplItem(P(fld.fold_typedef((*t).clone())))) + } }, IIForeign(i) => IIForeign(fld.fold_foreign_item(i)) }; @@ -924,14 +962,16 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, IITraitItem(_, ref trait_item) => { let trait_item_id = match *trait_item { ProvidedMethod(ref m) => m.id, - RequiredMethod(ref m) => m.id + RequiredMethod(ref m) => m.id, + TypeTraitItem(ref ty) => ty.id, }; collector.insert(trait_item_id, NodeTraitItem(trait_item)); } IIImplItem(_, ref impl_item) => { let impl_item_id = match *impl_item { - MethodImplItem(ref m) => m.id + MethodImplItem(ref m) => m.id, + TypeImplItem(ref ti) => ti.id, }; collector.insert(impl_item_id, NodeImplItem(impl_item)); @@ -1007,16 +1047,30 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String { pprust::mac_to_string(mac), id) } } + TypeImplItem(ref t) => { + format!("typedef {} in {} (id={})", + token::get_ident(t.ident), + map.path_to_string(id), + id) + } } } - Some(NodeTraitItem(ref ti)) => { - let ident = match **ti { - ProvidedMethod(ref m) => m.pe_ident(), - RequiredMethod(ref m) => m.ident - }; - format!("method {} in {} (id={})", - token::get_ident(ident), - map.path_to_string(id), id) + Some(NodeTraitItem(ref tm)) => { + match **tm { + RequiredMethod(_) | ProvidedMethod(_) => { + let m = ast_util::trait_item_to_ty_method(&**tm); + format!("method {} in {} (id={})", + token::get_ident(m.ident), + map.path_to_string(id), + id) + } + TypeTraitItem(ref t) => { + format!("type item {} in {} (id={})", + token::get_ident(t.ident), + map.path_to_string(id), + id) + } + } } Some(NodeVariant(ref variant)) => { format!("variant {} in {} (id={})", diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index becfe715f29e2..6d61c851476c3 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -213,6 +213,62 @@ pub fn impl_pretty_name(trait_ref: &Option, ty: &Ty) -> Ident { token::gensym_ident(pretty.as_slice()) } +pub fn trait_method_to_ty_method(method: &Method) -> TypeMethod { + match method.node { + MethDecl(ident, + ref generics, + abi, + ref explicit_self, + fn_style, + ref decl, + _, + vis) => { + TypeMethod { + ident: ident, + attrs: method.attrs.clone(), + fn_style: fn_style, + decl: (*decl).clone(), + generics: generics.clone(), + explicit_self: (*explicit_self).clone(), + id: method.id, + span: method.span, + vis: vis, + abi: abi, + } + }, + MethMac(_) => fail!("expected non-macro method declaration") + } +} + +/// extract a TypeMethod from a TraitItem. if the TraitItem is +/// a default, pull out the useful fields to make a TypeMethod +// +// NB: to be used only after expansion is complete, and macros are gone. +pub fn trait_item_to_ty_method(method: &TraitItem) -> TypeMethod { + match *method { + RequiredMethod(ref m) => (*m).clone(), + ProvidedMethod(ref m) => trait_method_to_ty_method(&**m), + TypeTraitItem(_) => { + fail!("trait_method_to_ty_method(): expected method but found \ + typedef") + } + } +} + +pub fn split_trait_methods(trait_methods: &[TraitItem]) + -> (Vec, Vec> ) { + let mut reqd = Vec::new(); + let mut provd = Vec::new(); + for trt_method in trait_methods.iter() { + match *trt_method { + RequiredMethod(ref tm) => reqd.push((*tm).clone()), + ProvidedMethod(ref m) => provd.push((*m).clone()), + TypeTraitItem(_) => {} + } + }; + (reqd, provd) +} + pub fn struct_field_visibility(field: ast::StructField) -> Visibility { match field.node.kind { ast::NamedField(_, v) | ast::UnnamedField(v) => v @@ -471,6 +527,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { match *tm { ast::RequiredMethod(ref m) => self.operation.visit_id(m.id), ast::ProvidedMethod(ref m) => self.operation.visit_id(m.id), + ast::TypeTraitItem(ref typ) => self.operation.visit_id(typ.id), } visit::walk_trait_item(self, tm); } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index cb96cd911b5c6..3b250de870165 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -235,13 +235,15 @@ fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool { fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitItem) -> bool { match *meth { ast::RequiredMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()), - ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()) + ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()), + ast::TypeTraitItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()), } } fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool { match *impl_item { ast::MethodImplItem(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()), + ast::TypeImplItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()), } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 6c7bbb2384c12..7a7dbc54c9ef9 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -90,7 +90,10 @@ impl<'a> MacResult for ParserAnyMacro<'a> { let mut parser = self.parser.borrow_mut(); match parser.token { EOF => break, - _ => ret.push(parser.parse_method(None)) + _ => { + let attrs = parser.parse_outer_attributes(); + ret.push(parser.parse_method(attrs, ast::Inherited)) + } } } self.ensure_complete_parse(false); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e22e55193fca3..5203ed0a07341 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -68,6 +68,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("import_shadowing", Active), ("advanced_slice_patterns", Active), ("tuple_indexing", Active), + ("associated_types", Active), // if you change this list without updating src/doc/rust.md, cmr will be sad @@ -235,7 +236,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { } } - ast::ItemImpl(..) => { + ast::ItemImpl(_, _, _, ref items) => { if attr::contains_name(i.attrs.as_slice(), "unsafe_destructor") { self.gate_feature("unsafe_destructor", @@ -244,6 +245,18 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { many unsafe patterns and may be \ removed in the future"); } + + for item in items.iter() { + match *item { + ast::MethodImplItem(_) => {} + ast::TypeImplItem(ref typedef) => { + self.gate_feature("associated_types", + typedef.span, + "associated types are \ + experimental") + } + } + } } _ => {} @@ -252,6 +265,17 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { visit::walk_item(self, i); } + fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { + match *trait_item { + ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} + ast::TypeTraitItem(ref ti) => { + self.gate_feature("associated_types", + ti.span, + "associated types are experimental") + } + } + } + fn visit_mac(&mut self, macro: &ast::Mac) { let ast::MacInvocTT(ref path, _, _) = macro.node; let id = path.segments.last().unwrap().identifier; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4806c5fa7c062..3beba5bcda4b2 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -287,6 +287,15 @@ pub trait Folder { noop_fold_where_predicate(where_predicate, self) } + fn fold_typedef(&mut self, typedef: Typedef) -> Typedef { + noop_fold_typedef(typedef, self) + } + + fn fold_associated_type(&mut self, associated_type: AssociatedType) + -> AssociatedType { + noop_fold_associated_type(associated_type, self) + } + fn new_id(&mut self, i: NodeId) -> NodeId { i } @@ -414,6 +423,13 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { fld.fold_opt_bounds(bounds), id) } + TyQPath(ref qpath) => { + TyQPath(P(QPath { + for_type: fld.fold_ty(qpath.for_type.clone()), + trait_name: fld.fold_path(qpath.trait_name.clone()), + item_name: fld.fold_ident(qpath.item_name.clone()), + })) + } TyFixedLengthVec(ty, e) => { TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) } @@ -735,6 +751,44 @@ pub fn noop_fold_where_predicate( } } +pub fn noop_fold_typedef(t: Typedef, folder: &mut T) + -> Typedef + where T: Folder { + let new_id = folder.new_id(t.id); + let new_span = folder.new_span(t.span); + let new_attrs = t.attrs.iter().map(|attr| { + folder.fold_attribute((*attr).clone()) + }).collect(); + let new_ident = folder.fold_ident(t.ident); + let new_type = folder.fold_ty(t.typ); + ast::Typedef { + ident: new_ident, + typ: new_type, + id: new_id, + span: new_span, + vis: t.vis, + attrs: new_attrs, + } +} + +pub fn noop_fold_associated_type(at: AssociatedType, folder: &mut T) + -> AssociatedType + where T: Folder { + let new_id = folder.new_id(at.id); + let new_span = folder.new_span(at.span); + let new_ident = folder.fold_ident(at.ident); + let new_attrs = at.attrs + .iter() + .map(|attr| folder.fold_attribute((*attr).clone())) + .collect(); + ast::AssociatedType { + ident: new_ident, + attrs: new_attrs, + id: new_id, + span: new_span, + } +} + pub fn noop_fold_struct_def(struct_def: P, fld: &mut T) -> P { struct_def.map(|StructDef {fields, ctor_id, super_struct, is_virtual}| StructDef { fields: fields.move_map(|f| fld.fold_struct_field(f)), @@ -857,31 +911,59 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { ItemStruct(struct_def, folder.fold_generics(generics)) } ItemImpl(generics, ifce, ty, impl_items) => { + let mut new_impl_items = Vec::new(); + for impl_item in impl_items.iter() { + match *impl_item { + MethodImplItem(ref x) => { + for method in folder.fold_method((*x).clone()) + .move_iter() { + new_impl_items.push(MethodImplItem(method)) + } + } + TypeImplItem(ref t) => { + new_impl_items.push(TypeImplItem( + P(folder.fold_typedef((**t).clone())))); + } + } + } + let ifce = match ifce { + None => None, + Some(ref trait_ref) => { + Some(folder.fold_trait_ref((*trait_ref).clone())) + } + }; ItemImpl(folder.fold_generics(generics), - ifce.map(|p| folder.fold_trait_ref(p)), + ifce, folder.fold_ty(ty), - impl_items.into_iter().flat_map(|impl_item| match impl_item { - MethodImplItem(x) => { - folder.fold_method(x).into_iter().map(|x| MethodImplItem(x)) - } - }).collect()) + new_impl_items) } ItemTrait(generics, unbound, bounds, methods) => { let bounds = folder.fold_bounds(bounds); - let methods = methods.into_iter().flat_map(|method| match method { - RequiredMethod(m) => { - SmallVector::one(RequiredMethod(folder.fold_type_method(m))).into_iter() - } - ProvidedMethod(method) => { - // the awkward collect/iter idiom here is because - // even though an iter and a map satisfy the same trait bound, - // they're not actually the same type, so the method arms - // don't unify. - let methods: SmallVector = - folder.fold_method(method).into_iter() - .map(|m| ProvidedMethod(m)).collect(); - methods.into_iter() - } + let methods = methods.into_iter().flat_map(|method| { + let r = match method { + RequiredMethod(m) => { + SmallVector::one(RequiredMethod( + folder.fold_type_method(m))) + .move_iter() + } + ProvidedMethod(method) => { + // the awkward collect/iter idiom here is because + // even though an iter and a map satisfy the same + // trait bound, they're not actually the same type, so + // the method arms don't unify. + let methods: SmallVector = + folder.fold_method(method).move_iter() + .map(|m| ProvidedMethod(m)).collect(); + methods.move_iter() + } + TypeTraitItem(at) => { + SmallVector::one(TypeTraitItem(P( + folder.fold_associated_type( + (*at).clone())))) + .move_iter() + } + }; + r }).collect(); ItemTrait(folder.fold_generics(generics), unbound, @@ -893,7 +975,18 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { } pub fn noop_fold_type_method(m: TypeMethod, fld: &mut T) -> TypeMethod { - let TypeMethod {id, ident, attrs, fn_style, abi, decl, generics, explicit_self, vis, span} = m; + let TypeMethod { + id, + ident, + attrs, + fn_style, + abi, + decl, + generics, + explicit_self, + vis, + span + } = m; TypeMethod { id: fld.new_id(id), ident: fld.fold_ident(ident), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ea392c8772328..ff4fd41fbd78f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -11,11 +11,11 @@ #![macro_escape] use abi; -use ast::{BareFnTy, ClosureTy}; +use ast::{AssociatedType, BareFnTy, ClosureTy}; use ast::{RegionTyParamBound, TraitTyParamBound}; use ast::{ProvidedMethod, Public, FnStyle}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; -use ast::{BiBitAnd, BiBitOr, BiBitXor, Block}; +use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, Block}; use ast::{BlockCheckMode, UnBox}; use ast::{CaptureByRef, CaptureByValue, CaptureClause}; use ast::{Crate, CrateConfig, Decl, DeclItem}; @@ -42,7 +42,7 @@ use ast::{MatchSeq, MatchTok, Method, MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; -use ast::{BiRem, RequiredMethod}; +use ast::{QPath, RequiredMethod}; use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StructVariantKind, BiSub}; @@ -52,10 +52,10 @@ use ast::{TokenTree, TraitItem, TraitRef, TTDelim, TTSeq, TTTok}; use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; -use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyRptr}; -use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq}; -use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound}; -use ast::{UnnamedField, UnsafeBlock}; +use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath}; +use ast::{TyRptr, TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq}; +use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind}; +use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock}; use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause, WherePredicate}; @@ -1235,86 +1235,125 @@ impl<'a> Parser<'a> { (decl, lifetime_defs) } - /// Parse the methods in a trait declaration - pub fn parse_trait_methods(&mut self) -> Vec { + /// Parses `type Foo;` in a trait declaration only. The `type` keyword has + /// already been parsed. + fn parse_associated_type(&mut self, attrs: Vec) + -> AssociatedType { + let lo = self.span.lo; + let ident = self.parse_ident(); + let hi = self.span.hi; + self.expect(&token::SEMI); + AssociatedType { + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + ident: ident, + attrs: attrs, + } + } + + /// Parses `type Foo = TYPE;` in an implementation declaration only. The + /// `type` keyword has already been parsed. + fn parse_typedef(&mut self, attrs: Vec, vis: Visibility) + -> Typedef { + let lo = self.span.lo; + let ident = self.parse_ident(); + self.expect(&token::EQ); + let typ = self.parse_ty(true); + let hi = self.span.hi; + self.expect(&token::SEMI); + Typedef { + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + ident: ident, + vis: vis, + attrs: attrs, + typ: typ, + } + } + + /// Parse the items in a trait declaration + pub fn parse_trait_items(&mut self) -> Vec { self.parse_unspanned_seq( &token::LBRACE, &token::RBRACE, seq_sep_none(), |p| { let attrs = p.parse_outer_attributes(); - let lo = p.span.lo; - - // NB: at the moment, trait methods are public by default; this - // could change. - let vis = p.parse_visibility(); - let abi = if p.eat_keyword(keywords::Extern) { - p.parse_opt_abi().unwrap_or(abi::C) - } else if attr::contains_name(attrs.as_slice(), - "rust_call_abi_hack") { - // FIXME(stage0, pcwalton): Remove this awful hack after a - // snapshot, and change to `extern "rust-call" fn`. - abi::RustCall + + if p.eat_keyword(keywords::Type) { + TypeTraitItem(P(p.parse_associated_type(attrs))) } else { - abi::Rust - }; - let style = p.parse_fn_style(); - let ident = p.parse_ident(); + let lo = p.span.lo; - let mut generics = p.parse_generics(); + let vis = p.parse_visibility(); + let abi = if p.eat_keyword(keywords::Extern) { + p.parse_opt_abi().unwrap_or(abi::C) + } else if attr::contains_name(attrs.as_slice(), + "rust_call_abi_hack") { + // FIXME(stage0, pcwalton): Remove this awful hack after a + // snapshot, and change to `extern "rust-call" fn`. + abi::RustCall + } else { + abi::Rust + }; - let (explicit_self, d) = p.parse_fn_decl_with_self(|p| { - // This is somewhat dubious; We don't want to allow argument - // names to be left off if there is a definition... - p.parse_arg_general(false) - }); + let style = p.parse_fn_style(); + let ident = p.parse_ident(); + let mut generics = p.parse_generics(); - p.parse_where_clause(&mut generics); + let (explicit_self, d) = p.parse_fn_decl_with_self(|p| { + // This is somewhat dubious; We don't want to allow + // argument names to be left off if there is a + // definition... + p.parse_arg_general(false) + }); - let hi = p.last_span.hi; - match p.token { - token::SEMI => { - p.bump(); - debug!("parse_trait_methods(): parsing required method"); - RequiredMethod(TypeMethod { - ident: ident, - attrs: attrs, - fn_style: style, - decl: d, - generics: generics, - abi: abi, - explicit_self: explicit_self, - id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), - vis: vis, - }) - } - token::LBRACE => { - debug!("parse_trait_methods(): parsing provided method"); - let (inner_attrs, body) = - p.parse_inner_attrs_and_block(); - let mut attrs = attrs; - attrs.extend(inner_attrs.into_iter()); - ProvidedMethod(P(ast::Method { - attrs: attrs, - id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), - node: ast::MethDecl(ident, - generics, - abi, - explicit_self, - style, - d, - body, - vis) - })) - } + p.parse_where_clause(&mut generics); + + let hi = p.last_span.hi; + match p.token { + token::SEMI => { + p.bump(); + debug!("parse_trait_methods(): parsing required method"); + RequiredMethod(TypeMethod { + ident: ident, + attrs: attrs, + fn_style: style, + decl: d, + generics: generics, + abi: abi, + explicit_self: explicit_self, + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + vis: vis, + }) + } + token::LBRACE => { + debug!("parse_trait_methods(): parsing provided method"); + let (inner_attrs, body) = + p.parse_inner_attrs_and_block(); + let attrs = attrs.append(inner_attrs.as_slice()); + ProvidedMethod(P(ast::Method { + attrs: attrs, + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + node: ast::MethDecl(ident, + generics, + abi, + explicit_self, + style, + d, + body, + vis) + })) + } - _ => { - let token_str = p.this_token_to_string(); - p.fatal((format!("expected `;` or `{{`, found `{}`", - token_str)).as_slice()) - } + _ => { + let token_str = p.this_token_to_string(); + p.fatal((format!("expected `;` or `{{`, found `{}`", + token_str)).as_slice()) + } + } } }) } @@ -1455,12 +1494,11 @@ impl<'a> Parser<'a> { } else if self.token_is_closure_keyword() || self.token == token::BINOP(token::OR) || self.token == token::OROR || - self.token == token::LT { + (self.token == token::LT && + self.look_ahead(1, |t| { + *t == token::GT || Parser::token_is_lifetime(t) + })) { // CLOSURE - // - // FIXME(pcwalton): Eventually `token::LT` will not unambiguously - // introduce a closure, once procs can have lifetime bounds. We - // will need to refactor the grammar a little bit at that point. self.parse_ty_closure() } else if self.eat_keyword(keywords::Typeof) { @@ -1472,6 +1510,20 @@ impl<'a> Parser<'a> { TyTypeof(e) } else if self.eat_keyword(keywords::Proc) { self.parse_proc_type() + } else if self.token == token::LT { + // QUALIFIED PATH + self.bump(); + let for_type = self.parse_ty(true); + self.expect_keyword(keywords::As); + let trait_name = self.parse_path(LifetimeAndTypesWithoutColons); + self.expect(&token::GT); + self.expect(&token::MOD_SEP); + let item_name = self.parse_ident(); + TyQPath(P(QPath { + for_type: for_type, + trait_name: trait_name.path, + item_name: item_name, + })) } else if self.token == token::MOD_SEP || is_ident_or_path(&self.token) { // NAMED TYPE @@ -2071,7 +2123,7 @@ impl<'a> Parser<'a> { } } hi = self.last_span.hi; - }, + } _ => { if self.eat_keyword(keywords::Ref) { return self.parse_lambda_expr(CaptureByRef); @@ -4215,14 +4267,9 @@ impl<'a> Parser<'a> { /// Parse a method in a trait impl, starting with `attrs` attributes. pub fn parse_method(&mut self, - already_parsed_attrs: Option>) + attrs: Vec, + visa: Visibility) -> P { - let next_attrs = self.parse_outer_attributes(); - let attrs = match already_parsed_attrs { - Some(mut a) => { a.push_all_move(next_attrs); a } - None => next_attrs - }; - let lo = self.span.lo; // code copied from parse_macro_use_or_failure... abstraction! @@ -4251,7 +4298,6 @@ impl<'a> Parser<'a> { self.span.hi) }; (ast::MethMac(m), self.span.hi, attrs) } else { - let visa = self.parse_visibility(); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi().unwrap_or(abi::C) } else if attr::contains_name(attrs.as_slice(), @@ -4302,18 +4348,28 @@ impl<'a> Parser<'a> { self.parse_where_clause(&mut tps); - let meths = self.parse_trait_methods(); + let meths = self.parse_trait_items(); (ident, ItemTrait(tps, sized, bounds, meths), None) } fn parse_impl_items(&mut self) -> (Vec, Vec) { let mut impl_items = Vec::new(); self.expect(&token::LBRACE); - let (inner_attrs, next) = self.parse_inner_attrs_and_next(); - let mut method_attrs = Some(next); + let (inner_attrs, mut method_attrs) = + self.parse_inner_attrs_and_next(); while !self.eat(&token::RBRACE) { - impl_items.push(MethodImplItem(self.parse_method(method_attrs))); - method_attrs = None; + method_attrs.push_all_move(self.parse_outer_attributes()); + let vis = self.parse_visibility(); + if self.eat_keyword(keywords::Type) { + impl_items.push(TypeImplItem(P(self.parse_typedef( + method_attrs, + vis)))) + } else { + impl_items.push(MethodImplItem(self.parse_method( + method_attrs, + vis))); + } + method_attrs = self.parse_outer_attributes(); } (impl_items, inner_attrs) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d0df95d711ee4..0ae5303641bc6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -9,10 +9,11 @@ // except according to those terms. use abi; -use ast::{FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind}; -use ast::{FnUnboxedClosureKind, MethodImplItem}; -use ast::{RegionTyParamBound, TraitTyParamBound, UnboxedClosureKind}; -use ast::{UnboxedFnTyParamBound, RequiredMethod, ProvidedMethod}; +use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; +use ast::{FnOnceUnboxedClosureKind}; +use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound}; +use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem}; +use ast::{UnboxedClosureKind, UnboxedFnTyParamBound}; use ast; use ast_util; use owned_slice::OwnedSlice; @@ -660,6 +661,16 @@ impl<'a> State<'a> { ast::TyPath(ref path, ref bounds, _) => { try!(self.print_bounded_path(path, bounds)); } + ast::TyQPath(ref qpath) => { + try!(word(&mut self.s, "<")); + try!(self.print_type(&*qpath.for_type)); + try!(space(&mut self.s)); + try!(self.word_space("as")); + try!(self.print_path(&qpath.trait_name, false)); + try!(word(&mut self.s, ">")); + try!(word(&mut self.s, "::")); + try!(self.print_ident(qpath.item_name)); + } ast::TyFixedLengthVec(ref ty, ref v) => { try!(word(&mut self.s, "[")); try!(self.print_type(&**ty)); @@ -708,6 +719,22 @@ impl<'a> State<'a> { } } + fn print_associated_type(&mut self, typedef: &ast::AssociatedType) + -> IoResult<()> { + try!(self.word_space("type")); + try!(self.print_ident(typedef.ident)); + word(&mut self.s, ";") + } + + fn print_typedef(&mut self, typedef: &ast::Typedef) -> IoResult<()> { + try!(self.word_space("type")); + try!(self.print_ident(typedef.ident)); + try!(space(&mut self.s)); + try!(self.word_space("=")); + try!(self.print_type(&*typedef.typ)); + word(&mut self.s, ";") + } + /// Pretty-print an item pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> { try!(self.hardbreak_if_not_bol()); @@ -825,6 +852,9 @@ impl<'a> State<'a> { ast::MethodImplItem(ref meth) => { try!(self.print_method(&**meth)); } + ast::TypeImplItem(ref typ) => { + try!(self.print_typedef(&**typ)); + } } } try!(self.bclose(item.span)); @@ -1071,13 +1101,15 @@ impl<'a> State<'a> { m: &ast::TraitItem) -> IoResult<()> { match *m { RequiredMethod(ref ty_m) => self.print_ty_method(ty_m), - ProvidedMethod(ref m) => self.print_method(&**m) + ProvidedMethod(ref m) => self.print_method(&**m), + TypeTraitItem(ref t) => self.print_associated_type(&**t), } } pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> IoResult<()> { match *ii { MethodImplItem(ref m) => self.print_method(&**m), + TypeImplItem(ref td) => self.print_typedef(&**td), } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 30a38e28729f0..d425c60f4c91f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -116,12 +116,19 @@ pub trait Visitor<'v> { fn visit_attribute(&mut self, _attr: &'v Attribute) {} } -pub fn walk_inlined_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v InlinedItem) { +pub fn walk_inlined_item<'v,V>(visitor: &mut V, item: &'v InlinedItem) + where V: Visitor<'v> { match *item { IIItem(ref i) => visitor.visit_item(&**i), IIForeign(ref i) => visitor.visit_foreign_item(&**i), IITraitItem(_, ref ti) => visitor.visit_trait_item(ti), - IIImplItem(_, MethodImplItem(ref m)) => walk_method_helper(visitor, &**m) + IIImplItem(_, MethodImplItem(ref m)) => { + walk_method_helper(visitor, &**m) + } + IIImplItem(_, TypeImplItem(ref typedef)) => { + visitor.visit_ident(typedef.span, typedef.ident); + visitor.visit_ty(&*typedef.typ); + } } } @@ -248,6 +255,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { MethodImplItem(ref method) => { walk_method_helper(visitor, &**method) } + TypeImplItem(ref typedef) => { + visitor.visit_ident(typedef.span, typedef.ident); + visitor.visit_ty(&*typedef.typ); + } } } } @@ -366,6 +377,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { None => { } } } + TyQPath(ref qpath) => { + visitor.visit_ty(&*qpath.for_type); + visitor.visit_path(&qpath.trait_name, typ.id); + visitor.visit_ident(typ.span, qpath.item_name); + } TyFixedLengthVec(ref ty, ref expression) => { visitor.visit_ty(&**ty); visitor.visit_expr(&**expression) @@ -573,10 +589,11 @@ pub fn walk_ty_method<'v, V: Visitor<'v>>(visitor: &mut V, method_type: &'v Type pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_method: &'v TraitItem) { match *trait_method { - RequiredMethod(ref method_type) => { - visitor.visit_ty_method(method_type) - } + RequiredMethod(ref method_type) => visitor.visit_ty_method(method_type), ProvidedMethod(ref method) => walk_method_helper(visitor, &**method), + TypeTraitItem(ref associated_type) => { + visitor.visit_ident(associated_type.span, associated_type.ident) + } } } diff --git a/src/test/compile-fail/associated-types-feature-gate.rs b/src/test/compile-fail/associated-types-feature-gate.rs new file mode 100644 index 0000000000000..d95b94f006760 --- /dev/null +++ b/src/test/compile-fail/associated-types-feature-gate.rs @@ -0,0 +1,33 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Get { + type Value; //~ ERROR associated types are experimental + fn get(&self) -> Get::Value; +} + +struct Struct { + x: int, +} + +impl Get for Struct { + type Value = int; //~ ERROR associated types are experimental + fn get(&self) -> int { + self.x + } +} + +fn main() { + let s = Struct { + x: 100, + }; + assert_eq!(s.get(), 100); +} + diff --git a/src/test/compile-fail/associated-types-in-ambiguous-context.rs b/src/test/compile-fail/associated-types-in-ambiguous-context.rs new file mode 100644 index 0000000000000..a2c01fe62f6bb --- /dev/null +++ b/src/test/compile-fail/associated-types-in-ambiguous-context.rs @@ -0,0 +1,39 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Value; + fn get(&self) -> ::Value; +} + +fn get(x: T, y: U) -> Get::Value {} +//~^ ERROR ambiguous associated type + +trait Other { + fn uhoh(&self, foo: U, bar: ::Value) {} + //~^ ERROR this associated type is not allowed in this context +} + +impl Other for T { + fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} + //~^ ERROR this associated type is not allowed in this context +} + +trait Grab { + type Value; + fn grab(&self) -> Grab::Value; + //~^ ERROR ambiguous associated type +} + +fn main() { +} + diff --git a/src/test/compile-fail/associated-types-in-wrong-context.rs b/src/test/compile-fail/associated-types-in-wrong-context.rs new file mode 100644 index 0000000000000..8fbfc33896b41 --- /dev/null +++ b/src/test/compile-fail/associated-types-in-wrong-context.rs @@ -0,0 +1,32 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Value; + fn get(&self) -> ::Value; +} + +fn get(x: int) -> ::Value {} +//~^ ERROR this associated type is not allowed in this context + +struct Struct { + x: int, +} + +impl Struct { + fn uhoh(foo: ::Value) {} + //~^ ERROR this associated type is not allowed in this context +} + +fn main() { +} + diff --git a/src/test/compile-fail/class-method-missing.rs b/src/test/compile-fail/class-method-missing.rs index ca97a8997689f..17cf36b73f643 100644 --- a/src/test/compile-fail/class-method-missing.rs +++ b/src/test/compile-fail/class-method-missing.rs @@ -17,7 +17,7 @@ struct cat { } impl animal for cat { - //~^ ERROR not all trait methods implemented, missing: `eat` + //~^ ERROR not all trait items implemented, missing: `eat` } fn cat(in_x : uint) -> cat { diff --git a/src/test/compile-fail/issue-3344.rs b/src/test/compile-fail/issue-3344.rs index 293f372866d10..b88272ed4666e 100644 --- a/src/test/compile-fail/issue-3344.rs +++ b/src/test/compile-fail/issue-3344.rs @@ -10,7 +10,7 @@ #[deriving(PartialEq)] struct thing(uint); -impl PartialOrd for thing { //~ ERROR not all trait methods implemented, missing: `partial_cmp` +impl PartialOrd for thing { //~ ERROR not all trait items implemented, missing: `partial_cmp` fn le(&self, other: &thing) -> bool { true } fn ge(&self, other: &thing) -> bool { true } } diff --git a/src/test/compile-fail/missing-derivable-attr.rs b/src/test/compile-fail/missing-derivable-attr.rs index 4e45f33fe9b14..db960ac340913 100644 --- a/src/test/compile-fail/missing-derivable-attr.rs +++ b/src/test/compile-fail/missing-derivable-attr.rs @@ -20,7 +20,7 @@ impl MyEq for int { fn eq(&self, other: &int) -> bool { *self == *other } } -impl MyEq for A {} //~ ERROR not all trait methods implemented, missing: `eq` +impl MyEq for A {} //~ ERROR not all trait items implemented, missing: `eq` fn main() { } diff --git a/src/test/run-pass/associated-types-in-default-method.rs b/src/test/run-pass/associated-types-in-default-method.rs new file mode 100644 index 0000000000000..e01b18a64db22 --- /dev/null +++ b/src/test/run-pass/associated-types-in-default-method.rs @@ -0,0 +1,39 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Value; + fn get(&self) -> &::Value; + fn grab(&self) -> &::Value { + self.get() + } +} + +struct Struct { + x: int, +} + +impl Get for Struct { + type Value = int; + fn get(&self) -> &int { + &self.x + } +} + +fn main() { + let s = Struct { + x: 100, + }; + assert_eq!(*s.grab(), 100); +} + + diff --git a/src/test/run-pass/associated-types-in-fn.rs b/src/test/run-pass/associated-types-in-fn.rs new file mode 100644 index 0000000000000..4ed213e85d878 --- /dev/null +++ b/src/test/run-pass/associated-types-in-fn.rs @@ -0,0 +1,39 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Value; + fn get(&self) -> &::Value; +} + +struct Struct { + x: int, +} + +impl Get for Struct { + type Value = int; + fn get(&self) -> &int { + &self.x + } +} + +fn grab(x: &T) -> &::Value { + x.get() +} + +fn main() { + let s = Struct { + x: 100, + }; + assert_eq!(*grab(&s), 100); +} + diff --git a/src/test/run-pass/associated-types-in-impl-generics.rs b/src/test/run-pass/associated-types-in-impl-generics.rs new file mode 100644 index 0000000000000..f6aaaf3b3fa15 --- /dev/null +++ b/src/test/run-pass/associated-types-in-impl-generics.rs @@ -0,0 +1,47 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Value; + fn get(&self) -> &::Value; +} + +struct Struct { + x: int, +} + +impl Get for Struct { + type Value = int; + fn get(&self) -> &int { + &self.x + } +} + +trait Grab { + type U; + fn grab(&self) -> &::U; +} + +impl Grab for T { + type U = ::Value; + fn grab(&self) -> &::Value { + self.get() + } +} + +fn main() { + let s = Struct { + x: 100, + }; + assert_eq!(*s.grab(), 100); +} + diff --git a/src/test/run-pass/associated-types-in-inherent-method.rs b/src/test/run-pass/associated-types-in-inherent-method.rs new file mode 100644 index 0000000000000..341682692460f --- /dev/null +++ b/src/test/run-pass/associated-types-in-inherent-method.rs @@ -0,0 +1,41 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Value; + fn get(&self) -> &::Value; +} + +struct Struct { + x: int, +} + +impl Get for Struct { + type Value = int; + fn get(&self) -> &int { + &self.x + } +} + +impl Struct { + fn grab(x: &T) -> &::Value { + x.get() + } +} + +fn main() { + let s = Struct { + x: 100, + }; + assert_eq!(*Struct::grab(&s), 100); +} + diff --git a/src/test/run-pass/associated-types-simple.rs b/src/test/run-pass/associated-types-simple.rs new file mode 100644 index 0000000000000..82ae0d89b4605 --- /dev/null +++ b/src/test/run-pass/associated-types-simple.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Value; + fn get(&self) -> &::Value; +} + +struct Struct { + x: int, +} + +impl Get for Struct { + type Value = int; + fn get(&self) -> &int { + &self.x + } +} + +fn main() { + let s = Struct { + x: 100, + }; + assert_eq!(*s.get(), 100); +} + diff --git a/src/test/run-pass/macro-method-issue-4621.rs b/src/test/run-pass/macro-method-issue-4621.rs index 99d47e4bfc097..b5400edb41fc4 100644 --- a/src/test/run-pass/macro-method-issue-4621.rs +++ b/src/test/run-pass/macro-method-issue-4621.rs @@ -12,7 +12,7 @@ struct A; -macro_rules! make_thirteen_method {() => (pub fn thirteen(&self)->int {13})} +macro_rules! make_thirteen_method {() => (fn thirteen(&self)->int {13})} impl A { make_thirteen_method!() } fn main() {