@@ -12,78 +12,7 @@ let iflog cx thunk =
12
12
else ()
13
13
;;
14
14
15
- let mutability_checking_visitor
16
- (cx :ctxt )
17
- (inner :Walk.visitor )
18
- : Walk.visitor =
19
- (*
20
- * This visitor enforces the following rules:
21
- *
22
- * - A channel type carrying a mutable type is illegal.
23
- *
24
- * - Writing to an immutable slot is illegal.
25
- *
26
- * - Forming a mutable alias to an immutable slot is illegal.
27
- *
28
- *)
29
- let visit_ty_pre t =
30
- match t with
31
- Ast. TY_chan t' when type_has_state cx t' ->
32
- err None " channel of mutable type: %a " Ast. sprintf_ty t'
33
- | _ -> ()
34
- in
35
-
36
- let check_write s dst =
37
- let is_init = Hashtbl. mem cx.ctxt_stmt_is_init s.id in
38
- let dst_ty = lval_ty cx dst in
39
- let is_mutable =
40
- match dst_ty with
41
- Ast. TY_mutable _ -> true
42
- | _ -> false
43
- in
44
- iflog cx
45
- (fun _ -> log cx " checking %swrite to %slval #%d = %a of type %a"
46
- (if is_init then " initializing " else " " )
47
- (if is_mutable then " mutable " else " " )
48
- (int_of_node (lval_base_id dst))
49
- Ast. sprintf_lval dst
50
- Ast. sprintf_ty dst_ty);
51
- if (is_mutable or is_init)
52
- then ()
53
- else err (Some s.id)
54
- " writing to immutable type %a in statement %a"
55
- Ast. sprintf_ty dst_ty Ast. sprintf_stmt s
56
- in
57
- (* FIXME (issue #75): enforce the no-write-alias-to-immutable-slot
58
- * rule.
59
- *)
60
- let visit_stmt_pre s =
61
- begin
62
- match s.node with
63
- Ast. STMT_copy (lv_dst , _ )
64
- | Ast. STMT_call (lv_dst, _, _)
65
- | Ast. STMT_spawn (lv_dst, _, _, _, _)
66
- | Ast. STMT_recv (lv_dst, _)
67
- | Ast. STMT_bind (lv_dst, _, _)
68
- | Ast. STMT_new_rec (lv_dst, _, _)
69
- | Ast. STMT_new_tup (lv_dst, _)
70
- | Ast. STMT_new_vec (lv_dst, _, _)
71
- | Ast. STMT_new_str (lv_dst, _)
72
- | Ast. STMT_new_port lv_dst
73
- | Ast. STMT_new_chan (lv_dst, _)
74
- | Ast. STMT_new_box (lv_dst , _ , _ ) ->
75
- check_write s lv_dst
76
- | _ -> ()
77
- end ;
78
- inner.Walk. visit_stmt_pre s
79
- in
80
-
81
- { inner with
82
- Walk. visit_ty_pre = visit_ty_pre;
83
- Walk. visit_stmt_pre = visit_stmt_pre }
84
- ;;
85
-
86
- let function_effect_propagation_visitor
15
+ let effect_calculating_visitor
87
16
(item_effect :(node_id, Ast.effect) Hashtbl.t )
88
17
(cx :ctxt )
89
18
(inner :Walk.visitor )
@@ -93,6 +22,7 @@ let function_effect_propagation_visitor
93
22
* its statements:
94
23
*
95
24
* - Communication statements lower to 'impure'
25
+ * - Writing to anything other than a local slot lowers to 'impure'
96
26
* - Native calls lower to 'unsafe'
97
27
* - Calling a function with effect e lowers to e.
98
28
*)
@@ -159,13 +89,27 @@ let function_effect_propagation_visitor
159
89
end;
160
90
in
161
91
92
+ let note_write s dst =
93
+ (* FIXME (issue #182): this is too aggressive; won't permit writes to
94
+ * interior components of records or tuples. It should at least do that,
95
+ * possibly handle escape analysis on the pointee for things like vecs as
96
+ * well. *)
97
+ if lval_base_is_slot cx dst
98
+ then
99
+ let base_slot = lval_base_slot cx dst in
100
+ match dst, base_slot.Ast. slot_mode with
101
+ (Ast. LVAL_base _ , Ast. MODE_local) -> ()
102
+ | _ -> lower_to s Ast. EFF_impure
103
+ in
104
+
162
105
let visit_stmt_pre s =
163
106
begin
164
107
match s.node with
165
108
Ast. STMT_send _
166
109
| Ast. STMT_recv _ -> lower_to s Ast. EFF_impure
167
110
168
- | Ast. STMT_call (_ , fn , _ ) ->
111
+ | Ast. STMT_call (lv_dst , fn , _ ) ->
112
+ note_write s lv_dst;
169
113
let lower_to_callee_ty t =
170
114
match simplified_ty t with
171
115
Ast. TY_fn (_ , taux ) ->
@@ -185,6 +129,19 @@ let function_effect_propagation_visitor
185
129
| Some (REQUIRED_LIB_rust _ , _ ) -> ()
186
130
| Some _ -> lower_to s Ast. EFF_unsafe
187
131
end
132
+
133
+ | Ast. STMT_copy (lv_dst, _)
134
+ | Ast. STMT_spawn (lv_dst, _, _, _, _)
135
+ | Ast. STMT_bind (lv_dst, _, _)
136
+ | Ast. STMT_new_rec (lv_dst, _, _)
137
+ | Ast. STMT_new_tup (lv_dst, _)
138
+ | Ast. STMT_new_vec (lv_dst, _, _)
139
+ | Ast. STMT_new_str (lv_dst, _)
140
+ | Ast. STMT_new_port lv_dst
141
+ | Ast. STMT_new_chan (lv_dst, _)
142
+ | Ast. STMT_new_box (lv_dst , _ , _ ) ->
143
+ note_write s lv_dst
144
+
188
145
| _ -> ()
189
146
end ;
190
147
inner.Walk. visit_stmt_pre s
@@ -200,19 +157,6 @@ let function_effect_propagation_visitor
200
157
Walk. visit_stmt_pre = visit_stmt_pre }
201
158
;;
202
159
203
- let binding_effect_propagation_visitor
204
- ((* cx*) _ :ctxt )
205
- (inner :Walk.visitor )
206
- : Walk.visitor =
207
- (* This visitor lowers the effect of an object or binding according
208
- * to its slots: holding a 'state' slot lowers any obj item, or
209
- * bind-stmt LHS, to 'state'.
210
- *
211
- * Binding (or implicitly just making a native 1st-class) makes the LHS
212
- * unsafe.
213
- *)
214
- inner
215
- ;;
216
160
217
161
let effect_checking_visitor
218
162
(item_auth :(node_id, Ast.effect) Hashtbl.t )
@@ -221,7 +165,7 @@ let effect_checking_visitor
221
165
(inner :Walk.visitor )
222
166
: Walk.visitor =
223
167
(*
224
- * This visitor checks that each type, item and obj declares
168
+ * This visitor checks that each fn declares
225
169
* effects consistent with what we calculated.
226
170
*)
227
171
let auth_stack = Stack. create () in
@@ -250,7 +194,8 @@ let effect_checking_visitor
250
194
end;
251
195
begin
252
196
match i.node.Ast. decl_item with
253
- Ast. MOD_ITEM_fn f ->
197
+ Ast. MOD_ITEM_fn f
198
+ when htab_search cx.ctxt_required_items i.id = None ->
254
199
let e =
255
200
match htab_search item_effect i.id with
256
201
None -> Ast. EFF_pure
@@ -319,11 +264,7 @@ let process_crate
319
264
let item_effect = Hashtbl. create 0 in
320
265
let passes =
321
266
[|
322
- (mutability_checking_visitor cx
323
- Walk. empty_visitor);
324
- (function_effect_propagation_visitor item_effect cx
325
- Walk. empty_visitor);
326
- (binding_effect_propagation_visitor cx
267
+ (effect_calculating_visitor item_effect cx
327
268
Walk. empty_visitor);
328
269
(effect_checking_visitor item_auth item_effect cx
329
270
Walk. empty_visitor);
0 commit comments