Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow macros in type expressions #15866

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/librustc/middle/typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,9 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
}
}
}
ast::TyMac(ref _mac) => {
tcx.sess.span_bug(ast_ty.span, "type macro not expanded");
}
ast::TyTypeof(_e) => {
tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
}
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,7 @@ pub enum Ty_ {
TyPath(Path, Option<OwnedSlice<TyParamBound>>, NodeId), // for #7264; see above
/// No-op; kept solely so that we can pretty-print faithfully
TyParen(P<Ty>),
TyMac(Mac),
TyTypeof(Gc<Expr>),
/// TyInfer means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
Expand Down
30 changes: 30 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ pub trait MacResult {
fn make_expr(&self) -> Option<Gc<ast::Expr>> {
None
}
/// Create an type.
fn make_ty(&self) -> Option<Gc<ast::Ty>> {
None
}
/// Create zero or more items.
fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
None
Expand Down Expand Up @@ -153,6 +157,20 @@ impl MacResult for MacExpr {
Some(self.e)
}
}
/// A convenience type for macros that return a single type.
pub struct MacTy {
t: Gc<ast::Ty>,
}
impl MacTy {
pub fn new(t: Gc<ast::Ty>) -> Box<MacResult> {
box MacTy { t: t } as Box<MacResult>
}
}
impl MacResult for MacTy {
fn make_ty(&self) -> Option<Gc<ast::Ty>> {
Some(self.t)
}
}
/// A convenience type for macros that return a single pattern.
pub struct MacPat {
p: Gc<ast::Pat>,
Expand Down Expand Up @@ -223,6 +241,15 @@ impl DummyResult {
}
}

/// A plain dummy type.
pub fn raw_ty(sp: Span) -> Gc<ast::Ty> {
box(GC) ast::Ty {
id: ast::DUMMY_NODE_ID,
node: ast::TyNil, // FIXME: Is this suitable?
span: sp,
}
}

/// A plain dummy pattern.
pub fn raw_pat(sp: Span) -> Gc<ast::Pat> {
box(GC) ast::Pat {
Expand All @@ -238,6 +265,9 @@ impl MacResult for DummyResult {
fn make_expr(&self) -> Option<Gc<ast::Expr>> {
Some(DummyResult::raw_expr(self.span))
}
fn make_ty(&self) -> Option<Gc<ast::Ty>> {
Some(DummyResult::raw_ty(self.span))
}
fn make_pat(&self) -> Option<Gc<ast::Pat>> {
Some(DummyResult::raw_pat(self.span))
}
Expand Down
54 changes: 51 additions & 3 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ast::{P, Block, Crate, DeclLocal, ExprMac, PatMac};
use ast::{P, Block, Crate, DeclLocal, ExprMac, PatMac, TyMac};
use ast::{Local, Ident, MacInvocTT};
use ast::{ItemMac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
use ast::TokenTree;
Expand All @@ -31,6 +31,36 @@ use util::small_vector::SmallVector;

use std::gc::{Gc, GC};

pub fn expand_ty(ty: Gc<ast::Ty>, fld: &mut MacroExpander) -> Gc<ast::Ty> {
match ty.node {
TyMac(ref mac) => {
let expanded_ty = match expand_mac_invoc(mac,&ty.span,
|r|{r.make_ty()},
|ty,fm|{mark_ty(ty,fm)},
fld) {
Some(ty) => ty,
None => {
return DummyResult::raw_ty(ty.span);
}
};

// Keep going, outside-in.
//
// FIXME(pcwalton): Is it necessary to clone the
// node here?
let fully_expanded =
fld.fold_ty(expanded_ty).node.clone();
fld.cx.bt_pop();

box(GC) ast::Ty {
id: ast::DUMMY_NODE_ID,
node: fully_expanded,
span: ty.span,
}
}
_ => noop_fold_ty(ty, fld)
}
}

pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
match e.node {
Expand Down Expand Up @@ -616,13 +646,15 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
} => {
// take it apart:
let Local {
ty: _,
ty: ty,
pat: pat,
init: init,
id: id,
span: span,
source: source,
} = **local;
// expand the ty (it might contain macro uses):
let expanded_ty = fld.fold_ty(ty);
// expand the pat (it might contain macro uses):
let expanded_pat = fld.fold_pat(pat);
// find the PatIdents in the pattern:
Expand All @@ -646,7 +678,7 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
let new_init_opt = init.map(|e| fld.fold_expr(e));
let rewritten_local =
box(GC) Local {
ty: local.ty,
ty: expanded_ty,
pat: rewritten_pat,
init: new_init_opt,
id: id,
Expand Down Expand Up @@ -988,6 +1020,10 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
expand_pat(pat, self)
}

fn fold_ty(&mut self, ty: Gc<ast::Ty>) -> Gc<ast::Ty> {
expand_ty(ty, self)
}

fn fold_item(&mut self, item: Gc<ast::Item>) -> SmallVector<Gc<ast::Item>> {
expand_item(item, self)
}
Expand Down Expand Up @@ -1115,6 +1151,11 @@ fn mark_expr(expr: Gc<ast::Expr>, m: Mrk) -> Gc<ast::Expr> {
Marker{mark:m}.fold_expr(expr)
}

// apply a given mark to the given type. Used following the expansion of a macro.
fn mark_ty(ty: Gc<ast::Ty>, m: Mrk) -> Gc<ast::Ty> {
Marker{mark:m}.fold_ty(ty)
}

// apply a given mark to the given pattern. Used following the expansion of a macro.
fn mark_pat(pat: Gc<ast::Pat>, m: Mrk) -> Gc<ast::Pat> {
Marker{mark:m}.fold_pat(pat)
Expand Down Expand Up @@ -1528,6 +1569,13 @@ mod test {
0)
}

// macro_rules in type
#[test] fn macro_in_type_posn(){
expand_crate_str(
"macro_rules! type_macro (()=>(int))
fn f(x: type_macro!()){}".to_string());
}

// macro_rules in method position. Sadly, unimplemented.
#[test] fn macro_in_method_posn(){
expand_crate_str(
Expand Down
5 changes: 5 additions & 0 deletions src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ impl<'a> ParserAnyMacro<'a> {
}

impl<'a> MacResult for ParserAnyMacro<'a> {
fn make_ty(&self) -> Option<Gc<ast::Ty>> {
let ret = self.parser.borrow_mut().parse_ty(true); // Allow plus in types?
self.ensure_complete_parse(true);
Some(ret)
}
fn make_expr(&self) -> Option<Gc<ast::Expr>> {
let ret = self.parser.borrow_mut().parse_expr();
self.ensure_complete_parse(true);
Expand Down
123 changes: 64 additions & 59 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,65 +160,7 @@ pub trait Folder {
}

fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
let id = self.new_id(t.id);
let node = match t.node {
TyNil | TyBot | TyInfer => t.node.clone(),
TyBox(ty) => TyBox(self.fold_ty(ty)),
TyUniq(ty) => TyUniq(self.fold_ty(ty)),
TyVec(ty) => TyVec(self.fold_ty(ty)),
TyPtr(ref mt) => TyPtr(fold_mt(mt, self)),
TyRptr(ref region, ref mt) => {
TyRptr(fold_opt_lifetime(region, self), fold_mt(mt, self))
}
TyClosure(ref f, ref region) => {
TyClosure(box(GC) ClosureTy {
fn_style: f.fn_style,
onceness: f.onceness,
bounds: fold_opt_bounds(&f.bounds, self),
decl: self.fold_fn_decl(&*f.decl),
lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(),
}, fold_opt_lifetime(region, self))
}
TyProc(ref f) => {
TyProc(box(GC) ClosureTy {
fn_style: f.fn_style,
onceness: f.onceness,
bounds: fold_opt_bounds(&f.bounds, self),
decl: self.fold_fn_decl(&*f.decl),
lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(),
})
}
TyBareFn(ref f) => {
TyBareFn(box(GC) BareFnTy {
lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(),
fn_style: f.fn_style,
abi: f.abi,
decl: self.fold_fn_decl(&*f.decl)
})
}
TyUnboxedFn(ref f) => {
TyUnboxedFn(box(GC) UnboxedFnTy {
decl: self.fold_fn_decl(&*f.decl),
})
}
TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()),
TyParen(ref ty) => TyParen(self.fold_ty(*ty)),
TyPath(ref path, ref bounds, id) => {
let id = self.new_id(id);
TyPath(self.fold_path(path),
fold_opt_bounds(bounds, self),
id)
}
TyFixedLengthVec(ty, e) => {
TyFixedLengthVec(self.fold_ty(ty), self.fold_expr(e))
}
TyTypeof(expr) => TyTypeof(self.fold_expr(expr)),
};
P(Ty {
id: id,
span: self.new_span(t.span),
node: node,
})
noop_fold_ty(t, self)
}

fn fold_mod(&mut self, m: &Mod) -> Mod {
Expand Down Expand Up @@ -1011,6 +953,69 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
}
}

pub fn noop_fold_ty<T: Folder>(t: P<Ty>, folder: &mut T) -> P<Ty> {
let id = folder.new_id(t.id);
let node = match t.node {
TyNil | TyBot | TyInfer => t.node.clone(),
TyBox(ty) => TyBox(folder.fold_ty(ty)),
TyUniq(ty) => TyUniq(folder.fold_ty(ty)),
TyVec(ty) => TyVec(folder.fold_ty(ty)),
TyPtr(ref mt) => TyPtr(fold_mt(mt, folder)),
TyRptr(ref region, ref mt) => {
TyRptr(fold_opt_lifetime(region, folder), fold_mt(mt, folder))
}
TyClosure(ref f, ref region) => {
TyClosure(box(GC) ClosureTy {
fn_style: f.fn_style,
onceness: f.onceness,
bounds: fold_opt_bounds(&f.bounds, folder),
decl: folder.fold_fn_decl(&*f.decl),
lifetimes: f.lifetimes.iter().map(|l| folder.fold_lifetime(l)).collect(),
}, fold_opt_lifetime(region, folder))
}
TyProc(ref f) => {
TyProc(box(GC) ClosureTy {
fn_style: f.fn_style,
onceness: f.onceness,
bounds: fold_opt_bounds(&f.bounds, folder),
decl: folder.fold_fn_decl(&*f.decl),
lifetimes: f.lifetimes.iter().map(|l| folder.fold_lifetime(l)).collect(),
})
}
TyBareFn(ref f) => {
TyBareFn(box(GC) BareFnTy {
lifetimes: f.lifetimes.iter().map(|l| folder.fold_lifetime(l)).collect(),
fn_style: f.fn_style,
abi: f.abi,
decl: folder.fold_fn_decl(&*f.decl)
})
}
TyUnboxedFn(ref f) => {
TyUnboxedFn(box(GC) UnboxedFnTy {
decl: folder.fold_fn_decl(&*f.decl),
})
}
TyTup(ref tys) => TyTup(tys.iter().map(|&ty| folder.fold_ty(ty)).collect()),
TyParen(ref ty) => TyParen(folder.fold_ty(*ty)),
TyMac(ref mac) => TyMac(folder.fold_mac(mac)),
TyPath(ref path, ref bounds, id) => {
let id = folder.new_id(id);
TyPath(folder.fold_path(path),
fold_opt_bounds(bounds, folder),
id)
}
TyFixedLengthVec(ty, e) => {
TyFixedLengthVec(folder.fold_ty(ty), folder.fold_expr(e))
}
TyTypeof(expr) => TyTypeof(folder.fold_expr(expr)),
};
P(Ty {
id: id,
span: folder.new_span(t.span),
node: node,
})
}

pub fn noop_fold_stmt<T: Folder>(s: &Stmt,
folder: &mut T) -> SmallVector<Gc<Stmt>> {
let nodes = match s.node {
Expand Down
23 changes: 21 additions & 2 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use ast::{TokenTree, TraitMethod, TraitRef, TTDelim, TTSeq, TTTok};
use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyRptr};
use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyMac, TyPtr, TyRptr};
use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock};
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
Expand Down Expand Up @@ -1456,7 +1456,26 @@ impl<'a> Parser<'a> {
path,
bounds
} = self.parse_path(mode);
TyPath(path, bounds, ast::DUMMY_NODE_ID)


if self.token == token::NOT {
// MACRO INVOCATION type
self.bump();

let ket = token::close_delimiter_for(&self.token)
.unwrap_or_else(|| self.fatal("expected open delimiter"));
self.bump();

let tts = self.parse_seq_to_end(&ket,
seq_sep_none(),
|p| p.parse_token_tree());
let hi = self.span.hi;

TyMac(codemap::Spanned {node: MacInvocTT(path, tts, EMPTY_CTXT),
span: mk_sp(lo, hi)})
} else {
TyPath(path, bounds, ast::DUMMY_NODE_ID)
}
} else if self.eat(&token::UNDERSCORE) {
// TYPE TO BE INFERRED
TyInfer
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,9 @@ impl<'a> State<'a> {
ast::TyPath(ref path, ref bounds, _) => {
try!(self.print_bounded_path(path, bounds));
}
ast::TyMac(ref mac) => {
try!(self.print_mac(mac));
}
ast::TyFixedLengthVec(ref ty, ref v) => {
try!(word(&mut self.s, "["));
try!(self.print_type(&**ty));
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,9 @@ pub fn walk_ty<E: Clone, V: Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
walk_ty_param_bounds(visitor, bounds, env.clone())
}
}
TyMac(ref macro) => {
visitor.visit_mac(macro, env.clone());
}
TyFixedLengthVec(ref ty, ref expression) => {
visitor.visit_ty(&**ty, env.clone());
visitor.visit_expr(&**expression, env)
Expand Down
Loading