@@ -20,7 +20,9 @@ type ty_pat =
20
20
type fn_ctx = {
21
21
fnctx_return_type : Ast .ty ;
22
22
fnctx_is_iter : bool ;
23
- mutable fnctx_just_saw_ret : bool
23
+ mutable fnctx_just_saw_ret : bool ;
24
+ fnctx_blocks : Common .node_id Stack .t ;
25
+ fnctx_slot_decls : (Ast .slot_key ,Common .node_id ) Hashtbl .t ;
24
26
}
25
27
26
28
exception Type_error of string * string
@@ -188,7 +190,7 @@ let type_error cx expected actual =
188
190
189
191
(* We explicitly curry [cx] like this to avoid threading it through all the
190
192
* inner functions. *)
191
- let check_stmt (cx :Semant.ctxt ) : (fn_ctx -> Ast.stmt -> unit) =
193
+ let check_block (cx :Semant.ctxt ) : (fn_ctx -> Ast.block -> unit) =
192
194
let pretty_ty_str = Semant. pretty_ty_str cx (Ast. sprintf_ty () ) in
193
195
194
196
(* Returns the part of the type that matters for typechecking. *)
@@ -894,7 +896,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
894
896
895
897
(* Again as above, we explicitly curry [fn_ctx] to avoid threading it
896
898
* through these functions. *)
897
- let check_stmt (fn_ctx :fn_ctx ) : (Ast.stmt -> unit) =
899
+ let check_block (fn_ctx :fn_ctx ) : (Ast.block -> unit) =
898
900
let check_ret (stmt :Ast.stmt ) : unit =
899
901
fn_ctx.fnctx_just_saw_ret < -
900
902
match stmt.Common. node with
@@ -904,7 +906,8 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
904
906
in
905
907
906
908
let rec check_block (block :Ast.block ) : unit =
907
- Array. iter check_stmt block.Common. node
909
+ Stack. push block.Common. id fn_ctx.fnctx_blocks;
910
+ Array. iter check_stmt' block.Common. node
908
911
909
912
and check_stmt (stmt :Ast.stmt ) : unit =
910
913
check_ret stmt;
@@ -1050,7 +1053,7 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
1050
1053
1051
1054
| Ast. STMT_while w | Ast. STMT_do_while w ->
1052
1055
let (stmts, expr) = w.Ast. while_lval in
1053
- Array. iter check_stmt stmts;
1056
+ Array. iter check_stmt' stmts;
1054
1057
demand Ast. TY_bool (check_expr expr);
1055
1058
check_block w.Ast. while_body
1056
1059
@@ -1098,7 +1101,10 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
1098
1101
let get_pat arm = fst arm.Common. node in
1099
1102
let pats = Array. map get_pat alt_tag.Ast. alt_tag_arms in
1100
1103
let ty = check_lval alt_tag.Ast. alt_tag_lval in
1101
- Array. iter (check_pat ty) pats
1104
+ let get_block arm = snd arm.Common. node in
1105
+ let blocks = Array. map get_block alt_tag.Ast. alt_tag_arms in
1106
+ Array. iter (check_pat ty) pats;
1107
+ Array. iter check_block blocks
1102
1108
1103
1109
| Ast. STMT_alt_type _ -> () (* TODO *)
1104
1110
@@ -1132,10 +1138,12 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
1132
1138
1133
1139
| Ast. STMT_block block -> check_block block
1134
1140
1135
- | Ast. STMT_decl _ -> () (* always well-typed *)
1136
- in
1141
+ | Ast. STMT_decl (Ast. DECL_slot (slot_key , _ )) ->
1142
+ Hashtbl. add fn_ctx.fnctx_slot_decls slot_key stmt.Common. id
1143
+
1144
+ | Ast. STMT_decl (Ast. DECL_mod_item _ ) -> () (* always well-typed *)
1137
1145
1138
- let check_stmt' stmt =
1146
+ and check_stmt' stmt =
1139
1147
try
1140
1148
check_stmt stmt
1141
1149
with Type_error (expected , actual ) ->
@@ -1145,9 +1153,9 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
1145
1153
expected
1146
1154
actual
1147
1155
in
1148
- check_stmt'
1156
+ check_block
1149
1157
in
1150
- check_stmt
1158
+ check_block
1151
1159
1152
1160
let create_tag_graph_nodes (cx :Semant.ctxt ) =
1153
1161
let make_graph_node id _ =
@@ -1259,8 +1267,6 @@ let check_for_tag_cycles (cx:Semant.ctxt) =
1259
1267
Hashtbl. iter check_node cx.Semant. ctxt_tag_containment
1260
1268
1261
1269
let process_crate (cx :Semant.ctxt ) (crate :Ast.crate ) : unit =
1262
- let fn_ctx_stack = Stack. create () in
1263
-
1264
1270
(* Verify that, if main is present, it has the right form. *)
1265
1271
let verify_main (item_id :Common.node_id ) : unit =
1266
1272
let path_name = Hashtbl. find cx.Semant. ctxt_all_item_names item_id in
@@ -1284,28 +1290,43 @@ let process_crate (cx:Semant.ctxt) (crate:Ast.crate) : unit =
1284
1290
in
1285
1291
1286
1292
let visitor (cx :Semant.ctxt ) (inner :Walk.visitor ) : Walk.visitor =
1287
- let push_fn_ctx (ret_ty :Ast.ty ) (is_iter :bool ) =
1288
- let fn_ctx = {
1293
+ let create_fn_ctx (ret_ty :Ast.ty ) (is_iter :bool ) =
1294
+ {
1289
1295
fnctx_return_type = ret_ty;
1290
1296
fnctx_is_iter = is_iter;
1291
- fnctx_just_saw_ret = false
1292
- } in
1293
- Stack. push fn_ctx fn_ctx_stack
1297
+ fnctx_just_saw_ret = false ;
1298
+ fnctx_blocks = Stack. create () ;
1299
+ fnctx_slot_decls = Hashtbl. create 0 ;
1300
+ }
1294
1301
in
1295
1302
1296
- let push_fn_ctx_of_ty_fn (ty_fn :Ast.ty_fn ) : unit =
1303
+ let create_fn_ctx_of_ty_fn (ty_fn :Ast.ty_fn ) : fn_ctx =
1297
1304
let (ty_sig, ty_fn_aux) = ty_fn in
1298
1305
let ret_ty = ty_sig.Ast. sig_output_slot.Ast. slot_ty in
1299
1306
let is_iter = ty_fn_aux.Ast. fn_is_iter in
1300
- push_fn_ctx (Common. option_get ret_ty) is_iter
1307
+ create_fn_ctx (Common. option_get ret_ty) is_iter
1301
1308
in
1302
1309
1303
- let finish_function (item_id :Common.node_id ) =
1304
- let fn_ctx = Stack. pop fn_ctx_stack in
1310
+ let finish_function (fn_ctx :fn_ctx ) (item_id :Common.node_id option ) =
1305
1311
if not fn_ctx.fnctx_just_saw_ret &&
1306
1312
fn_ctx.fnctx_return_type <> Ast. TY_nil &&
1307
1313
not fn_ctx.fnctx_is_iter then
1308
- Common. err (Some item_id) " this function must return a value"
1314
+ Common. err item_id " this function must return a value" ;
1315
+
1316
+ let check_for_slot_types_in_block block_id =
1317
+ let check_for_slot_type slot_key defn_id =
1318
+ match Hashtbl. find cx.Semant. ctxt_all_defns defn_id with
1319
+ Semant. DEFN_slot { Ast. slot_ty = None ; Ast. slot_mode = _ } ->
1320
+ let stmt_id = Hashtbl. find fn_ctx.fnctx_slot_decls slot_key in
1321
+ Common. err
1322
+ (Some stmt_id)
1323
+ " no type could be inferred for this slot"
1324
+ | _ -> ()
1325
+ in
1326
+ let block_slots = Hashtbl. find cx.Semant. ctxt_block_slots block_id in
1327
+ Hashtbl. iter check_for_slot_type block_slots
1328
+ in
1329
+ Stack. iter check_for_slot_types_in_block fn_ctx.fnctx_blocks
1309
1330
in
1310
1331
1311
1332
let check_fn_ty_validity item_id (ty_sig , _ ) =
@@ -1328,14 +1349,16 @@ let process_crate (cx:Semant.ctxt) (crate:Ast.crate) : unit =
1328
1349
let visit_mod_item_pre _ _ item =
1329
1350
let { Common. node = item; Common. id = item_id } = item in
1330
1351
match item.Ast. decl_item with
1331
- Ast. MOD_ITEM_fn _ when
1352
+ Ast. MOD_ITEM_fn fn when
1332
1353
not (Hashtbl. mem cx.Semant. ctxt_required_items item_id) ->
1333
1354
let fn_ty = Hashtbl. find cx.Semant. ctxt_all_item_types item_id in
1334
1355
begin
1335
1356
match fn_ty with
1336
1357
Ast. TY_fn ty_fn ->
1337
1358
check_fn_ty_validity item_id ty_fn;
1338
- push_fn_ctx_of_ty_fn ty_fn
1359
+ let fn_ctx = create_fn_ctx_of_ty_fn ty_fn in
1360
+ check_block cx fn_ctx fn.Ast. fn_body;
1361
+ finish_function fn_ctx (Some item_id)
1339
1362
| _ ->
1340
1363
Common. bug ()
1341
1364
" Type.visit_mod_item_pre: fn item didn't have a fn type"
@@ -1346,10 +1369,7 @@ let process_crate (cx:Semant.ctxt) (crate:Ast.crate) : unit =
1346
1369
let item_id = item.Common. id in
1347
1370
verify_main item_id;
1348
1371
match item.Common. node.Ast. decl_item with
1349
- Ast. MOD_ITEM_fn _ when
1350
- not (Hashtbl. mem cx.Semant. ctxt_required_items item_id) ->
1351
- finish_function item_id
1352
- | Ast. MOD_ITEM_tag (_ , id , n ) -> populate_tag_graph_node cx id n
1372
+ Ast. MOD_ITEM_tag (_ , id , n ) -> populate_tag_graph_node cx id n
1353
1373
| _ -> ()
1354
1374
in
1355
1375
@@ -1366,33 +1386,21 @@ let process_crate (cx:Semant.ctxt) (crate:Ast.crate) : unit =
1366
1386
match tsig.Ast. sig_output_slot with
1367
1387
{ Ast. slot_ty = Some (Ast. TY_obj (_ , methods ));
1368
1388
Ast. slot_mode = _ } ->
1369
- push_fn_ctx_of_ty_fn (Hashtbl. find methods ident)
1389
+ let fn_ty = Hashtbl. find methods ident in
1390
+ let fn_ctx = create_fn_ctx_of_ty_fn fn_ty in
1391
+ let obj_fns = obj.Common. node.Ast. obj_fns in
1392
+ let fn = Hashtbl. find obj_fns ident in
1393
+ check_block cx fn_ctx fn.Common. node.Ast. fn_body;
1394
+ finish_function fn_ctx (Some fn.Common. id)
1370
1395
| _ -> bad()
1371
1396
end
1372
1397
| _ -> bad()
1373
1398
in
1374
- let visit_obj_fn_post _ _ item = finish_function (item.Common. id) in
1375
-
1376
- let visit_obj_drop_pre _ _ = push_fn_ctx Ast. TY_nil false in
1377
- let visit_obj_drop_post _ _ = ignore (Stack. pop fn_ctx_stack) in
1378
1399
1379
- let visit_stmt_pre (stmt :Ast.stmt ) : unit =
1380
- try
1381
- iflog cx
1382
- begin
1383
- fun _ ->
1384
- log cx " " ;
1385
- log cx " typechecking stmt: %a" Ast. sprintf_stmt stmt;
1386
- log cx " " ;
1387
- end;
1388
- check_stmt cx (Stack. top fn_ctx_stack) stmt;
1389
- iflog cx
1390
- begin
1391
- fun _ ->
1392
- log cx " finished typechecking stmt: %a" Ast. sprintf_stmt stmt;
1393
- end;
1394
- with Common. Semant_err (None, msg ) ->
1395
- raise (Common. Semant_err ((Some stmt.Common. id), msg))
1400
+ let visit_obj_drop_pre _ block =
1401
+ let fn_ctx = create_fn_ctx Ast. TY_nil false in
1402
+ check_block cx fn_ctx block;
1403
+ finish_function fn_ctx None
1396
1404
in
1397
1405
1398
1406
let visit_crate_pre _ : unit = create_tag_graph_nodes cx in
@@ -1411,13 +1419,10 @@ let process_crate (cx:Semant.ctxt) (crate:Ast.crate) : unit =
1411
1419
1412
1420
{
1413
1421
inner with
1414
- Walk. visit_stmt_pre = visit_stmt_pre;
1415
1422
Walk. visit_mod_item_pre = visit_mod_item_pre;
1416
1423
Walk. visit_mod_item_post = visit_mod_item_post;
1417
1424
Walk. visit_obj_fn_pre = visit_obj_fn_pre;
1418
- Walk. visit_obj_fn_post = visit_obj_fn_post;
1419
1425
Walk. visit_obj_drop_pre = visit_obj_drop_pre;
1420
- Walk. visit_obj_drop_post = visit_obj_drop_post;
1421
1426
Walk. visit_crate_pre = visit_crate_pre;
1422
1427
Walk. visit_crate_post = visit_crate_post
1423
1428
}
0 commit comments