@@ -216,7 +216,31 @@ and CheckForNonTailRecCall (cenv: cenv) expr (tailCall: TailCall) =
216216 | _ -> ()
217217
218218/// 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
220244
221245/// Check call arguments, including the return argument. The receiver argument is handled differently.
222246and CheckCallWithReceiver cenv args ctxts =
@@ -330,7 +354,25 @@ and CheckExpr (cenv: cenv) origExpr (ctxt: PermitByRefExpr) (tailCall: TailCall)
330354 | TypeDefOfExpr g ty when isVoidTy g ty -> ()
331355
332356 // 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
334376
335377 | Expr.Lambda (_, _, _, argvs, _, m, bodyTy) -> CheckLambda cenv expr ( argvs, m, bodyTy) tailCall
336378
@@ -388,7 +430,7 @@ and CheckApplication cenv (f, argsl) (tailCall: TailCall) : unit =
388430 if hasReceiver then
389431 CheckCallWithReceiver cenv argsl ctxts
390432 else
391- CheckCall cenv argsl ctxts
433+ CheckCall cenv argsl ctxts tailCall
392434
393435and CheckLambda cenv expr ( argvs , m , bodyTy ) ( tailCall : TailCall ) =
394436 let valReprInfo =
@@ -470,12 +512,12 @@ and CheckExprOp cenv (op, tyargs, args, m) ctxt : unit =
470512 if hasReceiver then
471513 CheckCallWithReceiver cenv args argContexts
472514 else
473- CheckCall cenv args argContexts
515+ CheckCall cenv args argContexts TailCall.No
474516 | _ ->
475517 if hasReceiver then
476518 CheckCallWithReceiver cenv args argContexts
477519 else
478- CheckCall cenv args argContexts
520+ CheckCall cenv args argContexts TailCall.No
479521
480522 | TOp.Tuple tupInfo, _, _ when not ( evalTupInfoIsStruct tupInfo) ->
481523 match ctxt with
@@ -604,7 +646,7 @@ and CheckLambdas
604646 // allow byref to occur as return position for byref-typed top level function or method
605647 CheckExprPermitReturnableByRef cenv body
606648 else
607- CheckExprNoByrefs cenv ( TailCall.YesFromExpr cenv.g body) body // TailCall.Yes for CPS
649+ CheckExprNoByrefs cenv tailCall body
608650
609651 // This path is for expression bindings that are not actually lambdas
610652 | _ ->
0 commit comments