auto merge of #15646 : jbclements/rust/method-macros, r=cmr
This patch adds support for macros in method position. It follows roughly the template for Item macros, where an outer `Method` wrapper contains a `Method_` enum which can either be a macro invocation or a standard macro definition. One note; adding support for macros that expand into multiple methods is not included here, but should be a simple parser change, since this patch updates the type of fold_macro to return a smallvector of methods. For reviewers, please pay special attention to the parser changes; these are the ones I'm most concerned about. Because of the small change to the interface of fold_method, this is a ... [breaking change]
This commit is contained in:
commit
7a6208f2cc
@ -799,7 +799,7 @@ fn encode_info_for_method(ecx: &EncodeContext,
|
||||
} else {
|
||||
encode_symbol(ecx, ebml_w, m.def_id.node);
|
||||
}
|
||||
encode_method_argument_names(ebml_w, &*ast_method.decl);
|
||||
encode_method_argument_names(ebml_w, method_fn_decl(&*ast_method));
|
||||
}
|
||||
|
||||
ebml_w.end_tag();
|
||||
@ -1241,7 +1241,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
encode_method_sort(ebml_w, 'p');
|
||||
encode_inlined_item(ecx, ebml_w,
|
||||
IIMethodRef(def_id, true, &*m));
|
||||
encode_method_argument_names(ebml_w, &*m.decl);
|
||||
encode_method_argument_names(ebml_w, method_fn_decl(m));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ pub fn decode_inlined_item(cdata: &cstore::crate_metadata,
|
||||
let ident = match ii {
|
||||
ast::IIItem(i) => i.ident,
|
||||
ast::IIForeign(i) => i.ident,
|
||||
ast::IIMethod(_, _, m) => m.ident,
|
||||
ast::IIMethod(_, _, m) => ast_util::method_ident(&*m),
|
||||
};
|
||||
debug!("Fn named: {}", token::get_ident(ident));
|
||||
debug!("< Decoded inlined fn: {}::{}",
|
||||
@ -345,7 +345,9 @@ fn simplify_ast(ii: e::InlinedItemRef) -> ast::InlinedItem {
|
||||
// HACK we're not dropping items.
|
||||
e::IIItemRef(i) => ast::IIItem(fold::noop_fold_item(i, &mut fld)
|
||||
.expect_one("expected one item")),
|
||||
e::IIMethodRef(d, p, m) => ast::IIMethod(d, p, fold::noop_fold_method(m, &mut fld)),
|
||||
e::IIMethodRef(d, p, m) => ast::IIMethod(d, p, fold::noop_fold_method(m, &mut fld)
|
||||
.expect_one(
|
||||
"noop_fold_method must produce exactly one method")),
|
||||
e::IIForeignRef(i) => ast::IIForeign(fold::noop_fold_foreign_item(i, &mut fld))
|
||||
}
|
||||
}
|
||||
@ -387,7 +389,8 @@ fn renumber_and_map_ast(xcx: &ExtendedDecodeContext,
|
||||
ast::IIItem(fld.fold_item(i).expect_one("expected one item"))
|
||||
}
|
||||
ast::IIMethod(d, is_provided, m) => {
|
||||
ast::IIMethod(xcx.tr_def_id(d), is_provided, fld.fold_method(m))
|
||||
ast::IIMethod(xcx.tr_def_id(d), is_provided, fld.fold_method(m)
|
||||
.expect_one("expected one method"))
|
||||
}
|
||||
ast::IIForeign(i) => ast::IIForeign(fld.fold_foreign_item(i))
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use util::nodemap::NodeSet;
|
||||
use std::collections::HashSet;
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util;
|
||||
use syntax::ast_util::{local_def, is_local};
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::attr;
|
||||
@ -212,7 +213,7 @@ impl<'a> MarkSymbolVisitor<'a> {
|
||||
visit::walk_trait_method(self, &*trait_method, ctxt);
|
||||
}
|
||||
ast_map::NodeMethod(method) => {
|
||||
visit::walk_block(self, &*method.body, ctxt);
|
||||
visit::walk_block(self, ast_util::method_body(&*method), ctxt);
|
||||
}
|
||||
ast_map::NodeForeignItem(foreign_item) => {
|
||||
visit::walk_foreign_item(self, &*foreign_item, ctxt);
|
||||
@ -520,7 +521,8 @@ impl<'a> Visitor<()> for DeadVisitor<'a> {
|
||||
// Overwrite so that we don't warn the trait method itself.
|
||||
fn visit_trait_method(&mut self, trait_method: &ast::TraitMethod, _: ()) {
|
||||
match *trait_method {
|
||||
ast::Provided(ref method) => visit::walk_block(self, &*method.body, ()),
|
||||
ast::Provided(ref method) => visit::walk_block(self,
|
||||
ast_util::method_body(&**method), ()),
|
||||
ast::Required(_) => ()
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ use middle::typeck::MethodCall;
|
||||
use util::ppaux;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
@ -94,7 +95,7 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> {
|
||||
visit::FkItemFn(_, _, fn_style, _) =>
|
||||
(true, fn_style == ast::UnsafeFn),
|
||||
visit::FkMethod(_, _, method) =>
|
||||
(true, method.fn_style == ast::UnsafeFn),
|
||||
(true, ast_util::method_fn_style(method) == ast::UnsafeFn),
|
||||
_ => (false, false),
|
||||
};
|
||||
|
||||
|
@ -26,6 +26,7 @@ use util::nodemap::{NodeMap, NodeSet};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util;
|
||||
use syntax::ast_util::{is_local, local_def};
|
||||
use syntax::attr;
|
||||
use syntax::codemap::Span;
|
||||
@ -263,10 +264,10 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {
|
||||
|
||||
if public_ty || public_trait {
|
||||
for method in methods.iter() {
|
||||
let meth_public = match method.explicit_self.node {
|
||||
let meth_public = match ast_util::method_explicit_self(&**method).node {
|
||||
ast::SelfStatic => public_ty,
|
||||
_ => true,
|
||||
} && method.vis == ast::Public;
|
||||
} && ast_util::method_vis(&**method) == ast::Public;
|
||||
if meth_public || tr.is_some() {
|
||||
self.exported_items.insert(method.id);
|
||||
}
|
||||
@ -456,8 +457,8 @@ impl<'a> PrivacyVisitor<'a> {
|
||||
let imp = self.tcx.map.get_parent_did(closest_private_id);
|
||||
match ty::impl_trait_ref(self.tcx, imp) {
|
||||
Some(..) => return Allowable,
|
||||
_ if m.vis == ast::Public => return Allowable,
|
||||
_ => m.vis
|
||||
_ if ast_util::method_vis(&**m) == ast::Public => return Allowable,
|
||||
_ => ast_util::method_vis(&**m)
|
||||
}
|
||||
}
|
||||
Some(ast_map::NodeTraitMethod(_)) => {
|
||||
@ -1078,7 +1079,7 @@ impl<'a> SanePrivacyVisitor<'a> {
|
||||
"visibility qualifiers have no effect on trait \
|
||||
impls");
|
||||
for m in methods.iter() {
|
||||
check_inherited(m.span, m.vis, "");
|
||||
check_inherited(m.span, ast_util::method_vis(&**m), "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1110,7 +1111,7 @@ impl<'a> SanePrivacyVisitor<'a> {
|
||||
for m in methods.iter() {
|
||||
match *m {
|
||||
ast::Provided(ref m) => {
|
||||
check_inherited(m.span, m.vis,
|
||||
check_inherited(m.span, ast_util::method_vis(&**m),
|
||||
"unnecessary visibility");
|
||||
}
|
||||
ast::Required(ref m) => {
|
||||
@ -1148,7 +1149,7 @@ impl<'a> SanePrivacyVisitor<'a> {
|
||||
match item.node {
|
||||
ast::ItemImpl(_, _, _, ref methods) => {
|
||||
for m in methods.iter() {
|
||||
check_inherited(tcx, m.span, m.vis);
|
||||
check_inherited(tcx, m.span, ast_util::method_vis(&**m));
|
||||
}
|
||||
}
|
||||
ast::ItemForeignMod(ref fm) => {
|
||||
@ -1174,7 +1175,7 @@ impl<'a> SanePrivacyVisitor<'a> {
|
||||
match *m {
|
||||
ast::Required(..) => {}
|
||||
ast::Provided(ref m) => check_inherited(tcx, m.span,
|
||||
m.vis),
|
||||
ast_util::method_vis(&**m)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1344,7 +1345,7 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> {
|
||||
// methods will be visible as `Public::foo`.
|
||||
let mut found_pub_static = false;
|
||||
for method in methods.iter() {
|
||||
if method.explicit_self.node == ast::SelfStatic &&
|
||||
if ast_util::method_explicit_self(&**method).node == ast::SelfStatic &&
|
||||
self.exported_items.contains(&method.id) {
|
||||
found_pub_static = true;
|
||||
visit::walk_method_helper(self, &**method, ());
|
||||
|
@ -68,7 +68,7 @@ fn item_might_be_inlined(item: &ast::Item) -> bool {
|
||||
fn method_might_be_inlined(tcx: &ty::ctxt, method: &ast::Method,
|
||||
impl_src: ast::DefId) -> bool {
|
||||
if attributes_specify_inlining(method.attrs.as_slice()) ||
|
||||
generics_require_inlining(&method.generics) {
|
||||
generics_require_inlining(ast_util::method_generics(&*method)) {
|
||||
return true
|
||||
}
|
||||
if is_local(impl_src) {
|
||||
@ -200,7 +200,7 @@ impl<'a> ReachableContext<'a> {
|
||||
}
|
||||
}
|
||||
Some(ast_map::NodeMethod(method)) => {
|
||||
if generics_require_inlining(&method.generics) ||
|
||||
if generics_require_inlining(ast_util::method_generics(&*method)) ||
|
||||
attributes_specify_inlining(method.attrs.as_slice()) {
|
||||
true
|
||||
} else {
|
||||
@ -316,14 +316,14 @@ impl<'a> ReachableContext<'a> {
|
||||
// Keep going, nothing to get exported
|
||||
}
|
||||
ast::Provided(ref method) => {
|
||||
visit::walk_block(self, &*method.body, ())
|
||||
visit::walk_block(self, ast_util::method_body(&**method), ())
|
||||
}
|
||||
}
|
||||
}
|
||||
ast_map::NodeMethod(method) => {
|
||||
let did = self.tcx.map.get_parent_did(search_item);
|
||||
if method_might_be_inlined(self.tcx, &*method, did) {
|
||||
visit::walk_block(self, &*method.body, ())
|
||||
visit::walk_block(self, ast_util::method_body(&*method), ())
|
||||
}
|
||||
}
|
||||
// Nothing to recurse on for these
|
||||
|
@ -22,6 +22,7 @@ use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
|
||||
|
||||
use syntax::ast::*;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::ast_util::{local_def};
|
||||
use syntax::ast_util::{walk_pat, trait_method_to_ty_method};
|
||||
use syntax::ext::mtwt;
|
||||
@ -1298,20 +1299,20 @@ impl<'a> Resolver<'a> {
|
||||
// For each method...
|
||||
for method in methods.iter() {
|
||||
// Add the method to the module.
|
||||
let ident = method.ident;
|
||||
let ident = ast_util::method_ident(&**method);
|
||||
let method_name_bindings =
|
||||
self.add_child(ident,
|
||||
new_parent.clone(),
|
||||
ForbidDuplicateValues,
|
||||
method.span);
|
||||
let def = match method.explicit_self.node {
|
||||
let def = match ast_util::method_explicit_self(&**method).node {
|
||||
SelfStatic => {
|
||||
// Static methods become
|
||||
// `def_static_method`s.
|
||||
DefStaticMethod(local_def(method.id),
|
||||
FromImpl(local_def(
|
||||
item.id)),
|
||||
method.fn_style)
|
||||
ast_util::method_fn_style(&**method))
|
||||
}
|
||||
_ => {
|
||||
// Non-static methods become
|
||||
@ -1320,7 +1321,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let is_public = method.vis == ast::Public;
|
||||
let is_public = ast_util::method_vis(&**method) == ast::Public;
|
||||
method_name_bindings.define_value(def,
|
||||
method.span,
|
||||
is_public);
|
||||
@ -4003,13 +4004,15 @@ impl<'a> Resolver<'a> {
|
||||
fn resolve_method(&mut self,
|
||||
rib_kind: RibKind,
|
||||
method: &Method) {
|
||||
let method_generics = &method.generics;
|
||||
let method_generics = ast_util::method_generics(method);
|
||||
let type_parameters = HasTypeParameters(method_generics,
|
||||
FnSpace,
|
||||
method.id,
|
||||
rib_kind);
|
||||
|
||||
self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body);
|
||||
self.resolve_function(rib_kind, Some(ast_util::method_fn_decl(method)),
|
||||
type_parameters,
|
||||
ast_util::method_body(method));
|
||||
}
|
||||
|
||||
fn with_current_self_type<T>(&mut self, self_type: &Ty, f: |&mut Resolver| -> T) -> T {
|
||||
@ -4080,7 +4083,7 @@ impl<'a> Resolver<'a> {
|
||||
fn check_trait_method(&self, method: &Method) {
|
||||
// If there is a TraitRef in scope for an impl, then the method must be in the trait.
|
||||
for &(did, ref trait_ref) in self.current_trait_ref.iter() {
|
||||
let method_name = method.ident.name;
|
||||
let method_name = ast_util::method_ident(method).name;
|
||||
|
||||
if self.method_map.borrow().find(&(method_name, did)).is_none() {
|
||||
let path_str = self.path_idents_to_string(&trait_ref.path);
|
||||
|
@ -333,7 +333,7 @@ impl <'l> DxrVisitor<'l> {
|
||||
},
|
||||
};
|
||||
|
||||
qualname.push_str(get_ident(method.ident).get());
|
||||
qualname.push_str(get_ident(ast_util::method_ident(&*method)).get());
|
||||
let qualname = qualname.as_slice();
|
||||
|
||||
// record the decl for this def (if it has one)
|
||||
@ -349,17 +349,18 @@ impl <'l> DxrVisitor<'l> {
|
||||
decl_id,
|
||||
scope_id);
|
||||
|
||||
self.process_formals(&method.decl.inputs, qualname, e);
|
||||
let m_decl = ast_util::method_fn_decl(&*method);
|
||||
self.process_formals(&m_decl.inputs, qualname, e);
|
||||
|
||||
// walk arg and return types
|
||||
for arg in method.decl.inputs.iter() {
|
||||
for arg in m_decl.inputs.iter() {
|
||||
self.visit_ty(&*arg.ty, e);
|
||||
}
|
||||
self.visit_ty(&*method.decl.output, e);
|
||||
self.visit_ty(m_decl.output, e);
|
||||
// walk the fn body
|
||||
self.visit_block(&*method.body, DxrVisitorEnv::new_nested(method.id));
|
||||
self.visit_block(ast_util::method_body(&*method), DxrVisitorEnv::new_nested(method.id));
|
||||
|
||||
self.process_generic_params(&method.generics,
|
||||
self.process_generic_params(ast_util::method_generics(&*method),
|
||||
method.span,
|
||||
qualname,
|
||||
method.id,
|
||||
|
@ -1138,10 +1138,10 @@ pub fn create_function_debug_context(cx: &CrateContext,
|
||||
}
|
||||
}
|
||||
ast_map::NodeMethod(ref method) => {
|
||||
(method.ident,
|
||||
method.decl,
|
||||
&method.generics,
|
||||
method.body,
|
||||
(ast_util::method_ident(&**method),
|
||||
ast_util::method_fn_decl(&**method),
|
||||
ast_util::method_generics(&**method),
|
||||
ast_util::method_body(&**method),
|
||||
method.span,
|
||||
true)
|
||||
}
|
||||
@ -1167,10 +1167,10 @@ pub fn create_function_debug_context(cx: &CrateContext,
|
||||
ast_map::NodeTraitMethod(ref trait_method) => {
|
||||
match **trait_method {
|
||||
ast::Provided(ref method) => {
|
||||
(method.ident,
|
||||
method.decl,
|
||||
&method.generics,
|
||||
method.body,
|
||||
(ast_util::method_ident(&**method),
|
||||
ast_util::method_fn_decl(&**method),
|
||||
ast_util::method_generics(&**method),
|
||||
ast_util::method_body(&**method),
|
||||
method.span,
|
||||
true)
|
||||
}
|
||||
|
@ -128,11 +128,12 @@ pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
|
||||
let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did);
|
||||
let unparameterized =
|
||||
impl_tpt.generics.types.is_empty() &&
|
||||
mth.generics.ty_params.is_empty();
|
||||
ast_util::method_generics(&*mth).ty_params.is_empty();
|
||||
|
||||
if unparameterized {
|
||||
let llfn = get_item_val(ccx, mth.id);
|
||||
trans_fn(ccx, &*mth.decl, &*mth.body, llfn,
|
||||
trans_fn(ccx, ast_util::method_fn_decl(&*mth),
|
||||
ast_util::method_body(&*mth), llfn,
|
||||
¶m_substs::empty(), mth.id, []);
|
||||
}
|
||||
local_def(mth.id)
|
||||
|
@ -38,7 +38,7 @@ use std::c_str::ToCStr;
|
||||
use std::gc::Gc;
|
||||
use syntax::abi::Rust;
|
||||
use syntax::parse::token;
|
||||
use syntax::{ast, ast_map, visit};
|
||||
use syntax::{ast, ast_map, visit, ast_util};
|
||||
|
||||
/**
|
||||
The main "translation" pass for methods. Generates code
|
||||
@ -66,9 +66,10 @@ pub fn trans_impl(ccx: &CrateContext,
|
||||
return;
|
||||
}
|
||||
for method in methods.iter() {
|
||||
if method.generics.ty_params.len() == 0u {
|
||||
if ast_util::method_generics(&**method).ty_params.len() == 0u {
|
||||
let llfn = get_item_val(ccx, method.id);
|
||||
trans_fn(ccx, &*method.decl, &*method.body,
|
||||
trans_fn(ccx, ast_util::method_fn_decl(&**method),
|
||||
ast_util::method_body(&**method),
|
||||
llfn, ¶m_substs::empty(), method.id, []);
|
||||
} else {
|
||||
let mut v = TransItemVisitor{ ccx: ccx };
|
||||
@ -160,7 +161,7 @@ pub fn trans_static_method_callee(bcx: &Block,
|
||||
ast_map::NodeTraitMethod(method) => {
|
||||
let ident = match *method {
|
||||
ast::Required(ref m) => m.ident,
|
||||
ast::Provided(ref m) => m.ident
|
||||
ast::Provided(ref m) => ast_util::method_ident(&**m)
|
||||
};
|
||||
ident.name
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ use util::ppaux::Repr;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util;
|
||||
use syntax::ast_util::local_def;
|
||||
use std::hash::{sip, Hash};
|
||||
|
||||
@ -181,7 +182,8 @@ pub fn monomorphic_fn(ccx: &CrateContext,
|
||||
ast_map::NodeMethod(mth) => {
|
||||
let d = mk_lldecl();
|
||||
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
|
||||
trans_fn(ccx, &*mth.decl, &*mth.body, d, &psubsts, mth.id, []);
|
||||
trans_fn(ccx, ast_util::method_fn_decl(&*mth),
|
||||
ast_util::method_body(&*mth), d, &psubsts, mth.id, []);
|
||||
d
|
||||
}
|
||||
ast_map::NodeTraitMethod(method) => {
|
||||
@ -189,7 +191,8 @@ pub fn monomorphic_fn(ccx: &CrateContext,
|
||||
ast::Provided(mth) => {
|
||||
let d = mk_lldecl();
|
||||
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
|
||||
trans_fn(ccx, &*mth.decl, &*mth.body, d, &psubsts, mth.id, []);
|
||||
trans_fn(ccx, ast_util::method_fn_decl(&*mth),
|
||||
ast_util::method_body(&*mth), d, &psubsts, mth.id, []);
|
||||
d
|
||||
}
|
||||
_ => {
|
||||
|
@ -757,14 +757,16 @@ fn check_method_body(ccx: &CrateCtxt,
|
||||
let method_def_id = local_def(method.id);
|
||||
let method_ty = ty::method(ccx.tcx, method_def_id);
|
||||
let method_generics = &method_ty.generics;
|
||||
let m_body = ast_util::method_body(&*method);
|
||||
|
||||
let param_env = ty::construct_parameter_environment(ccx.tcx,
|
||||
method_generics,
|
||||
method.body.id);
|
||||
m_body.id);
|
||||
|
||||
let fty = ty::node_id_to_type(ccx.tcx, method.id);
|
||||
|
||||
check_bare_fn(ccx, &*method.decl, &*method.body, method.id, fty, param_env);
|
||||
check_bare_fn(ccx, ast_util::method_fn_decl(&*method),
|
||||
m_body, method.id, fty, param_env);
|
||||
}
|
||||
|
||||
fn check_impl_methods_against_trait(ccx: &CrateCtxt,
|
||||
@ -792,7 +794,7 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
|
||||
compare_impl_method(ccx.tcx,
|
||||
&*impl_method_ty,
|
||||
impl_method.span,
|
||||
impl_method.body.id,
|
||||
ast_util::method_body(&**impl_method).id,
|
||||
&**trait_method_ty,
|
||||
&impl_trait_ref.substs);
|
||||
}
|
||||
@ -815,7 +817,7 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
|
||||
for trait_method in trait_methods.iter() {
|
||||
let is_implemented =
|
||||
impl_methods.iter().any(
|
||||
|m| m.ident.name == trait_method.ident.name);
|
||||
|m| ast_util::method_ident(&**m).name == trait_method.ident.name);
|
||||
let is_provided =
|
||||
provided_methods.iter().any(
|
||||
|m| m.ident.name == trait_method.ident.name);
|
||||
|
@ -57,7 +57,8 @@ use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
|
||||
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::{local_def, split_trait_methods};
|
||||
use syntax::ast_util;
|
||||
use syntax::ast_util::{local_def, method_ident, split_trait_methods};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
@ -213,8 +214,11 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
|
||||
&ast::Provided(ref m) => {
|
||||
ty_method_of_trait_method(
|
||||
ccx, trait_id, &trait_def.generics,
|
||||
&m.id, &m.ident, &m.explicit_self,
|
||||
&m.generics, &m.fn_style, &*m.decl)
|
||||
&m.id, &ast_util::method_ident(&**m),
|
||||
ast_util::method_explicit_self(&**m),
|
||||
ast_util::method_generics(&**m),
|
||||
&ast_util::method_fn_style(&**m),
|
||||
ast_util::method_fn_decl(&**m))
|
||||
}
|
||||
});
|
||||
|
||||
@ -330,7 +334,7 @@ fn convert_methods(ccx: &CrateCtxt,
|
||||
let tcx = ccx.tcx;
|
||||
let mut seen_methods = HashSet::new();
|
||||
for m in ms.iter() {
|
||||
if !seen_methods.insert(m.ident.repr(ccx.tcx)) {
|
||||
if !seen_methods.insert(ast_util::method_ident(&**m).repr(tcx)) {
|
||||
tcx.sess.span_err(m.span, "duplicate method in trait impl");
|
||||
}
|
||||
|
||||
@ -342,9 +346,9 @@ fn convert_methods(ccx: &CrateCtxt,
|
||||
rcvr_visibility));
|
||||
let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
|
||||
debug!("method {} (id {}) has type {}",
|
||||
m.ident.repr(ccx.tcx),
|
||||
method_ident(&**m).repr(tcx),
|
||||
m.id,
|
||||
fty.repr(ccx.tcx));
|
||||
fty.repr(tcx));
|
||||
tcx.tcache.borrow_mut().insert(
|
||||
local_def(m.id),
|
||||
Polytype {
|
||||
@ -365,23 +369,24 @@ fn convert_methods(ccx: &CrateCtxt,
|
||||
rcvr_visibility: ast::Visibility)
|
||||
-> ty::Method
|
||||
{
|
||||
let fty = astconv::ty_of_method(ccx, m.id, m.fn_style,
|
||||
let fty = astconv::ty_of_method(ccx, m.id, ast_util::method_fn_style(&*m),
|
||||
untransformed_rcvr_ty,
|
||||
m.explicit_self, &*m.decl);
|
||||
*ast_util::method_explicit_self(&*m),
|
||||
ast_util::method_fn_decl(&*m));
|
||||
|
||||
// if the method specifies a visibility, use that, otherwise
|
||||
// inherit the visibility from the impl (so `foo` in `pub impl
|
||||
// { fn foo(); }` is public, but private in `priv impl { fn
|
||||
// foo(); }`).
|
||||
let method_vis = m.vis.inherit_from(rcvr_visibility);
|
||||
let method_vis = ast_util::method_vis(&*m).inherit_from(rcvr_visibility);
|
||||
|
||||
let m_ty_generics =
|
||||
ty_generics_for_fn_or_method(ccx, &m.generics,
|
||||
ty_generics_for_fn_or_method(ccx, ast_util::method_generics(&*m),
|
||||
(*rcvr_ty_generics).clone());
|
||||
ty::Method::new(m.ident,
|
||||
ty::Method::new(ast_util::method_ident(&*m),
|
||||
m_ty_generics,
|
||||
fty,
|
||||
m.explicit_self.node,
|
||||
ast_util::method_explicit_self(&*m).node,
|
||||
method_vis,
|
||||
local_def(m.id),
|
||||
container,
|
||||
|
@ -693,15 +693,18 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
Some(ref node) => match *node {
|
||||
ast_map::NodeItem(ref item) => {
|
||||
match item.node {
|
||||
ast::ItemFn(ref fn_decl, ref pur, _, ref gen, _) => {
|
||||
ast::ItemFn(fn_decl, ref pur, _, ref gen, _) => {
|
||||
Some((fn_decl, gen, *pur, item.ident, None, item.span))
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
ast_map::NodeMethod(ref m) => {
|
||||
Some((&m.decl, &m.generics, m.fn_style,
|
||||
m.ident, Some(m.explicit_self.node), m.span))
|
||||
Some((ast_util::method_fn_decl(&**m),
|
||||
ast_util::method_generics(&**m),
|
||||
ast_util::method_fn_style(&**m),
|
||||
ast_util::method_ident(&**m),
|
||||
Some(ast_util::method_explicit_self(&**m).node), m.span))
|
||||
},
|
||||
_ => None
|
||||
},
|
||||
@ -711,7 +714,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
= node_inner.expect("expect item fn");
|
||||
let taken = lifetimes_in_scope(self.tcx, scope_id);
|
||||
let life_giver = LifeGiver::with_taken(taken.as_slice());
|
||||
let rebuilder = Rebuilder::new(self.tcx, *fn_decl, expl_self,
|
||||
let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self,
|
||||
generics, same_regions, &life_giver);
|
||||
let (fn_decl, expl_self, generics) = rebuilder.rebuild();
|
||||
self.give_expl_lifetime_param(&fn_decl, fn_style, ident,
|
||||
@ -1452,7 +1455,7 @@ fn lifetimes_in_scope(tcx: &ty::ctxt,
|
||||
_ => None
|
||||
},
|
||||
ast_map::NodeMethod(m) => {
|
||||
taken.push_all(m.generics.lifetimes.as_slice());
|
||||
taken.push_all(ast_util::method_generics(&*m).lifetimes.as_slice());
|
||||
Some(m.id)
|
||||
},
|
||||
_ => None
|
||||
|
@ -695,29 +695,30 @@ pub struct Method {
|
||||
|
||||
impl Clean<Item> for ast::Method {
|
||||
fn clean(&self) -> Item {
|
||||
let inputs = match self.explicit_self.node {
|
||||
ast::SelfStatic => self.decl.inputs.as_slice(),
|
||||
_ => self.decl.inputs.slice_from(1)
|
||||
let fn_decl = ast_util::method_fn_decl(self);
|
||||
let inputs = match ast_util::method_explicit_self(self).node {
|
||||
ast::SelfStatic => fn_decl.inputs.as_slice(),
|
||||
_ => fn_decl.inputs.slice_from(1)
|
||||
};
|
||||
let decl = FnDecl {
|
||||
inputs: Arguments {
|
||||
values: inputs.iter().map(|x| x.clean()).collect(),
|
||||
},
|
||||
output: (self.decl.output.clean()),
|
||||
cf: self.decl.cf.clean(),
|
||||
output: (fn_decl.output.clean()),
|
||||
cf: fn_decl.cf.clean(),
|
||||
attrs: Vec::new()
|
||||
};
|
||||
Item {
|
||||
name: Some(self.ident.clean()),
|
||||
name: Some(ast_util::method_ident(self).clean()),
|
||||
attrs: self.attrs.clean().move_iter().collect(),
|
||||
source: self.span.clean(),
|
||||
def_id: ast_util::local_def(self.id),
|
||||
visibility: self.vis.clean(),
|
||||
visibility: ast_util::method_vis(self).clean(),
|
||||
stability: get_stability(ast_util::local_def(self.id)),
|
||||
inner: MethodItem(Method {
|
||||
generics: self.generics.clean(),
|
||||
self_: self.explicit_self.node.clean(),
|
||||
fn_style: self.fn_style.clone(),
|
||||
generics: ast_util::method_generics(self).clean(),
|
||||
self_: ast_util::method_explicit_self(self).node.clean(),
|
||||
fn_style: ast_util::method_fn_style(self).clone(),
|
||||
decl: decl,
|
||||
}),
|
||||
}
|
||||
|
@ -640,6 +640,8 @@ pub type Mac = Spanned<Mac_>;
|
||||
/// There's only one flavor, now, so this could presumably be simplified.
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
|
||||
pub enum Mac_ {
|
||||
// NB: the additional ident for a macro_rules-style macro is actually
|
||||
// stored in the enclosing item. Oog.
|
||||
MacInvocTT(Path, Vec<TokenTree> , SyntaxContext), // new macro-invocation
|
||||
}
|
||||
|
||||
@ -957,19 +959,20 @@ pub enum ExplicitSelf_ {
|
||||
|
||||
pub type ExplicitSelf = Spanned<ExplicitSelf_>;
|
||||
|
||||
// Represents a method declaration
|
||||
#[deriving(PartialEq, Eq, Encodable, Decodable, Hash)]
|
||||
pub struct Method {
|
||||
pub ident: Ident,
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub generics: Generics,
|
||||
pub explicit_self: ExplicitSelf,
|
||||
pub fn_style: FnStyle,
|
||||
pub decl: P<FnDecl>,
|
||||
pub body: P<Block>,
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub vis: Visibility,
|
||||
pub node: Method_
|
||||
}
|
||||
|
||||
#[deriving(PartialEq, Eq, Encodable, Decodable, Hash)]
|
||||
pub enum Method_ {
|
||||
/// Represents a method declaration
|
||||
MethDecl(Ident, Generics, ExplicitSelf, FnStyle, P<FnDecl>, P<Block>, Visibility),
|
||||
/// Represents a macro in method position
|
||||
MethMac(Mac),
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
|
||||
|
@ -304,8 +304,10 @@ impl Map {
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the name associated with the given NodeId's AST
|
||||
pub fn get_path_elem(&self, id: NodeId) -> PathElem {
|
||||
match self.get(id) {
|
||||
let node = self.get(id);
|
||||
match node {
|
||||
NodeItem(item) => {
|
||||
match item.node {
|
||||
ItemMod(_) | ItemForeignMod(_) => {
|
||||
@ -315,13 +317,19 @@ impl Map {
|
||||
}
|
||||
}
|
||||
NodeForeignItem(i) => PathName(i.ident.name),
|
||||
NodeMethod(m) => PathName(m.ident.name),
|
||||
NodeMethod(m) => match m.node {
|
||||
MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
|
||||
MethMac(_) => fail!("no path elem for {:?}", node)
|
||||
},
|
||||
NodeTraitMethod(tm) => match *tm {
|
||||
Required(ref m) => PathName(m.ident.name),
|
||||
Provided(ref m) => PathName(m.ident.name)
|
||||
Provided(m) => match m.node {
|
||||
MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
|
||||
MethMac(_) => fail!("no path elem for {:?}", node),
|
||||
}
|
||||
},
|
||||
NodeVariant(v) => PathName(v.node.name.name),
|
||||
node => fail!("no path elem for {:?}", node)
|
||||
_ => fail!("no path elem for {:?}", node)
|
||||
}
|
||||
}
|
||||
|
||||
@ -369,6 +377,8 @@ impl Map {
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a node ID and a closure, apply the closure to the array
|
||||
/// of attributes associated with the AST corresponding to the Node ID
|
||||
pub fn with_attrs<T>(&self, id: NodeId, f: |Option<&[Attribute]>| -> T) -> T {
|
||||
let node = self.get(id);
|
||||
let attrs = match node {
|
||||
@ -561,13 +571,14 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
|
||||
m
|
||||
}
|
||||
|
||||
fn fold_method(&mut self, m: Gc<Method>) -> Gc<Method> {
|
||||
fn fold_method(&mut self, m: Gc<Method>) -> SmallVector<Gc<Method>> {
|
||||
let parent = self.parent;
|
||||
self.parent = DUMMY_NODE_ID;
|
||||
let m = fold::noop_fold_method(&*m, self);
|
||||
let m = fold::noop_fold_method(&*m, self).expect_one(
|
||||
"noop_fold_method must produce exactly one method");
|
||||
assert_eq!(self.parent, m.id);
|
||||
self.parent = parent;
|
||||
m
|
||||
SmallVector::one(m)
|
||||
}
|
||||
|
||||
fn fold_fn_decl(&mut self, decl: &FnDecl) -> P<FnDecl> {
|
||||
@ -695,11 +706,15 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String {
|
||||
let path_str = map.path_to_str_with_ident(id, item.ident);
|
||||
format!("foreign item {} (id={})", path_str, id)
|
||||
}
|
||||
Some(NodeMethod(m)) => {
|
||||
format!("method {} in {} (id={})",
|
||||
token::get_ident(m.ident),
|
||||
map.path_to_string(id), id)
|
||||
}
|
||||
Some(NodeMethod(m)) => match m.node {
|
||||
MethDecl(ident, _, _, _, _, _, _) =>
|
||||
format!("method {} in {} (id={})",
|
||||
token::get_ident(ident),
|
||||
map.path_to_string(id), id),
|
||||
MethMac(ref mac) =>
|
||||
format!("method macro {} (id={})",
|
||||
pprust::mac_to_string(mac), id)
|
||||
},
|
||||
Some(NodeTraitMethod(ref tm)) => {
|
||||
let m = ast_util::trait_method_to_ty_method(&**tm);
|
||||
format!("method {} in {} (id={})",
|
||||
|
@ -240,32 +240,31 @@ pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: &Ty) -> Ident {
|
||||
token::gensym_ident(pretty.as_slice())
|
||||
}
|
||||
|
||||
pub fn public_methods(ms: Vec<Gc<Method>> ) -> Vec<Gc<Method>> {
|
||||
ms.move_iter().filter(|m| {
|
||||
match m.vis {
|
||||
Public => true,
|
||||
_ => false
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
|
||||
/// extract a TypeMethod from a TraitMethod. if the TraitMethod 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_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
|
||||
match *method {
|
||||
Required(ref m) => (*m).clone(),
|
||||
Provided(ref m) => {
|
||||
TypeMethod {
|
||||
ident: m.ident,
|
||||
attrs: m.attrs.clone(),
|
||||
fn_style: m.fn_style,
|
||||
decl: m.decl,
|
||||
generics: m.generics.clone(),
|
||||
explicit_self: m.explicit_self,
|
||||
id: m.id,
|
||||
span: m.span,
|
||||
vis: m.vis,
|
||||
Provided(m) => {
|
||||
match m.node {
|
||||
MethDecl(ident, ref generics, explicit_self, fn_style, decl, _, vis) => {
|
||||
TypeMethod {
|
||||
ident: ident,
|
||||
attrs: m.attrs.clone(),
|
||||
fn_style: fn_style,
|
||||
decl: decl,
|
||||
generics: generics.clone(),
|
||||
explicit_self: explicit_self,
|
||||
id: m.id,
|
||||
span: m.span,
|
||||
vis: vis,
|
||||
}
|
||||
},
|
||||
MethMac(_) => fail!("expected non-macro method declaration")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,6 +345,9 @@ pub trait IdVisitingOperation {
|
||||
fn visit_id(&self, node_id: NodeId);
|
||||
}
|
||||
|
||||
/// A visitor that applies its operation to all of the node IDs
|
||||
/// in a visitable thing.
|
||||
|
||||
pub struct IdVisitor<'a, O> {
|
||||
pub operation: &'a O,
|
||||
pub pass_through_items: bool,
|
||||
@ -740,6 +742,38 @@ pub fn static_has_significant_address(mutbl: ast::Mutability,
|
||||
inline == InlineNever || inline == InlineNone
|
||||
}
|
||||
|
||||
|
||||
/// Macro invocations are guaranteed not to occur after expansion is complete.
|
||||
/// extracting fields of a method requires a dynamic check to make sure that it's
|
||||
/// not a macro invocation, though this check is guaranteed to succeed, assuming
|
||||
/// that the invocations are indeed gone.
|
||||
macro_rules! method_field_extractor {
|
||||
($fn_name:ident, $field_ty:ty, $field_pat:pat, $result:ident) => {
|
||||
/// Returns the ident of a Method. To be used after expansion is complete
|
||||
pub fn $fn_name<'a>(method: &'a ast::Method) -> $field_ty {
|
||||
match method.node {
|
||||
$field_pat => $result,
|
||||
MethMac(_) => {
|
||||
fail!("expected an AST without macro invocations");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this is unhygienic in the lifetime 'a. In order to fix this, we'd have to
|
||||
// add :lifetime as a macro argument type, so that the 'a could be supplied by the macro
|
||||
// invocation.
|
||||
pub method_field_extractor!(method_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_),ident)
|
||||
pub method_field_extractor!(method_generics,&'a ast::Generics,
|
||||
MethDecl(_,ref generics,_,_,_,_,_),generics)
|
||||
pub method_field_extractor!(method_explicit_self,&'a ast::ExplicitSelf,
|
||||
MethDecl(_,_,ref explicit_self,_,_,_,_),explicit_self)
|
||||
pub method_field_extractor!(method_fn_style,ast::FnStyle,MethDecl(_,_,_,fn_style,_,_,_),fn_style)
|
||||
pub method_field_extractor!(method_fn_decl,P<ast::FnDecl>,MethDecl(_,_,_,_,decl,_,_),decl)
|
||||
pub method_field_extractor!(method_body,P<ast::Block>,MethDecl(_,_,_,_,_,body,_),body)
|
||||
pub method_field_extractor!(method_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,vis),vis)
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use ast::*;
|
||||
@ -765,3 +799,4 @@ mod test {
|
||||
.iter().map(ident_to_segment).collect::<Vec<PathSegment>>().as_slice()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,6 +104,9 @@ pub type IdentMacroExpanderFn =
|
||||
/// just into the compiler's internal macro table, for `make_def`).
|
||||
pub trait MacResult {
|
||||
/// Define a new macro.
|
||||
// this should go away; the idea that a macro might expand into
|
||||
// either a macro definition or an expression, depending on what
|
||||
// the context wants, is kind of silly.
|
||||
fn make_def(&self) -> Option<MacroDef> {
|
||||
None
|
||||
}
|
||||
@ -115,6 +118,12 @@ pub trait MacResult {
|
||||
fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Create zero or more methods.
|
||||
fn make_methods(&self) -> Option<SmallVector<Gc<ast::Method>>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Create a pattern.
|
||||
fn make_pat(&self) -> Option<Gc<ast::Pat>> {
|
||||
None
|
||||
@ -222,6 +231,7 @@ impl DummyResult {
|
||||
span: sp,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl MacResult for DummyResult {
|
||||
@ -232,6 +242,14 @@ impl MacResult for DummyResult {
|
||||
Some(DummyResult::raw_pat(self.span))
|
||||
}
|
||||
fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
|
||||
// this code needs a comment... why not always just return the Some() ?
|
||||
if self.expr_only {
|
||||
None
|
||||
} else {
|
||||
Some(SmallVector::zero())
|
||||
}
|
||||
}
|
||||
fn make_methods(&self) -> Option<SmallVector<Gc<ast::Method>>> {
|
||||
if self.expr_only {
|
||||
None
|
||||
} else {
|
||||
|
@ -648,16 +648,16 @@ impl<'a> MethodDef<'a> {
|
||||
|
||||
// Create the method.
|
||||
box(GC) ast::Method {
|
||||
ident: method_ident,
|
||||
attrs: self.attributes.clone(),
|
||||
generics: fn_generics,
|
||||
explicit_self: explicit_self,
|
||||
fn_style: ast::NormalFn,
|
||||
decl: fn_decl,
|
||||
body: body_block,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: trait_.span,
|
||||
vis: ast::Inherited,
|
||||
node: ast::MethDecl(method_ident,
|
||||
fn_generics,
|
||||
explicit_self,
|
||||
ast::NormalFn,
|
||||
fn_decl,
|
||||
body_block,
|
||||
ast::Inherited)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,92 +37,28 @@ pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
|
||||
// expr_mac should really be expr_ext or something; it's the
|
||||
// entry-point for all syntax extensions.
|
||||
ExprMac(ref mac) => {
|
||||
match (*mac).node {
|
||||
// it would almost certainly be cleaner to pass the whole
|
||||
// macro invocation in, rather than pulling it apart and
|
||||
// marking the tts and the ctxt separately. This also goes
|
||||
// for the other three macro invocation chunks of code
|
||||
// in this file.
|
||||
// Token-tree macros:
|
||||
MacInvocTT(ref pth, ref tts, _) => {
|
||||
if pth.segments.len() > 1u {
|
||||
fld.cx.span_err(pth.span,
|
||||
"expected macro name without module \
|
||||
separators");
|
||||
// let compilation continue
|
||||
return DummyResult::raw_expr(e.span);
|
||||
}
|
||||
let extname = pth.segments.get(0).identifier;
|
||||
let extnamestr = token::get_ident(extname);
|
||||
let marked_after = match fld.extsbox.find(&extname.name) {
|
||||
None => {
|
||||
fld.cx.span_err(
|
||||
pth.span,
|
||||
format!("macro undefined: '{}!'",
|
||||
extnamestr.get()).as_slice());
|
||||
|
||||
// let compilation continue
|
||||
return DummyResult::raw_expr(e.span);
|
||||
}
|
||||
Some(&NormalTT(ref expandfun, exp_span)) => {
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: e.span,
|
||||
callee: NameAndSpan {
|
||||
name: extnamestr.get().to_string(),
|
||||
format: MacroBang,
|
||||
span: exp_span,
|
||||
},
|
||||
});
|
||||
let fm = fresh_mark();
|
||||
// mark before:
|
||||
let marked_before = mark_tts(tts.as_slice(), fm);
|
||||
|
||||
// The span that we pass to the expanders we want to
|
||||
// be the root of the call stack. That's the most
|
||||
// relevant span and it's the actual invocation of
|
||||
// the macro.
|
||||
let mac_span = original_span(fld.cx);
|
||||
|
||||
let expanded = match expandfun.expand(fld.cx,
|
||||
mac_span.call_site,
|
||||
marked_before.as_slice()).make_expr() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
fld.cx.span_err(
|
||||
pth.span,
|
||||
format!("non-expression macro in expression position: {}",
|
||||
extnamestr.get().as_slice()
|
||||
).as_slice());
|
||||
return DummyResult::raw_expr(e.span);
|
||||
}
|
||||
};
|
||||
|
||||
// mark after:
|
||||
mark_expr(expanded,fm)
|
||||
}
|
||||
_ => {
|
||||
fld.cx.span_err(
|
||||
pth.span,
|
||||
format!("'{}' is not a tt-style macro",
|
||||
extnamestr.get()).as_slice());
|
||||
return DummyResult::raw_expr(e.span);
|
||||
}
|
||||
};
|
||||
|
||||
// Keep going, outside-in.
|
||||
//
|
||||
// FIXME(pcwalton): Is it necessary to clone the
|
||||
// node here?
|
||||
let fully_expanded =
|
||||
fld.fold_expr(marked_after).node.clone();
|
||||
fld.cx.bt_pop();
|
||||
|
||||
box(GC) ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: fully_expanded,
|
||||
span: e.span,
|
||||
}
|
||||
let expanded_expr = match expand_mac_invoc(mac,&e.span,
|
||||
|r|{r.make_expr()},
|
||||
|expr,fm|{mark_expr(expr,fm)},
|
||||
fld) {
|
||||
Some(expr) => expr,
|
||||
None => {
|
||||
return DummyResult::raw_expr(e.span);
|
||||
}
|
||||
};
|
||||
|
||||
// Keep going, outside-in.
|
||||
//
|
||||
// FIXME(pcwalton): Is it necessary to clone the
|
||||
// node here?
|
||||
let fully_expanded =
|
||||
fld.fold_expr(expanded_expr).node.clone();
|
||||
fld.cx.bt_pop();
|
||||
|
||||
box(GC) ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: fully_expanded,
|
||||
span: e.span,
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,6 +182,88 @@ pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Expand a (not-ident-style) macro invocation. Returns the result
|
||||
/// of expansion and the mark which must be applied to the result.
|
||||
/// Our current interface doesn't allow us to apply the mark to the
|
||||
/// result until after calling make_expr, make_items, etc.
|
||||
fn expand_mac_invoc<T>(mac: &ast::Mac, span: &codemap::Span,
|
||||
parse_thunk: |Box<MacResult>|->Option<T>,
|
||||
mark_thunk: |T,Mrk|->T,
|
||||
fld: &mut MacroExpander)
|
||||
-> Option<T> {
|
||||
match (*mac).node {
|
||||
// it would almost certainly be cleaner to pass the whole
|
||||
// macro invocation in, rather than pulling it apart and
|
||||
// marking the tts and the ctxt separately. This also goes
|
||||
// for the other three macro invocation chunks of code
|
||||
// in this file.
|
||||
// Token-tree macros:
|
||||
MacInvocTT(ref pth, ref tts, _) => {
|
||||
if pth.segments.len() > 1u {
|
||||
fld.cx.span_err(pth.span,
|
||||
"expected macro name without module \
|
||||
separators");
|
||||
// let compilation continue
|
||||
return None;
|
||||
}
|
||||
let extname = pth.segments.get(0).identifier;
|
||||
let extnamestr = token::get_ident(extname);
|
||||
match fld.extsbox.find(&extname.name) {
|
||||
None => {
|
||||
fld.cx.span_err(
|
||||
pth.span,
|
||||
format!("macro undefined: '{}!'",
|
||||
extnamestr.get()).as_slice());
|
||||
|
||||
// let compilation continue
|
||||
None
|
||||
}
|
||||
Some(&NormalTT(ref expandfun, exp_span)) => {
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: *span,
|
||||
callee: NameAndSpan {
|
||||
name: extnamestr.get().to_string(),
|
||||
format: MacroBang,
|
||||
span: exp_span,
|
||||
},
|
||||
});
|
||||
let fm = fresh_mark();
|
||||
let marked_before = mark_tts(tts.as_slice(), fm);
|
||||
|
||||
// The span that we pass to the expanders we want to
|
||||
// be the root of the call stack. That's the most
|
||||
// relevant span and it's the actual invocation of
|
||||
// the macro.
|
||||
let mac_span = original_span(fld.cx);
|
||||
|
||||
let expanded = expandfun.expand(fld.cx,
|
||||
mac_span.call_site,
|
||||
marked_before.as_slice());
|
||||
let parsed = match parse_thunk(expanded) {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
fld.cx.span_err(
|
||||
pth.span,
|
||||
format!("non-expression macro in expression position: {}",
|
||||
extnamestr.get().as_slice()
|
||||
).as_slice());
|
||||
return None;
|
||||
}
|
||||
};
|
||||
Some(mark_thunk(parsed,fm))
|
||||
}
|
||||
_ => {
|
||||
fld.cx.span_err(
|
||||
pth.span,
|
||||
format!("'{}' is not a tt-style macro",
|
||||
extnamestr.get()).as_slice());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rename loop label and expand its loop body
|
||||
///
|
||||
/// The renaming procedure for loop is different in the sense that the loop
|
||||
@ -526,7 +544,7 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
|
||||
match expanded.make_items() {
|
||||
Some(items) => {
|
||||
items.move_iter()
|
||||
.flat_map(|i| mark_item(i, fm).move_iter())
|
||||
.map(|i| mark_item(i, fm))
|
||||
.flat_map(|i| fld.fold_item(i).move_iter())
|
||||
.collect()
|
||||
}
|
||||
@ -543,79 +561,27 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
|
||||
return items;
|
||||
}
|
||||
|
||||
// expand a stmt
|
||||
/// Expand a stmt
|
||||
//
|
||||
// I don't understand why this returns a vector... it looks like we're
|
||||
// half done adding machinery to allow macros to expand into multiple statements.
|
||||
fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<Gc<Stmt>> {
|
||||
// why the copying here and not in expand_expr?
|
||||
// looks like classic changed-in-only-one-place
|
||||
let (pth, tts, semi) = match s.node {
|
||||
StmtMac(ref mac, semi) => {
|
||||
match mac.node {
|
||||
MacInvocTT(ref pth, ref tts, _) => {
|
||||
(pth, (*tts).clone(), semi)
|
||||
}
|
||||
}
|
||||
}
|
||||
let (mac, semi) = match s.node {
|
||||
StmtMac(ref mac, semi) => (mac, semi),
|
||||
_ => return expand_non_macro_stmt(s, fld)
|
||||
};
|
||||
if pth.segments.len() > 1u {
|
||||
fld.cx.span_err(pth.span, "expected macro name without module separators");
|
||||
return SmallVector::zero();
|
||||
}
|
||||
let extname = pth.segments.get(0).identifier;
|
||||
let extnamestr = token::get_ident(extname);
|
||||
let marked_after = match fld.extsbox.find(&extname.name) {
|
||||
let expanded_stmt = match expand_mac_invoc(mac,&s.span,
|
||||
|r|{r.make_stmt()},
|
||||
|sts,mrk|{mark_stmt(sts,mrk)},
|
||||
fld) {
|
||||
Some(stmt) => stmt,
|
||||
None => {
|
||||
fld.cx.span_err(pth.span,
|
||||
format!("macro undefined: '{}!'",
|
||||
extnamestr).as_slice());
|
||||
return SmallVector::zero();
|
||||
}
|
||||
|
||||
Some(&NormalTT(ref expandfun, exp_span)) => {
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: s.span,
|
||||
callee: NameAndSpan {
|
||||
name: extnamestr.get().to_string(),
|
||||
format: MacroBang,
|
||||
span: exp_span,
|
||||
}
|
||||
});
|
||||
let fm = fresh_mark();
|
||||
// mark before expansion:
|
||||
let marked_tts = mark_tts(tts.as_slice(), fm);
|
||||
|
||||
// See the comment in expand_expr for why we want the original span,
|
||||
// not the current mac.span.
|
||||
let mac_span = original_span(fld.cx);
|
||||
|
||||
let expanded = match expandfun.expand(fld.cx,
|
||||
mac_span.call_site,
|
||||
marked_tts.as_slice()).make_stmt() {
|
||||
Some(stmt) => stmt,
|
||||
None => {
|
||||
fld.cx.span_err(pth.span,
|
||||
format!("non-statement macro in statement position: {}",
|
||||
extnamestr).as_slice());
|
||||
return SmallVector::zero();
|
||||
}
|
||||
};
|
||||
|
||||
mark_stmt(&*expanded,fm)
|
||||
}
|
||||
|
||||
_ => {
|
||||
fld.cx.span_err(pth.span, format!("'{}' is not a tt-style macro",
|
||||
extnamestr).as_slice());
|
||||
return SmallVector::zero();
|
||||
}
|
||||
};
|
||||
|
||||
// Keep going, outside-in.
|
||||
let fully_expanded = fld.fold_stmt(&*marked_after);
|
||||
if fully_expanded.is_empty() {
|
||||
fld.cx.span_err(pth.span, "macro didn't expand to a statement");
|
||||
return SmallVector::zero();
|
||||
}
|
||||
let fully_expanded = fld.fold_stmt(&*expanded_stmt);
|
||||
fld.cx.bt_pop();
|
||||
let fully_expanded: SmallVector<Gc<Stmt>> = fully_expanded.move_iter()
|
||||
.map(|s| box(GC) Spanned { span: s.span, node: s.node.clone() })
|
||||
@ -939,23 +905,42 @@ impl<'a> Folder for PatIdentRenamer<'a> {
|
||||
}
|
||||
|
||||
// expand a method
|
||||
fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> Gc<ast::Method> {
|
||||
fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast::Method>> {
|
||||
let id = fld.new_id(m.id);
|
||||
let (rewritten_fn_decl, rewritten_body)
|
||||
= expand_and_rename_fn_decl_and_block(m.decl,m.body,fld);
|
||||
match m.node {
|
||||
ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
|
||||
let (rewritten_fn_decl, rewritten_body)
|
||||
= expand_and_rename_fn_decl_and_block(decl,body,fld);
|
||||
SmallVector::one(box(GC) ast::Method {
|
||||
attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
|
||||
id: id,
|
||||
span: fld.new_span(m.span),
|
||||
node: ast::MethDecl(fld.fold_ident(ident),
|
||||
fold_generics(generics, fld),
|
||||
fld.fold_explicit_self(explicit_self),
|
||||
fn_style,
|
||||
rewritten_fn_decl,
|
||||
rewritten_body,
|
||||
vis)
|
||||
})
|
||||
},
|
||||
ast::MethMac(ref mac) => {
|
||||
let maybe_new_methods =
|
||||
expand_mac_invoc(mac, &m.span,
|
||||
|r|{r.make_methods()},
|
||||
|meths,mark|{
|
||||
meths.move_iter().map(|m|{mark_method(m,mark)})
|
||||
.collect()},
|
||||
fld);
|
||||
|
||||
// all of the other standard stuff:
|
||||
box(GC) ast::Method {
|
||||
id: id,
|
||||
ident: fld.fold_ident(m.ident),
|
||||
attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
|
||||
generics: fold_generics(&m.generics, fld),
|
||||
explicit_self: fld.fold_explicit_self(&m.explicit_self),
|
||||
fn_style: m.fn_style,
|
||||
decl: rewritten_fn_decl,
|
||||
body: rewritten_body,
|
||||
span: fld.new_span(m.span),
|
||||
vis: m.vis
|
||||
let new_methods = match maybe_new_methods {
|
||||
Some(methods) => methods,
|
||||
None => SmallVector::zero()
|
||||
};
|
||||
|
||||
// expand again if necessary
|
||||
new_methods.move_iter().flat_map(|m| fld.fold_method(m).move_iter()).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1013,7 +998,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
expand_arm(arm, self)
|
||||
}
|
||||
|
||||
fn fold_method(&mut self, method: Gc<ast::Method>) -> Gc<ast::Method> {
|
||||
fn fold_method(&mut self, method: Gc<ast::Method>) -> SmallVector<Gc<ast::Method>> {
|
||||
expand_method(method, self)
|
||||
}
|
||||
|
||||
@ -1128,12 +1113,19 @@ fn mark_pat(pat: Gc<ast::Pat>, m: Mrk) -> Gc<ast::Pat> {
|
||||
// apply a given mark to the given stmt. Used following the expansion of a macro.
|
||||
fn mark_stmt(expr: &ast::Stmt, m: Mrk) -> Gc<ast::Stmt> {
|
||||
Marker{mark:m}.fold_stmt(expr)
|
||||
.expect_one("marking a stmt didn't return a stmt")
|
||||
.expect_one("marking a stmt didn't return exactly one stmt")
|
||||
}
|
||||
|
||||
// apply a given mark to the given item. Used following the expansion of a macro.
|
||||
fn mark_item(expr: Gc<ast::Item>, m: Mrk) -> SmallVector<Gc<ast::Item>> {
|
||||
fn mark_item(expr: Gc<ast::Item>, m: Mrk) -> Gc<ast::Item> {
|
||||
Marker{mark:m}.fold_item(expr)
|
||||
.expect_one("marking an item didn't return exactly one item")
|
||||
}
|
||||
|
||||
// apply a given mark to the given item. Used following the expansion of a macro.
|
||||
fn mark_method(expr: Gc<ast::Method>, m: Mrk) -> Gc<ast::Method> {
|
||||
Marker{mark:m}.fold_method(expr)
|
||||
.expect_one("marking an item didn't return exactly one method")
|
||||
}
|
||||
|
||||
fn original_span(cx: &ExtCtxt) -> Gc<codemap::ExpnInfo> {
|
||||
@ -1527,9 +1519,9 @@ mod test {
|
||||
}
|
||||
|
||||
// macro_rules in method position. Sadly, unimplemented.
|
||||
#[ignore] #[test] fn macro_in_method_posn(){
|
||||
#[test] fn macro_in_method_posn(){
|
||||
expand_crate_str(
|
||||
"macro_rules! my_method (() => fn thirteen(&self) -> int {13})
|
||||
"macro_rules! my_method (() => (fn thirteen(&self) -> int {13}))
|
||||
struct A;
|
||||
impl A{ my_method!()}
|
||||
fn f(){A.thirteen;}".to_string());
|
||||
|
@ -38,7 +38,7 @@ struct ParserAnyMacro<'a> {
|
||||
impl<'a> ParserAnyMacro<'a> {
|
||||
/// Make sure we don't have any tokens left to parse, so we don't
|
||||
/// silently drop anything. `allow_semi` is so that "optional"
|
||||
/// semilons at the end of normal expressions aren't complained
|
||||
/// semicolons at the end of normal expressions aren't complained
|
||||
/// about e.g. the semicolon in `macro_rules! kapow( () => {
|
||||
/// fail!(); } )` doesn't get picked up by .parse_expr(), but it's
|
||||
/// allowed to be there.
|
||||
@ -73,6 +73,9 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
|
||||
let mut ret = SmallVector::zero();
|
||||
loop {
|
||||
let mut parser = self.parser.borrow_mut();
|
||||
// so... do outer attributes attached to the macro invocation
|
||||
// just disappear? This question applies to make_methods, as
|
||||
// well.
|
||||
match parser.parse_item_with_outer_attributes() {
|
||||
Some(item) => ret.push(item),
|
||||
None => break
|
||||
@ -81,6 +84,20 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
|
||||
self.ensure_complete_parse(false);
|
||||
Some(ret)
|
||||
}
|
||||
|
||||
fn make_methods(&self) -> Option<SmallVector<Gc<ast::Method>>> {
|
||||
let mut ret = SmallVector::zero();
|
||||
loop {
|
||||
let mut parser = self.parser.borrow_mut();
|
||||
match parser.token {
|
||||
EOF => break,
|
||||
_ => ret.push(parser.parse_method(None))
|
||||
}
|
||||
}
|
||||
self.ensure_complete_parse(false);
|
||||
Some(ret)
|
||||
}
|
||||
|
||||
fn make_stmt(&self) -> Option<Gc<ast::Stmt>> {
|
||||
let attrs = self.parser.borrow_mut().parse_outer_attributes();
|
||||
let ret = self.parser.borrow_mut().parse_stmt(attrs);
|
||||
|
@ -114,7 +114,7 @@ pub trait Folder {
|
||||
noop_fold_type_method(m, self)
|
||||
}
|
||||
|
||||
fn fold_method(&mut self, m: Gc<Method>) -> Gc<Method> {
|
||||
fn fold_method(&mut self, m: Gc<Method>) -> SmallVector<Gc<Method>> {
|
||||
noop_fold_method(&*m, self)
|
||||
}
|
||||
|
||||
@ -465,10 +465,16 @@ fn fold_interpolated<T: Folder>(nt : &token::Nonterminal, fld: &mut T) -> token:
|
||||
match *nt {
|
||||
token::NtItem(item) =>
|
||||
token::NtItem(fld.fold_item(item)
|
||||
// this is probably okay, because the only folds likely
|
||||
// to peek inside interpolated nodes will be renamings/markings,
|
||||
// which map single items to single items
|
||||
.expect_one("expected fold to produce exactly one item")),
|
||||
token::NtBlock(block) => token::NtBlock(fld.fold_block(block)),
|
||||
token::NtStmt(stmt) =>
|
||||
token::NtStmt(fld.fold_stmt(stmt)
|
||||
// this is probably okay, because the only folds likely
|
||||
// to peek inside interpolated nodes will be renamings/markings,
|
||||
// which map single items to single items
|
||||
.expect_one("expected fold to produce exactly one statement")),
|
||||
token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)),
|
||||
token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)),
|
||||
@ -683,15 +689,26 @@ pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_
|
||||
ItemImpl(fold_generics(generics, folder),
|
||||
ifce.as_ref().map(|p| fold_trait_ref(p, folder)),
|
||||
folder.fold_ty(ty),
|
||||
methods.iter().map(|x| folder.fold_method(*x)).collect()
|
||||
methods.iter().flat_map(|x| folder.fold_method(*x).move_iter()).collect()
|
||||
)
|
||||
}
|
||||
ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
|
||||
let methods = methods.iter().map(|method| {
|
||||
match *method {
|
||||
Required(ref m) => Required(folder.fold_type_method(m)),
|
||||
Provided(method) => Provided(folder.fold_method(method))
|
||||
}
|
||||
let methods = methods.iter().flat_map(|method| {
|
||||
let r = match *method {
|
||||
Required(ref m) =>
|
||||
SmallVector::one(Required(folder.fold_type_method(m))).move_iter(),
|
||||
Provided(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::TraitMethod> =
|
||||
folder.fold_method(method).move_iter()
|
||||
.map(|m| Provided(m)).collect();
|
||||
methods.move_iter()
|
||||
}
|
||||
};
|
||||
r
|
||||
}).collect();
|
||||
ItemTrait(fold_generics(generics, folder),
|
||||
unbound.clone(),
|
||||
@ -791,20 +808,27 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> Gc<Method> {
|
||||
// Default fold over a method.
|
||||
// Invariant: produces exactly one method.
|
||||
pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> SmallVector<Gc<Method>> {
|
||||
let id = folder.new_id(m.id); // Needs to be first, for ast_map.
|
||||
box(GC) Method {
|
||||
id: id,
|
||||
ident: folder.fold_ident(m.ident),
|
||||
SmallVector::one(box(GC) Method {
|
||||
attrs: m.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
|
||||
generics: fold_generics(&m.generics, folder),
|
||||
explicit_self: folder.fold_explicit_self(&m.explicit_self),
|
||||
fn_style: m.fn_style,
|
||||
decl: folder.fold_fn_decl(&*m.decl),
|
||||
body: folder.fold_block(m.body),
|
||||
id: id,
|
||||
span: folder.new_span(m.span),
|
||||
vis: m.vis
|
||||
}
|
||||
node: match m.node {
|
||||
MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
|
||||
MethDecl(folder.fold_ident(ident),
|
||||
fold_generics(generics, folder),
|
||||
folder.fold_explicit_self(explicit_self),
|
||||
fn_style,
|
||||
folder.fold_fn_decl(&*decl),
|
||||
folder.fold_block(body),
|
||||
vis)
|
||||
},
|
||||
MethMac(ref mac) => MethMac(folder.fold_mac(mac)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn noop_fold_pat<T: Folder>(p: Gc<Pat>, folder: &mut T) -> Gc<Pat> {
|
||||
|
@ -1249,16 +1249,10 @@ impl<'a> Parser<'a> {
|
||||
p.parse_inner_attrs_and_block();
|
||||
let attrs = attrs.append(inner_attrs.as_slice());
|
||||
Provided(box(GC) ast::Method {
|
||||
ident: ident,
|
||||
attrs: attrs,
|
||||
generics: generics,
|
||||
explicit_self: explicit_self,
|
||||
fn_style: style,
|
||||
decl: d,
|
||||
body: body,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: mk_sp(lo, hi),
|
||||
vis: vis,
|
||||
node: ast::MethDecl(ident, generics, explicit_self, style, d, body, vis)
|
||||
})
|
||||
}
|
||||
|
||||
@ -3252,6 +3246,7 @@ impl<'a> Parser<'a> {
|
||||
} else if is_ident(&self.token)
|
||||
&& !token::is_any_keyword(&self.token)
|
||||
&& self.look_ahead(1, |t| *t == token::NOT) {
|
||||
// it's a macro invocation:
|
||||
|
||||
check_expected_item(self, !item_attrs.is_empty());
|
||||
|
||||
@ -4027,7 +4022,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Parse a method in a trait impl, starting with `attrs` attributes.
|
||||
fn parse_method(&mut self,
|
||||
pub fn parse_method(&mut self,
|
||||
already_parsed_attrs: Option<Vec<Attribute>>) -> Gc<Method> {
|
||||
let next_attrs = self.parse_outer_attributes();
|
||||
let attrs = match already_parsed_attrs {
|
||||
@ -4037,28 +4032,50 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let lo = self.span.lo;
|
||||
|
||||
let visa = self.parse_visibility();
|
||||
let fn_style = self.parse_fn_style();
|
||||
let ident = self.parse_ident();
|
||||
let generics = self.parse_generics();
|
||||
let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
|
||||
p.parse_arg()
|
||||
});
|
||||
// code copied from parse_macro_use_or_failure... abstraction!
|
||||
let (method_, hi, new_attrs) = {
|
||||
if !token::is_any_keyword(&self.token)
|
||||
&& self.look_ahead(1, |t| *t == token::NOT)
|
||||
&& (self.look_ahead(2, |t| *t == token::LPAREN)
|
||||
|| self.look_ahead(2, |t| *t == token::LBRACE)) {
|
||||
// method macro.
|
||||
let pth = self.parse_path(NoTypesAllowed).path;
|
||||
self.expect(&token::NOT);
|
||||
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
|
||||
let hi = body.span.hi;
|
||||
let attrs = attrs.append(inner_attrs.as_slice());
|
||||
// eat a matched-delimiter token tree:
|
||||
let tts = match token::close_delimiter_for(&self.token) {
|
||||
Some(ket) => {
|
||||
self.bump();
|
||||
self.parse_seq_to_end(&ket,
|
||||
seq_sep_none(),
|
||||
|p| p.parse_token_tree())
|
||||
}
|
||||
None => self.fatal("expected open delimiter")
|
||||
};
|
||||
let m_ = ast::MacInvocTT(pth, tts, EMPTY_CTXT);
|
||||
let m: ast::Mac = codemap::Spanned { node: m_,
|
||||
span: mk_sp(self.span.lo,
|
||||
self.span.hi) };
|
||||
(ast::MethMac(m), self.span.hi, attrs)
|
||||
} else {
|
||||
let visa = self.parse_visibility();
|
||||
let fn_style = self.parse_fn_style();
|
||||
let ident = self.parse_ident();
|
||||
let generics = self.parse_generics();
|
||||
let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
|
||||
p.parse_arg()
|
||||
});
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
|
||||
let new_attrs = attrs.append(inner_attrs.as_slice());
|
||||
(ast::MethDecl(ident, generics, explicit_self, fn_style, decl, body, visa),
|
||||
body.span.hi, new_attrs)
|
||||
}
|
||||
};
|
||||
box(GC) ast::Method {
|
||||
ident: ident,
|
||||
attrs: attrs,
|
||||
generics: generics,
|
||||
explicit_self: explicit_self,
|
||||
fn_style: fn_style,
|
||||
decl: decl,
|
||||
body: body,
|
||||
attrs: new_attrs,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: mk_sp(lo, hi),
|
||||
vis: visa,
|
||||
node: method_,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,6 +245,10 @@ pub fn arg_to_string(arg: &ast::Arg) -> String {
|
||||
to_string(|s| s.print_arg(arg))
|
||||
}
|
||||
|
||||
pub fn mac_to_string(arg: &ast::Mac) -> String {
|
||||
to_string(|s| s.print_mac(arg))
|
||||
}
|
||||
|
||||
pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
|
||||
match vis {
|
||||
ast::Public => format!("pub {}", s),
|
||||
@ -342,6 +346,7 @@ impl<'a> State<'a> {
|
||||
match self.s.last_token() { pp::End => true, _ => false }
|
||||
}
|
||||
|
||||
// is this the beginning of a line?
|
||||
pub fn is_bol(&mut self) -> bool {
|
||||
self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok()
|
||||
}
|
||||
@ -627,6 +632,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pretty-print an item
|
||||
pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
|
||||
try!(self.hardbreak_if_not_bol());
|
||||
try!(self.maybe_print_comment(item.span.lo));
|
||||
@ -998,11 +1004,26 @@ impl<'a> State<'a> {
|
||||
try!(self.hardbreak_if_not_bol());
|
||||
try!(self.maybe_print_comment(meth.span.lo));
|
||||
try!(self.print_outer_attributes(meth.attrs.as_slice()));
|
||||
try!(self.print_fn(&*meth.decl, Some(meth.fn_style), abi::Rust,
|
||||
meth.ident, &meth.generics, Some(meth.explicit_self.node),
|
||||
meth.vis));
|
||||
try!(word(&mut self.s, " "));
|
||||
self.print_block_with_attrs(&*meth.body, meth.attrs.as_slice())
|
||||
match meth.node {
|
||||
ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
|
||||
try!(self.print_fn(&*decl, Some(fn_style), abi::Rust,
|
||||
ident, generics, Some(explicit_self.node),
|
||||
vis));
|
||||
try!(word(&mut self.s, " "));
|
||||
self.print_block_with_attrs(&*body, meth.attrs.as_slice())
|
||||
},
|
||||
ast::MethMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
|
||||
..}) => {
|
||||
// code copied from ItemMac:
|
||||
try!(self.print_path(pth, false));
|
||||
try!(word(&mut self.s, "! "));
|
||||
try!(self.cbox(indent_unit));
|
||||
try!(self.popen());
|
||||
try!(self.print_tts(tts.as_slice()));
|
||||
try!(self.pclose());
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_outer_attributes(&mut self,
|
||||
|
@ -560,15 +560,21 @@ pub fn walk_fn_decl<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||
pub fn walk_method_helper<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||
method: &Method,
|
||||
env: E) {
|
||||
visitor.visit_ident(method.span, method.ident, env.clone());
|
||||
visitor.visit_fn(&FkMethod(method.ident, &method.generics, method),
|
||||
&*method.decl,
|
||||
&*method.body,
|
||||
method.span,
|
||||
method.id,
|
||||
env.clone());
|
||||
for attr in method.attrs.iter() {
|
||||
visitor.visit_attribute(attr, env.clone());
|
||||
match method.node {
|
||||
MethDecl(ident, ref generics, _, _, decl, body, _) => {
|
||||
visitor.visit_ident(method.span, ident, env.clone());
|
||||
visitor.visit_fn(&FkMethod(ident, generics, method),
|
||||
decl,
|
||||
body,
|
||||
method.span,
|
||||
method.id,
|
||||
env.clone());
|
||||
for attr in method.attrs.iter() {
|
||||
visitor.visit_attribute(attr, env.clone());
|
||||
}
|
||||
|
||||
},
|
||||
MethMac(ref mac) => visitor.visit_mac(mac, env.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,8 +592,12 @@ pub fn walk_fn<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||
}
|
||||
FkMethod(_, generics, method) => {
|
||||
visitor.visit_generics(generics, env.clone());
|
||||
|
||||
visitor.visit_explicit_self(&method.explicit_self, env.clone());
|
||||
match method.node {
|
||||
MethDecl(_, _, ref explicit_self, _, _, _, _) =>
|
||||
visitor.visit_explicit_self(explicit_self, env.clone()),
|
||||
MethMac(ref mac) =>
|
||||
visitor.visit_mac(mac, env.clone())
|
||||
}
|
||||
}
|
||||
FkFnBlock(..) => {}
|
||||
}
|
||||
|
23
src/test/run-pass/macro-method-issue-4621.rs
Normal file
23
src/test/run-pass/macro-method-issue-4621.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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(macro_rules)]
|
||||
|
||||
struct A;
|
||||
|
||||
macro_rules! make_thirteen_method {() => (pub fn thirteen(&self)->int {13})}
|
||||
impl A { make_thirteen_method!() }
|
||||
|
||||
fn main() {
|
||||
assert_eq!(A.thirteen(),13);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user