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
+2
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
+14 -7
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 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
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()
}
}
}
+21
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 @@ fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
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> {
+6
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)
}
+25 -2
View File
@@ -23,7 +23,7 @@
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',
}
}
+137 -33
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 add_to_index(item: &Item, rbml_w: &Encoder,
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 add_to_index(item: &Item, rbml_w: &Encoder,
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 add_to_index(item: &Item, rbml_w: &Encoder,
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 add_to_index(item: &Item, rbml_w: &Encoder,
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 add_to_index(item: &Item, rbml_w: &Encoder,
}
}
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');
}
}
+5
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
}
+2
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));
}
+18 -3
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 @@ fn tr(&self, dcx: &DecodeContext) -> 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),
+7 -1
View File
@@ -118,6 +118,9 @@ fn lookup_and_handle_method(&mut self, id: ast::NodeId,
ty::MethodTraitItem(method) => {
self.check_def_id(method.def_id);
}
ty::TypeTraitItem(typedef) => {
self.check_def_id(typedef.def_id);
}
}
}
}
@@ -226,6 +229,7 @@ fn visit_node(&mut self, node: &ast_map::Node) {
ast::MethodImplItem(ref method) => {
visit::walk_block(self, method.pe_body());
}
ast::TypeImplItem(_) => {}
}
}
ast_map::NodeForeignItem(foreign_item) => {
@@ -341,6 +345,7 @@ fn visit_item(&mut self, item: &ast::Item) {
ast::MethodImplItem(ref method) => {
self.worklist.push(method.id);
}
ast::TypeImplItem(_) => {}
}
}
}
@@ -544,7 +549,8 @@ fn visit_trait_item(&mut self, trait_method: &ast::TraitItem) {
ast::ProvidedMethod(ref method) => {
visit::walk_block(self, &*method.pe_body())
}
ast::RequiredMethod(_) => ()
ast::RequiredMethod(_) => {}
ast::TypeTraitItem(_) => {}
}
}
}
+5 -2
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 @@ pub fn def_id(&self) -> ast::DefId {
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 @@ pub fn variant_def_ids(&self) -> Option<(ast::DefId, ast::DefId)> {
}
}
}
+3
View File
@@ -134,6 +134,9 @@ fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
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(_) => {
+5 -2
View File
@@ -319,7 +319,9 @@ fn from_def(def: &def::Def) -> 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 @@ pub fn cat_def(&self,
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,
+46 -2
View File
@@ -82,8 +82,13 @@ fn visit_item(&mut self, item: &ast::Item) {
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 @@ fn visit_item(&mut self, item: &ast::Item) {
self.exported_items.insert(method.id);
}
}
ast::TypeImplItem(_) => {}
}
}
}
@@ -290,6 +296,10 @@ fn visit_item(&mut self, item: &ast::Item) {
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 @@ fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
}
}
}
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 @@ fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
_ => m.pe_vis()
}
}
ast::TypeImplItem(_) => return Allowable,
}
}
Some(ast_map::NodeTraitItem(_)) => {
@@ -670,6 +706,7 @@ fn check_static_method(&mut self,
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 @@ fn check_sane_privacy(&self, item: &ast::Item) {
ast::MethodImplItem(ref m) => {
check_inherited(m.span, m.pe_vis(), "");
}
ast::TypeImplItem(_) => {}
}
}
}
@@ -1149,6 +1187,7 @@ fn check_sane_privacy(&self, item: &ast::Item) {
check_inherited(m.span, m.vis,
"unnecessary visibility");
}
ast::TypeTraitItem(_) => {}
}
}
}
@@ -1184,6 +1223,7 @@ fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) {
ast::MethodImplItem(ref m) => {
check_inherited(tcx, m.span, m.pe_vis());
}
ast::TypeImplItem(_) => {}
}
}
}
@@ -1211,6 +1251,7 @@ fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) {
ast::RequiredMethod(..) => {}
ast::ProvidedMethod(ref m) => check_inherited(tcx, m.span,
m.pe_vis()),
ast::TypeTraitItem(_) => {}
}
}
}
@@ -1351,6 +1392,7 @@ fn visit_item(&mut self, item: &ast::Item) {
ast::MethodImplItem(ref m) => {
self.exported_items.contains(&m.id)
}
ast::TypeImplItem(_) => false,
}
});
@@ -1367,6 +1409,7 @@ fn visit_item(&mut self, item: &ast::Item) {
ast::MethodImplItem(ref method) => {
visit::walk_method_helper(self, &**method)
}
ast::TypeImplItem(_) => {}
}
}
}
@@ -1401,6 +1444,7 @@ fn visit_item(&mut self, item: &ast::Item) {
visit::walk_method_helper(self, &**method);
}
}
ast::TypeImplItem(_) => {}
}
}
if found_pub_static {
+5 -1
View File
@@ -197,6 +197,7 @@ fn def_id_represents_local_inlined_item(&self, def_id: ast::DefId) -> bool {
match *trait_method {
ast::RequiredMethod(_) => false,
ast::ProvidedMethod(_) => true,
ast::TypeTraitItem(_) => false,
}
}
Some(ast_map::NodeImplItem(impl_item)) => {
@@ -225,6 +226,7 @@ fn def_id_represents_local_inlined_item(&self, def_id: ast::DefId) -> bool {
}
}
}
ast::TypeImplItem(_) => false,
}
}
Some(_) => false,
@@ -327,8 +329,9 @@ fn propagate_node(&mut self, node: &ast_map::Node,
// 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 @@ fn propagate_node(&mut self, node: &ast_map::Node,
visit::walk_block(self, method.pe_body())
}
}
ast::TypeImplItem(_) => {}
}
}
// Nothing to recurse on for these
+160 -39
View File
@@ -37,13 +37,15 @@
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 @@ fn build_reduced_graph_for_item(&mut self,
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 @@ fn build_reduced_graph_for_item(&mut self,
// 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 @@ fn handle_external_def(&mut self,
is_public,
DUMMY_SP)
}
DefTy(..) => {
DefTy(..) | DefAssociatedTy(..) => {
debug!("(building reduced graph for external \
crate) building type {}", final_ident);
@@ -4065,6 +4110,9 @@ fn resolve_item(&mut self, item: &Item) {
ProvidedMethod(m.id)),
&**m)
}
ast::TypeTraitItem(_) => {
visit::walk_trait_item(this, method);
}
}
}
});
@@ -4509,6 +4557,14 @@ fn resolve_implementation(&mut self,
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 @@ fn resolve_type(&mut self, ty: &Ty) {
});
}
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 @@ fn resolve_module_relative_path(&mut self,
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;
+22 -33
View File
@@ -227,6 +227,7 @@ fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
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 @@ fn process_method(&mut self, method: &ast::Method) {
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 @@ fn process_impl(&mut self,
ast::MethodImplItem(ref method) => {
visit::walk_method_helper(self, &**method)
}
ast::TypeImplItem(ref typedef) => {
visit::walk_ty(self, &*typedef.typ)
}
}
}
}
@@ -764,12 +769,7 @@ fn process_path(&mut self,
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 @@ fn process_path(&mut self,
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 @@ fn process_method_call(&mut self,
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 @@ fn process_method_call(&mut self,
ty::MethodTraitItem(method) => {
method.provided_source.unwrap_or(def_id)
}
ty::TypeTraitItem(_) => def_id,
};
(Some(def_id), decl_id)
}
@@ -913,23 +909,15 @@ fn process_method_call(&mut self,
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 @@ fn visit_trait_item(&mut self, tm: &ast::TraitItem) {
qualname,
method_type.id);
}
ast::ProvidedMethod(ref method) => self.process_method(&**method)
ast::ProvidedMethod(ref method) => self.process_method(&**method),
ast::TypeTraitItem(_) => {}
}
}
+9 -4
View File
@@ -16,8 +16,9 @@
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 @@ fn visit_trait_item(&mut self, t: &TraitItem) {
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));
}
+12 -3
View File
@@ -630,7 +630,12 @@ fn fold_ty(&mut self, t: ty::t) -> ty::t {
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 @@ fn fold_ty(&mut self, t: ty::t) -> ty::t {
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 @@ fn check(this: &SubstFolder,
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());
}
}
+16 -3
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()")
}
}
}
+5 -1
View File
@@ -203,7 +203,7 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: def::Def, ref_expr: &ast::
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?!")
}
}
}
};
+5
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) => {
+6
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")
}
}
}
};
+21 -12
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()
}
@@ -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) => {
+1
View File
@@ -92,6 +92,7 @@ pub fn visit(&mut self, ty_name: &str, args: &[ValueRef]) {
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));
+148 -10
View File
@@ -97,30 +97,37 @@ pub fn id(&self) -> ast::DefId {
#[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 @@ pub fn container(&self) -> ImplOrTraitItemContainer {
#[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 @@ pub fn container_id(&self) -> ast::DefId {
}
}
#[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 @@ pub fn for_item(cx: &ctxt, id: NodeId) -> 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 @@ pub fn for_item(cx: &ctxt, id: NodeId) -> 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 @@ pub fn for_def(def: &TypeParameterDef) -> 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 @@ fn push_types_from_defs(tcx: &ty::ctxt,
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);
}
+1
View File
@@ -301,6 +301,7 @@ fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeParame
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),
}
+183 -33
View File
@@ -70,14 +70,30 @@
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) => {
+16 -2
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 @@ fn push_unboxed_closure_call_candidate_if_applicable(
.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 @@ fn push_inherent_candidates_from_bounds_inner(
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 @@ fn push_candidates_from_impl(&mut self,
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 @@ fn report_candidate(&self, idx: uint, origin: &MethodOrigin) {
// 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
+110 -4
View File
@@ -126,7 +126,7 @@
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 @@ fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
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(..) => {
+5 -1
View File
@@ -22,7 +22,7 @@
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 @@ fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
MethodTraitItemId(
local_def(ast_method.id))
}
ast::TypeImplItem(ref typedef) => {
TypeTraitItemId(local_def(typedef.id))
}
}
}).collect();
@@ -393,6 +396,7 @@ fn add_external_impl(&self,
.insert(item_def_id.def_id(), source);
}
}
ty::TypeTraitItem(_) => {}
}
}
+1082 -186
View File
@@ -138,7 +138,13 @@ pub trait ToTy {
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t;
}
impl<'a, 'tcx> ToTy for CrateCtxt<'a, 'tcx> {
impl<'a,'tcx> ToTy for ImplCtxt<'a,'tcx> {
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t {
ast_ty_to_ty(self, rs, ast_ty)
}
}
impl<'a,'tcx> ToTy for CrateCtxt<'a,'tcx> {
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t {
ast_ty_to_ty(self, rs, ast_ty)
}
@@ -158,6 +164,9 @@ fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype {
let abi = self.tcx.map.get_foreign_abi(id.node);
ty_of_foreign_item(self, &*foreign_item, abi)
}
Some(ast_map::NodeTraitItem(trait_item)) => {
ty_of_trait_item(self, &*trait_item)
}
x => {
self.tcx.sess.bug(format!("unexpected sort of node \
in get_item_ty(): {:?}",
@@ -175,6 +184,22 @@ fn ty_infer(&self, span: Span) -> ty::t {
"the type placeholder `_` is not allowed within types on item signatures.");
ty::mk_err()
}
fn associated_types_of_trait_are_valid(&self, _: ty::t, _: ast::DefId)
-> bool {
false
}
fn associated_type_binding(&self,
span: Span,
_: Option<ty::t>,
_: ast::DefId,
_: ast::DefId)
-> ty::t {
self.tcx().sess.span_err(span, "associated types may not be \
referenced here");
ty::mk_err()
}
}
pub fn get_enum_variant_types(ccx: &CrateCtxt,
@@ -201,7 +226,10 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
ast::StructVariantKind(ref struct_def) => {
let pty = Polytype {
generics: ty_generics_for_type(ccx, generics),
generics: ty_generics_for_type(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes),
ty: enum_ty
};
@@ -214,7 +242,10 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
};
let pty = Polytype {
generics: ty_generics_for_type(ccx, generics),
generics: ty_generics_for_type(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes),
ty: result_ty
};
@@ -244,6 +275,7 @@ fn collect_trait_methods(ccx: &CrateCtxt,
ccx,
trait_id,
&trait_def.generics,
trait_items.as_slice(),
&m.id,
&m.ident,
&m.explicit_self,
@@ -257,6 +289,7 @@ fn collect_trait_methods(ccx: &CrateCtxt,
ccx,
trait_id,
&trait_def.generics,
trait_items.as_slice(),
&m.id,
&m.pe_ident(),
m.pe_explicit_self(),
@@ -265,6 +298,12 @@ fn collect_trait_methods(ccx: &CrateCtxt,
&m.pe_fn_style(),
&*m.pe_fn_decl())
}
ast::TypeTraitItem(ref at) => {
tcx.sess.span_bug(at.span,
"there shouldn't \
be a type trait \
item here")
}
});
if ty_method.explicit_self ==
@@ -277,6 +316,22 @@ fn collect_trait_methods(ccx: &CrateCtxt,
.insert(ty_method.def_id,
ty::MethodTraitItem(ty_method));
}
ast::TypeTraitItem(ref ast_associated_type) => {
let trait_did = local_def(trait_id);
let associated_type = ty::AssociatedType {
ident: ast_associated_type.ident,
vis: ast::Public,
def_id: local_def(ast_associated_type.id),
container: TraitContainer(trait_did),
};
let trait_item = ty::TypeTraitItem(Rc::new(
associated_type));
tcx.impl_or_trait_items
.borrow_mut()
.insert(associated_type.def_id,
trait_item);
}
}
}
@@ -293,6 +348,9 @@ fn collect_trait_methods(ccx: &CrateCtxt,
ty::MethodTraitItemId(local_def(
method.id))
}
ast::TypeTraitItem(ref typedef) => {
ty::TypeTraitItemId(local_def(typedef.id))
}
}
}).collect());
@@ -314,9 +372,10 @@ fn make_static_method_ty(ccx: &CrateCtxt, m: &ty::Method) {
ty: ty::mk_bare_fn(ccx.tcx, m.fty.clone()) });
}
fn ty_method_of_trait_method(this: &CrateCtxt,
fn ty_method_of_trait_method(ccx: &CrateCtxt,
trait_id: ast::NodeId,
trait_generics: &ty::Generics,
trait_items: &[ast::TraitItem],
m_id: &ast::NodeId,
m_ident: &ast::Ident,
m_explicit_self: &ast::ExplicitSelf,
@@ -325,20 +384,31 @@ fn ty_method_of_trait_method(this: &CrateCtxt,
m_fn_style: &ast::FnStyle,
m_decl: &ast::FnDecl)
-> ty::Method {
let trait_self_ty = ty::mk_self_type(this.tcx, local_def(trait_id));
let ty_generics =
ty_generics_for_fn_or_method(
ccx,
m_generics,
(*trait_generics).clone(),
DontCreateTypeParametersForAssociatedTypes);
let (fty, explicit_self_category) =
astconv::ty_of_method(this,
let (fty, explicit_self_category) = {
let tmcx = TraitMethodCtxt {
ccx: ccx,
trait_id: local_def(trait_id),
trait_items: trait_items.as_slice(),
method_generics: &ty_generics,
};
let trait_self_ty = ty::mk_self_type(tmcx.tcx(),
local_def(trait_id));
astconv::ty_of_method(&tmcx,
*m_id,
*m_fn_style,
trait_self_ty,
m_explicit_self,
m_decl,
m_abi);
let ty_generics =
ty_generics_for_fn_or_method(this,
m_generics,
(*trait_generics).clone());
m_abi)
};
ty::Method::new(
*m_ident,
ty_generics,
@@ -386,12 +456,73 @@ pub fn convert_field(ccx: &CrateCtxt,
}
}
fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt,
container: ImplOrTraitItemContainer,
mut ms: I,
untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics,
rcvr_visibility: ast::Visibility) {
fn convert_associated_type(ccx: &CrateCtxt,
trait_def: &ty::TraitDef,
associated_type: &ast::AssociatedType)
-> ty::Polytype {
// Find the type parameter ID corresponding to this
// associated type.
let type_parameter_def = trait_def.generics
.types
.get_slice(subst::TypeSpace)
.iter()
.find(|def| {
def.def_id == local_def(associated_type.id)
});
let type_parameter_def = match type_parameter_def {
Some(type_parameter_def) => type_parameter_def,
None => {
ccx.tcx().sess.span_bug(associated_type.span,
"`convert_associated_type()` didn't find \
a type parameter ID corresponding to \
this type")
}
};
let param_type = ty::mk_param(ccx.tcx,
subst::TypeSpace,
type_parameter_def.index,
local_def(associated_type.id));
ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.id),
Polytype {
generics: ty::Generics::empty(),
ty: param_type,
});
write_ty_to_tcx(ccx.tcx, associated_type.id, param_type);
let associated_type = Rc::new(ty::AssociatedType {
ident: associated_type.ident,
vis: ast::Public,
def_id: local_def(associated_type.id),
container: TraitContainer(trait_def.trait_ref.def_id),
});
ccx.tcx
.impl_or_trait_items
.borrow_mut()
.insert(associated_type.def_id,
ty::TypeTraitItem(associated_type));
Polytype {
generics: ty::Generics::empty(),
ty: param_type,
}
}
enum ConvertMethodContext<'a> {
/// Used when converting implementation methods.
ImplConvertMethodContext,
/// Used when converting method signatures. The def ID is the def ID of
/// the trait we're translating.
TraitConvertMethodContext(ast::DefId, &'a [ast::TraitItem]),
}
fn convert_methods<'a,I>(ccx: &CrateCtxt,
convert_method_context: ConvertMethodContext,
container: ImplOrTraitItemContainer,
mut ms: I,
untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics,
rcvr_visibility: ast::Visibility)
where I: Iterator<&'a ast::Method> {
debug!("convert_methods(untransformed_rcvr_ty={}, \
rcvr_ty_generics={})",
untransformed_rcvr_ty.repr(ccx.tcx),
@@ -400,11 +531,12 @@ fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt,
let tcx = ccx.tcx;
let mut seen_methods = HashSet::new();
for m in ms {
if !seen_methods.insert(m.pe_ident().repr(ccx.tcx)) {
if !seen_methods.insert(m.pe_ident().repr(tcx)) {
tcx.sess.span_err(m.span, "duplicate method in trait impl");
}
let mty = Rc::new(ty_of_method(ccx,
convert_method_context,
container,
m,
untransformed_rcvr_ty,
@@ -412,9 +544,9 @@ fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt,
rcvr_visibility));
let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
debug!("method {} (id {}) has type {}",
m.pe_ident().repr(ccx.tcx),
m.pe_ident().repr(tcx),
m.id,
fty.repr(ccx.tcx));
fty.repr(tcx));
tcx.tcache.borrow_mut().insert(
local_def(m.id),
Polytype {
@@ -433,6 +565,7 @@ fn convert_methods<'a, I: Iterator<&'a ast::Method>>(ccx: &CrateCtxt,
}
fn ty_of_method(ccx: &CrateCtxt,
convert_method_context: ConvertMethodContext,
container: ImplOrTraitItemContainer,
m: &ast::Method,
untransformed_rcvr_ty: ty::t,
@@ -453,14 +586,43 @@ fn ty_of_method(ccx: &CrateCtxt,
_ => m.pe_abi(),
};
let (fty, explicit_self_category) =
astconv::ty_of_method(ccx,
m.id,
m.pe_fn_style(),
untransformed_rcvr_ty,
m.pe_explicit_self(),
&*m.pe_fn_decl(),
real_abi);
let m_ty_generics =
ty_generics_for_fn_or_method(
ccx,
m.pe_generics(),
(*rcvr_ty_generics).clone(),
CreateTypeParametersForAssociatedTypes);
let (fty, explicit_self_category) = match convert_method_context {
ImplConvertMethodContext => {
let imcx = ImplMethodCtxt {
ccx: ccx,
method_generics: &m_ty_generics,
};
astconv::ty_of_method(&imcx,
m.id,
m.pe_fn_style(),
untransformed_rcvr_ty,
m.pe_explicit_self(),
&*m.pe_fn_decl(),
real_abi)
}
TraitConvertMethodContext(trait_id, trait_items) => {
let tmcx = TraitMethodCtxt {
ccx: ccx,
trait_id: trait_id,
trait_items: trait_items,
method_generics: &m_ty_generics,
};
astconv::ty_of_method(&tmcx,
m.id,
m.pe_fn_style(),
untransformed_rcvr_ty,
m.pe_explicit_self(),
&*m.pe_fn_decl(),
real_abi)
}
};
// if the method specifies a visibility, use that, otherwise
// inherit the visibility from the impl (so `foo` in `pub impl
@@ -468,9 +630,6 @@ fn ty_of_method(ccx: &CrateCtxt,
// foo(); }`).
let method_vis = m.pe_vis().inherit_from(rcvr_visibility);
let m_ty_generics =
ty_generics_for_fn_or_method(ccx, m.pe_generics(),
(*rcvr_ty_generics).clone());
ty::Method::new(m.pe_ident(),
m_ty_generics,
fty,
@@ -507,6 +666,404 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
}
}
fn is_associated_type_valid_for_param(ty: ty::t,
trait_id: ast::DefId,
generics: &ty::Generics)
-> bool {
match ty::get(ty).sty {
ty::ty_param(param_ty) => {
let type_parameter = generics.types.get(param_ty.space,
param_ty.idx);
for trait_bound in type_parameter.bounds.trait_bounds.iter() {
if trait_bound.def_id == trait_id {
return true
}
}
}
_ => {}
}
false
}
fn find_associated_type_in_generics(tcx: &ty::ctxt,
span: Span,
ty: Option<ty::t>,
associated_type_id: ast::DefId,
generics: &ty::Generics)
-> ty::t {
let ty = match ty {
None => {
tcx.sess.span_bug(span,
"find_associated_type_in_generics(): no self \
type")
}
Some(ty) => ty,
};
match ty::get(ty).sty {
ty::ty_param(ref param_ty) => {
/*let type_parameter = generics.types.get(param_ty.space,
param_ty.idx);
let param_id = type_parameter.def_id;*/
let param_id = param_ty.def_id;
for type_parameter in generics.types.iter() {
if type_parameter.def_id == associated_type_id
&& type_parameter.associated_with == Some(param_id) {
return ty::mk_param_from_def(tcx, type_parameter)
}
}
tcx.sess.span_bug(span,
"find_associated_type_in_generics(): didn't \
find associated type anywhere in the generics \
list")
}
_ => {
tcx.sess.span_bug(span,
"find_associated_type_in_generics(): self type \
is not a parameter")
}
}
}
fn type_is_self(ty: ty::t) -> bool {
match ty::get(ty).sty {
ty::ty_param(ref param_ty) if param_ty.is_self() => true,
_ => false,
}
}
struct ImplCtxt<'a,'tcx:'a> {
ccx: &'a CrateCtxt<'a,'tcx>,
opt_trait_ref_id: Option<ast::DefId>,
impl_items: &'a [ast::ImplItem],
impl_generics: &'a ty::Generics,
}
impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
self.ccx.tcx
}
fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype {
self.ccx.get_item_ty(id)
}
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
self.ccx.get_trait_def(id)
}
fn ty_infer(&self, span: Span) -> ty::t {
self.ccx.ty_infer(span)
}
fn associated_types_of_trait_are_valid(&self,
ty: ty::t,
trait_id: ast::DefId)
-> bool {
// OK if the trait with the associated type is the trait we're
// implementing.
match self.opt_trait_ref_id {
Some(trait_ref_id) if trait_ref_id == trait_id => {
if type_is_self(ty) {
return true
}
}
Some(_) | None => {}
}
// OK if the trait with the associated type is one of the traits in
// our bounds.
is_associated_type_valid_for_param(ty, trait_id, self.impl_generics)
}
fn associated_type_binding(&self,
span: Span,
ty: Option<ty::t>,
trait_id: ast::DefId,
associated_type_id: ast::DefId)
-> ty::t {
ensure_associated_types(self, trait_id);
let associated_type_ids = ty::associated_types_for_trait(self.ccx.tcx,
trait_id);
match self.opt_trait_ref_id {
Some(trait_ref_id) if trait_ref_id == trait_id => {
// It's an associated type on the trait that we're
// implementing.
let associated_type_id =
associated_type_ids.iter()
.find(|id| {
id.def_id == associated_type_id
})
.expect("associated_type_binding(): \
expected associated type ID \
in trait");
let associated_type =
ty::impl_or_trait_item(self.ccx.tcx,
associated_type_id.def_id);
for impl_item in self.impl_items.iter() {
match *impl_item {
ast::MethodImplItem(_) => {}
ast::TypeImplItem(ref typedef) => {
if associated_type.ident().name == typedef.ident
.name {
return self.ccx.to_ty(&ExplicitRscope,
&*typedef.typ)
}
}
}
}
self.ccx
.tcx
.sess
.span_bug(span,
"ImplCtxt::associated_type_binding(): didn't \
find associated type")
}
Some(_) | None => {}
}
// OK then, it should be an associated type on one of the traits in
// our bounds.
find_associated_type_in_generics(self.ccx.tcx,
span,
ty,
associated_type_id,
self.impl_generics)
}
}
struct FnCtxt<'a,'tcx:'a> {
ccx: &'a CrateCtxt<'a,'tcx>,
generics: &'a ty::Generics,
}
impl<'a,'tcx> AstConv<'tcx> for FnCtxt<'a,'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
self.ccx.tcx
}
fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype {
self.ccx.get_item_ty(id)
}
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
self.ccx.get_trait_def(id)
}
fn ty_infer(&self, span: Span) -> ty::t {
self.ccx.ty_infer(span)
}
fn associated_types_of_trait_are_valid(&self,
ty: ty::t,
trait_id: ast::DefId)
-> bool {
// OK if the trait with the associated type is one of the traits in
// our bounds.
is_associated_type_valid_for_param(ty, trait_id, self.generics)
}
fn associated_type_binding(&self,
span: Span,
ty: Option<ty::t>,
_: ast::DefId,
associated_type_id: ast::DefId)
-> ty::t {
debug!("collect::FnCtxt::associated_type_binding()");
// The ID should map to an associated type on one of the traits in
// our bounds.
find_associated_type_in_generics(self.ccx.tcx,
span,
ty,
associated_type_id,
self.generics)
}
}
struct ImplMethodCtxt<'a,'tcx:'a> {
ccx: &'a CrateCtxt<'a,'tcx>,
method_generics: &'a ty::Generics,
}
impl<'a,'tcx> AstConv<'tcx> for ImplMethodCtxt<'a,'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
self.ccx.tcx
}
fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype {
self.ccx.get_item_ty(id)
}
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
self.ccx.get_trait_def(id)
}
fn ty_infer(&self, span: Span) -> ty::t {
self.ccx.ty_infer(span)
}
fn associated_types_of_trait_are_valid(&self,
ty: ty::t,
trait_id: ast::DefId)
-> bool {
is_associated_type_valid_for_param(ty, trait_id, self.method_generics)
}
fn associated_type_binding(&self,
span: Span,
ty: Option<ty::t>,
_: ast::DefId,
associated_type_id: ast::DefId)
-> ty::t {
debug!("collect::ImplMethodCtxt::associated_type_binding()");
// The ID should map to an associated type on one of the traits in
// our bounds.
find_associated_type_in_generics(self.ccx.tcx,
span,
ty,
associated_type_id,
self.method_generics)
}
}
struct TraitMethodCtxt<'a,'tcx:'a> {
ccx: &'a CrateCtxt<'a,'tcx>,
trait_id: ast::DefId,
trait_items: &'a [ast::TraitItem],
method_generics: &'a ty::Generics,
}
impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
self.ccx.tcx
}
fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype {
self.ccx.get_item_ty(id)
}
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
self.ccx.get_trait_def(id)
}
fn ty_infer(&self, span: Span) -> ty::t {
self.ccx.ty_infer(span)
}
fn associated_types_of_trait_are_valid(&self,
ty: ty::t,
trait_id: ast::DefId)
-> bool {
// OK if the trait with the associated type is this trait.
if self.trait_id == trait_id && type_is_self(ty) {
return true
}
// OK if the trait with the associated type is one of the traits in
// our bounds.
is_associated_type_valid_for_param(ty, trait_id, self.method_generics)
}
fn associated_type_binding(&self,
span: Span,
ty: Option<ty::t>,
trait_id: ast::DefId,
associated_type_id: ast::DefId)
-> ty::t {
debug!("collect::TraitMethodCtxt::associated_type_binding()");
// If this is one of our own associated types, return it.
if trait_id == self.trait_id {
let mut index = 0;
for item in self.trait_items.iter() {
match *item {
ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
ast::TypeTraitItem(ref item) => {
if local_def(item.id) == associated_type_id {
return ty::mk_param(self.tcx(),
subst::TypeSpace,
index,
associated_type_id)
}
index += 1;
}
}
}
self.ccx
.tcx
.sess
.span_bug(span,
"TraitMethodCtxt::associated_type_binding(): \
didn't find associated type anywhere in the item \
list")
}
// The ID should map to an associated type on one of the traits in
// our bounds.
find_associated_type_in_generics(self.ccx.tcx,
span,
ty,
associated_type_id,
self.method_generics)
}
}
struct GenericsCtxt<'a,AC:'a> {
chain: &'a AC,
associated_types_generics: &'a ty::Generics,
}
impl<'a,'tcx,AC:AstConv<'tcx>> AstConv<'tcx> for GenericsCtxt<'a,AC> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
self.chain.tcx()
}
fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype {
self.chain.get_item_ty(id)
}
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
self.chain.get_trait_def(id)
}
fn ty_infer(&self, span: Span) -> ty::t {
self.chain.ty_infer(span)
}
fn associated_types_of_trait_are_valid(&self,
ty: ty::t,
trait_id: ast::DefId)
-> bool {
// OK if the trait with the associated type is one of the traits in
// our bounds.
is_associated_type_valid_for_param(ty,
trait_id,
self.associated_types_generics)
}
fn associated_type_binding(&self,
span: Span,
ty: Option<ty::t>,
_: ast::DefId,
associated_type_id: ast::DefId)
-> ty::t {
debug!("collect::GenericsCtxt::associated_type_binding()");
// The ID should map to an associated type on one of the traits in
// our bounds.
find_associated_type_in_generics(self.chain.tcx(),
span,
ty,
associated_type_id,
self.associated_types_generics)
}
}
pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
let tcx = ccx.tcx;
debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id);
@@ -525,14 +1082,22 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
ref opt_trait_ref,
ref selfty,
ref impl_items) => {
let ty_generics = ty_generics_for_type(ccx, generics);
// Create generics from the generics specified in the impl head.
let ty_generics = ty_generics_for_type(
ccx,
generics,
CreateTypeParametersForAssociatedTypes);
let selfty = ccx.to_ty(&ExplicitRscope, &**selfty);
write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.borrow_mut().insert(local_def(it.id),
Polytype {
generics: ty_generics.clone(),
ty: selfty});
tcx.tcache
.borrow_mut()
.insert(local_def(it.id),
Polytype {
generics: ty_generics.clone(),
ty: selfty,
});
// If there is a trait reference, treat the methods as always public.
// This is to work around some incorrect behavior in privacy checking:
@@ -545,6 +1110,20 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
it.vis
};
let icx = ImplCtxt {
ccx: ccx,
opt_trait_ref_id: match *opt_trait_ref {
None => None,
Some(ref ast_trait_ref) => {
Some(lookup_def_tcx(tcx,
ast_trait_ref.path.span,
ast_trait_ref.ref_id).def_id())
}
},
impl_items: impl_items.as_slice(),
impl_generics: &ty_generics,
};
let mut methods = Vec::new();
for impl_item in impl_items.iter() {
match *impl_item {
@@ -555,10 +1134,33 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
method.pe_explicit_self());
methods.push(&**method);
}
ast::TypeImplItem(ref typedef) => {
let typ = icx.to_ty(&ExplicitRscope, &*typedef.typ);
tcx.tcache
.borrow_mut()
.insert(local_def(typedef.id),
Polytype {
generics: ty::Generics::empty(),
ty: typ,
});
write_ty_to_tcx(ccx.tcx, typedef.id, typ);
let associated_type = Rc::new(ty::AssociatedType {
ident: typedef.ident,
vis: typedef.vis,
def_id: local_def(typedef.id),
container: ty::ImplContainer(local_def(it.id)),
});
tcx.impl_or_trait_items
.borrow_mut()
.insert(local_def(typedef.id),
ty::TypeTraitItem(associated_type));
}
}
}
convert_methods(ccx,
ImplConvertMethodContext,
ImplContainer(local_def(it.id)),
methods.into_iter(),
selfty,
@@ -566,7 +1168,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
parent_visibility);
for trait_ref in opt_trait_ref.iter() {
instantiate_trait_ref(ccx, trait_ref, selfty);
instantiate_trait_ref(&icx, trait_ref, selfty, None);
}
},
ast::ItemTrait(_, _, _, ref trait_methods) => {
@@ -595,16 +1197,27 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
self_type,
method.pe_explicit_self())
}
ast::TypeTraitItem(ref associated_type) => {
convert_associated_type(ccx,
&*trait_def,
&**associated_type);
}
}
}
// Run convert_methods on the provided methods.
let untransformed_rcvr_ty = ty::mk_self_type(tcx, local_def(it.id));
let untransformed_rcvr_ty = ty::mk_self_type(tcx,
local_def(it.id));
let convert_method_context =
TraitConvertMethodContext(local_def(it.id),
trait_methods.as_slice());
convert_methods(ccx,
convert_method_context,
TraitContainer(local_def(it.id)),
trait_methods.iter().filter_map(|m| match *m {
ast::RequiredMethod(_) => None,
ast::ProvidedMethod(ref m) => Some(&**m)
ast::ProvidedMethod(ref m) => Some(&**m),
ast::TypeTraitItem(_) => None,
}),
untransformed_rcvr_ty,
&trait_def.generics,
@@ -765,9 +1378,12 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) {
ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), pty);
}
pub fn instantiate_trait_ref(ccx: &CrateCtxt,
ast_trait_ref: &ast::TraitRef,
self_ty: ty::t) -> Rc<ty::TraitRef> {
pub fn instantiate_trait_ref<'tcx,AC>(this: &AC,
ast_trait_ref: &ast::TraitRef,
self_ty: ty::t,
associated_type: Option<ty::t>)
-> Rc<ty::TraitRef>
where AC: AstConv<'tcx> {
/*!
* Instantiates the path for the given trait reference, assuming that
* it's bound to a valid trait type. Returns the def_id for the defining
@@ -777,18 +1393,24 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt,
// FIXME(#5121) -- distinguish early vs late lifetime params
let rscope = ExplicitRscope;
match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) {
match lookup_def_tcx(this.tcx(),
ast_trait_ref.path.span,
ast_trait_ref.ref_id) {
def::DefTrait(trait_did) => {
let trait_ref =
astconv::ast_path_to_trait_ref(
ccx, &rscope, trait_did, Some(self_ty), &ast_trait_ref.path);
astconv::ast_path_to_trait_ref(this,
&rscope,
trait_did,
Some(self_ty),
associated_type,
&ast_trait_ref.path);
ccx.tcx.trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
trait_ref.clone());
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
trait_ref.clone());
trait_ref
}
_ => {
ccx.tcx.sess.span_fatal(
this.tcx().sess.span_fatal(
ast_trait_ref.path.span,
format!("`{}` is not a trait",
path_to_string(&ast_trait_ref.path)).as_slice());
@@ -796,14 +1418,14 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt,
}
}
pub fn instantiate_unboxed_fn_ty(ccx: &CrateCtxt,
unboxed_function: &ast::UnboxedFnTy,
param_ty: ty::ParamTy)
-> Rc<ty::TraitRef>
{
pub fn instantiate_unboxed_fn_ty<'tcx,AC>(this: &AC,
unboxed_function: &ast::UnboxedFnTy,
param_ty: ty::ParamTy)
-> Rc<ty::TraitRef>
where AC: AstConv<'tcx> {
let rscope = ExplicitRscope;
let param_ty = param_ty.to_ty(ccx.tcx);
Rc::new(astconv::trait_ref_for_unboxed_function(ccx,
let param_ty = param_ty.to_ty(this.tcx());
Rc::new(astconv::trait_ref_for_unboxed_function(this,
&rscope,
unboxed_function,
Some(param_ty)))
@@ -831,9 +1453,12 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
_ => {}
}
let (generics, unbound, bounds) = match it.node {
ast::ItemTrait(ref generics, ref unbound, ref bounds, _) => {
(generics, unbound, bounds)
let (generics, unbound, bounds, items) = match it.node {
ast::ItemTrait(ref generics,
ref unbound,
ref supertraits,
ref items) => {
(generics, unbound, supertraits, items.as_slice())
}
ref s => {
tcx.sess.span_bug(
@@ -842,12 +1467,13 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
}
};
let substs = mk_trait_substs(ccx, it.id, generics);
let substs = mk_trait_substs(ccx, it.id, generics, items);
let ty_generics = ty_generics_for_trait(ccx,
it.id,
&substs,
generics);
generics,
items);
let self_param_ty = ty::ParamTy::for_self(def_id);
@@ -870,9 +1496,9 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
fn mk_trait_substs(ccx: &CrateCtxt,
trait_id: ast::NodeId,
generics: &ast::Generics)
-> subst::Substs
{
generics: &ast::Generics,
items: &[ast::TraitItem])
-> subst::Substs {
// Creates a no-op substitution for the trait's type parameters.
let regions =
generics.lifetimes
@@ -884,7 +1510,8 @@ fn mk_trait_substs(ccx: &CrateCtxt,
def.lifetime.name))
.collect();
let types =
// Start with the generics in the type parameters...
let mut types: Vec<_> =
generics.ty_params
.iter()
.enumerate()
@@ -892,6 +1519,20 @@ fn mk_trait_substs(ccx: &CrateCtxt,
i, local_def(def.id)))
.collect();
// ...and add generics synthesized from the associated types.
for item in items.iter() {
match *item {
ast::TypeTraitItem(ref trait_item) => {
let index = types.len();
types.push(ty::mk_param(ccx.tcx,
subst::TypeSpace,
index,
local_def(trait_item.id)))
}
ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
}
}
let self_ty =
ty::mk_param(ccx.tcx, subst::SelfSpace, 0, local_def(trait_id));
@@ -916,13 +1557,22 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
return pty;
}
ast::ItemFn(ref decl, fn_style, abi, ref generics, _) => {
let ty_generics = ty_generics_for_fn_or_method(ccx, generics,
ty::Generics::empty());
let tofd = astconv::ty_of_bare_fn(ccx,
it.id,
fn_style,
abi,
&**decl);
let ty_generics = ty_generics_for_fn_or_method(
ccx,
generics,
ty::Generics::empty(),
CreateTypeParametersForAssociatedTypes);
let tofd = {
let fcx = FnCtxt {
ccx: ccx,
generics: &ty_generics,
};
astconv::ty_of_bare_fn(&fcx,
it.id,
fn_style,
abi,
&**decl)
};
let pty = Polytype {
generics: ty_generics,
ty: ty::mk_bare_fn(ccx.tcx, tofd)
@@ -930,7 +1580,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
debug!("type of {} (id {}) is {}",
token::get_ident(it.ident),
it.id,
ppaux::ty_to_string(tcx, pty.ty));
pty.repr(tcx));
ccx.tcx.tcache.borrow_mut().insert(local_def(it.id), pty.clone());
return pty;
@@ -944,7 +1594,10 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
let pty = {
let ty = ccx.to_ty(&ExplicitRscope, &**t);
Polytype {
generics: ty_generics_for_type(ccx, generics),
generics: ty_generics_for_type(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes),
ty: ty
}
};
@@ -954,7 +1607,10 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
}
ast::ItemEnum(_, ref generics) => {
// Create a new generic polytype.
let ty_generics = ty_generics_for_type(ccx, generics);
let ty_generics = ty_generics_for_type(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes);
let substs = mk_item_substs(ccx, &ty_generics);
let t = ty::mk_enum(tcx, local_def(it.id), substs);
let pty = Polytype {
@@ -969,7 +1625,10 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
tcx.sess.span_bug(it.span, "invoked ty_of_item on trait");
}
ast::ItemStruct(_, ref generics) => {
let ty_generics = ty_generics_for_type(ccx, generics);
let ty_generics = ty_generics_for_type(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes);
let substs = mk_item_substs(ccx, &ty_generics);
let t = ty::mk_struct(tcx, local_def(it.id), substs);
let pty = Polytype {
@@ -1006,30 +1665,88 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
}
}
fn ty_of_trait_item(ccx: &CrateCtxt, trait_item: &ast::TraitItem)
-> ty::Polytype {
match *trait_item {
ast::RequiredMethod(ref m) => {
ccx.tcx.sess.span_bug(m.span,
"ty_of_trait_item() on required method")
}
ast::ProvidedMethod(ref m) => {
ccx.tcx.sess.span_bug(m.span,
"ty_of_trait_item() on provided method")
}
ast::TypeTraitItem(ref associated_type) => {
let parent = ccx.tcx.map.get_parent(associated_type.id);
let trait_def = match ccx.tcx.map.get(parent) {
ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item),
_ => {
ccx.tcx.sess.span_bug(associated_type.span,
"associated type's parent wasn't \
an item?!")
}
};
convert_associated_type(ccx, &*trait_def, &**associated_type)
}
}
}
fn ty_generics_for_type(ccx: &CrateCtxt,
generics: &ast::Generics)
-> ty::Generics
{
generics: &ast::Generics,
create_type_parameters_for_associated_types:
CreateTypeParametersForAssociatedTypesFlag)
-> ty::Generics {
ty_generics(ccx,
subst::TypeSpace,
generics.lifetimes.as_slice(),
generics.ty_params.as_slice(),
ty::Generics::empty(),
&generics.where_clause)
&generics.where_clause,
create_type_parameters_for_associated_types)
}
fn ty_generics_for_trait(ccx: &CrateCtxt,
trait_id: ast::NodeId,
substs: &subst::Substs,
generics: &ast::Generics)
generics: &ast::Generics,
items: &[ast::TraitItem])
-> ty::Generics {
let mut generics = ty_generics(ccx,
subst::TypeSpace,
generics.lifetimes.as_slice(),
generics.ty_params.as_slice(),
ty::Generics::empty(),
&generics.where_clause);
let mut generics =
ty_generics(ccx,
subst::TypeSpace,
generics.lifetimes.as_slice(),
generics.ty_params.as_slice(),
ty::Generics::empty(),
&generics.where_clause,
DontCreateTypeParametersForAssociatedTypes);
// Add in type parameters for any associated types.
for item in items.iter() {
match *item {
ast::TypeTraitItem(ref associated_type) => {
let def = ty::TypeParameterDef {
space: subst::TypeSpace,
index: generics.types.len(subst::TypeSpace),
ident: associated_type.ident,
def_id: local_def(associated_type.id),
bounds: ty::ParamBounds {
builtin_bounds: ty::empty_builtin_bounds(),
trait_bounds: Vec::new(),
region_bounds: Vec::new(),
},
associated_with: Some(local_def(trait_id)),
default: None,
};
ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.id,
def.clone());
generics.types.push(subst::TypeSpace, def);
}
ast::ProvidedMethod(_) | ast::RequiredMethod(_) => {}
}
}
// Add in the self type parameter.
//
// Something of a hack: use the node id for the trait, also as
// the node id for the Self type parameter.
let param_id = trait_id;
@@ -1048,6 +1765,7 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
builtin_bounds: ty::empty_builtin_bounds(),
trait_bounds: vec!(self_trait_ref),
},
associated_with: None,
default: None
};
@@ -1058,41 +1776,48 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
generics
}
fn ty_generics_for_fn_or_method(ccx: &CrateCtxt,
generics: &ast::Generics,
base_generics: ty::Generics)
-> ty::Generics {
fn ty_generics_for_fn_or_method<'tcx,AC>(
this: &AC,
generics: &ast::Generics,
base_generics: ty::Generics,
create_type_parameters_for_associated_types:
CreateTypeParametersForAssociatedTypesFlag)
-> ty::Generics
where AC: AstConv<'tcx> {
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
ty_generics(ccx,
ty_generics(this,
subst::FnSpace,
early_lifetimes.as_slice(),
generics.ty_params.as_slice(),
base_generics,
&generics.where_clause)
&generics.where_clause,
create_type_parameters_for_associated_types)
}
// Add the Sized bound, unless the type parameter is marked as `Sized?`.
fn add_unsized_bound(ccx: &CrateCtxt,
unbound: &Option<ast::TyParamBound>,
bounds: &mut ty::BuiltinBounds,
desc: &str,
span: Span) {
let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
fn add_unsized_bound<'tcx,AC>(this: &AC,
unbound: &Option<ast::TyParamBound>,
bounds: &mut ty::BuiltinBounds,
desc: &str,
span: Span)
where AC: AstConv<'tcx> {
let kind_id = this.tcx().lang_items.require(SizedTraitLangItem);
match unbound {
&Some(ast::TraitTyParamBound(ref tpb)) => {
// FIXME(#8559) currently requires the unbound to be built-in.
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb);
match kind_id {
Ok(kind_id) if trait_def_id != kind_id => {
ccx.tcx.sess.span_warn(span,
format!("default bound relaxed \
for a {}, but this does \
nothing because the given \
bound is not a default. \
Only `Sized?` is supported.",
desc).as_slice());
ty::try_add_builtin_trait(ccx.tcx,
this.tcx().sess.span_warn(span,
format!("default bound relaxed \
for a {}, but this \
does nothing because \
the given bound is not \
a default. \
Only `Sized?` is \
supported.",
desc).as_slice());
ty::try_add_builtin_trait(this.tcx(),
kind_id,
bounds);
}
@@ -1100,28 +1825,104 @@ fn add_unsized_bound(ccx: &CrateCtxt,
}
}
_ if kind_id.is_ok() => {
ty::try_add_builtin_trait(ccx.tcx,
kind_id.unwrap(),
bounds);
ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds);
}
// No lang item for Sized, so we can't add it as a bound.
_ => {}
}
}
fn ty_generics(ccx: &CrateCtxt,
space: subst::ParamSpace,
lifetime_defs: &[ast::LifetimeDef],
types: &[ast::TyParam],
base_generics: ty::Generics,
where_clause: &ast::WhereClause)
-> ty::Generics
{
#[deriving(Clone, PartialEq, Eq)]
enum CreateTypeParametersForAssociatedTypesFlag {
DontCreateTypeParametersForAssociatedTypes,
CreateTypeParametersForAssociatedTypes,
}
fn ensure_associated_types<'tcx,AC>(this: &AC, trait_id: ast::DefId)
where AC: AstConv<'tcx> {
if this.tcx().trait_associated_types.borrow().contains_key(&trait_id) {
return
}
if trait_id.krate == ast::LOCAL_CRATE {
match this.tcx().map.find(trait_id.node) {
Some(ast_map::NodeItem(item)) => {
match item.node {
ast::ItemTrait(_, _, _, ref trait_items) => {
let mut result = Vec::new();
let mut index = 0;
for trait_item in trait_items.iter() {
match *trait_item {
ast::RequiredMethod(_) |
ast::ProvidedMethod(_) => {}
ast::TypeTraitItem(ref associated_type) => {
let info = ty::AssociatedTypeInfo {
def_id: local_def(associated_type.id),
index: index,
ident: associated_type.ident,
};
result.push(info);
index += 1;
}
}
}
this.tcx()
.trait_associated_types
.borrow_mut()
.insert(trait_id, Rc::new(result));
return
}
_ => {
this.tcx().sess.bug("ensure_associated_types() \
called on non-trait")
}
}
}
_ => {
this.tcx().sess.bug("ensure_associated_types() called on \
non-trait")
}
}
}
// Cross-crate case.
let mut result = Vec::new();
let mut index = 0;
let trait_items = ty::trait_items(this.tcx(), trait_id);
for trait_item in trait_items.iter() {
match *trait_item {
ty::MethodTraitItem(_) => {}
ty::TypeTraitItem(ref associated_type) => {
let info = ty::AssociatedTypeInfo {
def_id: associated_type.def_id,
index: index,
ident: associated_type.ident
};
result.push(info);
index += 1;
}
}
}
this.tcx().trait_associated_types.borrow_mut().insert(trait_id,
Rc::new(result));
}
fn ty_generics<'tcx,AC>(this: &AC,
space: subst::ParamSpace,
lifetime_defs: &[ast::LifetimeDef],
types: &[ast::TyParam],
base_generics: ty::Generics,
where_clause: &ast::WhereClause,
create_type_parameters_for_associated_types:
CreateTypeParametersForAssociatedTypesFlag)
-> ty::Generics
where AC: AstConv<'tcx> {
let mut result = base_generics;
for (i, l) in lifetime_defs.iter().enumerate() {
let bounds = l.bounds.iter()
.map(|l| ast_region_to_region(ccx.tcx, l))
.map(|l| ast_region_to_region(this.tcx(), l))
.collect();
let def = ty::RegionParameterDef { name: l.lifetime.name,
space: space,
@@ -1132,80 +1933,170 @@ fn ty_generics(ccx: &CrateCtxt,
result.regions.push(space, def);
}
assert!(result.types.is_empty_in(space));
// First, create the virtual type parameters for associated types if
// necessary.
let mut associated_types_generics = ty::Generics::empty();
match create_type_parameters_for_associated_types {
DontCreateTypeParametersForAssociatedTypes => {}
CreateTypeParametersForAssociatedTypes => {
let mut index = 0;
for param in types.iter() {
for bound in param.bounds.iter() {
match *bound {
ast::TraitTyParamBound(ref trait_bound) => {
match lookup_def_tcx(this.tcx(),
trait_bound.path.span,
trait_bound.ref_id) {
def::DefTrait(trait_did) => {
ensure_associated_types(this, trait_did);
let associated_types =
ty::associated_types_for_trait(
this.tcx(),
trait_did);
for associated_type_info in
associated_types.iter() {
let associated_type_trait_item =
ty::impl_or_trait_item(
this.tcx(),
associated_type_info.def_id);
let def = ty::TypeParameterDef {
ident: associated_type_trait_item
.ident(),
def_id:
associated_type_info.def_id,
space: space,
index: types.len() + index,
bounds: ty::ParamBounds {
builtin_bounds:
ty::empty_builtin_bounds(),
trait_bounds: Vec::new(),
region_bounds: Vec::new(),
},
associated_with: {
Some(local_def(param.id))
},
default: None,
};
associated_types_generics.types
.push(space,
def);
index += 1;
}
}
_ => {
this.tcx().sess.span_bug(trait_bound.path
.span,
"not a trait?!")
}
}
}
_ => {}
}
}
}
}
}
// Now create the real type parameters.
let gcx = GenericsCtxt {
chain: this,
associated_types_generics: &associated_types_generics,
};
for (i, param) in types.iter().enumerate() {
let def = get_or_create_type_parameter_def(ccx,
let def = get_or_create_type_parameter_def(&gcx,
space,
param,
i,
where_clause);
debug!("ty_generics: def for type param: {}", def.repr(ccx.tcx));
debug!("ty_generics: def for type param: {}, {}",
def.repr(this.tcx()),
space);
result.types.push(space, def);
}
// Append the associated types to the result.
for associated_type_param in associated_types_generics.types
.get_slice(space)
.iter() {
assert!(result.types.get_slice(space).len() ==
associated_type_param.index);
debug!("ty_generics: def for associated type: {}, {}",
associated_type_param.repr(this.tcx()),
space);
result.types.push(space, (*associated_type_param).clone());
}
return result;
fn get_or_create_type_parameter_def(ccx: &CrateCtxt,
fn get_or_create_type_parameter_def<'tcx,AC>(
this: &AC,
space: subst::ParamSpace,
param: &ast::TyParam,
index: uint,
where_clause: &ast::WhereClause)
-> ty::TypeParameterDef {
match ccx.tcx.ty_param_defs.borrow().find(&param.id) {
-> ty::TypeParameterDef
where AC: AstConv<'tcx> {
match this.tcx().ty_param_defs.borrow().find(&param.id) {
Some(d) => { return (*d).clone(); }
None => { }
}
let param_ty = ty::ParamTy::new(space, index, local_def(param.id));
let bounds = compute_bounds(ccx,
let bounds = compute_bounds(this,
param.ident.name,
param_ty,
param.bounds.as_slice(),
&param.unbound,
param.span,
where_clause);
let default = param.default.as_ref().map(|path| {
let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &**path);
let cur_idx = index;
let default = match param.default {
None => None,
Some(ref path) => {
let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path);
let cur_idx = index;
ty::walk_ty(ty, |t| {
match ty::get(t).sty {
ty::ty_param(p) => if p.idx > cur_idx {
span_err!(ccx.tcx.sess, path.span, E0128,
"type parameters with a default cannot use \
forward declared identifiers");
},
_ => {}
}
});
ty::walk_ty(ty, |t| {
match ty::get(t).sty {
ty::ty_param(p) => if p.idx > cur_idx {
span_err!(this.tcx().sess, path.span, E0128,
"type parameters with a default cannot use \
forward declared identifiers");
},
_ => {}
}
});
ty
});
Some(ty)
}
};
let def = ty::TypeParameterDef {
space: space,
index: index,
ident: param.ident,
def_id: local_def(param.id),
associated_with: None,
bounds: bounds,
default: default
};
ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone());
def
}
}
fn compute_bounds(
ccx: &CrateCtxt,
name_of_bounded_thing: ast::Name,
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
unbound: &Option<ast::TyParamBound>,
span: Span,
where_clause: &ast::WhereClause)
-> ty::ParamBounds
{
fn compute_bounds<'tcx,AC>(this: &AC,
name_of_bounded_thing: ast::Name,
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
unbound: &Option<ast::TyParamBound>,
span: Span,
where_clause: &ast::WhereClause)
-> ty::ParamBounds
where AC: AstConv<'tcx> {
/*!
* Translate the AST's notion of ty param bounds (which are an
* enum consisting of a newtyped Ty or a region) to ty's
@@ -1213,21 +2104,23 @@ fn compute_bounds(
* traits, or the built-in trait (formerly known as kind): Send.
*/
let mut param_bounds = conv_param_bounds(ccx,
let mut param_bounds = conv_param_bounds(this,
span,
param_ty,
ast_bounds,
where_clause);
add_unsized_bound(ccx,
add_unsized_bound(this,
unbound,
&mut param_bounds.builtin_bounds,
"type parameter",
span);
check_bounds_compatible(ccx.tcx, name_of_bounded_thing,
&param_bounds, span);
check_bounds_compatible(this.tcx(),
name_of_bounded_thing,
&param_bounds,
span);
param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
@@ -1258,31 +2151,36 @@ fn check_bounds_compatible(tcx: &ty::ctxt,
}
}
fn conv_param_bounds(ccx: &CrateCtxt,
span: Span,
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
where_clause: &ast::WhereClause)
-> ty::ParamBounds
{
fn conv_param_bounds<'tcx,AC>(this: &AC,
span: Span,
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
where_clause: &ast::WhereClause)
-> ty::ParamBounds
where AC: AstConv<'tcx> {
let all_bounds =
merge_param_bounds(ccx, param_ty, ast_bounds, where_clause);
merge_param_bounds(this.tcx(), param_ty, ast_bounds, where_clause);
let astconv::PartitionedBounds { builtin_bounds,
trait_bounds,
region_bounds,
unboxed_fn_ty_bounds } =
astconv::partition_bounds(ccx.tcx, span, all_bounds.as_slice());
astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice());
let unboxed_fn_ty_bounds =
unboxed_fn_ty_bounds.into_iter()
.map(|b| instantiate_unboxed_fn_ty(ccx, b, param_ty));
.map(|b| instantiate_unboxed_fn_ty(this, b, param_ty));
let trait_bounds: Vec<Rc<ty::TraitRef>> =
trait_bounds.into_iter()
.map(|b| instantiate_trait_ref(ccx, b, param_ty.to_ty(ccx.tcx)))
.map(|b| {
instantiate_trait_ref(this,
b,
param_ty.to_ty(this.tcx()),
Some(param_ty.to_ty(this.tcx())))
})
.chain(unboxed_fn_ty_bounds)
.collect();
let region_bounds: Vec<ty::Region> =
region_bounds.move_iter()
.map(|r| ast_region_to_region(ccx.tcx, r))
.map(|r| ast_region_to_region(this.tcx(), r))
.collect();
ty::ParamBounds {
region_bounds: region_bounds,
@@ -1291,12 +2189,11 @@ fn conv_param_bounds(ccx: &CrateCtxt,
}
}
fn merge_param_bounds<'a>(ccx: &CrateCtxt,
fn merge_param_bounds<'a>(tcx: &ty::ctxt,
param_ty: ty::ParamTy,
ast_bounds: &'a [ast::TyParamBound],
where_clause: &'a ast::WhereClause)
-> Vec<&'a ast::TyParamBound>
{
-> Vec<&'a ast::TyParamBound> {
/*!
* Merges the bounds declared on a type parameter with those
* found from where clauses into a single list.
@@ -1309,15 +2206,13 @@ fn merge_param_bounds<'a>(ccx: &CrateCtxt,
}
for predicate in where_clause.predicates.iter() {
let predicate_param_id = ccx.tcx
.def_map
.borrow()
.find(&predicate.id)
.expect("compute_bounds(): resolve \
didn't resolve the type \
parameter identifier in a \
`where` clause")
.def_id();
let predicate_param_id =
tcx.def_map
.borrow()
.find(&predicate.id)
.expect("compute_bounds(): resolve didn't resolve the type \
parameter identifier in a `where` clause")
.def_id();
if param_ty.def_id != predicate_param_id {
continue
}
@@ -1334,8 +2229,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
def_id: ast::DefId,
ast_generics: &ast::Generics,
abi: abi::Abi)
-> ty::Polytype {
-> ty::Polytype {
for i in decl.inputs.iter() {
match (*i).pat.node {
ast::PatIdent(_, _, _) => (),
@@ -1347,9 +2241,11 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
}
}
let ty_generics_for_fn_or_method =
ty_generics_for_fn_or_method(ccx, ast_generics,
ty::Generics::empty());
let ty_generics_for_fn_or_method = ty_generics_for_fn_or_method(
ccx,
ast_generics,
ty::Generics::empty(),
DontCreateTypeParametersForAssociatedTypes);
let rb = BindingRscope::new(def_id.node);
let input_tys = decl.inputs
.iter()
@@ -871,6 +871,7 @@ fn give_suggestion(&self, same_regions: &[SameRegions]) {
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
+1
View File
@@ -522,6 +522,7 @@ fn visit_item(&mut self, item: &ast::Item) {
self.add_constraints_from_sig(&method.fty.sig,
self.covariant);
}
ty::TypeTraitItem(_) => {}
}
}
}
+5 -3
View File
@@ -603,9 +603,11 @@ fn repr(&self, _tcx: &ctxt) -> String {
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)
}
}
+4
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 {
+57 -1
View File
@@ -17,7 +17,7 @@
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 @@ fn clean(&self, cx: &DocContext) -> Type {
pub enum TraitItem {
RequiredMethod(Item),
ProvidedMethod(Item),
TypeTraitItem(Item),
}
impl TraitItem {
@@ -952,6 +954,7 @@ pub fn item<'a>(&'a self) -> &'a Item {
match *self {
RequiredMethod(ref item) => item,
ProvidedMethod(ref item) => item,
TypeTraitItem(ref item) => item,
}
}
}
@@ -961,6 +964,7 @@ fn clean(&self, cx: &DocContext) -> 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 @@ fn clean(&self, cx: &DocContext) -> 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 @@ fn clean(&self, cx: &DocContext) -> Item {
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 @@ fn clean(&self, _: &DocContext) -> 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 {
+6
View File
@@ -55,6 +55,12 @@ fn vtrm<T: DocFolder>(this: &mut T, trm: TraitItem)
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);
+3
View File
@@ -38,6 +38,7 @@ pub enum ItemType {
ForeignStatic = 14,
Macro = 15,
Primitive = 16,
AssociatedType = 17,
}
impl ItemType {
@@ -60,6 +61,7 @@ pub fn to_static_str(&self) -> &'static str {
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,
}
}
+1
View File
@@ -1512,6 +1512,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
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'>\
+3
View File
@@ -175,6 +175,9 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
// Primitives are never stripped
clean::PrimitiveItem(..) => {}
// Associated types are never stripped
clean::AssociatedTypeItem(..) => {}
}
let fastreturn = match i.inner {
+3 -2
View File
@@ -22,7 +22,7 @@
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()
+34
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>),
+3
View File
@@ -207,6 +207,9 @@ fn handle<A>(self,
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 {
+81 -27
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 @@ pub fn get_path_elem(&self, id: NodeId) -> PathElem {
}
}
}
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 @@ pub fn with_attrs<T>(&self, id: NodeId, f: |Option<&[Attribute]>| -> T) -> T {
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 @@ pub fn opt_span(&self, id: NodeId) -> Option<Span> {
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 @@ fn name(&self) -> Name {
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 @@ fn visit_item(&mut self, i: &'ast Item) {
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 @@ fn visit_item(&mut self, i: &'ast Item) {
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={})",
+57
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 @@ fn visit_trait_item(&mut self, tm: &ast::TraitItem) {
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);
}
+3 -1
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()),
}
}
+4 -1
View File
@@ -90,7 +90,10 @@ fn make_methods(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Meth
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);
+25 -1
View File
@@ -68,6 +68,7 @@
("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 @@ fn visit_item(&mut self, i: &ast::Item) {
}
}
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 @@ fn visit_item(&mut self, i: &ast::Item) {
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 @@ fn visit_item(&mut self, i: &ast::Item) {
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;
+115 -22
View File
@@ -287,6 +287,15 @@ fn fold_where_predicate(&mut self, where_predicate: WherePredicate)
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),
+149 -93
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::{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::{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 @@ pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool)
(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 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
} 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 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
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 @@ pub fn parse_bottom_expr(&mut self) -> P<Expr> {
}
}
hi = self.last_span.hi;
},
}
_ => {
if self.eat_keyword(keywords::Ref) {
return self.parse_lambda_expr(CaptureByRef);
@@ -4215,14 +4267,9 @@ fn parse_item_fn(&mut self, fn_style: FnStyle, abi: abi::Abi) -> ItemInfo {
/// 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 @@ pub fn parse_method(&mut self,
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 @@ fn parse_item_trait(&mut self) -> ItemInfo {
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)
}
+37 -5
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 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> {
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 @@ pub fn print_foreign_item(&mut self,
}
}
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 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
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 @@ pub fn print_trait_method(&mut self,
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),
}
}
+22 -5
View File
@@ -116,12 +116,19 @@ fn visit_path(&mut self, path: &'v Path, _id: ast::NodeId) {
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)
}
}
}
@@ -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);
}
@@ -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() {
}
@@ -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() {
}
@@ -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 {
+1 -1
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 }
}
@@ -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() {
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
+1 -1
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() {