Skip to content

quote_* macros lose hygiene, gensym and span information #15962

Closed
@huonw

Description

@huonw

The quote_* macros stringify everything, which loses vital information.

// gensym.rs
#![feature(plugin_registrar, managed_boxes, quote)]
#![crate_type = "dylib"]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::{Span};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("test_quote", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, _: &[ast::TokenTree]) -> Box<base::MacResult> {
    // expand to `{ let foo = true; foo }`, with a gensym'd foo.
    let ident = token::gensym_ident("foo");
    let decl = quote_stmt!(&mut *cx, let $ident = true;);
    let result = cx.expr_block(cx.block(sp, vec![decl], Some(cx.expr_ident(sp, ident))));

    println!("{}", result);

    MacExpr::new(result)
}
// test_gensym.rs
#![feature(phase)]

#[phase(plugin)] extern crate gensym;

fn main() {
    let a = test_quote!();
}
[...]
test_gensym.rs:6:13: 6:27 error: unresolved name `foo`.
test_gensym.rs:6     let a = test_quote!();
                             ^~~~~~~~~~~~~~
test_gensym.rs:1:1: 7:1 note: in expansion of test_quote!
test_gensym.rs:6:13: 6:27 note: expansion site
error: aborting due to previous error

Beautified/trimmed version of the output of the println!

Expr {
    node: ExprBlock(Block {
        view_items: [],
        stmts: [Spanned {
            node: StmtDecl(Spanned {
                node: DeclLocal(Local {
                    ty: Ty {
                        node: TyInfer,
                        span: Span {
                            lo: BytePos(7677),
                            hi: BytePos(7677),
                            expn_info: None
                        }
                    },
                    pat: Pat {
                        node: PatIdent(BindByValue(MutImmutable), Spanned {
                            node: "foo" (269),
                            span: Span {
                                lo: BytePos(7677),
                                hi: BytePos(7680),
                                expn_info: None
                            }
                        }, None),
                        span: Span {
                            lo: BytePos(7677),
                            hi: BytePos(7680),
                            expn_info: None
                        }
                    },
                    init: Some(Expr {
                        node: ExprLit(Spanned {
                            node: LitBool(true),
                            span: Span {
                                lo: BytePos(83),
                                hi: BytePos(97),
                                expn_info: None
                            }
                        }),
                        span: Span {
                            lo: BytePos(83),
                            hi: BytePos(97),
                            expn_info: None
                        }
                    }),
                    span: Span {
                        lo: BytePos(7677),
                        hi: BytePos(97),
                        expn_info: None
                    },
                    source: LocalLet
                }),
            }, 4294967295),
        }],
        expr: Some(Expr {
            node: ExprPath(Path {
                global: false,
                segments: [PathSegment {
                    identifier: "foo" (268)# 0,
                    lifetimes: [],
                    types: OwnedSlice {
                        {}
                    }
                }]
            }),
        }),
        rules: DefaultBlock,
    }),
}

Of particular attention is the difference in Name between node: "foo" (269)
identifier: "foo" (268)# 0,, and also the 7677 etc. numbers in the spans inside theDeclLocal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-syntaxextArea: Syntax extensions

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions