@@ -216,7 +216,31 @@ and CheckForNonTailRecCall (cenv: cenv) expr (tailCall: TailCall) =
216
216
| _ -> ()
217
217
218
218
/// Check call arguments, including the return argument.
219
- and CheckCall cenv args ctxts = CheckExprs cenv args ctxts TailCall.No
219
+ and CheckCall cenv args ctxts ( tailCall : TailCall ) =
220
+ // detect CPS-like expressions
221
+ let rec (| IsAppInLambdaBody | _ |) e =
222
+ match stripDebugPoints e with
223
+ | Expr.TyLambda ( bodyExpr = bodyExpr)
224
+ | Expr.Lambda ( bodyExpr = bodyExpr) ->
225
+ match ( stripDebugPoints bodyExpr) with
226
+ | Expr.App _ -> Some( TailCall.YesFromExpr cenv.g e)
227
+ | IsAppInLambdaBody t -> Some t
228
+ | _ -> None
229
+ | _ -> None
230
+
231
+ // if we haven't already decided this is no tail call, try to detect CPS-like expressions
232
+ let tailCall =
233
+ if tailCall = TailCall.No then
234
+ tailCall
235
+ else
236
+ args
237
+ |> List.tryPick ( fun a ->
238
+ match a with
239
+ | IsAppInLambdaBody t -> Some t
240
+ | _ -> None)
241
+ |> Option.defaultValue TailCall.No
242
+
243
+ CheckExprs cenv args ctxts tailCall
220
244
221
245
/// Check call arguments, including the return argument. The receiver argument is handled differently.
222
246
and CheckCallWithReceiver cenv args ctxts =
@@ -330,7 +354,25 @@ and CheckExpr (cenv: cenv) origExpr (ctxt: PermitByRefExpr) (tailCall: TailCall)
330
354
| TypeDefOfExpr g ty when isVoidTy g ty -> ()
331
355
332
356
// Check an application
333
- | Expr.App ( f, _ fty, _ tyargs, argsl, _ m) -> CheckApplication cenv ( f, argsl) tailCall
357
+ | Expr.App ( f, _ fty, _ tyargs, argsl, _ m) ->
358
+ // detect expressions like List.collect
359
+ let checkArgForLambdaWithAppOfMustTailCall e =
360
+ match stripDebugPoints e with
361
+ | Expr.TyLambda ( bodyExpr = bodyExpr)
362
+ | Expr.Lambda ( bodyExpr = bodyExpr) ->
363
+ match bodyExpr with
364
+ | Expr.App ( ValUseAtApp ( vref, _ valUseFlags), _ formalType, _ typeArgs, _ exprs, _ range) ->
365
+ cenv.mustTailCall.Contains vref.Deref
366
+ | _ -> false
367
+ | _ -> false
368
+
369
+ let tailCall =
370
+ if argsl |> List.exists checkArgForLambdaWithAppOfMustTailCall then
371
+ TailCall.No
372
+ else
373
+ tailCall
374
+
375
+ CheckApplication cenv ( f, argsl) tailCall
334
376
335
377
| Expr.Lambda (_, _, _, argvs, _, m, bodyTy) -> CheckLambda cenv expr ( argvs, m, bodyTy) tailCall
336
378
@@ -388,7 +430,7 @@ and CheckApplication cenv (f, argsl) (tailCall: TailCall) : unit =
388
430
if hasReceiver then
389
431
CheckCallWithReceiver cenv argsl ctxts
390
432
else
391
- CheckCall cenv argsl ctxts
433
+ CheckCall cenv argsl ctxts tailCall
392
434
393
435
and CheckLambda cenv expr ( argvs , m , bodyTy ) ( tailCall : TailCall ) =
394
436
let valReprInfo =
@@ -470,12 +512,12 @@ and CheckExprOp cenv (op, tyargs, args, m) ctxt : unit =
470
512
if hasReceiver then
471
513
CheckCallWithReceiver cenv args argContexts
472
514
else
473
- CheckCall cenv args argContexts
515
+ CheckCall cenv args argContexts TailCall.No
474
516
| _ ->
475
517
if hasReceiver then
476
518
CheckCallWithReceiver cenv args argContexts
477
519
else
478
- CheckCall cenv args argContexts
520
+ CheckCall cenv args argContexts TailCall.No
479
521
480
522
| TOp.Tuple tupInfo, _, _ when not ( evalTupInfoIsStruct tupInfo) ->
481
523
match ctxt with
@@ -604,7 +646,7 @@ and CheckLambdas
604
646
// allow byref to occur as return position for byref-typed top level function or method
605
647
CheckExprPermitReturnableByRef cenv body
606
648
else
607
- CheckExprNoByrefs cenv ( TailCall.YesFromExpr cenv.g body) body // TailCall.Yes for CPS
649
+ CheckExprNoByrefs cenv tailCall body
608
650
609
651
// This path is for expression bindings that are not actually lambdas
610
652
| _ ->
0 commit comments