Skip to content

Commit e3361bc

Browse files
committed
adjust fold to fold over interpolated items/exprs/etc.
Closes #15221
1 parent 2f73b78 commit e3361bc

File tree

2 files changed

+70
-19
lines changed

2 files changed

+70
-19
lines changed

src/libsyntax/ext/expand.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,7 +1281,7 @@ mod test {
12811281
0)
12821282
}
12831283

1284-
// FIXME #9384, match variable hygiene. Should expand into
1284+
// match variable hygiene. Should expand into
12851285
// fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
12861286
#[test] fn issue_9384(){
12871287
run_renaming_test(
@@ -1293,7 +1293,7 @@ mod test {
12931293
0)
12941294
}
12951295

1296-
// FIXME #15221, somehow pats aren't getting labeled correctly?
1296+
// interpolated nodes weren't getting labeled.
12971297
// should expand into
12981298
// fn main(){let g1_1 = 13; g1_1}}
12991299
#[test] fn pat_expand_issue_15221(){

src/libsyntax/fold.rs

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -389,36 +389,80 @@ fn fold_arg_<T: Folder>(a: &Arg, fld: &mut T) -> Arg {
389389
}
390390
}
391391

392-
// build a new vector of tts by appling the Folder's fold_ident to
393-
// all of the identifiers in the token trees.
394-
pub fn fold_tts<T: Folder>(tts: &[TokenTree], fld: &mut T) -> Vec<TokenTree> {
395-
tts.iter().map(|tt| {
396-
match *tt {
397-
TTTok(span, ref tok) =>
398-
TTTok(span,maybe_fold_ident(tok,fld)),
399-
TTDelim(ref tts) => TTDelim(Rc::new(fold_tts(tts.as_slice(), fld))),
400-
TTSeq(span, ref pattern, ref sep, is_optional) =>
392+
pub fn fold_tt<T: Folder>(tt: &TokenTree, fld: &mut T) -> TokenTree {
393+
match *tt {
394+
TTTok(span, ref tok) =>
395+
TTTok(span, fold_token(tok,fld)),
396+
TTDelim(ref tts) => TTDelim(Rc::new(fold_tts(tts.as_slice(), fld))),
397+
TTSeq(span, ref pattern, ref sep, is_optional) =>
401398
TTSeq(span,
402399
Rc::new(fold_tts(pattern.as_slice(), fld)),
403-
sep.as_ref().map(|tok|maybe_fold_ident(tok,fld)),
400+
sep.as_ref().map(|tok| fold_token(tok,fld)),
404401
is_optional),
405-
TTNonterminal(sp,ref ident) =>
402+
TTNonterminal(sp,ref ident) =>
406403
TTNonterminal(sp,fld.fold_ident(*ident))
407-
}
408-
}).collect()
404+
}
405+
}
406+
407+
pub fn fold_tts<T: Folder>(tts: &[TokenTree], fld: &mut T) -> Vec<TokenTree> {
408+
tts.iter().map(|tt| fold_tt(tt,fld)).collect()
409409
}
410410

411-
// apply ident folder if it's an ident, otherwise leave it alone
412-
fn maybe_fold_ident<T: Folder>(t: &token::Token, fld: &mut T) -> token::Token {
411+
412+
// apply ident folder if it's an ident, apply other folds to interpolated nodes
413+
fn fold_token<T: Folder>(t: &token::Token, fld: &mut T) -> token::Token {
413414
match *t {
414415
token::IDENT(id, followed_by_colons) => {
415416
token::IDENT(fld.fold_ident(id), followed_by_colons)
416417
}
417418
token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id)),
419+
token::INTERPOLATED(ref nt) => token::INTERPOLATED(fold_interpolated(nt,fld)),
418420
_ => (*t).clone()
419421
}
420422
}
421423

424+
// apply folder to elements of interpolated nodes
425+
//
426+
// NB: this can occur only when applying a fold to partially expanded code, where
427+
// parsed pieces have gotten implanted ito *other* macro invocations. This is relevant
428+
// for macro hygiene, but possibly not elsewhere.
429+
//
430+
// One problem here occurs because the types for fold_item, fold_stmt, etc. allow the
431+
// folder to return *multiple* items; this is a problem for the nodes here, because
432+
// they insist on having exactly one piece. One solution would be to mangle the fold
433+
// trait to include one-to-many and one-to-one versions of these entry points, but that
434+
// would probably confuse a lot of people and help very few. Instead, I'm just going
435+
// to put in dynamic checks. I think the performance impact of this will be pretty much
436+
// nonexistent. The danger is that someone will apply a fold to a partially expanded
437+
// node, and will be confused by the fact that their "fold_item" or "fold_stmt" isn't
438+
// getting called on NtItem or NtStmt nodes. Hopefully they'll wind up reading this
439+
// comment, and doing something appropriate.
440+
//
441+
// BTW, design choice: I considered just changing the type of, e.g., NtItem to contain
442+
// multiple items, but decided against it when I looked at parse_item_or_view_item and
443+
// tried to figure out what I would do with multiple items there....
444+
fn fold_interpolated<T: Folder>(nt : &token::Nonterminal, fld: &mut T) -> token::Nonterminal {
445+
match *nt {
446+
token::NtItem(item) =>
447+
token::NtItem(fld.fold_item(item)
448+
.expect_one("expected fold to produce exactly one item")),
449+
token::NtBlock(block) => token::NtBlock(fld.fold_block(block)),
450+
token::NtStmt(stmt) =>
451+
token::NtStmt(fld.fold_stmt(stmt)
452+
.expect_one("expected fold to produce exactly one statement")),
453+
token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)),
454+
token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)),
455+
token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)),
456+
token::NtIdent(ref id, is_mod_name) =>
457+
token::NtIdent(box fld.fold_ident(**id),is_mod_name),
458+
token::NtMeta(meta_item) => token::NtMeta(fold_meta_item_(meta_item,fld)),
459+
token::NtPath(ref path) => token::NtPath(box fld.fold_path(*path)),
460+
token::NtTT(tt) => token::NtTT(box (GC) fold_tt(tt,fld)),
461+
// it looks to me like we can leave out the matchers: token::NtMatchers(matchers)
462+
_ => (*nt).clone()
463+
}
464+
}
465+
422466
pub fn noop_fold_fn_decl<T: Folder>(decl: &FnDecl, fld: &mut T) -> P<FnDecl> {
423467
P(FnDecl {
424468
inputs: decl.inputs.iter().map(|x| fold_arg_(x, fld)).collect(), // bad copy
@@ -672,8 +716,15 @@ pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
672716
}
673717
}
674718

719+
// fold one item into possibly many items
675720
pub fn noop_fold_item<T: Folder>(i: &Item,
676721
folder: &mut T) -> SmallVector<Gc<Item>> {
722+
SmallVector::one(box(GC) noop_fold_item_(i,folder))
723+
}
724+
725+
726+
// fold one item into exactly one item
727+
pub fn noop_fold_item_<T: Folder>(i: &Item, folder: &mut T) -> Item {
677728
let id = folder.new_id(i.id); // Needs to be first, for ast_map.
678729
let node = folder.fold_item_underscore(&i.node);
679730
let ident = match node {
@@ -684,14 +735,14 @@ pub fn noop_fold_item<T: Folder>(i: &Item,
684735
_ => i.ident
685736
};
686737

687-
SmallVector::one(box(GC) Item {
738+
Item {
688739
id: id,
689740
ident: folder.fold_ident(ident),
690741
attrs: i.attrs.iter().map(|e| folder.fold_attribute(*e)).collect(),
691742
node: node,
692743
vis: i.vis,
693744
span: folder.new_span(i.span)
694-
})
745+
}
695746
}
696747

697748
pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem,

0 commit comments

Comments
 (0)