Skip to content

Commit c9eb9ee

Browse files
committed
rewrite purity check to search through scope chain
1 parent 6ca6a3b commit c9eb9ee

File tree

1 file changed

+67
-63
lines changed

1 file changed

+67
-63
lines changed

src/rustc/middle/borrowck.rs

+67-63
Original file line numberDiff line numberDiff line change
@@ -505,14 +505,11 @@ enum check_loan_ctxt = @{
505505
// we are in a ctor, we track the self id
506506
mut in_ctor: bool,
507507

508-
mut is_pure: purity_cause
508+
mut declared_purity: ast::purity
509509
};
510510

511511
// if we are enforcing purity, why are we doing so?
512512
enum purity_cause {
513-
// not enforcing purity:
514-
pc_impure,
515-
516513
// enforcing purity because fn was declared pure:
517514
pc_declaration,
518515

@@ -529,7 +526,7 @@ fn check_loans(bccx: borrowck_ctxt,
529526
req_maps: req_maps,
530527
reported: int_hash(),
531528
mut in_ctor: false,
532-
mut is_pure: pc_impure});
529+
mut declared_purity: ast::impure_fn});
533530
let vt = visit::mk_vt(@{visit_expr: check_loans_in_expr,
534531
visit_block: check_loans_in_block,
535532
visit_fn: check_loans_in_fn
@@ -556,6 +553,37 @@ impl methods for assignment_type {
556553
impl methods for check_loan_ctxt {
557554
fn tcx() -> ty::ctxt { self.bccx.tcx }
558555

556+
fn purity(scope_id: ast::node_id) -> option<purity_cause> {
557+
let default_purity = alt self.declared_purity {
558+
// an unsafe declaration overrides all
559+
ast::unsafe_fn { ret none; }
560+
561+
// otherwise, remember what was declared as the
562+
// default, but we must scan for requirements
563+
// imposed by the borrow check
564+
ast::pure_fn { some(pc_declaration) }
565+
ast::crust_fn | ast::impure_fn { none }
566+
};
567+
568+
// scan to see if this scope or any enclosing scope requires
569+
// purity. if so, that overrides the declaration.
570+
571+
let mut scope_id = scope_id;
572+
let region_map = self.tcx().region_map;
573+
let pure_map = self.req_maps.pure_map;
574+
loop {
575+
alt pure_map.find(scope_id) {
576+
none {}
577+
some(e) {ret some(pc_cmt(e));}
578+
}
579+
580+
alt region_map.find(scope_id) {
581+
none { ret default_purity; }
582+
some(next_scope_id) { scope_id = next_scope_id; }
583+
}
584+
}
585+
}
586+
559587
fn walk_loans(scope_id: ast::node_id,
560588
f: fn(loan) -> bool) {
561589
let mut scope_id = scope_id;
@@ -590,7 +618,7 @@ impl methods for check_loan_ctxt {
590618

591619
// when we are in a pure context, we check each call to ensure
592620
// that the function which is invoked is itself pure.
593-
fn check_pure(expr: @ast::expr) {
621+
fn check_pure(pc: purity_cause, expr: @ast::expr) {
594622
let tcx = self.tcx();
595623
alt ty::get(tcx.ty(expr)).struct {
596624
ty::ty_fn(_) {
@@ -645,7 +673,7 @@ impl methods for check_loan_ctxt {
645673
}
646674
ast::impure_fn | ast::unsafe_fn {
647675
self.report_purity_error(
648-
expr.span,
676+
pc, expr.span,
649677
"access to non-pure functions");
650678
}
651679
}
@@ -654,21 +682,6 @@ impl methods for check_loan_ctxt {
654682
}
655683
}
656684

657-
fn check_for_purity_requirement(scope_id: ast::node_id) {
658-
// if we are not already enforcing purity, check whether the
659-
// gather pass thought we needed to enforce purity for this
660-
// scope.
661-
alt self.is_pure {
662-
pc_declaration | pc_cmt(*) { }
663-
pc_impure {
664-
alt self.req_maps.pure_map.find(scope_id) {
665-
none {}
666-
some(e) {self.is_pure = pc_cmt(e)}
667-
}
668-
}
669-
}
670-
}
671-
672685
fn check_for_conflicting_loans(scope_id: ast::node_id) {
673686
let new_loanss = alt self.req_maps.req_loan_map.find(scope_id) {
674687
none { ret; }
@@ -739,10 +752,14 @@ impl methods for check_loan_ctxt {
739752
// if this is a pure function, only loan-able state can be
740753
// assigned, because it is uniquely tied to this function and
741754
// is not visible from the outside
742-
if self.is_pure != pc_impure && cmt.lp.is_none() {
743-
self.report_purity_error(
744-
ex.span,
745-
at.ing_form(self.bccx.cmt_to_str(cmt)));
755+
alt self.purity(ex.id) {
756+
none {}
757+
some(pc) {
758+
if cmt.lp.is_none() {
759+
self.report_purity_error(
760+
pc, ex.span, at.ing_form(self.bccx.cmt_to_str(cmt)));
761+
}
762+
}
746763
}
747764

748765
// check for a conflicting loan as well, except in the case of
@@ -775,11 +792,8 @@ impl methods for check_loan_ctxt {
775792
self.bccx.add_to_mutbl_map(cmt);
776793
}
777794

778-
fn report_purity_error(sp: span, msg: str) {
779-
alt copy self.is_pure {
780-
pc_impure {
781-
self.tcx().sess.bug("report_purity_error() called when impure");
782-
}
795+
fn report_purity_error(pc: purity_cause, sp: span, msg: str) {
796+
alt pc {
783797
pc_declaration {
784798
self.tcx().sess.span_err(
785799
sp,
@@ -855,7 +869,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
855869
visitor: visit::vt<check_loan_ctxt>) {
856870

857871
save_and_restore(self.in_ctor) {||
858-
save_and_restore(self.is_pure) {||
872+
save_and_restore(self.declared_purity) {||
859873
// In principle, we could consider fk_anon(*) or
860874
// fk_fn_block(*) to be in a ctor, I suppose, but the
861875
// purpose of the in_ctor flag is to allow modifications
@@ -870,10 +884,7 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
870884
// NDM this doesn't seem algother right, what about fn items
871885
// nested in pure fns? etc?
872886

873-
alt decl.purity {
874-
ast::pure_fn { self.is_pure = pc_declaration; }
875-
_ { }
876-
}
887+
self.declared_purity = decl.purity;
877888

878889
visit::visit_fn(fk, decl, body, sp, id, self, visitor);
879890
}
@@ -884,16 +895,7 @@ fn check_loans_in_expr(expr: @ast::expr,
884895
&&self: check_loan_ctxt,
885896
vt: visit::vt<check_loan_ctxt>) {
886897
self.check_for_conflicting_loans(expr.id);
887-
save_and_restore(self.is_pure) {||
888-
self.check_for_purity_requirement(expr.id);
889-
check_loans_in_expr_1(expr, self, vt);
890-
}
891-
}
892898

893-
// avoid rightward drift by breaking this out into its own fn
894-
fn check_loans_in_expr_1(expr: @ast::expr,
895-
&&self: check_loan_ctxt,
896-
vt: visit::vt<check_loan_ctxt>) {
897899
alt expr.node {
898900
ast::expr_swap(l, r) {
899901
self.check_assignment(at_swap, l);
@@ -936,9 +938,12 @@ fn check_loans_in_expr_1(expr: @ast::expr,
936938
}
937939
}
938940
ast::expr_call(f, args, _) {
939-
if self.is_pure != pc_impure {
940-
self.check_pure(f);
941-
for args.each { |arg| self.check_pure(arg) }
941+
alt self.purity(expr.id) {
942+
none {}
943+
some(pc) {
944+
self.check_pure(pc, f);
945+
for args.each { |arg| self.check_pure(pc, arg) }
946+
}
942947
}
943948
let arg_tys = ty::ty_fn_args(ty::expr_ty(self.tcx(), f));
944949
vec::iter2(args, arg_tys) { |arg, arg_ty|
@@ -963,28 +968,17 @@ fn check_loans_in_expr_1(expr: @ast::expr,
963968
fn check_loans_in_block(blk: ast::blk,
964969
&&self: check_loan_ctxt,
965970
vt: visit::vt<check_loan_ctxt>) {
966-
save_and_restore(self.is_pure) {||
971+
save_and_restore(self.declared_purity) {||
967972
self.check_for_conflicting_loans(blk.node.id);
968-
self.check_for_purity_requirement(blk.node.id);
969973

970974
alt blk.node.rules {
971975
ast::default_blk {
972976
}
973977
ast::unchecked_blk {
974-
alt self.is_pure {
975-
pc_impure | pc_declaration {
976-
self.is_pure = pc_impure;
977-
}
978-
pc_cmt(_) {
979-
// unchecked does not override purity requirements due
980-
// to borrows; unchecked didn't seem strong enough to
981-
// justify potential memory unsafety to me
982-
}
983-
}
978+
self.declared_purity = ast::impure_fn;
984979
}
985980
ast::unsafe_blk {
986-
// unsafe blocks override everything
987-
self.is_pure = pc_impure;
981+
self.declared_purity = ast::unsafe_fn;
988982
}
989983
}
990984

@@ -1472,6 +1466,15 @@ impl categorize_methods for borrowck_ctxt {
14721466
ty_to_str(self.tcx, cmt.ty)]
14731467
}
14741468

1469+
fn pk_to_sigil(pk: ptr_kind) -> str {
1470+
alt pk {
1471+
uniq_ptr {"~"}
1472+
gc_ptr {"@"}
1473+
region_ptr {"&"}
1474+
unsafe_ptr {"*"}
1475+
}
1476+
}
1477+
14751478
fn cmt_to_str(cmt: cmt) -> str {
14761479
let mut_str = self.mut_to_str(cmt.mutbl);
14771480
alt cmt.cat {
@@ -1482,7 +1485,8 @@ impl categorize_methods for borrowck_ctxt {
14821485
cat_rvalue { "non-lvalue" }
14831486
cat_local(_) { mut_str + " local variable" }
14841487
cat_arg(_) { mut_str + " argument" }
1485-
cat_deref(*) { "dereference of " + mut_str + " pointer" }
1488+
cat_deref(_, _, pk) { #fmt["dereference of %s %s pointer",
1489+
mut_str, self.pk_to_sigil(pk)] }
14861490
cat_stack_upvar(_) { mut_str + " upvar" }
14871491
cat_comp(_, comp_field(_)) { mut_str + " field" }
14881492
cat_comp(_, comp_tuple) { "tuple content" }

0 commit comments

Comments
 (0)