refactor Method definition to make space for macros

This change propagates to many locations, but because of the
Macro Exterminator (or, more properly, the invariant that it
protects), macro invocations can't occur downstream of expansion.
This means that in librustc and librustdoc, extracting the
desired field can simply assume that it can't be a macro
invocation. Functions in ast_util abstract over this check.
This commit is contained in:
John Clements 2014-07-11 21:22:11 -07:00
parent e178ebf681
commit b0b4b3122a
25 changed files with 277 additions and 173 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,
&param_substs::empty(), mth.id, []);
}
local_def(mth.id)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -633,6 +633,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
}
@ -950,19 +952,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)]

View file

@ -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 {
@ -695,11 +705,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={})",

View file

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

View file

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

View file

@ -941,21 +941,25 @@ impl<'a> Folder for PatIdentRenamer<'a> {
// expand a method
fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> 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);
// 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,
id: id,
span: fld.new_span(m.span),
vis: m.vis
node: 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);
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) => fail!("expansion in method position not implemented yet!")
}
}
}

View file

@ -794,16 +794,21 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem,
pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> 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),
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)),
}
}
}

View file

@ -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)
})
}
@ -4049,16 +4043,10 @@ impl<'a> Parser<'a> {
let hi = body.span.hi;
let attrs = attrs.append(inner_attrs.as_slice());
box(GC) ast::Method {
ident: ident,
attrs: attrs,
generics: generics,
explicit_self: explicit_self,
fn_style: fn_style,
decl: decl,
body: body,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
vis: visa,
node: ast::MethDecl(ident, generics, explicit_self, fn_style, decl, body, visa),
}
}

View file

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

View file

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