Skip to content

Commit 0ddf6f4

Browse files
committed
auto merge of #15233 : jbclements/rust/match-var-hygiene-etc, r=cmr
This PR includes two big things and a bunch of little ones. 1) It enables hygiene for variables bound by 'match' expressions. 2) It fixes a bug discovered indirectly (#15221), wherein fold traversal failed to visit nonterminal nodes. 3) It fixes a small bug in the macro tutorial. It also adds tests for the first two, and makes a bunch of small comment improvements and cleanup.
2 parents afdfe40 + 04ced03 commit 0ddf6f4

22 files changed

+288
-177
lines changed

src/doc/guide-macros.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ macro_rules! biased_match_rec (
355355
_ => { $err }
356356
}
357357
);
358+
// Produce the requested values
358359
( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
359360
)
360361
@@ -364,7 +365,7 @@ macro_rules! biased_match (
364365
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
365366
binds $bind_res:ident
366367
) => (
367-
let ( $( $bind_res ),* ) = biased_match_rec!(
368+
let $bind_res = biased_match_rec!(
368369
$( ($e) ~ ($p) else $err ; )*
369370
binds $bind_res
370371
);

src/libsyntax/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ pub enum Decl_ {
401401
DeclItem(Gc<Item>),
402402
}
403403

404+
/// represents one arm of a 'match'
404405
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
405406
pub struct Arm {
406407
pub attrs: Vec<Attribute>,

src/libsyntax/ext/expand.rs

Lines changed: 135 additions & 97 deletions
Large diffs are not rendered by default.

src/libsyntax/ext/mtwt.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use std::collections::HashMap;
3030
// change the semantics--everything here is immutable--but
3131
// it should cut down on memory use *a lot*; applying a mark
3232
// to a tree containing 50 identifiers would otherwise generate
33+
// 50 new contexts
3334
pub struct SCTable {
3435
table: RefCell<Vec<SyntaxContext_>>,
3536
mark_memo: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
@@ -160,7 +161,7 @@ fn with_resolve_table_mut<T>(op: |&mut ResolveTable| -> T) -> T {
160161
}
161162

162163
// Resolve a syntax object to a name, per MTWT.
163-
// adding memorization to possibly resolve 500+ seconds in resolve for librustc (!)
164+
// adding memoization to resolve 500+ seconds in resolve for librustc (!)
164165
fn resolve_internal(id: Ident,
165166
table: &SCTable,
166167
resolve_table: &mut ResolveTable) -> Name {

src/libsyntax/fold.rs

Lines changed: 93 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub trait Folder {
8686
kind: sf.node.kind,
8787
id: id,
8888
ty: self.fold_ty(sf.node.ty),
89-
attrs: sf.node.attrs.iter().map(|e| fold_attribute_(*e, self)).collect()
89+
attrs: sf.node.attrs.iter().map(|e| self.fold_attribute(*e)).collect()
9090
},
9191
span: self.new_span(sf.span)
9292
}
@@ -118,7 +118,7 @@ pub trait Folder {
118118

119119
fn fold_arm(&mut self, a: &Arm) -> Arm {
120120
Arm {
121-
attrs: a.attrs.iter().map(|x| fold_attribute_(*x, self)).collect(),
121+
attrs: a.attrs.iter().map(|x| self.fold_attribute(*x)).collect(),
122122
pats: a.pats.iter().map(|x| self.fold_pat(*x)).collect(),
123123
guard: a.guard.map(|x| self.fold_expr(x)),
124124
body: self.fold_expr(a.body),
@@ -251,7 +251,7 @@ pub trait Folder {
251251
}
252252
}
253253

254-
let attrs = v.node.attrs.iter().map(|x| fold_attribute_(*x, self)).collect();
254+
let attrs = v.node.attrs.iter().map(|x| self.fold_attribute(*x)).collect();
255255

256256
let de = match v.node.disr_expr {
257257
Some(e) => Some(self.fold_expr(e)),
@@ -344,6 +344,21 @@ pub trait Folder {
344344
fn fold_lifetime(&mut self, l: &Lifetime) -> Lifetime {
345345
noop_fold_lifetime(l, self)
346346
}
347+
348+
//used in noop_fold_item and noop_fold_crate
349+
fn fold_attribute(&mut self, at: Attribute) -> Attribute {
350+
Spanned {
351+
span: self.new_span(at.span),
352+
node: ast::Attribute_ {
353+
id: at.node.id,
354+
style: at.node.style,
355+
value: fold_meta_item_(at.node.value, self),
356+
is_sugared_doc: at.node.is_sugared_doc
357+
}
358+
}
359+
}
360+
361+
347362
}
348363

349364
/* some little folds that probably aren't useful to have in Folder itself*/
@@ -364,19 +379,6 @@ fn fold_meta_item_<T: Folder>(mi: Gc<MetaItem>, fld: &mut T) -> Gc<MetaItem> {
364379
span: fld.new_span(mi.span) }
365380
}
366381

367-
//used in noop_fold_item and noop_fold_crate
368-
fn fold_attribute_<T: Folder>(at: Attribute, fld: &mut T) -> Attribute {
369-
Spanned {
370-
span: fld.new_span(at.span),
371-
node: ast::Attribute_ {
372-
id: at.node.id,
373-
style: at.node.style,
374-
value: fold_meta_item_(at.node.value, fld),
375-
is_sugared_doc: at.node.is_sugared_doc
376-
}
377-
}
378-
}
379-
380382
//used in noop_fold_foreign_item and noop_fold_fn_decl
381383
fn fold_arg_<T: Folder>(a: &Arg, fld: &mut T) -> Arg {
382384
let id = fld.new_id(a.id); // Needs to be first, for ast_map.
@@ -387,53 +389,80 @@ fn fold_arg_<T: Folder>(a: &Arg, fld: &mut T) -> Arg {
387389
}
388390
}
389391

390-
// build a new vector of tts by appling the Folder's fold_ident to
391-
// all of the identifiers in the token trees.
392-
//
393-
// This is part of hygiene magic. As far as hygiene is concerned, there
394-
// are three types of let pattern bindings or loop labels:
395-
// - those defined and used in non-macro part of the program
396-
// - those used as part of macro invocation arguments
397-
// - those defined and used inside macro definitions
398-
// Lexically, type 1 and 2 are in one group and type 3 the other. If they
399-
// clash, in order for let and loop label to work hygienically, one group
400-
// or the other needs to be renamed. The problem is that type 2 and 3 are
401-
// parsed together (inside the macro expand function). After being parsed and
402-
// AST being constructed, they can no longer be distinguished from each other.
403-
//
404-
// For that reason, type 2 let bindings and loop labels are actually renamed
405-
// in the form of tokens instead of AST nodes, here. There are wasted effort
406-
// since many token::IDENT are not necessary part of let bindings and most
407-
// token::LIFETIME are certainly not loop labels. But we can't tell in their
408-
// token form. So this is less ideal and hacky but it works.
409-
pub fn fold_tts<T: Folder>(tts: &[TokenTree], fld: &mut T) -> Vec<TokenTree> {
410-
tts.iter().map(|tt| {
411-
match *tt {
412-
TTTok(span, ref tok) =>
413-
TTTok(span,maybe_fold_ident(tok,fld)),
414-
TTDelim(ref tts) => TTDelim(Rc::new(fold_tts(tts.as_slice(), fld))),
415-
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) =>
416398
TTSeq(span,
417399
Rc::new(fold_tts(pattern.as_slice(), fld)),
418-
sep.as_ref().map(|tok|maybe_fold_ident(tok,fld)),
400+
sep.as_ref().map(|tok| fold_token(tok,fld)),
419401
is_optional),
420-
TTNonterminal(sp,ref ident) =>
402+
TTNonterminal(sp,ref ident) =>
421403
TTNonterminal(sp,fld.fold_ident(*ident))
422-
}
423-
}).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()
424409
}
425410

426-
// apply ident folder if it's an ident, otherwise leave it alone
427-
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 {
428414
match *t {
429415
token::IDENT(id, followed_by_colons) => {
430416
token::IDENT(fld.fold_ident(id), followed_by_colons)
431417
}
432418
token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id)),
419+
token::INTERPOLATED(ref nt) => token::INTERPOLATED(fold_interpolated(nt,fld)),
433420
_ => (*t).clone()
434421
}
435422
}
436423

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+
437466
pub fn noop_fold_fn_decl<T: Folder>(decl: &FnDecl, fld: &mut T) -> P<FnDecl> {
438467
P(FnDecl {
439468
inputs: decl.inputs.iter().map(|x| fold_arg_(x, fld)).collect(), // bad copy
@@ -526,7 +555,7 @@ fn fold_struct_field<T: Folder>(f: &StructField, fld: &mut T) -> StructField {
526555
kind: f.node.kind,
527556
id: id,
528557
ty: fld.fold_ty(f.node.ty),
529-
attrs: f.node.attrs.iter().map(|a| fold_attribute_(*a, fld)).collect(),
558+
attrs: f.node.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
530559
},
531560
span: fld.new_span(f.span),
532561
}
@@ -578,7 +607,7 @@ pub fn noop_fold_view_item<T: Folder>(vi: &ViewItem, folder: &mut T)
578607
};
579608
ViewItem {
580609
node: inner_view_item,
581-
attrs: vi.attrs.iter().map(|a| fold_attribute_(*a, folder)).collect(),
610+
attrs: vi.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
582611
vis: vi.vis,
583612
span: folder.new_span(vi.span),
584613
}
@@ -658,7 +687,7 @@ pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMeth
658687
TypeMethod {
659688
id: id,
660689
ident: fld.fold_ident(m.ident),
661-
attrs: m.attrs.iter().map(|a| fold_attribute_(*a, fld)).collect(),
690+
attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
662691
fn_style: m.fn_style,
663692
decl: fld.fold_fn_decl(&*m.decl),
664693
generics: fold_generics(&m.generics, fld),
@@ -681,14 +710,21 @@ pub fn noop_fold_mod<T: Folder>(m: &Mod, folder: &mut T) -> Mod {
681710
pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
682711
Crate {
683712
module: folder.fold_mod(&c.module),
684-
attrs: c.attrs.iter().map(|x| fold_attribute_(*x, folder)).collect(),
713+
attrs: c.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
685714
config: c.config.iter().map(|x| fold_meta_item_(*x, folder)).collect(),
686715
span: folder.new_span(c.span),
687716
}
688717
}
689718

719+
// fold one item into possibly many items
690720
pub fn noop_fold_item<T: Folder>(i: &Item,
691721
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 {
692728
let id = folder.new_id(i.id); // Needs to be first, for ast_map.
693729
let node = folder.fold_item_underscore(&i.node);
694730
let ident = match node {
@@ -699,14 +735,14 @@ pub fn noop_fold_item<T: Folder>(i: &Item,
699735
_ => i.ident
700736
};
701737

702-
SmallVector::one(box(GC) Item {
738+
Item {
703739
id: id,
704740
ident: folder.fold_ident(ident),
705-
attrs: i.attrs.iter().map(|e| fold_attribute_(*e, folder)).collect(),
741+
attrs: i.attrs.iter().map(|e| folder.fold_attribute(*e)).collect(),
706742
node: node,
707743
vis: i.vis,
708744
span: folder.new_span(i.span)
709-
})
745+
}
710746
}
711747

712748
pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem,
@@ -715,7 +751,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem,
715751
box(GC) ForeignItem {
716752
id: id,
717753
ident: folder.fold_ident(ni.ident),
718-
attrs: ni.attrs.iter().map(|x| fold_attribute_(*x, folder)).collect(),
754+
attrs: ni.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
719755
node: match ni.node {
720756
ForeignItemFn(ref fdec, ref generics) => {
721757
ForeignItemFn(P(FnDecl {
@@ -739,7 +775,7 @@ pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> Gc<Method> {
739775
box(GC) Method {
740776
id: id,
741777
ident: folder.fold_ident(m.ident),
742-
attrs: m.attrs.iter().map(|a| fold_attribute_(*a, folder)).collect(),
778+
attrs: m.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
743779
generics: fold_generics(&m.generics, folder),
744780
explicit_self: folder.fold_explicit_self(&m.explicit_self),
745781
fn_style: m.fn_style,

src/libsyntax/parse/token.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ pub enum Nonterminal {
114114
NtPat( Gc<ast::Pat>),
115115
NtExpr(Gc<ast::Expr>),
116116
NtTy( P<ast::Ty>),
117+
// see IDENT, above, for meaning of bool in NtIdent:
117118
NtIdent(Box<ast::Ident>, bool),
118119
NtMeta(Gc<ast::MetaItem>), // stuff inside brackets for attributes
119120
NtPath(Box<ast::Path>),

src/test/bench/msgsend-ring-mutex-arcs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
// This also serves as a pipes test, because Arcs are implemented with pipes.
1717

18-
// ignore-pretty FIXME #15189
18+
// no-pretty-expanded FIXME #15189
1919

2020
extern crate time;
2121

src/test/bench/msgsend-ring-rw-arcs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
// This also serves as a pipes test, because Arcs are implemented with pipes.
1717

18-
// ignore-pretty FIXME #15189
18+
// no-pretty-expanded FIXME #15189
1919

2020
extern crate time;
2121

src/test/bench/shootout-meteor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
3939
// OF THE POSSIBILITY OF SUCH DAMAGE.
4040

41-
// ignore-pretty FIXME #15189
41+
// no-pretty-expanded FIXME #15189
4242

4343
#![feature(phase)]
4444
#[phase(plugin)] extern crate green;

src/test/bench/shootout-spectralnorm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-pretty FIXME #15189
11+
// no-pretty-expanded FIXME #15189
1212

1313
#![feature(phase)]
1414
#![allow(non_snake_case_functions)]

src/test/run-pass/backtrace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-pretty FIXME #15189
11+
// no-pretty-expanded FIXME #15189
1212
// ignore-win32 FIXME #13259
1313
extern crate native;
1414

src/test/run-pass/deriving-cmp-generic-enum.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-pretty FIXME #15189
11+
// no-pretty-expanded FIXME #15189
1212

1313
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
1414
enum E<T> {

src/test/run-pass/deriving-cmp-generic-struct-enum.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-pretty FIXME #15189
11+
// no-pretty-expanded FIXME #15189
1212

1313
#![feature(struct_variant)]
1414

src/test/run-pass/deriving-cmp-generic-struct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-pretty FIXME #15189
11+
// no-pretty-expanded FIXME #15189
1212

1313
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
1414
struct S<T> {

src/test/run-pass/deriving-cmp-generic-tuple-struct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-pretty FIXME #15189
11+
// no-pretty-expanded FIXME #15189
1212

1313
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
1414
struct TS<T>(T,T);

0 commit comments

Comments
 (0)