Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix StackOverflow in big-ish nested CEs #17002

Merged
merged 3 commits into from
Apr 8, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 73 additions & 71 deletions src/Compiler/Checking/CheckComputationExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2596,83 +2596,85 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol
trans CompExprTranslationPass.Initial CustomOperationsMode.Denied emptyVarSpace comp id

and trans firstTry q varSpace comp translatedCtxt =
match tryTrans firstTry q varSpace comp translatedCtxt with
| Some e -> e
| None ->
// This only occurs in final position in a sequence
match comp with
// "do! expr;" in final position is treated as { let! () = expr in return () } when Return is provided (and no Zero with Default attribute is available) or as { let! () = expr in zero } otherwise
| SynExpr.DoBang(rhsExpr, m) ->
let mUnit = rhsExpr.Range
let rhsExpr = mkSourceExpr rhsExpr
cenv.stackGuard.Guard
<| fun () ->
match tryTrans firstTry q varSpace comp translatedCtxt with
| Some e -> e
| None ->
// This only occurs in final position in a sequence
match comp with
// "do! expr;" in final position is treated as { let! () = expr in return () } when Return is provided (and no Zero with Default attribute is available) or as { let! () = expr in zero } otherwise
| SynExpr.DoBang(rhsExpr, m) ->
let mUnit = rhsExpr.Range
let rhsExpr = mkSourceExpr rhsExpr

if isQuery then
error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), m))
if isQuery then
error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), m))

let bodyExpr =
if
isNil (
TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Return" builderTy
let bodyExpr =
if
isNil (
TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Return" builderTy
)
then
SynExpr.ImplicitZero m
else
match
TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Zero" builderTy
with
| minfo :: _ when MethInfoHasAttribute cenv.g m cenv.g.attrib_DefaultValueAttribute minfo -> SynExpr.ImplicitZero m
| _ -> SynExpr.YieldOrReturn((false, true), SynExpr.Const(SynConst.Unit, m), m)

let letBangBind =
SynExpr.LetOrUseBang(
DebugPointAtBinding.NoneAtDo,
false,
false,
SynPat.Const(SynConst.Unit, mUnit),
rhsExpr,
[],
bodyExpr,
m,
SynExprLetOrUseBangTrivia.Zero
)
then
SynExpr.ImplicitZero m
else
match
TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Zero" builderTy
with
| minfo :: _ when MethInfoHasAttribute cenv.g m cenv.g.attrib_DefaultValueAttribute minfo -> SynExpr.ImplicitZero m
| _ -> SynExpr.YieldOrReturn((false, true), SynExpr.Const(SynConst.Unit, m), m)

let letBangBind =
SynExpr.LetOrUseBang(
DebugPointAtBinding.NoneAtDo,
false,
false,
SynPat.Const(SynConst.Unit, mUnit),
rhsExpr,
[],
bodyExpr,
m,
SynExprLetOrUseBangTrivia.Zero
)

trans CompExprTranslationPass.Initial q varSpace letBangBind translatedCtxt
trans CompExprTranslationPass.Initial q varSpace letBangBind translatedCtxt

// "expr;" in final position is treated as { expr; zero }
// Suppress the sequence point on the "zero"
| _ ->
// Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore comp
if isQuery && checkForBinaryApp comp then
trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) translatedCtxt
else
if isQuery && not comp.IsArbExprAndThusAlreadyReportedError then
match comp with
| SynExpr.JoinIn _ -> () // an error will be reported later when we process innerComp1 as a sequential
| _ -> errorR (Error(FSComp.SR.tcUnrecognizedQueryOperator (), comp.RangeOfFirstPortion))

trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) (fun holeFill ->
let fillExpr =
if enableImplicitYield then
let implicitYieldExpr = mkSynCall "Yield" comp.Range [ comp ]

SynExpr.SequentialOrImplicitYield(
DebugPointAtSequential.SuppressExpr,
comp,
holeFill,
implicitYieldExpr,
comp.Range
)
else
SynExpr.Sequential(
DebugPointAtSequential.SuppressExpr,
true,
comp,
holeFill,
comp.Range,
SynExprSequentialTrivia.Zero
)
// "expr;" in final position is treated as { expr; zero }
// Suppress the sequence point on the "zero"
| _ ->
// Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore comp
if isQuery && checkForBinaryApp comp then
trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) translatedCtxt
else
if isQuery && not comp.IsArbExprAndThusAlreadyReportedError then
match comp with
| SynExpr.JoinIn _ -> () // an error will be reported later when we process innerComp1 as a sequential
| _ -> errorR (Error(FSComp.SR.tcUnrecognizedQueryOperator (), comp.RangeOfFirstPortion))

trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) (fun holeFill ->
let fillExpr =
if enableImplicitYield then
let implicitYieldExpr = mkSynCall "Yield" comp.Range [ comp ]

SynExpr.SequentialOrImplicitYield(
DebugPointAtSequential.SuppressExpr,
comp,
holeFill,
implicitYieldExpr,
comp.Range
)
else
SynExpr.Sequential(
DebugPointAtSequential.SuppressExpr,
true,
comp,
holeFill,
comp.Range,
SynExprSequentialTrivia.Zero
)

translatedCtxt fillExpr)
translatedCtxt fillExpr)

and transBind q varSpace bindRange addBindDebugPoint bindName bindArgs (consumePat: SynPat) (innerComp: SynExpr) translatedCtxt =

Expand Down
Loading