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

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