diff --git a/src/comp/front/config.rs b/src/comp/front/config.rs index 4aa1c07be57c..526bf20ebb76 100644 --- a/src/comp/front/config.rs +++ b/src/comp/front/config.rs @@ -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); ret {stmts: vec::map(fld.fold_stmt, filtered_stmts), 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 { diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index 8e0b71caf848..d76e26064a7f 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -4,7 +4,8 @@ import std::option; import std::vec; import syntax::ast; 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::print::pprust; import front::attr; @@ -189,8 +190,8 @@ fn mk_tests(cx: &test_ctxt) -> @ast::item { // The vector of test_descs for this crate let test_descs = mk_test_desc_vec(cx); - let body_: ast::blk_ = - {stmts: [], expr: option::some(test_descs), id: cx.next_node_id()}; + let body_: ast::blk_ = checked_blk([], option::some(test_descs), + cx.next_node_id()); let body = nospan(body_); let fn_ = {decl: decl, proto: proto, body: body}; @@ -305,10 +306,8 @@ fn mk_main(cx: &test_ctxt) -> @ast::item { let test_main_call_expr = mk_test_main_call(cx); - let body_: ast::blk_ = - {stmts: [], - expr: option::some(test_main_call_expr), - id: cx.next_node_id()}; + let body_: ast::blk_ = checked_blk([], option::some(test_main_call_expr), + cx.next_node_id()); let body = {node: body_, span: dummy_sp()}; let fn_ = {decl: decl, proto: proto, body: body}; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index ad199ba5cb3d..7519e2541f58 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -2081,7 +2081,12 @@ fn check_expr_with_unifier(fcx: &@fn_ctxt, expr: &@ast::expr, unify: &unifier, check_fn(fcx.ccx, f, id, some(fcx)); } 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 = alt b.node.expr { some(expr) { expr_ty(tcx, expr) } diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 4caddb5e25bd..d44baebb6f3d 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -82,7 +82,8 @@ tag meta_item_ { type blk = spanned; -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}; @@ -223,6 +224,15 @@ tag 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; tag mac_ { diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index 48bdfc47b68c..517e252dd9cc 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -184,10 +184,14 @@ fn eq_ty(a: &@ty, b: &@ty) -> bool { ret std::box::ptr_eq(a, b); } fn hash_ty(t: &@ty) -> uint { ret t.span.lo << 16u + t.span.hi; } 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}; } +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 { ret {mut: f.mut, ty: f.ty, ident: f.ident, id: f.id}; diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index a91b2f31814b..770ed307e141 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -255,7 +255,8 @@ fn noop_fold_method(m: &method_, fld: ast_fold) -> method_ { fn noop_fold_block(b: &blk_, fld: ast_fold) -> blk_ { ret {stmts: vec::map(fld.fold_stmt, b.stmts), 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_ { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index f7329bd3b3b8..729338b4b302 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -837,7 +837,7 @@ fn parse_bottom_expr(p: &parser) -> @ast::expr { } else if p.peek() == token::BINOP(token::OR) { ret parse_fn_block_expr(p); } 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)); } } else if eat_word(p, "if") { @@ -860,6 +860,10 @@ fn parse_bottom_expr(p: &parser) -> @ast::expr { ret parse_fn_expr(p, ast::proto_block); } else if eat_word(p, "lambda") { 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 { p.bump(); let mut = parse_mutability(p); @@ -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)) } else if p.peek() == token::POUND_LBRACE { 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); } else if p.peek() == token::ELLIPSIS { p.bump(); @@ -1309,7 +1313,7 @@ fn parse_fn_expr(p: &parser, proto: ast::proto) -> @ast::expr { fn parse_fn_block_expr(p: &parser) -> @ast::expr { let lo = p.get_last_lo_pos(); 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}; 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 { fn parse_block(p: &parser) -> ast::blk { let lo = p.get_lo_pos(); - expect(p, token::LBRACE); - be parse_block_tail(p, lo); + if eat_word(p, "unchecked") { + 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 "#{"... -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 expr: option::t<@ast::expr> = none; while p.peek() != token::RBRACE { @@ -1710,7 +1722,7 @@ fn parse_block_tail(p: &parser, lo: uint) -> ast::blk { } let hi = p.get_hi_pos(); 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); } diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 051c114002b5..52ee1eaeacc1 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -579,6 +579,11 @@ tag embed_type { block_macro; block_block_fn; block_normal; } fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type, indented: uint) { + alt blk.node.rules { + ast::unchecked. { word(s.s, "unchecked"); } + _ {} + } + maybe_print_comment(s, blk.span.lo); let ann_node = node_block(s, blk); s.ann.pre(ann_node);