提交 f841e894 编写于 作者: T Tim Chevalier

Support unchecked blocks

This patch supports the syntax

    unchecked {
      ...
    }

    to disable purity checking within a block. Presumably it will only be
    used within a declared "pure fn". However, there is no checking that it
    doesn't occur elsewhere, and it would be harmless for it to do so.

    I went with Lindsey's suggestion for the syntax, but it's subject to
    change.

    This allows you to write code that uses predicates that call arbitrary
    Rust functions, but you must declare your intentions by wrapping it in
    an unchecked { ... } block. The test case run-pass/unchecked-predicates.rs
    demonstrates how to do that.
上级 d9bc3cb1
...@@ -77,7 +77,7 @@ fn fold_block(cfg: &ast::crate_cfg, b: &ast::blk_, fld: fold::ast_fold) -> ...@@ -77,7 +77,7 @@ fn fold_block(cfg: &ast::crate_cfg, b: &ast::blk_, fld: fold::ast_fold) ->
let filtered_stmts = vec::filter_map(filter, b.stmts); let filtered_stmts = vec::filter_map(filter, b.stmts);
ret {stmts: vec::map(fld.fold_stmt, filtered_stmts), ret {stmts: vec::map(fld.fold_stmt, filtered_stmts),
expr: option::map(fld.fold_expr, b.expr), expr: option::map(fld.fold_expr, b.expr),
id: b.id}; id: b.id, rules: b.rules};
} }
fn item_in_cfg(cfg: &ast::crate_cfg, item: &@ast::item) -> bool { fn item_in_cfg(cfg: &ast::crate_cfg, item: &@ast::item) -> bool {
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
import std::vec; import std::vec;
import syntax::ast; import syntax::ast;
import syntax::ast_util; import syntax::ast_util;
import syntax::ast_util::dummy_sp; import syntax::ast_util::*;
//import syntax::ast_util::dummy_sp;
import syntax::fold; import syntax::fold;
import syntax::print::pprust; import syntax::print::pprust;
import front::attr; import front::attr;
...@@ -189,8 +190,8 @@ fn mk_tests(cx: &test_ctxt) -> @ast::item { ...@@ -189,8 +190,8 @@ fn mk_tests(cx: &test_ctxt) -> @ast::item {
// The vector of test_descs for this crate // The vector of test_descs for this crate
let test_descs = mk_test_desc_vec(cx); let test_descs = mk_test_desc_vec(cx);
let body_: ast::blk_ = let body_: ast::blk_ = checked_blk([], option::some(test_descs),
{stmts: [], expr: option::some(test_descs), id: cx.next_node_id()}; cx.next_node_id());
let body = nospan(body_); let body = nospan(body_);
let fn_ = {decl: decl, proto: proto, body: body}; let fn_ = {decl: decl, proto: proto, body: body};
...@@ -305,10 +306,8 @@ fn mk_main(cx: &test_ctxt) -> @ast::item { ...@@ -305,10 +306,8 @@ fn mk_main(cx: &test_ctxt) -> @ast::item {
let test_main_call_expr = mk_test_main_call(cx); let test_main_call_expr = mk_test_main_call(cx);
let body_: ast::blk_ = let body_: ast::blk_ = checked_blk([], option::some(test_main_call_expr),
{stmts: [], cx.next_node_id());
expr: option::some(test_main_call_expr),
id: cx.next_node_id()};
let body = {node: body_, span: dummy_sp()}; let body = {node: body_, span: dummy_sp()};
let fn_ = {decl: decl, proto: proto, body: body}; let fn_ = {decl: decl, proto: proto, body: body};
......
...@@ -2081,7 +2081,12 @@ fn check_binop_type_compat(fcx: &@fn_ctxt, span: span, ty: ty::t, ...@@ -2081,7 +2081,12 @@ fn check_binop_type_compat(fcx: &@fn_ctxt, span: span, ty: ty::t,
check_fn(fcx.ccx, f, id, some(fcx)); check_fn(fcx.ccx, f, id, some(fcx));
} }
ast::expr_block(b) { ast::expr_block(b) {
bot = check_block(fcx, b); // If this is an unchecked block, turn off purity-checking
let fcx_for_block = alt b.node.rules {
ast::unchecked. { @{ purity: ast::impure_fn with *fcx } }
_ { fcx }
};
bot = check_block(fcx_for_block, b);
let typ = let typ =
alt b.node.expr { alt b.node.expr {
some(expr) { expr_ty(tcx, expr) } some(expr) { expr_ty(tcx, expr) }
......
...@@ -82,7 +82,8 @@ ...@@ -82,7 +82,8 @@
type blk = spanned<blk_>; type blk = spanned<blk_>;
type blk_ = {stmts: [@stmt], expr: option::t<@expr>, id: node_id}; type blk_ = {stmts: [@stmt], expr: option::t<@expr>,
id: node_id, rules: check_mode};
type pat = {id: node_id, node: pat_, span: span}; type pat = {id: node_id, node: pat_, span: span};
...@@ -223,6 +224,15 @@ ...@@ -223,6 +224,15 @@
expr_uniq(@expr); expr_uniq(@expr);
} }
/*
// Says whether this is a block the user marked as
// "unchecked"
tag blk_sort {
blk_unchecked; // declared as "exception to effect-checking rules"
blk_checked; // all typing rules apply
}
*/
type mac = spanned<mac_>; type mac = spanned<mac_>;
tag mac_ { tag mac_ {
......
...@@ -184,10 +184,14 @@ fn is_constraint_arg(e: @expr) -> bool { ...@@ -184,10 +184,14 @@ fn is_constraint_arg(e: @expr) -> bool {
fn hash_ty(t: &@ty) -> uint { ret t.span.lo << 16u + t.span.hi; } fn hash_ty(t: &@ty) -> uint { ret t.span.lo << 16u + t.span.hi; }
fn block_from_expr(e: @expr) -> blk { fn block_from_expr(e: @expr) -> blk {
let blk_ = {stmts: [], expr: option::some::<@expr>(e), id: e.id}; let blk_ = checked_blk([], option::some::<@expr>(e), e.id);
ret {node: blk_, span: e.span}; ret {node: blk_, span: e.span};
} }
fn checked_blk(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id)
-> blk_ {
ret {stmts: stmts1, expr: expr1, id: id1, rules: checked};
}
fn obj_field_from_anon_obj_field(f: &anon_obj_field) -> obj_field { fn obj_field_from_anon_obj_field(f: &anon_obj_field) -> obj_field {
ret {mut: f.mut, ty: f.ty, ident: f.ident, id: f.id}; ret {mut: f.mut, ty: f.ty, ident: f.ident, id: f.id};
......
...@@ -255,7 +255,8 @@ fn noop_fold_method(m: &method_, fld: ast_fold) -> method_ { ...@@ -255,7 +255,8 @@ fn noop_fold_method(m: &method_, fld: ast_fold) -> method_ {
fn noop_fold_block(b: &blk_, fld: ast_fold) -> blk_ { fn noop_fold_block(b: &blk_, fld: ast_fold) -> blk_ {
ret {stmts: vec::map(fld.fold_stmt, b.stmts), ret {stmts: vec::map(fld.fold_stmt, b.stmts),
expr: option::map(fld.fold_expr, b.expr), expr: option::map(fld.fold_expr, b.expr),
id: b.id}; id: b.id,
rules: b.rules};
} }
fn noop_fold_stmt(s: &stmt_, fld: ast_fold) -> stmt_ { fn noop_fold_stmt(s: &stmt_, fld: ast_fold) -> stmt_ {
......
...@@ -837,7 +837,7 @@ fn parse_bottom_expr(p: &parser) -> @ast::expr { ...@@ -837,7 +837,7 @@ fn parse_bottom_expr(p: &parser) -> @ast::expr {
} else if p.peek() == token::BINOP(token::OR) { } else if p.peek() == token::BINOP(token::OR) {
ret parse_fn_block_expr(p); ret parse_fn_block_expr(p);
} else { } else {
let blk = parse_block_tail(p, lo); let blk = parse_block_tail(p, lo, ast::checked);
ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk)); ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk));
} }
} else if eat_word(p, "if") { } else if eat_word(p, "if") {
...@@ -860,6 +860,10 @@ fn parse_bottom_expr(p: &parser) -> @ast::expr { ...@@ -860,6 +860,10 @@ fn parse_bottom_expr(p: &parser) -> @ast::expr {
ret parse_fn_expr(p, ast::proto_block); ret parse_fn_expr(p, ast::proto_block);
} else if eat_word(p, "lambda") { } else if eat_word(p, "lambda") {
ret parse_fn_expr(p, ast::proto_closure); ret parse_fn_expr(p, ast::proto_closure);
} else if eat_word(p, "unchecked") {
expect(p, token::LBRACE);
let blk = parse_block_tail(p, lo, ast::unchecked);
ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk));
} else if p.peek() == token::LBRACKET { } else if p.peek() == token::LBRACKET {
p.bump(); p.bump();
let mut = parse_mutability(p); let mut = parse_mutability(p);
...@@ -876,7 +880,7 @@ fn parse_bottom_expr(p: &parser) -> @ast::expr { ...@@ -876,7 +880,7 @@ fn parse_bottom_expr(p: &parser) -> @ast::expr {
ret mk_mac_expr(p, lo, p.get_hi_pos(), ast::mac_embed_type(ty)) ret mk_mac_expr(p, lo, p.get_hi_pos(), ast::mac_embed_type(ty))
} else if p.peek() == token::POUND_LBRACE { } else if p.peek() == token::POUND_LBRACE {
p.bump(); p.bump();
let blk = ast::mac_embed_block(parse_block_tail(p, lo)); let blk = ast::mac_embed_block(parse_block_tail(p, lo, ast::checked));
ret mk_mac_expr(p, lo, p.get_hi_pos(), blk); ret mk_mac_expr(p, lo, p.get_hi_pos(), blk);
} else if p.peek() == token::ELLIPSIS { } else if p.peek() == token::ELLIPSIS {
p.bump(); p.bump();
...@@ -1309,7 +1313,7 @@ fn parse_fn_expr(p: &parser, proto: ast::proto) -> @ast::expr { ...@@ -1309,7 +1313,7 @@ fn parse_fn_expr(p: &parser, proto: ast::proto) -> @ast::expr {
fn parse_fn_block_expr(p: &parser) -> @ast::expr { fn parse_fn_block_expr(p: &parser) -> @ast::expr {
let lo = p.get_last_lo_pos(); let lo = p.get_last_lo_pos();
let decl = parse_fn_block_decl(p); let decl = parse_fn_block_decl(p);
let body = parse_block_tail(p, lo); let body = parse_block_tail(p, lo, ast::checked);
let _fn = {decl: decl, proto: ast::proto_block, body: body}; let _fn = {decl: decl, proto: ast::proto_block, body: body};
ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn)); ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn));
} }
...@@ -1664,12 +1668,20 @@ fn stmt_ends_with_semi(stmt: &ast::stmt) -> bool { ...@@ -1664,12 +1668,20 @@ fn stmt_ends_with_semi(stmt: &ast::stmt) -> bool {
fn parse_block(p: &parser) -> ast::blk { fn parse_block(p: &parser) -> ast::blk {
let lo = p.get_lo_pos(); let lo = p.get_lo_pos();
expect(p, token::LBRACE); if eat_word(p, "unchecked") {
be parse_block_tail(p, lo); be parse_block_tail(p, lo, ast::unchecked);
}
else {
expect(p, token::LBRACE);
be parse_block_tail(p, lo, ast::checked);
}
} }
// Precondition: already parsed the '{' or '#{'
// I guess that also means "already parsed the 'impure'" if
// necessary, and this should take a qualifier.
// some blocks start with "#{"... // some blocks start with "#{"...
fn parse_block_tail(p: &parser, lo: uint) -> ast::blk { fn parse_block_tail(p: &parser, lo: uint, s: ast::check_mode) -> ast::blk {
let stmts: [@ast::stmt] = []; let stmts: [@ast::stmt] = [];
let expr: option::t<@ast::expr> = none; let expr: option::t<@ast::expr> = none;
while p.peek() != token::RBRACE { while p.peek() != token::RBRACE {
...@@ -1710,7 +1722,7 @@ fn parse_block_tail(p: &parser, lo: uint) -> ast::blk { ...@@ -1710,7 +1722,7 @@ fn parse_block_tail(p: &parser, lo: uint) -> ast::blk {
} }
let hi = p.get_hi_pos(); let hi = p.get_hi_pos();
p.bump(); p.bump();
let bloc = {stmts: stmts, expr: expr, id: p.get_id()}; let bloc = {stmts: stmts, expr: expr, id: p.get_id(), rules: s};
ret spanned(lo, hi, bloc); ret spanned(lo, hi, bloc);
} }
......
...@@ -579,6 +579,11 @@ fn print_block(s: &ps, blk: &ast::blk) { ...@@ -579,6 +579,11 @@ fn print_block(s: &ps, blk: &ast::blk) {
fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type, fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type,
indented: uint) { indented: uint) {
alt blk.node.rules {
ast::unchecked. { word(s.s, "unchecked"); }
_ {}
}
maybe_print_comment(s, blk.span.lo); maybe_print_comment(s, blk.span.lo);
let ann_node = node_block(s, blk); let ann_node = node_block(s, blk);
s.ann.pre(ann_node); s.ann.pre(ann_node);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册