Skip to content

Commit 44e2dc2

Browse files
committed
Improve mutability checking. Closes #118.
1 parent 8bd8413 commit 44e2dc2

9 files changed

+60
-15
lines changed

src/boot/me/effect.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ let mutability_checking_visitor
5151
if (is_mutable or is_init)
5252
then ()
5353
else err (Some s.id)
54-
"writing to non-mutable slot of type %a in statement %a"
54+
"writing to immutable type %a in statement %a"
5555
Ast.sprintf_ty dst_ty Ast.sprintf_stmt s
5656
in
5757
(* FIXME (issue #75): enforce the no-write-alias-to-immutable-slot

src/boot/me/type.ml

+32-11
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
4545

4646
let get_slot_ty (slot:Ast.slot) : Ast.ty =
4747
match slot.Ast.slot_ty with
48-
Some ty -> ty
48+
Some ty -> ty
4949
| None -> Common.bug () "get_slot_ty: no type in slot"
5050
in
5151

@@ -62,7 +62,11 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
6262
in
6363

6464
let maybe_mutable (mutability:Ast.mutability) (ty:Ast.ty) : Ast.ty =
65-
if mutability = Ast.MUT_mutable then Ast.TY_mutable ty else ty
65+
let res =
66+
if mutability = Ast.MUT_mutable then Ast.TY_mutable ty else ty
67+
in
68+
log cx "maybe_mutable: %a -> %a" Ast.sprintf_ty ty Ast.sprintf_ty res;
69+
res
6670
in
6771

6872
(*
@@ -229,7 +233,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
229233
()
230234
"internal_check_slot: supplied defn wasn't a slot at all"
231235
in
232-
match infer, slot.Ast.slot_ty with
236+
match infer, slot.Ast.slot_ty with
233237
Some expected, Some actual ->
234238
demand expected actual;
235239
actual
@@ -301,6 +305,10 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
301305
| `Module items -> Ast.sprintf_mod_items chan items
302306
in
303307

308+
let _ = log cx "base lval %a, base type %a"
309+
Ast.sprintf_lval base sprintf_itype ()
310+
in
311+
304312
let rec typecheck base_ity =
305313
match base_ity, comp with
306314
`Type (Ast.TY_rec ty_rec), Ast.COMP_named (Ast.COMP_ident id) ->
@@ -455,14 +463,14 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
455463
: (Ast.ty * int) =
456464
let yield_ty ty =
457465
let (ty, n_boxes) = if deref then unbox ty else (ty, 0) in
458-
(maybe_mutable mut ty, n_boxes)
466+
(maybe_mutable mut ty, n_boxes)
459467
in
460468
match infer, internal_check_lval infer lval with
461469
| None, LTYPE_mono ty -> yield_ty ty
462470
| Some expected, LTYPE_mono actual ->
463471
demand expected actual;
464472
yield_ty actual
465-
| None, (LTYPE_poly _ as lty) ->
473+
| None, (LTYPE_poly _ as lty) ->
466474
Common.err
467475
None
468476
"not enough context to automatically instantiate the polymorphic \
@@ -487,9 +495,21 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
487495
* Get the real one. *)
488496
let lval_id = Semant.lval_base_id lval in
489497
let lval = Hashtbl.find cx.Semant.ctxt_all_lvals lval_id in
498+
let _ = log cx "generic_check_lval %a mut=%s deref=%s infer=%s"
499+
Ast.sprintf_lval lval
500+
(if mut = Ast.MUT_mutable then "mutable" else "immutable")
501+
(if deref then "true" else "false")
502+
(match infer with
503+
None -> "<none>"
504+
| Some t -> Fmt.fmt_to_str Ast.fmt_ty t)
505+
in
490506
let (lval_ty, n_boxes) =
491507
internal_check_outer_lval ~mut:mut ~deref:deref infer lval
492508
in
509+
let _ = log cx "checked lval %a with type %a"
510+
Ast.sprintf_lval lval
511+
Ast.sprintf_ty lval_ty
512+
in
493513

494514
if Hashtbl.mem cx.Semant.ctxt_all_lval_types lval_id then
495515
assert ((Hashtbl.find cx.Semant.ctxt_all_lval_types lval_id) = lval_ty)
@@ -514,8 +534,8 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
514534
implemented; please add explicit dereference operators";
515535
Hashtbl.replace cx.Semant.ctxt_auto_deref_lval lval_id (n_boxes > 0);
516536

517-
(* Before demoting the lval to a value, strip off mutability. *)
518-
fundamental_ty lval_ty
537+
(* Before demoting the lval to a value, strip off mutability. *)
538+
fundamental_ty lval_ty
519539

520540
(* Note that this function should be avoided when possible, because it
521541
* cannot perform type inference. In general you should prefer
@@ -538,11 +558,12 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
538558
in
539559

540560
let infer_lval
541-
?mut:(mut=Ast.MUT_mutable)
561+
?mut:(mut=Ast.MUT_immutable)
542562
(ty:Ast.ty)
543563
(lval:Ast.lval)
544564
: unit =
545-
ignore (generic_check_lval ?mut:mut ~deref:false (Some ty) lval)
565+
ignore (generic_check_lval ?mut:mut ~deref:false
566+
(Some (Ast.TY_mutable ty)) lval)
546567
in
547568

548569
(*
@@ -574,7 +595,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
574595
| Ast.EXPR_binary (binop, lhs, rhs) ->
575596
let operand_ty = check_atom ~deref:true lhs in
576597
demand operand_ty (check_atom ~deref:true rhs);
577-
check_binop binop operand_ty
598+
check_binop binop operand_ty
578599
| Ast.EXPR_unary (Ast.UNOP_not, atom) ->
579600
demand Ast.TY_bool (check_atom ~deref:true atom);
580601
Ast.TY_bool
@@ -596,7 +617,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
596617
let check_fn (callee:Ast.lval) (args:Ast.atom array) : Ast.ty =
597618
let arg_tys = Array.map check_atom args in
598619
let callee_ty = check_lval callee in
599-
demand_fn (Array.map (fun ty -> Some ty) arg_tys) callee_ty
620+
demand_fn (Array.map (fun ty -> Some ty) arg_tys) callee_ty
600621
in
601622

602623
let rec check_pat (expected:Ast.ty) (pat:Ast.pat) : unit =

src/test/compile-fail/writing-through-read-alias.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// -*- rust -*-
22

3-
// error-pattern: writing to non-mutable slot
3+
// error-pattern: writing to immutable type
44

55
type point = rec(int x, int y, int z);
66

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// error-pattern: writing to immutable type
2+
obj objy(int x) {
3+
fn foo() -> () {
4+
x = 5;
5+
}
6+
}
7+
fn main() {
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// error-pattern: writing to immutable type
2+
fn main() {
3+
let rec(int x) r = rec(x=1);
4+
r.x = 6;
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// error-pattern: writing to immutable type
2+
fn main() {
3+
let tup(int) t = tup(1);
4+
t._0 = 5;
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// error-pattern: writing to immutable type
2+
fn main() {
3+
let vec[int] v = vec(1, 2, 3);
4+
v.(1) = 4;
5+
}

src/test/run-pass/foreach-nested-2.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ iter range(int start, int stop) -> int {
1414
}
1515

1616
fn main() {
17-
let vec[int] a = vec(-1, -1, -1, -1, -1, -1, -1, -1);
17+
let vec[mutable int] a =
18+
vec[mutable](-1, -1, -1, -1, -1, -1, -1, -1);
1819
let int p = 0;
1920

2021
for each (int i in two()) {

src/test/run-pass/foreach-nested.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ iter two() -> int {
66
}
77

88
fn main() {
9-
let vec[int] a = vec(-1, -1, -1, -1);
9+
let vec[mutable int] a = vec[mutable](-1, -1, -1, -1);
1010
let int p = 0;
1111

1212
for each (int i in two()) {

0 commit comments

Comments
 (0)