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. `<T as Foo>::Bar`--are supported.
This commit is contained in:
Patrick Walton 2014-08-05 19:44:21 -07:00
parent 8067f4425d
commit 78a841810e
67 changed files with 3031 additions and 550 deletions

View File

@ -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

@ -1 +1 @@
Subproject commit 2dba541881fb8e35246d653bbe2e7c7088777a4a
Subproject commit aae04170ccbfeea620502106b581c3c216cd132a

View File

@ -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()
}
}
}

View File

@ -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<ty::t>,
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> {

View File

@ -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)
}

View File

@ -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<IdentInterner>,
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<IdentInterner>,
};
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<IdentInterner>,
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<IdentInterner>,
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',
}
}

View File

@ -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<P<ast::Typedef>>) {
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');
}
}

View File

@ -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
}

View File

@ -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));
}

View File

@ -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),

View File

@ -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(_) => {}
}
}
}

View File

@ -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 {
}
}
}

View File

@ -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(_) => {

View File

@ -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,

View File

@ -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 {

View File

@ -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

View File

@ -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)
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)
}
};
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)
}
ast::ProvidedMethod(ref m) => {
(m.id, m.pe_ident(), m.pe_fn_style(), m.pe_explicit_self(), m.span)
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)
}
};
// 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)
}
_ => {
// Non-static methods become `def_method`s.
(DefMethod(local_def(m_id),
Some(local_def(item.id))),
NonstaticMethodTraitItemKind)
}
};
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;

View File

@ -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(_) => {}
}
}

View File

@ -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));
}

View File

@ -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());
}
}

View File

@ -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()")
}
}
}

View File

@ -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?!")
}
}
}
};

View File

@ -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) => {

View File

@ -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")
}
}
}
};

View File

@ -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()
}

View File

@ -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) => {

View File

@ -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));

View File

@ -97,30 +97,37 @@ impl ImplOrTraitItemContainer {
#[deriving(Clone)]
pub enum ImplOrTraitItem {
MethodTraitItem(Rc<Method>),
TypeTraitItem(Rc<AssociatedType>),
}
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<CaptureModeMap>,
/// Maps def IDs to true if and only if they're associated types.
pub associated_types: RefCell<DefIdMap<bool>>,
/// Maps def IDs of traits to information about their associated types.
pub trait_associated_types:
RefCell<DefIdMap<Rc<Vec<AssociatedTypeInfo>>>>,
}
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<ast::DefId>,
pub bounds: ParamBounds,
pub default: Option<ty::t>,
}
@ -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<Rc<Method>> {
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<Ordering> {
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<Vec<AssociatedTypeInfo>> {
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<Vec<ImplOrTraitItemId>> {
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);
}

View File

@ -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),
}

View File

@ -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<ty::TraitDef>;
// 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<ty::t>,
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<ty::t>,
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<ty::t>,
associated_ty: Option<ty::t>,
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<ty::t>,
path: &ast::Path) -> Rc<ty::TraitRef> {
pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
rscope: &RS,
trait_def_id: ast::DefId,
self_ty: Option<ty::t>,
associated_type: Option<ty::t>,
path: &ast::Path)
-> Rc<ty::TraitRef>
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 `<Type \
as {}>::{}`",
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) => {

View File

@ -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

View File

@ -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<ty::t>,
_: 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(..) => {

View File

@ -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(_) => {}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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(_) => {}
}
}
}

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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<Type> 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<TraitItem> 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<TraitItem> for ast::TraitItem {
#[deriving(Clone, Encodable, Decodable)]
pub enum ImplItem {
MethodImplItem(Item),
TypeImplItem(Item),
}
impl Clean<ImplItem> 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<Item> 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<Item> 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<Stability> for attr::Stability {
}
}
impl Clean<Item> 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<Item> 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<Item> 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<ast::DefId>,
t: ty::t, name: &str,
fallback: fn(Box<Type>) -> Type) -> Type {

View File

@ -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);

View File

@ -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,
}
}

View File

@ -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,
"<h2 id='{id}' class='section-header'>\

View File

@ -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 {

View File

@ -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<ModuleSummary>) {
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()

View File

@ -555,6 +555,18 @@ pub enum Expr_ {
ExprParen(P<Expr>)
}
/// A "qualified path":
///
/// <Vec<T> as SomeTrait>::SomeAssociatedItem
/// ^~~~~ ^~~~~~~~~ ^~~~~~~~~~~~~~~~~~
/// for_type trait_name item_name
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct QPath {
pub for_type: P<Ty>,
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<Method>),
TypeTraitItem(P<AssociatedType>),
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum ImplItem {
MethodImplItem(P<Method>),
TypeImplItem(P<Typedef>),
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct AssociatedType {
pub id: NodeId,
pub span: Span,
pub ident: Ident,
pub attrs: Vec<Attribute>,
}
#[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<Attribute>,
pub typ: P<Ty>,
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
@ -917,6 +949,8 @@ pub enum Ty_ {
TyUnboxedFn(P<UnboxedFnTy>),
TyTup(Vec<P<Ty>> ),
TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above
/// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
TyQPath(P<QPath>),
/// No-op; kept solely so that we can pretty-print faithfully
TyParen(P<Ty>),
TyTypeof(P<Expr>),

View File

@ -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 {

View File

@ -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={})",

View File

@ -213,6 +213,62 @@ pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, 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<TypeMethod>, Vec<P<Method>> ) {
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);
}

View File

@ -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()),
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
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<T: Folder>(
}
}
pub fn noop_fold_typedef<T>(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<T>(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<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> {
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<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
ItemStruct(struct_def, folder.fold_generics(generics))
}
ItemImpl(generics, ifce, ty, impl_items) => {
ItemImpl(folder.fold_generics(generics),
ifce.map(|p| folder.fold_trait_ref(p)),
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))
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))
}
}).collect())
}
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,
folder.fold_ty(ty),
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<ast::TraitItem> =
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<ast::TraitItem> =
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<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
}
pub fn noop_fold_type_method<T: Folder>(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),

View File

@ -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<TraitItem> {
/// Parses `type Foo;` in a trait declaration only. The `type` keyword has
/// already been parsed.
fn parse_associated_type(&mut self, attrs: Vec<Attribute>)
-> 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<Attribute>, 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<TraitItem> {
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 token_str = p.this_token_to_string();
p.fatal((format!("expected `;` or `{{`, found `{}`",
token_str)).as_slice())
}
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())
}
}
}
})
}
@ -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<Vec<Attribute>>)
attrs: Vec<Attribute>,
visa: Visibility)
-> P<Method> {
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<ImplItem>, Vec<Attribute>) {
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)
}

View File

@ -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),
}
}

View File

@ -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)
}
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(associated_types)]
trait Get {
type Value;
fn get(&self) -> <Self as Get>::Value;
}
fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {}
//~^ ERROR ambiguous associated type
trait Other {
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
//~^ ERROR this associated type is not allowed in this context
}
impl<T:Get> Other for T {
fn uhoh<U:Get>(&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() {
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(associated_types)]
trait Get {
type Value;
fn get(&self) -> <Self as Get>::Value;
}
fn get(x: int) -> <int as Get>::Value {}
//~^ ERROR this associated type is not allowed in this context
struct Struct {
x: int,
}
impl Struct {
fn uhoh<T>(foo: <T as Get>::Value) {}
//~^ ERROR this associated type is not allowed in this context
}
fn main() {
}

View File

@ -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 {

View File

@ -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 }
}

View File

@ -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() {
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(associated_types)]
trait Get {
type Value;
fn get(&self) -> &<Self as Get>::Value;
fn grab(&self) -> &<Self as Get>::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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(associated_types)]
trait Get {
type Value;
fn get(&self) -> &<Self as Get>::Value;
}
struct Struct {
x: int,
}
impl Get for Struct {
type Value = int;
fn get(&self) -> &int {
&self.x
}
}
fn grab<T:Get>(x: &T) -> &<T as Get>::Value {
x.get()
}
fn main() {
let s = Struct {
x: 100,
};
assert_eq!(*grab(&s), 100);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(associated_types)]
trait Get {
type Value;
fn get(&self) -> &<Self as Get>::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) -> &<Self as Grab>::U;
}
impl<T:Get> Grab for T {
type U = <T as Get>::Value;
fn grab(&self) -> &<T as Get>::Value {
self.get()
}
}
fn main() {
let s = Struct {
x: 100,
};
assert_eq!(*s.grab(), 100);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(associated_types)]
trait Get {
type Value;
fn get(&self) -> &<Self as Get>::Value;
}
struct Struct {
x: int,
}
impl Get for Struct {
type Value = int;
fn get(&self) -> &int {
&self.x
}
}
impl Struct {
fn grab<T:Get>(x: &T) -> &<T as Get>::Value {
x.get()
}
}
fn main() {
let s = Struct {
x: 100,
};
assert_eq!(*Struct::grab(&s), 100);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(associated_types)]
trait Get {
type Value;
fn get(&self) -> &<Self as Get>::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);
}

View File

@ -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() {