@@ -185,6 +185,7 @@ type error =
185
185
| Uncurried_function_escapes
186
186
| Local_return_annotation_mismatch of Location .t
187
187
| Function_returns_local
188
+ | Tail_call_local_returning
188
189
| Bad_tail_annotation of [`Conflict |`Not_a_tailcall ]
189
190
| Optional_poly_param
190
191
| Exclave_in_nontail_position
@@ -268,20 +269,20 @@ let mk_expected ?explanation ty = { ty; explanation; }
268
269
let case lhs rhs =
269
270
{c_lhs = lhs; c_guard = None ; c_rhs = rhs}
270
271
271
- type function_position = Tail | Nontail
272
+ type position_in_function = FTail | FNontail
272
273
273
274
274
- type region_position =
275
+ type position_in_region =
275
276
(* not the tail of a region*)
276
277
| RNontail
277
278
(* tail of a region,
278
279
together with the mode of that region,
279
280
and whether it is also the tail of a function
280
281
(for tail call escape detection) *)
281
- | RTail of Value_mode .t * function_position
282
+ | RTail of Value_mode .t * position_in_function
282
283
283
284
type expected_mode =
284
- { position : region_position ;
285
+ { position : position_in_region ;
285
286
escaping_context : Env .escaping_context option ;
286
287
(* the upper bound of mode*)
287
288
mode : Value_mode .t ;
@@ -306,23 +307,59 @@ type expected_mode =
306
307
(* for t in tuple_modes, t <= regional_to_global mode *)
307
308
}
308
309
309
- let tail_call_escape = function
310
- | RTail (_ , Tail) -> true
311
- | _ -> false
310
+ type position_and_mode = {
311
+ (* apply_position of the current application *)
312
+ apply_position : apply_position ;
313
+ (* [Some m] if [position] is [Tail], where m is the mode of the surrounding
314
+ function's return mode *)
315
+ region_mode : Value_mode .t option ;
316
+ }
317
+
318
+ let position_and_mode_default = {
319
+ apply_position = Default ;
320
+ region_mode = None ;
321
+ }
312
322
313
- let apply_position env (expected_mode : expected_mode ) sexp : apply_position =
323
+ (* * The function produces two values, apply_position and region_mode.
324
+ Invariant: if apply_position = Tail, then region_mode = Some ... *)
325
+ let position_and_mode env (expected_mode : expected_mode ) sexp
326
+ : position_and_mode =
314
327
let fail err =
315
328
raise (Error (sexp.pexp_loc, env, Bad_tail_annotation err))
316
329
in
317
- match
318
- Builtin_attributes. tailcall sexp.pexp_attributes,
319
- tail_call_escape expected_mode.position
320
- with
321
- | Ok (None | Some `Tail_if_possible ), false -> Default
322
- | Ok (None | Some `Tail | Some `Tail_if_possible ), true -> Tail
323
- | Ok (Some `Nontail), _ -> Nontail
324
- | Ok (Some `Tail), false -> fail `Not_a_tailcall
325
- | Error `Conflict , _ -> fail `Conflict
330
+ let requested =
331
+ match Builtin_attributes. tailcall sexp.pexp_attributes with
332
+ | Ok r -> r
333
+ | Error `Conflict -> fail `Conflict
334
+ in
335
+ match expected_mode.position with
336
+ | RTail (m ,FTail) -> begin
337
+ match requested with
338
+ | Some `Tail | Some `Tail_if_possible | None ->
339
+ {apply_position = Tail ; region_mode = Some m}
340
+ | Some `Nontail -> {apply_position = Nontail ; region_mode = None }
341
+ end
342
+ | RNontail | RTail (_ , FNontail) -> begin
343
+ match requested with
344
+ | None | Some `Tail_if_possible ->
345
+ {apply_position = Default ; region_mode = None }
346
+ | Some `Nontail -> {apply_position = Nontail ; region_mode = None }
347
+ | Some `Tail -> fail `Not_a_tailcall
348
+ end
349
+
350
+ (* ap_mode is the return mode of the current application *)
351
+ let check_tail_call_local_returning loc env ap_mode {region_mode; _} =
352
+ match region_mode with
353
+ | Some region_mode -> begin
354
+ (* This application is at the tail of a function with a region;
355
+ if ap_mode is local, funct_ret_mode needs to be local as well. *)
356
+ match
357
+ Value_mode. submode (Value_mode. of_alloc ap_mode) region_mode
358
+ with
359
+ | Ok () -> ()
360
+ | Error _ -> raise (Error (loc, env, Tail_call_local_returning ))
361
+ end
362
+ | None -> ()
326
363
327
364
let mode_default mode =
328
365
{ position = RNontail ;
@@ -335,14 +372,14 @@ let mode_default mode =
335
372
mode is the mode of the function region *)
336
373
let mode_return mode =
337
374
{ (mode_default (Value_mode. local_to_regional mode)) with
338
- position = RTail (mode, Tail );
375
+ position = RTail (mode, FTail );
339
376
escaping_context = Some Return ;
340
377
}
341
378
342
379
(* used when entering a region.*)
343
380
let mode_region mode =
344
381
{ (mode_default (Value_mode. local_to_regional mode)) with
345
- position = RTail (mode, Nontail );
382
+ position = RTail (mode, FNontail );
346
383
escaping_context = None ;
347
384
}
348
385
@@ -405,7 +442,7 @@ let mode_argument ~funct ~index ~position ~partial_app alloc_mode =
405
442
406
443
let mode_lazy =
407
444
{ mode_global with
408
- position = RTail (Value_mode. global, Tail ) }
445
+ position = RTail (Value_mode. global, FTail ) }
409
446
410
447
411
448
let submode ~loc ~env ~reason mode expected_mode =
@@ -4412,9 +4449,9 @@ and type_expect_
4412
4449
end
4413
4450
| Pexp_apply (sfunct , sargs ) ->
4414
4451
assert (sargs <> [] );
4415
- let position = apply_position env expected_mode sexp in
4452
+ let pm = position_and_mode env expected_mode sexp in
4416
4453
let funct_mode, funct_expected_mode =
4417
- match position with
4454
+ match pm.apply_position with
4418
4455
| Tail ->
4419
4456
let mode = Value_mode. local_to_regional (Value_mode. newvar () ) in
4420
4457
mode, mode_tailcall_function mode
@@ -4479,12 +4516,12 @@ and type_expect_
4479
4516
| _ ->
4480
4517
(rt, funct), sargs
4481
4518
in
4482
- let (args, ty_res, ap_mode, position ) =
4483
- type_application env loc expected_mode position funct funct_mode sargs rt
4519
+ let (args, ty_res, ap_mode, pm ) =
4520
+ type_application env loc expected_mode pm funct funct_mode sargs rt
4484
4521
in
4485
4522
4486
4523
rue {
4487
- exp_desc = Texp_apply (funct, args, position , ap_mode);
4524
+ exp_desc = Texp_apply (funct, args, pm.apply_position , ap_mode);
4488
4525
exp_loc = loc; exp_extra = [] ;
4489
4526
exp_type = ty_res;
4490
4527
exp_attributes = sexp.pexp_attributes;
@@ -4903,7 +4940,7 @@ and type_expect_
4903
4940
(mk_expected ~explanation: While_loop_conditional Predef. type_bool)
4904
4941
in
4905
4942
let body_env = Env. add_region_lock env in
4906
- let position = RTail (Value_mode. local, Nontail ) in
4943
+ let position = RTail (Value_mode. local, FNontail ) in
4907
4944
let wh_body =
4908
4945
type_statement ~explanation: While_loop_body
4909
4946
~position body_env sbody
@@ -4929,7 +4966,7 @@ and type_expect_
4929
4966
type_for_loop_index ~loc ~env ~param
4930
4967
in
4931
4968
let new_env = Env. add_region_lock new_env in
4932
- let position = RTail (Value_mode. local, Nontail ) in
4969
+ let position = RTail (Value_mode. local, FNontail ) in
4933
4970
let for_body =
4934
4971
type_statement ~explanation: For_loop_body ~position new_env sbody
4935
4972
in
@@ -5050,7 +5087,7 @@ and type_expect_
5050
5087
| Pexp_send (e , {txt =met } ) ->
5051
5088
if ! Clflags. principal then begin_def () ;
5052
5089
let obj = type_exp env mode_global e in
5053
- let ap_pos = apply_position env expected_mode sexp in
5090
+ let pm = position_and_mode env expected_mode sexp in
5054
5091
let (meth, typ) =
5055
5092
match obj.exp_desc with
5056
5093
| Texp_ident (_ , _ , {val_kind = Val_self (sign , meths , _ , _ )} , _ ) ->
@@ -5154,7 +5191,7 @@ and type_expect_
5154
5191
assert false
5155
5192
in
5156
5193
rue {
5157
- exp_desc = Texp_send (obj, meth, ap_pos ,
5194
+ exp_desc = Texp_send (obj, meth, pm.apply_position ,
5158
5195
register_allocation expected_mode
5159
5196
);
5160
5197
exp_loc = loc; exp_extra = [] ;
@@ -5163,14 +5200,14 @@ and type_expect_
5163
5200
exp_env = env }
5164
5201
| Pexp_new cl ->
5165
5202
let (cl_path, cl_decl) = Env. lookup_class ~loc: cl.loc cl.txt env in
5166
- let ap_pos = apply_position env expected_mode sexp in
5203
+ let pm = position_and_mode env expected_mode sexp in
5167
5204
begin match cl_decl.cty_new with
5168
5205
None ->
5169
5206
raise(Error (loc, env, Virtual_class cl.txt))
5170
5207
| Some ty ->
5171
5208
rue {
5172
5209
exp_desc =
5173
- Texp_new (cl_path, cl, cl_decl, ap_pos );
5210
+ Texp_new (cl_path, cl, cl_decl, pm.apply_position );
5174
5211
exp_loc = loc; exp_extra = [] ;
5175
5212
exp_type = instance ty;
5176
5213
exp_attributes = sexp.pexp_attributes;
@@ -6465,7 +6502,8 @@ and type_apply_arg env ~app_loc ~funct ~index ~position ~partial_app (lbl, arg)
6465
6502
(lbl, Arg (arg, Value_mode. global))
6466
6503
| Omitted _ as arg -> (lbl, arg)
6467
6504
6468
- and type_application env app_loc expected_mode position funct funct_mode sargs ret_tvar =
6505
+ and type_application env app_loc expected_mode pm
6506
+ funct funct_mode sargs ret_tvar =
6469
6507
let is_ignore funct =
6470
6508
is_prim ~name: " %ignore" funct &&
6471
6509
(try ignore (filter_arrow_mono env (instance funct.exp_type) Nolabel ); true
@@ -6489,11 +6527,12 @@ and type_application env app_loc expected_mode position funct funct_mode sargs r
6489
6527
submode ~loc: app_loc ~env ~reason: Other
6490
6528
mode_res expected_mode;
6491
6529
let marg =
6492
- mode_argument ~funct ~index: 0 ~position ~partial_app: false marg
6530
+ mode_argument ~funct ~index: 0 ~position: (pm.apply_position)
6531
+ ~partial_app: false marg
6493
6532
in
6494
6533
let exp = type_expect env marg sarg (mk_expected ty_arg) in
6495
6534
check_partial_application ~statement: false exp;
6496
- ([Nolabel , Arg exp], ty_res, ap_mode, position )
6535
+ ([Nolabel , Arg exp], ty_res, ap_mode, pm )
6497
6536
| _ ->
6498
6537
let ty = funct.exp_type in
6499
6538
let ignore_labels =
@@ -6519,10 +6558,11 @@ and type_application env app_loc expected_mode position funct funct_mode sargs r
6519
6558
(Value_mode. regional_to_local_alloc funct_mode) sargs ret_tvar
6520
6559
in
6521
6560
let partial_app = is_partial_apply untyped_args in
6522
- let position = if partial_app then Default else position in
6561
+ let pm = if partial_app then position_and_mode_default else pm in
6523
6562
let args =
6524
6563
List. mapi (fun index arg ->
6525
- type_apply_arg env ~app_loc ~funct ~index ~position ~partial_app arg)
6564
+ type_apply_arg env ~app_loc ~funct ~index
6565
+ ~position: (pm.apply_position) ~partial_app arg)
6526
6566
untyped_args
6527
6567
in
6528
6568
let ty_ret, mode_ret, args =
@@ -6540,7 +6580,9 @@ and type_application env app_loc expected_mode position funct funct_mode sargs r
6540
6580
in
6541
6581
submode ~loc: app_loc ~env ~reason: (Application ty_ret)
6542
6582
mode_ret expected_mode;
6543
- args, ty_ret, ap_mode, position
6583
+
6584
+ check_tail_call_local_returning app_loc env ap_mode pm;
6585
+ args, ty_ret, ap_mode, pm
6544
6586
6545
6587
and type_construct env (expected_mode : expected_mode ) loc lid sarg
6546
6588
ty_expected_explained attrs =
@@ -8312,7 +8354,11 @@ let report_error ~loc env = function
8312
8354
" Optional parameters cannot be polymorphic"
8313
8355
| Function_returns_local ->
8314
8356
Location. errorf ~loc
8315
- " This function is local returning, but was expected otherwise"
8357
+ " This function is local-returning, but was expected otherwise"
8358
+ | Tail_call_local_returning ->
8359
+ Location. errorf ~loc
8360
+ " @[This application is local-returning, but is at the tail @ \
8361
+ position of a function that is not local-returning@]"
8316
8362
| Layout_not_enabled c ->
8317
8363
Location. errorf ~loc
8318
8364
" @[Layout %s is used here, but the appropriate layouts extension is \
0 commit comments