Skip to content

Commit be93b29

Browse files
committed
rustc: Implement parsing and typechecking for "once fn"
1 parent 9aadfc3 commit be93b29

File tree

22 files changed

+266
-61
lines changed

22 files changed

+266
-61
lines changed

src/libsyntax/ast.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,25 @@ enum region_ {
10591059
re_named(ident)
10601060
}
10611061

1062+
#[auto_serialize]
1063+
#[auto_deserialize]
1064+
enum Onceness {
1065+
Once,
1066+
Many
1067+
}
1068+
1069+
impl Onceness : cmp::Eq {
1070+
pure fn eq(other: &Onceness) -> bool {
1071+
match (self, *other) {
1072+
(Once, Once) | (Many, Many) => true,
1073+
_ => false
1074+
}
1075+
}
1076+
pure fn ne(other: &Onceness) -> bool {
1077+
!self.eq(other)
1078+
}
1079+
}
1080+
10621081
#[auto_serialize]
10631082
#[auto_deserialize]
10641083
enum ty_ {
@@ -1070,7 +1089,7 @@ enum ty_ {
10701089
ty_ptr(mt),
10711090
ty_rptr(@region, mt),
10721091
ty_rec(~[ty_field]),
1073-
ty_fn(proto, purity, @~[ty_param_bound], fn_decl),
1092+
ty_fn(proto, purity, Onceness, @~[ty_param_bound], fn_decl),
10741093
ty_tup(~[@Ty]),
10751094
ty_path(@path, node_id),
10761095
ty_fixed_length(@Ty, Option<uint>),

src/libsyntax/fold.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -524,10 +524,11 @@ fn noop_fold_ty(t: ty_, fld: ast_fold) -> ty_ {
524524
ty_ptr(mt) => ty_ptr(fold_mt(mt, fld)),
525525
ty_rptr(region, mt) => ty_rptr(region, fold_mt(mt, fld)),
526526
ty_rec(fields) => ty_rec(vec::map(fields, |f| fold_field(*f, fld))),
527-
ty_fn(proto, purity, bounds, decl) =>
528-
ty_fn(proto, purity,
529-
@vec::map(*bounds,
530-
|x| fold_ty_param_bound(*x, fld)),
527+
ty_fn(proto, purity, onceness, bounds, decl) =>
528+
ty_fn(proto,
529+
purity,
530+
onceness,
531+
@vec::map(*bounds, |x| fold_ty_param_bound(*x, fld)),
531532
fold_fn_decl(decl, fld)),
532533
ty_tup(tys) => ty_tup(vec::map(tys, |ty| fld.fold_ty(*ty))),
533534
ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)),

src/libsyntax/parse/parser.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ impl Parser {
287287

288288
pure fn id_to_str(id: ident) -> @~str { self.sess.interner.get(id) }
289289

290-
fn parse_ty_fn(purity: ast::purity) -> ty_ {
290+
fn parse_ty_fn(purity: ast::purity, onceness: ast::Onceness) -> ty_ {
291291
let proto, bounds;
292292
if self.eat_keyword(~"extern") {
293293
self.expect_keyword(~"fn");
@@ -298,7 +298,17 @@ impl Parser {
298298
proto = self.parse_fn_ty_proto();
299299
bounds = self.parse_optional_ty_param_bounds();
300300
};
301-
ty_fn(proto, purity, bounds, self.parse_ty_fn_decl())
301+
ty_fn(proto, purity, onceness, bounds, self.parse_ty_fn_decl())
302+
}
303+
304+
fn parse_ty_fn_with_onceness(purity: ast::purity) -> ty_ {
305+
let onceness = self.parse_optional_onceness();
306+
self.parse_ty_fn(purity, onceness)
307+
}
308+
309+
fn parse_ty_fn_with_purity_and_onceness() -> ty_ {
310+
let purity = self.parse_optional_purity();
311+
self.parse_ty_fn_with_onceness(purity)
302312
}
303313

304314
fn parse_ty_fn_decl() -> fn_decl {
@@ -526,15 +536,18 @@ impl Parser {
526536
let region = self.parse_region_with_sep();
527537
let mt = self.parse_mt();
528538
ty_rptr(region, mt)
539+
} else if self.eat_keyword(~"once") {
540+
self.parse_ty_fn(ast::impure_fn, ast::Once)
529541
} else if self.eat_keyword(~"pure") {
530-
self.parse_ty_fn(ast::pure_fn)
542+
self.parse_ty_fn_with_onceness(ast::pure_fn)
531543
} else if self.eat_keyword(~"unsafe") {
532-
self.parse_ty_fn(ast::unsafe_fn)
544+
self.parse_ty_fn_with_onceness(ast::unsafe_fn)
533545
} else if self.is_keyword(~"fn") {
534-
self.parse_ty_fn(ast::impure_fn)
546+
self.parse_ty_fn_with_onceness(ast::impure_fn)
535547
} else if self.eat_keyword(~"extern") {
536548
self.expect_keyword(~"fn");
537-
ty_fn(proto_bare, ast::impure_fn, @~[], self.parse_ty_fn_decl())
549+
ty_fn(proto_bare, ast::impure_fn, ast::Many, @~[],
550+
self.parse_ty_fn_decl())
538551
} else if self.token == token::MOD_SEP || is_ident(self.token) {
539552
let path = self.parse_path_with_tps(colons_before_params);
540553
ty_path(path, self.get_id())
@@ -2275,6 +2288,20 @@ impl Parser {
22752288
self.get_id()), span: self.last_span}
22762289
}
22772290

2291+
fn parse_optional_purity() -> ast::purity {
2292+
if self.eat_keyword(~"pure") {
2293+
ast::pure_fn
2294+
} else if self.eat_keyword(~"unsafe") {
2295+
ast::unsafe_fn
2296+
} else {
2297+
ast::impure_fn
2298+
}
2299+
}
2300+
2301+
fn parse_optional_onceness() -> ast::Onceness {
2302+
if self.eat_keyword(~"once") { ast::Once } else { ast::Many }
2303+
}
2304+
22782305
fn parse_optional_ty_param_bounds() -> @~[ty_param_bound] {
22792306
let mut bounds = ~[];
22802307
if self.eat(token::COLON) {

src/libsyntax/parse/token.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ fn strict_keyword_table() -> HashMap<~str, ()> {
427427
~"if", ~"impl",
428428
~"let", ~"log", ~"loop",
429429
~"match", ~"mod", ~"move", ~"mut",
430+
~"once",
430431
~"priv", ~"pub", ~"pure",
431432
~"ref", ~"return",
432433
~"struct",

src/libsyntax/print/pprust.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,9 @@ fn print_type_ex(s: ps, &&ty: @ast::Ty, print_colons: bool) {
394394
commasep(s, inconsistent, elts, print_type);
395395
pclose(s);
396396
}
397-
ast::ty_fn(proto, purity, bounds, d) => {
398-
print_ty_fn(s, Some(proto), purity, bounds, d, None, None, None);
397+
ast::ty_fn(proto, purity, onceness, bounds, d) => {
398+
print_ty_fn(s, Some(proto), purity, onceness, bounds, d, None, None,
399+
None);
399400
}
400401
ast::ty_path(path, _) => print_path(s, path, print_colons),
401402
ast::ty_fixed_length(t, v) => {
@@ -804,7 +805,7 @@ fn print_ty_method(s: ps, m: ast::ty_method) {
804805
hardbreak_if_not_bol(s);
805806
maybe_print_comment(s, m.span.lo);
806807
print_outer_attributes(s, m.attrs);
807-
print_ty_fn(s, None, m.purity,
808+
print_ty_fn(s, None, m.purity, ast::Many,
808809
@~[], m.decl, Some(m.ident), Some(m.tps),
809810
Some(m.self_ty.node));
810811
word(s.s, ~";");
@@ -1273,7 +1274,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
12731274
cbox(s, indent_unit);
12741275
// head-box, will be closed by print-block at start
12751276
ibox(s, 0u);
1276-
word(s.s, fn_header_info_to_str(None, None, Some(proto),
1277+
word(s.s, fn_header_info_to_str(None, None, Some(proto), ast::Many,
12771278
ast::inherited));
12781279
print_fn_args_and_ret(s, decl, *cap_clause, None);
12791280
space(s.s);
@@ -1606,12 +1607,15 @@ fn print_self_ty(s: ps, self_ty: ast::self_ty_) -> bool {
16061607
return true;
16071608
}
16081609

1609-
fn print_fn(s: ps, decl: ast::fn_decl, purity: Option<ast::purity>,
1610+
fn print_fn(s: ps,
1611+
decl: ast::fn_decl,
1612+
purity: Option<ast::purity>,
16101613
name: ast::ident,
16111614
typarams: ~[ast::ty_param],
16121615
opt_self_ty: Option<ast::self_ty_>,
16131616
vis: ast::visibility) {
1614-
head(s, fn_header_info_to_str(opt_self_ty, purity, None, vis));
1617+
head(s, fn_header_info_to_str(opt_self_ty, purity, None, ast::Many,
1618+
vis));
16151619
print_ident(s, name);
16161620
print_type_params(s, typarams);
16171621
print_fn_args_and_ret(s, decl, ~[], opt_self_ty);
@@ -1831,14 +1835,17 @@ fn print_arg(s: ps, input: ast::arg) {
18311835
end(s);
18321836
}
18331837

1834-
fn print_ty_fn(s: ps, opt_proto: Option<ast::proto>, purity: ast::purity,
1838+
fn print_ty_fn(s: ps,
1839+
opt_proto: Option<ast::proto>,
1840+
purity: ast::purity,
1841+
onceness: ast::Onceness,
18351842
bounds: @~[ast::ty_param_bound],
18361843
decl: ast::fn_decl, id: Option<ast::ident>,
18371844
tps: Option<~[ast::ty_param]>,
18381845
opt_self_ty: Option<ast::self_ty_>) {
18391846
ibox(s, indent_unit);
18401847
word(s.s, fn_header_info_to_str(opt_self_ty, Some(purity), opt_proto,
1841-
ast::inherited));
1848+
onceness, ast::inherited));
18421849
print_bounds(s, bounds);
18431850
match id { Some(id) => { word(s.s, ~" "); print_ident(s, id); } _ => () }
18441851
match tps { Some(tps) => print_type_params(s, tps), _ => () }
@@ -2062,6 +2069,7 @@ fn next_comment(s: ps) -> Option<comments::cmnt> {
20622069
fn fn_header_info_to_str(opt_sty: Option<ast::self_ty_>,
20632070
opt_purity: Option<ast::purity>,
20642071
opt_p: Option<ast::proto>,
2072+
onceness: ast::Onceness,
20652073
vis: ast::visibility) -> ~str {
20662074

20672075
let mut s = visibility_qualified(vis, ~"");
@@ -2082,6 +2090,11 @@ fn fn_header_info_to_str(opt_sty: Option<ast::self_ty_>,
20822090
20832091
str::push_str(&mut s, opt_proto_to_str(opt_p));
20842092
2093+
match onceness {
2094+
ast::Once => str::push_str(&mut s, ~"once "),
2095+
ast::Many => {}
2096+
}
2097+
20852098
return s;
20862099
}
20872100
@@ -2101,6 +2114,13 @@ pure fn purity_to_str(p: ast::purity) -> ~str {
21012114
}
21022115
}
21032116
2117+
pure fn onceness_to_str(o: ast::Onceness) -> ~str {
2118+
match o {
2119+
ast::Once => ~"once",
2120+
ast::Many => ~"many"
2121+
}
2122+
}
2123+
21042124
fn print_purity(s: ps, p: ast::purity) {
21052125
match p {
21062126
ast::impure_fn => (),

src/libsyntax/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ fn visit_ty<E>(t: @Ty, e: E, v: vt<E>) {
203203
ty_tup(ts) => for ts.each |tt| {
204204
v.visit_ty(*tt, e, v);
205205
},
206-
ty_fn(_, _, bounds, decl) => {
206+
ty_fn(_, _, _, bounds, decl) => {
207207
for decl.inputs.each |a| { v.visit_ty(a.ty, e, v); }
208208
visit_ty_param_bounds(bounds, e, v);
209209
v.visit_ty(decl.output, e, v);

src/rustc/metadata/tydecode.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,14 @@ fn parse_purity(c: char) -> purity {
387387
}
388388
}
389389

390+
fn parse_onceness(c: char) -> ast::Onceness {
391+
match c {
392+
'o' => ast::Once,
393+
'm' => ast::Many,
394+
_ => fail ~"parse_onceness: bad onceness"
395+
}
396+
}
397+
390398
fn parse_arg(st: @pstate, conv: conv_did) -> ty::arg {
391399
{mode: parse_mode(st),
392400
ty: parse_ty(st, conv)}
@@ -406,6 +414,7 @@ fn parse_mode(st: @pstate) -> ast::mode {
406414
fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy {
407415
let proto = parse_proto(st);
408416
let purity = parse_purity(next(st));
417+
let onceness = parse_onceness(next(st));
409418
let bounds = parse_bounds(st, conv);
410419
assert (next(st) == '[');
411420
let mut inputs: ~[ty::arg] = ~[];
@@ -418,6 +427,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy {
418427
return FnTyBase {
419428
meta: FnMeta {purity: purity,
420429
proto: proto,
430+
onceness: onceness,
421431
bounds: bounds,
422432
ret_style: ret_style},
423433
sig: FnSig {inputs: inputs,

src/rustc/metadata/tyencode.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,17 @@ fn enc_purity(w: io::Writer, p: purity) {
349349
}
350350
}
351351

352+
fn enc_onceness(w: io::Writer, o: Onceness) {
353+
match o {
354+
Once => w.write_char('o'),
355+
Many => w.write_char('m')
356+
}
357+
}
358+
352359
fn enc_ty_fn(w: io::Writer, cx: @ctxt, ft: ty::FnTy) {
353360
enc_proto(w, cx, ft.meta.proto);
354361
enc_purity(w, ft.meta.purity);
362+
enc_onceness(w, ft.meta.onceness);
355363
enc_bounds(w, cx, ft.meta.bounds);
356364
w.write_char('[');
357365
for ft.sig.inputs.each |arg| {

src/rustc/middle/lint.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: ast::fn_decl,
841841
let span = arg_ast.ty.span;
842842
// Recurse to check fn-type argument
843843
match arg_ast.ty.node {
844-
ast::ty_fn(_, _, _, decl) => {
844+
ast::ty_fn(_, _, _, _, decl) => {
845845
check_fn_deprecated_modes(tcx, arg_ty.ty,
846846
decl, span, id);
847847
}
@@ -856,7 +856,7 @@ fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: ast::fn_decl,
856856
// Functions with preceding sigil are parsed
857857
// as pointers of functions
858858
match mt.ty.node {
859-
ast::ty_fn(_, _, _, decl) => {
859+
ast::ty_fn(_, _, _, _, decl) => {
860860
check_fn_deprecated_modes(
861861
tcx, arg_ty.ty,
862862
decl, span, id);
@@ -889,7 +889,7 @@ fn check_item_deprecated_modes(tcx: ty::ctxt, it: @ast::item) {
889889
match it.node {
890890
ast::item_ty(ty, _) => {
891891
match ty.node {
892-
ast::ty_fn(_, _, _, decl) => {
892+
ast::ty_fn(_, _, _, _, decl) => {
893893
let fn_ty = ty::node_id_to_type(tcx, it.id);
894894
check_fn_deprecated_modes(
895895
tcx, fn_ty, decl, ty.span, it.id)

src/rustc/middle/region.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -624,8 +624,8 @@ fn determine_rp_in_ty(ty: @ast::Ty,
624624
}
625625
}
626626

627-
ast::ty_fn(ast::proto_bare, _, _, _) |
628-
ast::ty_fn(ast::proto_block, _, _, _) if cx.anon_implies_rp => {
627+
ast::ty_fn(ast::proto_bare, _, _, _, _) |
628+
ast::ty_fn(ast::proto_block, _, _, _, _) if cx.anon_implies_rp => {
629629
debug!("referenced bare fn type with regions %s",
630630
pprust::ty_to_str(ty, cx.sess.intr()));
631631
cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant));
@@ -672,8 +672,8 @@ fn determine_rp_in_ty(ty: @ast::Ty,
672672
match ty.node {
673673
ast::ty_box(mt) | ast::ty_uniq(mt) => {
674674
match mt.ty.node {
675-
ast::ty_fn(ast::proto_bare, _, _, _) |
676-
ast::ty_fn(ast::proto_block, _, _, _) => {
675+
ast::ty_fn(ast::proto_bare, _, _, _, _) |
676+
ast::ty_fn(ast::proto_block, _, _, _, _) => {
677677
do cx.with(cx.item_id, false) {
678678
visit_mt(mt, cx, visitor);
679679
}
@@ -706,7 +706,7 @@ fn determine_rp_in_ty(ty: @ast::Ty,
706706
}
707707
}
708708

709-
ast::ty_fn(_, _, bounds, decl) => {
709+
ast::ty_fn(_, _, _, bounds, decl) => {
710710
// fn() binds the & region, so do not consider &T types that
711711
// appear *inside* a fn() type to affect the enclosing item:
712712
do cx.with(cx.item_id, false) {

src/rustc/middle/trans/foreign.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
10001000
proto:
10011001
ty::proto_vstore(ty::vstore_slice(
10021002
ty::re_bound(ty::br_anon(0)))),
1003+
onceness: ast::Many,
10031004
bounds: @~[],
10041005
ret_style: ast::return_val},
10051006
sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val),

src/rustc/middle/trans/monomorphize.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> Option<ty::t> {
250250
tcx,
251251
FnTyBase {meta: FnMeta {purity: ast::impure_fn,
252252
proto: fty.meta.proto,
253+
onceness: ast::Many,
253254
bounds: @~[],
254255
ret_style: ast::return_val},
255256
sig: FnSig {inputs: ~[],
@@ -261,6 +262,7 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> Option<ty::t> {
261262
tcx,
262263
FnTyBase {meta: FnMeta {purity: ast::impure_fn,
263264
proto: box_proto,
265+
onceness: ast::Many,
264266
bounds: @~[],
265267
ret_style: ast::return_val},
266268
sig: FnSig {inputs: ~[],

0 commit comments

Comments
 (0)