aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-07-23 15:29:17 -0700
committerGraydon Hoare <[email protected]>2010-07-23 15:29:17 -0700
commit44e2dc2789a8b3a19024ec67e25f8bd4d28afdce (patch)
treeef2c5effdfa8ce4a1efce2ab8c3a142a574acbf4
parentAdd test for writing-through-uninit bug (reported on IRC by jrmuizel), plus f... (diff)
downloadrust-44e2dc2789a8b3a19024ec67e25f8bd4d28afdce.tar.xz
rust-44e2dc2789a8b3a19024ec67e25f8bd4d28afdce.zip
Improve mutability checking. Closes #118.
-rw-r--r--src/boot/me/effect.ml2
-rw-r--r--src/boot/me/type.ml43
-rw-r--r--src/test/compile-fail/writing-through-read-alias.rs2
-rw-r--r--src/test/compile-fail/writing-to-immutable-obj.rs8
-rw-r--r--src/test/compile-fail/writing-to-immutable-rec.rs5
-rw-r--r--src/test/compile-fail/writing-to-immutable-tup.rs5
-rw-r--r--src/test/compile-fail/writing-to-immutable-vec.rs5
-rw-r--r--src/test/run-pass/foreach-nested-2.rs3
-rw-r--r--src/test/run-pass/foreach-nested.rs2
9 files changed, 60 insertions, 15 deletions
diff --git a/src/boot/me/effect.ml b/src/boot/me/effect.ml
index be0c5af2..c55e1d12 100644
--- a/src/boot/me/effect.ml
+++ b/src/boot/me/effect.ml
@@ -51,7 +51,7 @@ let mutability_checking_visitor
if (is_mutable or is_init)
then ()
else err (Some s.id)
- "writing to non-mutable slot of type %a in statement %a"
+ "writing to immutable type %a in statement %a"
Ast.sprintf_ty dst_ty Ast.sprintf_stmt s
in
(* FIXME (issue #75): enforce the no-write-alias-to-immutable-slot
diff --git a/src/boot/me/type.ml b/src/boot/me/type.ml
index 9d74959a..7943e88b 100644
--- a/src/boot/me/type.ml
+++ b/src/boot/me/type.ml
@@ -45,7 +45,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
let get_slot_ty (slot:Ast.slot) : Ast.ty =
match slot.Ast.slot_ty with
- Some ty -> ty
+ Some ty -> ty
| None -> Common.bug () "get_slot_ty: no type in slot"
in
@@ -62,7 +62,11 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
in
let maybe_mutable (mutability:Ast.mutability) (ty:Ast.ty) : Ast.ty =
- if mutability = Ast.MUT_mutable then Ast.TY_mutable ty else ty
+ let res =
+ if mutability = Ast.MUT_mutable then Ast.TY_mutable ty else ty
+ in
+ log cx "maybe_mutable: %a -> %a" Ast.sprintf_ty ty Ast.sprintf_ty res;
+ res
in
(*
@@ -229,7 +233,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
()
"internal_check_slot: supplied defn wasn't a slot at all"
in
- match infer, slot.Ast.slot_ty with
+ match infer, slot.Ast.slot_ty with
Some expected, Some actual ->
demand expected actual;
actual
@@ -301,6 +305,10 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
| `Module items -> Ast.sprintf_mod_items chan items
in
+ let _ = log cx "base lval %a, base type %a"
+ Ast.sprintf_lval base sprintf_itype ()
+ in
+
let rec typecheck base_ity =
match base_ity, comp with
`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) =
: (Ast.ty * int) =
let yield_ty ty =
let (ty, n_boxes) = if deref then unbox ty else (ty, 0) in
- (maybe_mutable mut ty, n_boxes)
+ (maybe_mutable mut ty, n_boxes)
in
match infer, internal_check_lval infer lval with
| None, LTYPE_mono ty -> yield_ty ty
| Some expected, LTYPE_mono actual ->
demand expected actual;
yield_ty actual
- | None, (LTYPE_poly _ as lty) ->
+ | None, (LTYPE_poly _ as lty) ->
Common.err
None
"not enough context to automatically instantiate the polymorphic \
@@ -487,9 +495,21 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
* Get the real one. *)
let lval_id = Semant.lval_base_id lval in
let lval = Hashtbl.find cx.Semant.ctxt_all_lvals lval_id in
+ let _ = log cx "generic_check_lval %a mut=%s deref=%s infer=%s"
+ Ast.sprintf_lval lval
+ (if mut = Ast.MUT_mutable then "mutable" else "immutable")
+ (if deref then "true" else "false")
+ (match infer with
+ None -> "<none>"
+ | Some t -> Fmt.fmt_to_str Ast.fmt_ty t)
+ in
let (lval_ty, n_boxes) =
internal_check_outer_lval ~mut:mut ~deref:deref infer lval
in
+ let _ = log cx "checked lval %a with type %a"
+ Ast.sprintf_lval lval
+ Ast.sprintf_ty lval_ty
+ in
if Hashtbl.mem cx.Semant.ctxt_all_lval_types lval_id then
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) =
implemented; please add explicit dereference operators";
Hashtbl.replace cx.Semant.ctxt_auto_deref_lval lval_id (n_boxes > 0);
- (* Before demoting the lval to a value, strip off mutability. *)
- fundamental_ty lval_ty
+ (* Before demoting the lval to a value, strip off mutability. *)
+ fundamental_ty lval_ty
(* Note that this function should be avoided when possible, because it
* cannot perform type inference. In general you should prefer
@@ -538,11 +558,12 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
in
let infer_lval
- ?mut:(mut=Ast.MUT_mutable)
+ ?mut:(mut=Ast.MUT_immutable)
(ty:Ast.ty)
(lval:Ast.lval)
: unit =
- ignore (generic_check_lval ?mut:mut ~deref:false (Some ty) lval)
+ ignore (generic_check_lval ?mut:mut ~deref:false
+ (Some (Ast.TY_mutable ty)) lval)
in
(*
@@ -574,7 +595,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
| Ast.EXPR_binary (binop, lhs, rhs) ->
let operand_ty = check_atom ~deref:true lhs in
demand operand_ty (check_atom ~deref:true rhs);
- check_binop binop operand_ty
+ check_binop binop operand_ty
| Ast.EXPR_unary (Ast.UNOP_not, atom) ->
demand Ast.TY_bool (check_atom ~deref:true atom);
Ast.TY_bool
@@ -596,7 +617,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
let check_fn (callee:Ast.lval) (args:Ast.atom array) : Ast.ty =
let arg_tys = Array.map check_atom args in
let callee_ty = check_lval callee in
- demand_fn (Array.map (fun ty -> Some ty) arg_tys) callee_ty
+ demand_fn (Array.map (fun ty -> Some ty) arg_tys) callee_ty
in
let rec check_pat (expected:Ast.ty) (pat:Ast.pat) : unit =
diff --git a/src/test/compile-fail/writing-through-read-alias.rs b/src/test/compile-fail/writing-through-read-alias.rs
index b3d21521..2a8ec11e 100644
--- a/src/test/compile-fail/writing-through-read-alias.rs
+++ b/src/test/compile-fail/writing-through-read-alias.rs
@@ -1,6 +1,6 @@
// -*- rust -*-
-// error-pattern: writing to non-mutable slot
+// error-pattern: writing to immutable type
type point = rec(int x, int y, int z);
diff --git a/src/test/compile-fail/writing-to-immutable-obj.rs b/src/test/compile-fail/writing-to-immutable-obj.rs
new file mode 100644
index 00000000..ffa2cebe
--- /dev/null
+++ b/src/test/compile-fail/writing-to-immutable-obj.rs
@@ -0,0 +1,8 @@
+// error-pattern: writing to immutable type
+obj objy(int x) {
+ fn foo() -> () {
+ x = 5;
+ }
+}
+fn main() {
+}
diff --git a/src/test/compile-fail/writing-to-immutable-rec.rs b/src/test/compile-fail/writing-to-immutable-rec.rs
new file mode 100644
index 00000000..42206fe4
--- /dev/null
+++ b/src/test/compile-fail/writing-to-immutable-rec.rs
@@ -0,0 +1,5 @@
+// error-pattern: writing to immutable type
+fn main() {
+ let rec(int x) r = rec(x=1);
+ r.x = 6;
+}
diff --git a/src/test/compile-fail/writing-to-immutable-tup.rs b/src/test/compile-fail/writing-to-immutable-tup.rs
new file mode 100644
index 00000000..bd974dcc
--- /dev/null
+++ b/src/test/compile-fail/writing-to-immutable-tup.rs
@@ -0,0 +1,5 @@
+// error-pattern: writing to immutable type
+fn main() {
+ let tup(int) t = tup(1);
+ t._0 = 5;
+}
diff --git a/src/test/compile-fail/writing-to-immutable-vec.rs b/src/test/compile-fail/writing-to-immutable-vec.rs
new file mode 100644
index 00000000..341037c3
--- /dev/null
+++ b/src/test/compile-fail/writing-to-immutable-vec.rs
@@ -0,0 +1,5 @@
+// error-pattern: writing to immutable type
+fn main() {
+ let vec[int] v = vec(1, 2, 3);
+ v.(1) = 4;
+} \ No newline at end of file
diff --git a/src/test/run-pass/foreach-nested-2.rs b/src/test/run-pass/foreach-nested-2.rs
index 35487e7d..d8d67c14 100644
--- a/src/test/run-pass/foreach-nested-2.rs
+++ b/src/test/run-pass/foreach-nested-2.rs
@@ -14,7 +14,8 @@ iter range(int start, int stop) -> int {
}
fn main() {
- let vec[int] a = vec(-1, -1, -1, -1, -1, -1, -1, -1);
+ let vec[mutable int] a =
+ vec[mutable](-1, -1, -1, -1, -1, -1, -1, -1);
let int p = 0;
for each (int i in two()) {
diff --git a/src/test/run-pass/foreach-nested.rs b/src/test/run-pass/foreach-nested.rs
index 848adb26..6287477a 100644
--- a/src/test/run-pass/foreach-nested.rs
+++ b/src/test/run-pass/foreach-nested.rs
@@ -6,7 +6,7 @@ iter two() -> int {
}
fn main() {
- let vec[int] a = vec(-1, -1, -1, -1);
+ let vec[mutable int] a = vec[mutable](-1, -1, -1, -1);
let int p = 0;
for each (int i in two()) {