From 8b099b632002092f5b523c7188b710505fdf7be3 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Tue, 26 Jul 2022 16:14:03 -0700
Subject: [PATCH 01/15] Integer n .. step .. m for loop optimization
---
src/Compiler/Checking/CheckExpressions.fs | 23 +-
src/Compiler/Checking/PostInferenceChecks.fs | 3 +-
src/Compiler/CodeGen/IlxGen.fs | 165 ++++--
src/Compiler/FSStrings.resx | 3 +
src/Compiler/Optimize/LowerStateMachines.fs | 40 +-
src/Compiler/Optimize/Optimizer.fs | 26 +-
src/Compiler/TypedTree/TypedTree.fs | 5 +-
src/Compiler/TypedTree/TypedTree.fsi | 3 +
src/Compiler/TypedTree/TypedTreeOps.fs | 23 +-
src/Compiler/TypedTree/TypedTreeOps.fsi | 6 +-
src/Compiler/TypedTree/TypedTreePickle.fs | 4 +-
src/Compiler/xlf/FSStrings.cs.xlf | 5 +
src/Compiler/xlf/FSStrings.de.xlf | 5 +
src/Compiler/xlf/FSStrings.es.xlf | 5 +
src/Compiler/xlf/FSStrings.fr.xlf | 5 +
src/Compiler/xlf/FSStrings.it.xlf | 5 +
src/Compiler/xlf/FSStrings.ja.xlf | 5 +
src/Compiler/xlf/FSStrings.ko.xlf | 5 +
src/Compiler/xlf/FSStrings.pl.xlf | 5 +
src/Compiler/xlf/FSStrings.pt-BR.xlf | 5 +
src/Compiler/xlf/FSStrings.ru.xlf | 5 +
src/Compiler/xlf/FSStrings.tr.xlf | 5 +
src/Compiler/xlf/FSStrings.zh-Hans.xlf | 5 +
src/Compiler/xlf/FSStrings.zh-Hant.xlf | 5 +
.../EmittedIL/ForLoop/ForLoop.fs | 160 ++++++
.../FSharp.Compiler.ComponentTests.fsproj | 1 +
.../Miscellaneous/ConstStepForLoops.fs | 498 ++++++++++++++++++
.../Miscellaneous/OptimizedForLoops.fs | 21 +
.../Miscellaneous/VariableStepForLoops.fs | 18 +
29 files changed, 1000 insertions(+), 64 deletions(-)
create mode 100644 tests/FSharp.Compiler.ComponentTests/Miscellaneous/ConstStepForLoops.fs
create mode 100644 tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
create mode 100644 tests/FSharp.Compiler.ComponentTests/Miscellaneous/VariableStepForLoops.fs
diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs
index 7e3baef258b..abc21996404 100644
--- a/src/Compiler/Checking/CheckExpressions.fs
+++ b/src/Compiler/Checking/CheckExpressions.fs
@@ -7698,7 +7698,12 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s
// optimize 'for i in n .. m do'
| Expr.App (Expr.Val (vref, _, _), _, [tyarg], [startExpr;finishExpr], _)
when valRefEq g vref g.range_op_vref && typeEquiv g tyarg g.int_ty ->
- (g.int32_ty, (fun _ x -> x), id, Choice1Of3 (startExpr, finishExpr))
+ (g.int32_ty, (fun _ x -> x), id, Choice1Of4 (startExpr, finishExpr))
+
+ // optimize 'for i in n .. step .. m do'
+ | Expr.App(Expr.Val(vref, _, _), _, [ tyarg; stepTyarg ], [ startExpr; stepExpr; finishExpr ], _)
+ when valRefEq g vref g.range_step_op_vref && typeEquiv g tyarg g.int_ty && typeEquiv g stepTyarg g.int_ty ->
+ (g.int32_ty, (fun _ x -> x), id, Choice2Of4(startExpr, stepExpr, finishExpr))
// optimize 'for i in arr do'
| _ when isArray1DTy g enumExprTy ->
@@ -7713,7 +7718,7 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s
let overallExprFixup overallExpr = mkLet spForBind mFor arrVar enumExpr overallExpr
// Ask for a loop over integers for the given range
- (elemTy, bodyExprFixup, overallExprFixup, Choice2Of3 (idxVar, mkZero g mFor, mkDecr g mFor (mkLdlen g mFor arrExpr)))
+ (elemTy, bodyExprFixup, overallExprFixup, Choice3Of4 (idxVar, mkZero g mFor, mkDecr g mFor (mkLdlen g mFor arrExpr)))
| _ ->
// try optimize 'for i in span do' for span or readonlyspan
@@ -7738,13 +7743,13 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s
let getLengthCallExpr, _ = BuildMethodCall tcVal g cenv.amap PossiblyMutates mWholeExpr true getLengthMethInfo ValUseFlag.NormalValUse [] [ spanExpr ] []
// Ask for a loop over integers for the given range
- (elemTy, bodyExprFixup, overallExprFixup, Choice2Of3 (idxVar, mkZero g mFor, mkDecr g mFor getLengthCallExpr))
+ (elemTy, bodyExprFixup, overallExprFixup, Choice3Of4 (idxVar, mkZero g mFor, mkDecr g mFor getLengthCallExpr))
| _ ->
let enumerableVar, enumerableExprInVar = mkCompGenLocal mEnumExpr "inputSequence" enumExprTy
let enumeratorVar, enumeratorExpr, _, enumElemTy, getEnumExpr, getEnumTy, guardExpr, _, currentExpr =
AnalyzeArbitraryExprAsEnumerable cenv env true mEnumExpr enumExprTy enumerableExprInVar
- (enumElemTy, (fun _ x -> x), id, Choice3Of3(enumerableVar, enumeratorVar, enumeratorExpr, getEnumExpr, getEnumTy, guardExpr, currentExpr))
+ (enumElemTy, (fun _ x -> x), id, Choice4Of4(enumerableVar, enumeratorVar, enumeratorExpr, getEnumExpr, getEnumTy, guardExpr, currentExpr))
let pat, _, vspecs, envinner, tpenv =
let env = { env with eIsControlFlow = false }
@@ -7782,15 +7787,19 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s
match iterationTechnique with
// Build iteration as a for loop
- | Choice1Of3(startExpr, finishExpr) ->
+ | Choice1Of4(startExpr, finishExpr) ->
mkFastForLoop g (spFor, spIn, mWholeExpr, elemVar, startExpr, true, finishExpr, bodyExpr)
+ // Build iteration as a for loop with step value
+ | Choice2Of4(startExpr, stepExpr, finishExpr) ->
+ mkIntegerForLoopWithStep g (spFor, spIn, elemVar, startExpr, stepExpr, finishExpr, bodyExpr, mWholeExpr)
+
// Build iteration as a for loop with a specific index variable that is not the same as the elemVar
- | Choice2Of3(idxVar, startExpr, finishExpr) ->
+ | Choice3Of4(idxVar, startExpr, finishExpr) ->
mkFastForLoop g (DebugPointAtFor.No, spIn, mWholeExpr, idxVar, startExpr, true, finishExpr, bodyExpr)
// Build iteration as a while loop with a try/finally disposal
- | Choice3Of3(enumerableVar, enumeratorVar, _, getEnumExpr, _, guardExpr, currentExpr) ->
+ | Choice4Of4(enumerableVar, enumeratorVar, _, getEnumExpr, _, guardExpr, currentExpr) ->
// This compiled for must be matched EXACTLY by CompiledForEachExpr
mkLet spForBind mFor enumerableVar enumExpr
diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs
index d8bca9c223c..62889308edb 100644
--- a/src/Compiler/Checking/PostInferenceChecks.fs
+++ b/src/Compiler/Checking/PostInferenceChecks.fs
@@ -1060,9 +1060,10 @@ and TryCheckResumableCodeConstructs cenv env expr : bool =
true
// Integer for-loops are allowed but their bodies are not currently resumable
- | IntegerForLoopExpr (_sp1, _sp2, _style, e1, e2, v, e3, _m) ->
+ | IntegerForLoopExpr (_sp1, _sp2, _style, e1, e2, v, e3, e4, _m) ->
CheckExprNoByrefs cenv { env with resumableCode = Resumable.None } e1
CheckExprNoByrefs cenv { env with resumableCode = Resumable.None } e2
+ Option.iter (CheckExprNoByrefs cenv { env with resumableCode = Resumable.None }) e4
BindVal cenv env v
CheckExprNoByrefs cenv { env with resumableCode = Resumable.None } e3
true
diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs
index 63c543cfed2..90d6b2dd696 100644
--- a/src/Compiler/CodeGen/IlxGen.fs
+++ b/src/Compiler/CodeGen/IlxGen.fs
@@ -2998,7 +2998,10 @@ and GenExprAux (cenv: cenv) (cgbuf: CodeGenBuffer) eenv expr (sequel: sequel) =
GenWhileLoop cenv cgbuf eenv (sp, e1, e2, m) sequel
| TOp.IntegerForLoop (spFor, spTo, dir),
[ Expr.Lambda (_, _, _, [ _ ], e1, _, _); Expr.Lambda (_, _, _, [ _ ], e2, _, _); Expr.Lambda (_, _, _, [ v ], e3, _, _) ],
- [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, m) sequel
+ [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, mkZero g (range()), m) sequel
+ | TOp.IntegerForLoop(spFor, spTo, dir),
+ [ Expr.Lambda(_, _, _, [ _ ], e1, _, _); Expr.Lambda (_, _, _, [ _ ], e2, _, _); Expr.Lambda (_, _, _, [ v ], e3, _, _); Expr.Lambda (_, _, _, [ _ ], e4, _, _) ],
+ [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, e4, m) sequel
| TOp.TryFinally (spTry, spFinally),
[ Expr.Lambda (_, _, _, [ _ ], e1, _, _); Expr.Lambda (_, _, _, [ _ ], e2, _, _) ],
[ resTy ] -> GenTryFinally cenv cgbuf eenv (e1, e2, m, resTy, spTry, spFinally) sequel
@@ -4869,7 +4872,7 @@ and GenTryFinally cenv cgbuf eenv (bodyExpr, handlerExpr, m, resTy, spTry, spFin
// Generate for-loop
//--------------------------------------------------------------------------
-and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, m) sequel =
+and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, stepExpr, m) sequel =
let eenv = SetIsInLoop true eenv
let g = cenv.g
@@ -4886,19 +4889,19 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, m)
let test = CG.GenerateDelayMark cgbuf "for_test"
let stack, eenvinner = EmitSaveStack cenv cgbuf eenv m (start, finish)
- let isUp =
- (match dir with
- | FSharpForLoopUp
- | CSharpForLoopUp -> true
- | FSharpForLoopDown -> false)
-
- let isFSharpStyle =
- (match dir with
- | FSharpForLoopUp
- | FSharpForLoopDown -> true
- | CSharpForLoopUp -> false)
+ let stepByOne, isFSharpStyle, isUp =
+ match dir with
+ | FSharpForLoopUp -> true, true, true
+ | FSharpForLoopDown -> true, true, false
+ | FSharpForLoopWithStep _ -> false, true, true
+ | CSharpForLoopUp -> true, false, true
+
+ let stepConst =
+ match stepExpr with
+ | Expr.Const(Const.Int32 i, _, _) when i <> 0 -> Some i
+ | _ -> None
- let finishIdx, eenvinner =
+ let finishIdx, stepIdx, eenvinner =
if isFSharpStyle then
// Ensure that we have an g.CompilerGlobalState
assert (g.CompilerGlobalState |> Option.isSome)
@@ -4909,9 +4912,14 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, m)
let v, _realloc, eenvinner =
AllocLocal cenv cgbuf eenvinner true (vName, g.ilg.typ_Int32, false) (start, finish)
- v, eenvinner
+ if not stepByOne && Option.isNone stepConst then
+ let v2, _realloc, eenvinner =
+ AllocLocal cenv cgbuf eenvinner true (vName, g.ilg.typ_Int32, false) (start, finish)
+ v, v2, eenvinner
+ else
+ v, -1, eenvinner
else
- -1, eenvinner
+ -1, -1, eenvinner
let _, eenvinner = AllocLocalVal cenv cgbuf v eenvinner None (start, finish)
@@ -4922,14 +4930,59 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, m)
GenExpr cenv cgbuf eenv e1 Continue
GenStoreVal cgbuf eenvinner m v
+ match dir, stepConst with
+ | FSharpForLoopWithStep, None ->
+ // Throw invalidarg at runtime if step is 0.
+ // Emulates behavior of the RangeInt32 enumerator that this replaces.
+ GenExpr cenv cgbuf eenvinner stepExpr Continue
+ EmitSetLocal cgbuf stepIdx
+ EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
+
+ let notZero = CG.GenerateDelayMark cgbuf "notZero"
+ CG.EmitInstr cgbuf (pop 1) Push0 (I_brcmp(BI_brtrue, notZero.CodeLabel))
+
+ let arg1 = mkString g stepExpr.Range (SR.GetString "StepCannotBeZero")
+ let arg2 = mkString g stepExpr.Range "step"
+ let invalidArgExpr = MakeArgumentExnExpr cenv eenv (arg1, arg2, stepExpr.Range)
+ GenExpr cenv cgbuf eenvinner invalidArgExpr Continue
+ CG.EmitInstr cgbuf (pop 1) Push0 I_throw
+
+ CG.SetMarkToHere cgbuf notZero
+ | _ -> ()
+
if isFSharpStyle then
GenExpr cenv cgbuf eenvinner e2 Continue
EmitSetLocal cgbuf finishIdx
EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp((if isUp then BI_blt else BI_bgt), finish.CodeLabel))
- else
+ match dir with
+ | FSharpForLoopUp ->
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, finish.CodeLabel))
+ | FSharpForLoopDown ->
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
+ | FSharpForLoopWithStep ->
+ match stepConst with
+ | Some stepC ->
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp((if stepC > 0 then BI_blt else BI_bgt), finish.CodeLabel))
+ | None ->
+ let testPassed = CG.GenerateDelayMark cgbuf "testPassed"
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, testPassed.CodeLabel))
+
+ EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
+ CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 0)
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, inner.CodeLabel))
+
+ CG.SetMarkToHere cgbuf testPassed
+ EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
+ GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
+
+ EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
+ CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 0)
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bge, finish.CodeLabel))
+
+ | CSharpForLoopUp ->
CG.EmitInstr cgbuf (pop 0) Push0 (I_br test.CodeLabel)
cgbuf.EmitStartOfHiddenCode()
@@ -4943,15 +4996,32 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, m)
// v++ or v--
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
- CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
+ match dir with
+ | FSharpForLoopUp
+ | FSharpForLoopDown
+ | CSharpForLoopUp ->
+ CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
+ CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
+ | FSharpForLoopWithStep _ ->
+ match stepConst with
+ | Some sc ->
+ let pos = sc > 0
+ CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 (if pos then sc else -sc))
+ CG.EmitInstr cgbuf (pop 1) Push0 (if pos then AI_add else AI_sub)
+ | None ->
+ EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
+ CG.EmitInstr cgbuf (pop 1) Push0 AI_add
+
GenStoreVal cgbuf eenvinner m v
- // .text
+ // .test
CG.SetMarkToHere cgbuf test
// FSharpForLoopUp: if v <> e2 + 1 then goto .inner
// FSharpForLoopDown: if v <> e2 - 1 then goto .inner
+ // FSharpForLoopWithStep: if (step > 0 && v <= e2) || (step < 0 && v >= e2) then goto .inner (variable step)
+ // FSharpForLoopWithStep: if v <= e2 then goto .inner (constant step > 0)
+ // FSharpForLoopWithStep: if v >= e2 then goto .inner (constant step < 0)
// CSharpStyle: if v < e2 then goto .inner
match spTo with
| DebugPointAtInOrTo.Yes spStart -> CG.EmitDebugPoint cgbuf spStart
@@ -4959,21 +5029,43 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, m)
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- let cmp =
- match dir with
- | FSharpForLoopUp
- | FSharpForLoopDown -> BI_bne_un
- | CSharpForLoopUp -> BI_blt
-
- let e2Sequel = (CmpThenBrOrContinue(pop 2, [ I_brcmp(cmp, inner.CodeLabel) ]))
-
- if isFSharpStyle then
+ match dir with
+ | FSharpForLoopUp
+ | FSharpForLoopDown ->
EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
- GenSequel cenv eenv.cloc cgbuf e2Sequel
- else
- GenExpr cenv cgbuf eenv e2 e2Sequel
+ CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_bne_un, inner.CodeLabel) ])
+ |> GenSequel cenv eenv.cloc cgbuf
+
+ | FSharpForLoopWithStep _ ->
+ EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
+
+ match stepConst with
+ | Some sc ->
+ let pos = sc > 0
+ CmpThenBrOrContinue(pop 2, [ I_brcmp((if pos then BI_ble else BI_bge), inner.CodeLabel) ])
+ | None ->
+ let testPassed = CG.GenerateDelayMark cgbuf "testPassed"
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_ble, testPassed.CodeLabel))
+
+ EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
+ CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 0)
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
+
+ CG.SetMarkToHere cgbuf testPassed
+ GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
+ EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bge, inner.CodeLabel))
+
+ EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
+ CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 0)
+ CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_bge, inner.CodeLabel) ])
+ |> GenSequel cenv eenv.cloc cgbuf
+
+ | CSharpForLoopUp ->
+ CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_blt, inner.CodeLabel) ])
+ |> GenExpr cenv cgbuf eenv e2
// .finish - loop-exit here
CG.SetMarkToHere cgbuf finish
@@ -5384,6 +5476,13 @@ and MakeNotSupportedExnExpr cenv eenv (argExpr, m) =
let mref = mkILCtorMethSpecForTy(ilTy, [ g.ilg.typ_String ]).MethodRef
Expr.Op(TOp.ILCall(false, false, false, true, NormalValUse, false, false, mref, [], [], [ ety ]), [], [ argExpr ], m)
+and MakeArgumentExnExpr cenv eenv (messageExpr, argNameExpr, m) =
+ let g = cenv.g
+ let ety = mkAppTy (g.FindSysTyconRef [ "System" ] "ArgumentException") []
+ let ilTy = GenType cenv m eenv.tyenv ety
+ let mref = mkILCtorMethSpecForTy(ilTy, [ g.ilg.typ_String; g.ilg.typ_String ]).MethodRef
+ Expr.Op(TOp.ILCall(false, false, false, true, NormalValUse, false, false, mref, [], [], [ ety ]), [], [ messageExpr; argNameExpr ], m)
+
and GenTraitCall (cenv: cenv) cgbuf eenv (traitInfo: TraitConstraintInfo, argExprs, m) expr sequel =
let g = cenv.g
let generateWitnesses = ComputeGenerateWitnesses g eenv
diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx
index 51f172fbbea..90582662531 100644
--- a/src/Compiler/FSStrings.resx
+++ b/src/Compiler/FSStrings.resx
@@ -1110,4 +1110,7 @@
Lowercase discriminated union cases are only allowed when using RequireQualifiedAccess attribute
+
+ The step of a range cannot be zero.
+
\ No newline at end of file
diff --git a/src/Compiler/Optimize/LowerStateMachines.fs b/src/Compiler/Optimize/LowerStateMachines.fs
index 31972252340..db32791ba14 100644
--- a/src/Compiler/Optimize/LowerStateMachines.fs
+++ b/src/Compiler/Optimize/LowerStateMachines.fs
@@ -481,8 +481,8 @@ type LowerStateMachine(g: TcGlobals) =
// The expanded code for state machines may use for loops, however the
// body must be synchronous.
- | IntegerForLoopExpr (sp1, sp2, style, e1, e2, v, e3, m) ->
- ConvertResumableIntegerForLoop env pcValInfo (sp1, sp2, style, e1, e2, v, e3, m)
+ | IntegerForLoopExpr (sp1, sp2, style, e1, e2, v, e3, step, m) ->
+ ConvertResumableIntegerForLoop env pcValInfo (sp1, sp2, style, e1, e2, v, e3, step, m)
// The expanded code for state machines may use try/with....
| TryWithExpr (spTry, spWith, resTy, bodyExpr, filterVar, filterExpr, handlerVar, handlerExpr, m) ->
@@ -673,13 +673,14 @@ type LowerStateMachine(g: TcGlobals) =
|> Result.Ok
| Result.Error err, _ | _, Result.Error err -> Result.Error err
- and ConvertResumableIntegerForLoop env pcValInfo (spFor, spTo, style, e1, e2, v, e3, m) =
+ and ConvertResumableIntegerForLoop env pcValInfo (spFor, spTo, style, e1, e2, v, e3, e4, m) =
if sm_verbose then printfn "IntegerForLoopExpr"
let res1 = ConvertResumableCode env pcValInfo e1
let res2 = ConvertResumableCode env pcValInfo e2
let res3 = ConvertResumableCode env pcValInfo e3
- match res1, res2, res3 with
- | Result.Ok res1, Result.Ok res2, Result.Ok res3 ->
+ let res4 = Option.map (ConvertResumableCode env pcValInfo) e4
+ match res1, res2, res3, res4 with
+ | Result.Ok res1, Result.Ok res2, Result.Ok res3, None ->
let eps = res1.entryPoints @ res2.entryPoints @ res3.entryPoints
if eps.Length > 0 then
Result.Error(FSComp.SR.reprResumableCodeContainsFastIntegerForLoop())
@@ -705,7 +706,34 @@ type LowerStateMachine(g: TcGlobals) =
thisVars = res1.thisVars @ res2.thisVars @ res3.thisVars
resumableVars = emptyFreeVars (* eps is empty, hence synchronous, no capture *) }
|> Result.Ok
- | Result.Error err, _, _ | _, Result.Error err, _ | _, _, Result.Error err -> Result.Error err
+ | Result.Ok res1, Result.Ok res2, Result.Ok res3, Some(Result.Ok res4) ->
+ let eps = res1.entryPoints @ res2.entryPoints @ res3.entryPoints @ res4.entryPoints
+ if eps.Length > 0 then
+ Result.Error(FSComp.SR.reprResumableCodeContainsFastIntegerForLoop())
+ else
+ { phase1 = mkIntegerForLoopWithStep g (spFor, spTo, v, res1.phase1, res4.phase1, res2.phase1, res3.phase1, m)
+ phase2 = (fun ctxt ->
+ let e1R = res1.phase2 ctxt
+ let e2R = res2.phase2 ctxt
+ let e3R = res3.phase2 ctxt
+ let e4R = res4.phase2 ctxt
+
+ // Clear the pcVal on backward branch, causing jump tables at entry to nested try-blocks to not activate
+ let e3R2 =
+ match pcValInfo with
+ | None -> e3R
+ | Some ((pcVal, _), _) ->
+ mkCompGenThenDoSequential m
+ e3R
+ (mkValSet m (mkLocalValRef pcVal) (mkZero g m))
+
+ mkIntegerForLoopWithStep g (spFor, spTo, v, e1R, e4R, e2R, e3R2, m))
+ entryPoints= eps
+ stateVars = res1.stateVars @ res2.stateVars @ res3.stateVars @res4.stateVars
+ thisVars = res1.thisVars @ res2.thisVars @ res3.thisVars @res3.thisVars
+ resumableVars = emptyFreeVars (* eps is empty, hence synchronous, no capture *) }
+ |> Result.Ok
+ | Result.Error err, _, _, _ | _, Result.Error err, _, _ | _, _, Result.Error err, _ | _, _, _, Some(Result.Error err) -> Result.Error err
and ConvertResumableTryWith env pcValInfo (spTry, spWith, resTy, bodyExpr, filterVar, filterExpr, handlerVar, handlerExpr, m) =
if sm_verbose then printfn "TryWithExpr"
diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs
index f4462122337..91079a6ca8e 100644
--- a/src/Compiler/Optimize/Optimizer.fs
+++ b/src/Compiler/Optimize/Optimizer.fs
@@ -2540,7 +2540,10 @@ and OptimizeExprOp cenv env (op, tyargs, args, m) =
OptimizeWhileLoop cenv { env with disableMethodSplitting=true } (spWhile, marker, e1, e2, m)
| TOp.IntegerForLoop (spFor, spTo, dir), _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _);Expr.Lambda (_, _, _, [v], e3, _, _)] ->
- OptimizeFastIntegerForLoop cenv { env with disableMethodSplitting=true } (spFor, spTo, v, e1, dir, e2, e3, m)
+ OptimizeFastIntegerForLoop cenv { env with disableMethodSplitting=true } (spFor, spTo, v, e1, dir, e2, e3, None, m)
+
+ | TOp.IntegerForLoop (spFor, spTo, dir), _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _);Expr.Lambda (_, _, _, [v], e3, _, _);Expr.Lambda (_, _, _, [_], e4, _, _)] ->
+ OptimizeFastIntegerForLoop cenv { env with disableMethodSplitting=true } (spFor, spTo, v, e1, dir, e2, e3, Some e4, m)
| TOp.TryFinally (spTry, spFinally), [resty], [Expr.Lambda (_, _, _, [_], e1, _, _); Expr.Lambda (_, _, _, [_], e2, _, _)] ->
OptimizeTryFinally cenv env (spTry, spFinally, e1, e2, m, resty)
@@ -2733,11 +2736,17 @@ and TryOptimizeUnionCaseGet cenv _env (e1info, cspec, _tys, n, m) =
| _ -> None
/// Optimize/analyze a for-loop
-and OptimizeFastIntegerForLoop cenv env (spFor, spTo, v, e1, dir, e2, e3, m) =
+and OptimizeFastIntegerForLoop cenv env (spFor, spTo, v, e1, dir, e2, e3, stepExpr, m) =
let g = cenv.g
let e1R, e1info = OptimizeExpr cenv env e1
let e2R, e2info = OptimizeExpr cenv env e2
+ let e4R, e4info =
+ match stepExpr with
+ | Some step ->
+ let e4R, e4info = OptimizeExpr cenv env step
+ Some e4R, Some e4info
+ | None -> None, None
let env = BindInternalValToUnknown cenv v env
let e3R, e3info = OptimizeExpr cenv env e3
// Try to replace F#-style loops with C# style loops that recompute their bounds but which are compiled more efficiently by the JITs, e.g.
@@ -2747,12 +2756,12 @@ and OptimizeFastIntegerForLoop cenv env (spFor, spTo, v, e1, dir, e2, e3, m) =
match dir, e2R with
// detect upwards for loops with bounds of the form "arr.Length - 1" and convert them to a C#-style for loop
| FSharpForLoopUp, Expr.Op (TOp.ILAsm ([ (AI_sub | AI_sub_ovf)], _), _, [Expr.Op (TOp.ILAsm ([ I_ldlen; (AI_conv DT_I4)], _), _, [arre], _); Expr.Const (Const.Int32 1, _, _)], _)
- when not (snd(OptimizeExpr cenv env arre)).HasEffect ->
+ when not (snd(OptimizeExpr cenv env arre)).HasEffect ->
mkLdlen g e2R.Range arre, CSharpForLoopUp
| FSharpForLoopUp, Expr.Op (TOp.ILAsm ([ (AI_sub | AI_sub_ovf)], _), _, [Expr.Op (TOp.ILCall(_,_,_,_,_,_,_, mth, _,_,_), _, [arre], _) as lenOp; Expr.Const (Const.Int32 1, _, _)], _)
- when
+ when
mth.Name = "get_Length" && (mth.DeclaringTypeRef.FullName = "System.Span`1" || mth.DeclaringTypeRef.FullName = "System.ReadOnlySpan`1")
&& not (snd(OptimizeExpr cenv env arre)).HasEffect ->
@@ -2767,13 +2776,18 @@ and OptimizeFastIntegerForLoop cenv env (spFor, spTo, v, e1, dir, e2, e3, m) =
| _ ->
e2R, dir
- let einfos = [e1info;e2info;e3info]
+ let einfos = [e1info;e2info;e3info; match e4info with Some e4i -> e4i | None -> ()]
let eff = OrEffects einfos
(* neither bounds nor body has an effect, and loops always terminate, hence eliminate the loop *)
if cenv.settings.EliminateForLoop && not eff then
mkUnit g m, { TotalSize=0; FunctionSize=0; HasEffect=false; MightMakeCriticalTailcall=false; Info=UnknownValue }
else
- let exprR = mkIntegerForLoop g (spFor, spTo, v, e1R, dir, e2R, e3R, m)
+ let exprR =
+ match e4R with
+ | Some e4R ->
+ mkIntegerForLoopWithStep g (spFor, spTo, v, e1R, e4R, e2R, e3R, m)
+ | None ->
+ mkIntegerForLoop g (spFor, spTo, v, e1R, dir, e2R, e3R, m)
exprR, { TotalSize=AddTotalSizes einfos + forAndWhileLoopSize
FunctionSize=AddFunctionSizes einfos + forAndWhileLoopSize
HasEffect=eff
diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs
index d71fd222745..26b085c17ab 100644
--- a/src/Compiler/TypedTree/TypedTree.fs
+++ b/src/Compiler/TypedTree/TypedTree.fs
@@ -4975,7 +4975,10 @@ type ForLoopStyle =
| FSharpForLoopUp
/// Evaluate start and end once, loop down
- | FSharpForLoopDown
+ | FSharpForLoopDown
+
+ /// Evaluate start, step, and end once
+ | FSharpForLoopWithStep
/// Evaluate start once and end multiple times, loop up
| CSharpForLoopUp
diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi
index 57037ba27d8..7fad3034496 100644
--- a/src/Compiler/TypedTree/TypedTree.fsi
+++ b/src/Compiler/TypedTree/TypedTree.fsi
@@ -3606,6 +3606,9 @@ type ForLoopStyle =
/// Evaluate start type end once, loop down
| FSharpForLoopDown
+ /// Evaluate start, step, and end once
+ | FSharpForLoopWithStep
+
/// Evaluate start once type end multiple times, loop up
| CSharpForLoopUp
diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs
index 8229107c74a..84d22f73b15 100644
--- a/src/Compiler/TypedTree/TypedTreeOps.fs
+++ b/src/Compiler/TypedTree/TypedTreeOps.fs
@@ -1522,6 +1522,9 @@ let mkWhile (g: TcGlobals) (spWhile, marker, guardExpr, bodyExpr, m) =
let mkIntegerForLoop (g: TcGlobals) (spFor, spIn, v, startExpr, dir, finishExpr, bodyExpr: Expr, m) =
Expr.Op (TOp.IntegerForLoop (spFor, spIn, dir), [], [mkDummyLambda g (startExpr, g.int_ty) ;mkDummyLambda g (finishExpr, g.int_ty);mkLambda bodyExpr.Range v (bodyExpr, g.unit_ty)], m)
+let mkIntegerForLoopWithStep (g: TcGlobals) (spFor, spIn, v, startExpr, stepExpr: Expr, finishExpr, bodyExpr: Expr, m) =
+ Expr.Op (TOp.IntegerForLoop (spFor, spIn, FSharpForLoopWithStep), [], [mkDummyLambda g (startExpr, g.int_ty) ;mkDummyLambda g (finishExpr, g.int_ty);mkLambda bodyExpr.Range v (bodyExpr, g.unit_ty); mkDummyLambda g (stepExpr, g.int_ty)], m)
+
let mkTryWith g (bodyExpr, filterVal, filterExpr: Expr, handlerVal, handlerExpr: Expr, m, ty, spTry, spWith) =
Expr.Op (TOp.TryWith (spTry, spWith), [ty], [mkDummyLambda g (bodyExpr, ty);mkLambda filterExpr.Range filterVal (filterExpr, ty);mkLambda handlerExpr.Range handlerVal (handlerExpr, ty)], m)
@@ -9713,11 +9716,11 @@ let (|RangeInt32Step|_|) g expr =
match expr with
// detect 'n .. m'
| Expr.App (Expr.Val (vf, _, _), _, [tyarg], [startExpr;finishExpr], _)
- when valRefEq g vf g.range_op_vref && typeEquiv g tyarg g.int_ty -> Some(startExpr, 1, finishExpr)
+ when valRefEq g vf g.range_op_vref && typeEquiv g tyarg g.int_ty -> Some(startExpr, mkOne g (range()), finishExpr)
// detect (RangeInt32 startExpr N finishExpr), the inlined/compiled form of 'n .. m' and 'n .. N .. m'
- | Expr.App (Expr.Val (vf, _, _), _, [], [startExpr; Int32Expr n; finishExpr], _)
- when valRefEq g vf g.range_int32_op_vref -> Some(startExpr, n, finishExpr)
+ | Expr.App (Expr.Val (vf, _, _), _, [], [startExpr; stepExpr; finishExpr], _)
+ when valRefEq g vf g.range_int32_op_vref -> Some(startExpr, stepExpr, finishExpr)
| _ -> None
@@ -9758,8 +9761,8 @@ let (|CompiledForEachExpr|_|) g expr =
let (|CompiledInt32RangeForEachExpr|_|) g expr =
match expr with
- | CompiledForEachExpr g (_, RangeInt32Step g (startExpr, step, finishExpr), elemVar, bodyExpr, ranges) ->
- Some (startExpr, step, finishExpr, elemVar, bodyExpr, ranges)
+ | CompiledForEachExpr g (_, RangeInt32Step g (startExpr, stepExpr, finishExpr), elemVar, bodyExpr, ranges) ->
+ Some (startExpr, stepExpr, finishExpr, elemVar, bodyExpr, ranges)
| _ -> None
| _ -> None
@@ -9773,12 +9776,16 @@ type OptimizeForExpressionOptions =
let DetectAndOptimizeForEachExpression g option expr =
match option, expr with
- | _, CompiledInt32RangeForEachExpr g (startExpr, (1 | -1 as step), finishExpr, elemVar, bodyExpr, ranges) ->
+ | _, CompiledInt32RangeForEachExpr g (startExpr, Int32Expr step, finishExpr, elemVar, bodyExpr, ranges) when step = 1 || step = -1 ->
let _mBody, spFor, spIn, _mFor, _mIn, _spInWhile, mWholeExpr = ranges
let spFor = match spFor with DebugPointAtBinding.Yes mFor -> DebugPointAtFor.Yes mFor | _ -> DebugPointAtFor.No
mkFastForLoop g (spFor, spIn, mWholeExpr, elemVar, startExpr, (step = 1), finishExpr, bodyExpr)
+ | _, CompiledInt32RangeForEachExpr g (startExpr, stepExpr, finishExpr, elemVar, bodyExpr, ranges) ->
+ let _mBody, spFor, spIn, _mFor, _mIn, _spInWhile, mWholeExpr = ranges
+ let spFor = match spFor with DebugPointAtBinding.Yes mFor -> DebugPointAtFor.Yes mFor | _ -> DebugPointAtFor.No
+ mkIntegerForLoopWithStep g (spFor, spIn, elemVar, startExpr, stepExpr, finishExpr, bodyExpr, mWholeExpr)
| OptimizeAllForExpressions, CompiledForEachExpr g (enumerableTy, enumerableExpr, elemVar, bodyExpr, ranges) ->
let mBody, spFor, spIn, mFor, mIn, spInWhile, mWholeExpr = ranges
@@ -9982,7 +9989,9 @@ let (|TryFinallyExpr|_|) expr =
let (|IntegerForLoopExpr|_|) expr =
match expr with
| Expr.Op (TOp.IntegerForLoop (sp1, sp2, style), _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _);Expr.Lambda (_, _, _, [v], e3, _, _)], m) ->
- Some (sp1, sp2, style, e1, e2, v, e3, m)
+ Some (sp1, sp2, style, e1, e2, v, e3, None, m)
+ | Expr.Op (TOp.IntegerForLoop (sp1, sp2, style), _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _);Expr.Lambda (_, _, _, [v], e3, _, _); Expr.Lambda (_, _, _, [_], stepExpr, _, _)], m) ->
+ Some (sp1, sp2, style, e1, e2, v, e3, Some stepExpr, m)
| _ -> None
let (|TryWithExpr|_|) expr =
diff --git a/src/Compiler/TypedTree/TypedTreeOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.fsi
index 5d27bff7fbc..df72560e744 100755
--- a/src/Compiler/TypedTree/TypedTreeOps.fsi
+++ b/src/Compiler/TypedTree/TypedTreeOps.fsi
@@ -165,6 +165,10 @@ val mkWhile: TcGlobals -> DebugPointAtWhile * SpecialWhileLoopMarker * Expr * Ex
val mkIntegerForLoop:
TcGlobals -> DebugPointAtFor * DebugPointAtInOrTo * Val * Expr * ForLoopStyle * Expr * Expr * range -> Expr
+/// Build a 'for' loop expression with step
+val mkIntegerForLoopWithStep:
+ TcGlobals -> DebugPointAtFor * DebugPointAtInOrTo * Val * Expr * Expr * Expr * Expr * range -> Expr
+
/// Build a 'try/with' expression
val mkTryWith:
TcGlobals ->
@@ -2578,7 +2582,7 @@ val (|WhileExpr|_|): Expr -> (DebugPointAtWhile * SpecialWhileLoopMarker * Expr
/// Recognise an integer for-loop expression
val (|IntegerForLoopExpr|_|):
- Expr -> (DebugPointAtFor * DebugPointAtInOrTo * ForLoopStyle * Expr * Expr * Val * Expr * range) option
+ Expr -> (DebugPointAtFor * DebugPointAtInOrTo * ForLoopStyle * Expr * Expr * Val * Expr * Expr option * range) option
/// Recognise a try-with expression
val (|TryWithExpr|_|):
diff --git a/src/Compiler/TypedTree/TypedTreePickle.fs b/src/Compiler/TypedTree/TypedTreePickle.fs
index 57c557d2b8a..672362c74df 100644
--- a/src/Compiler/TypedTree/TypedTreePickle.fs
+++ b/src/Compiler/TypedTree/TypedTreePickle.fs
@@ -2520,7 +2520,7 @@ and p_op x st =
-> p_byte 18 st; p_tup11 p_bool p_bool p_bool p_bool p_vrefFlags p_bool p_bool p_ILMethodRef p_tys p_tys p_tys (a1, a2, a3, a4, a5, a7, a8, a9, b, c, d) st
| TOp.Array -> p_byte 19 st
| TOp.While _ -> p_byte 20 st
- | TOp.IntegerForLoop (_, _, dir) -> p_byte 21 st; p_int (match dir with FSharpForLoopUp -> 0 | CSharpForLoopUp -> 1 | FSharpForLoopDown -> 2) st
+ | TOp.IntegerForLoop (_, _, dir) -> p_byte 21 st; p_int (match dir with FSharpForLoopUp -> 0 | CSharpForLoopUp -> 1 | FSharpForLoopDown -> 2 | FSharpForLoopWithStep -> 3) st
| TOp.Bytes bytes -> p_byte 22 st; p_bytes bytes st
| TOp.TryWith _ -> p_byte 23 st
| TOp.TryFinally _ -> p_byte 24 st
@@ -2585,7 +2585,7 @@ and u_op st =
TOp.ILCall (a1, a2, a3, a4, a5, a7, a8, a9, b, c, d)
| 19 -> TOp.Array
| 20 -> TOp.While (DebugPointAtWhile.No, NoSpecialWhileLoopMarker)
- | 21 -> let dir = match u_int st with 0 -> FSharpForLoopUp | 1 -> CSharpForLoopUp | 2 -> FSharpForLoopDown | _ -> failwith "unknown for loop"
+ | 21 -> let dir = match u_int st with 0 -> FSharpForLoopUp | 1 -> CSharpForLoopUp | 2 -> FSharpForLoopDown | 3 -> FSharpForLoopWithStep | _ -> failwith "unknown for loop"
TOp.IntegerForLoop (DebugPointAtFor.No, DebugPointAtInOrTo.No, dir)
| 22 -> TOp.Bytes (u_bytes st)
| 23 -> TOp.TryWith (DebugPointAtTry.No, DebugPointAtWith.No)
diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf
index 849a9018ef5..d6c9eb4c001 100644
--- a/src/Compiler/xlf/FSStrings.cs.xlf
+++ b/src/Compiler/xlf/FSStrings.cs.xlf
@@ -97,6 +97,11 @@
Neshoda v omezení typu. Typ \n {0} \nnení kompatibilní s typem\n {1}. {2}\n
+
+ The step of a range cannot be zero.
+ Krok rozsahu nemůže být nula.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
Identifikátory proměnných psané velkými písmeny se ve vzorech obecně nedoporučují. Můžou označovat chybějící otevřenou deklaraci nebo špatně napsaný název vzoru.
diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf
index 79176e0e2f1..5ec8f681f02 100644
--- a/src/Compiler/xlf/FSStrings.de.xlf
+++ b/src/Compiler/xlf/FSStrings.de.xlf
@@ -97,6 +97,11 @@
Die Typeinschränkungen stimmen nicht überein. Der Typ \n "{0}" \nist nicht mit folgendem Typ kompatibel:\n "{1}" {2}\n
+
+ The step of a range cannot be zero.
+ Der Schritt eines Bereichs darf nicht null sein.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
Variablenbezeichner in Großbuchstaben sollten im Allgemeinen nicht in Mustern verwendet werden und können ein Hinweis auf eine fehlende open-Deklaration oder einen falsch geschriebenen Musternamen sein.
diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf
index 8b09a7c5903..70906e277ed 100644
--- a/src/Compiler/xlf/FSStrings.es.xlf
+++ b/src/Compiler/xlf/FSStrings.es.xlf
@@ -97,6 +97,11 @@
No coinciden las restricciones de tipo. El tipo \n '{0}' \nno es compatible con el tipo\n '{1}' {2}\n
+
+ The step of a range cannot be zero.
+ El paso de un intervalo no puede ser cero.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
En general, los identificadores de variables en mayúscula no deben usarse en patrones y pueden indicar una declaración abierta que falta o un nombre de patrón mal escrito.
diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf
index f88d8e7182b..785e6d9b821 100644
--- a/src/Compiler/xlf/FSStrings.fr.xlf
+++ b/src/Compiler/xlf/FSStrings.fr.xlf
@@ -97,6 +97,11 @@
Incompatibilité de contrainte de type. Le type \n {0} \nn'est pas compatible avec le type\n {1} {2}\n
+
+ The step of a range cannot be zero.
+ Une étape d'une plage ne peut pas être zéro.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
Les identificateurs de variables en majuscules ne doivent généralement pas être utilisés dans les modèles. Ils peuvent indiquer une absence de déclaration open ou un nom de modèle mal orthographié.
diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf
index e46a3cb54d6..11ff98cc613 100644
--- a/src/Compiler/xlf/FSStrings.it.xlf
+++ b/src/Compiler/xlf/FSStrings.it.xlf
@@ -97,6 +97,11 @@
Vincolo di tipo non corrispondente. Il tipo \n '{0}' \nnon è compatibile con il tipo\n '{1}' {2}\n
+
+ The step of a range cannot be zero.
+ Il passaggio di un intervallo non può essere zero.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
In genere è consigliabile non usare identificatori di variabili scritti in maiuscolo nei criteri perché potrebbero indicare una dichiarazione OPEN mancante o un nome di criterio con ortografia errata.
diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf
index b0a149427b1..64f4c5101bc 100644
--- a/src/Compiler/xlf/FSStrings.ja.xlf
+++ b/src/Compiler/xlf/FSStrings.ja.xlf
@@ -97,6 +97,11 @@
型の制約が一致しません。次の型\n '{0}' \nは次の型と互換性がありません\n '{1}' {2}\n
+
+ The step of a range cannot be zero.
+ 範囲のステップをゼロにすることはできません。
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
通常、大文字の変数識別子はパターンに使用できません。また、欠落している open 宣言か、つづりが間違っているパターン名を示す可能性があります。
diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf
index da9ee85444d..cbd8b091856 100644
--- a/src/Compiler/xlf/FSStrings.ko.xlf
+++ b/src/Compiler/xlf/FSStrings.ko.xlf
@@ -97,6 +97,11 @@
형식 제약 조건이 일치하지 않습니다. \n '{0}' \n형식이\n '{1}' 형식과 호환되지 않습니다. {2}\n
+
+ The step of a range cannot be zero.
+ 범위의 단계는 0일 수 없습니다.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
일반적으로 대문자 변수 식별자는 패턴에 사용하지 말아야 합니다. 이러한 식별자는 열려 있는 선언이 없거나 철자가 잘못된 패턴 이름을 나타낼 수 있습니다.
diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf
index f89d330d272..adb34abdb1a 100644
--- a/src/Compiler/xlf/FSStrings.pl.xlf
+++ b/src/Compiler/xlf/FSStrings.pl.xlf
@@ -97,6 +97,11 @@
Niezgodność ograniczeń typów. Typ \n „{0}” \nnie jest zgodny z typem\n „{1}” {2}\n
+
+ The step of a range cannot be zero.
+ Wartością kroku w zakresie nie może być zero.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
Identyfikatory zmiennych pisane wielkimi literami nie powinny być na ogół używane we wzorcach i mogą oznaczać brak deklaracji otwierającej lub błąd pisowni w nazwie wzorca.
diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf
index a6f597c97aa..49cb2f2be2a 100644
--- a/src/Compiler/xlf/FSStrings.pt-BR.xlf
+++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf
@@ -97,6 +97,11 @@
Restrições de tipo incompatíveis. O tipo \n '{0}' \nnão é compatível com o tipo\n '{1}' {2}\n
+
+ The step of a range cannot be zero.
+ A etapa de um intervalo não pode ser zero.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
Identificadores de variáveis em maiúsculas geralmente não devem ser usados em padrões, podendo indicar uma declaração aberta ausente ou um nome de padrão escrito incorretamente.
diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf
index 310b7437a2e..d7b868d73a2 100644
--- a/src/Compiler/xlf/FSStrings.ru.xlf
+++ b/src/Compiler/xlf/FSStrings.ru.xlf
@@ -97,6 +97,11 @@
Несоответствие ограничений типов. Тип \n "{0}" \nнесовместим с типом\n "{1}" {2}\n
+
+ The step of a range cannot be zero.
+ Шагом диапазона не может быть ноль.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
Идентификаторы переменных в верхнем регистре обычно не должны использоваться в шаблонах, и могут указывать на отсутствующую открытую декларацию или неправильно написанное имя шаблона.
diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf
index c5cbc423360..9d3714fbf01 100644
--- a/src/Compiler/xlf/FSStrings.tr.xlf
+++ b/src/Compiler/xlf/FSStrings.tr.xlf
@@ -97,6 +97,11 @@
Tür kısıtlaması uyumsuzluğu. \n '{0}' \ntürü şu türle uyumlu değil:\n '{1}' {2}\n
+
+ The step of a range cannot be zero.
+ Aralığın adımı sıfır olamaz.
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
Büyük harfli değişken tanımlayıcıları desenlerde genel olarak kullanılmamalıdır. Bunlar, eksik bir açık bildirimin veya yanlış yazılmış bir desen adının göstergesi olabilirler.
diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf
index be3604df4bf..25d3d6d09ef 100644
--- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf
+++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf
@@ -97,6 +97,11 @@
类型约束不匹配。类型 \n “{0}” \n与类型\n “{1}” {2} 不兼容\n
+
+ The step of a range cannot be zero.
+ 范围的跨距不能为零。
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
通常不得在模式中使用大写的变量标识符,存在它们可能表示缺少某个开放声明或某个模式名称拼写错误。
diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf
index 67e6c25370e..ed0ac44e9ea 100644
--- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf
+++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf
@@ -97,6 +97,11 @@
類型條件約束不符。類型\n '{0}' \n不相容於類型\n '{1}' {2}\n
+
+ The step of a range cannot be zero.
+ 範圍步驟不能為零。
+
+
Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.
通常不應在樣式中使用大寫的變數識別碼。這可能表示缺少公開宣告或樣式名稱拼字錯誤。
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoop.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoop.fs
index 1775a580eff..ac54111a66c 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoop.fs
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoop.fs
@@ -130,3 +130,163 @@ module ForLoop =
compilation
|> verifyCompilation
+ []
+ let ``Strided integer for loops should not allocate a RangeInt32 enumerator``() =
+ FSharp """
+module ForLoops
+
+let loop1 () =
+ let s = System.Random().Next(2, 2) // avoid constant step optimization
+ for i in 0..s..10 do
+ System.Console.WriteLine i
+ """
+ |> compile
+ |> shouldSucceed
+ |> verifyIL ["""
+ .method public static void loop1() cil managed
+ {
+
+ .maxstack 5
+ .locals init (int32 V_0,
+ int32 V_1,
+ int32 V_2,
+ int32 V_3)
+ IL_0000: newobj instance void [mscorlib]System.Random::.ctor()
+ IL_0005: ldc.i4.2
+ IL_0006: ldc.i4.2
+ IL_0007: callvirt instance int32 [mscorlib]System.Random::Next(int32,
+ int32)
+ IL_000c: stloc.0
+ IL_000d: ldc.i4.0
+ IL_000e: stloc.3
+ IL_000f: ldloc.0
+ IL_0010: stloc.2
+ IL_0011: ldloc.2
+ IL_0012: brtrue.s IL_0024
+
+ IL_0014: ldstr "The step of a range cannot be zero."
+ IL_0019: ldstr "step"
+ IL_001e: newobj instance void [mscorlib]System.ArgumentException::.ctor(string,
+ string)
+ IL_0023: throw
+
+ IL_0024: ldc.i4.s 10
+ IL_0026: stloc.1
+ IL_0027: ldloc.1
+ IL_0028: ldloc.3
+ IL_0029: blt.s IL_002f
+
+ IL_002b: ldloc.2
+ IL_002c: ldc.i4.0
+ IL_002d: bgt.s IL_0037
+
+ IL_002f: ldloc.1
+ IL_0030: ldloc.3
+ IL_0031: bgt.s IL_0051
+
+ IL_0033: ldloc.2
+ IL_0034: ldc.i4.0
+ IL_0035: bge.s IL_0051
+
+ IL_0037: ldloc.3
+ IL_0038: call void [mscorlib]System.Console::WriteLine(int32)
+ IL_003d: ldloc.3
+ IL_003e: ldloc.2
+ IL_003f: add
+ IL_0040: stloc.3
+ IL_0041: ldloc.3
+ IL_0042: ldloc.1
+ IL_0043: ble.s IL_0049
+
+ IL_0045: ldloc.2
+ IL_0046: ldc.i4.0
+ IL_0047: bgt.s IL_0051
+
+ IL_0049: ldloc.3
+ IL_004a: ldloc.1
+ IL_004b: bge.s IL_0037
+
+ IL_004d: ldloc.2
+ IL_004e: ldc.i4.0
+ IL_004f: bge.s IL_0037
+
+ IL_0051: ret
+ }""" ]
+
+ []
+ let ``Strided integer for loops with constant step should be optimized``() =
+ FSharp """
+module ForLoops
+
+let loop2 () =
+ for i in 0..2..10 do
+ System.Console.WriteLine i
+ """
+ |> compile
+ |> shouldSucceed
+ |> verifyIL ["""
+ .method public static void loop2() cil managed
+ {
+
+ .maxstack 4
+ .locals init (int32 V_0,
+ int32 V_1)
+ IL_0000: ldc.i4.0
+ IL_0001: stloc.1
+ IL_0002: ldc.i4.s 10
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: ldloc.1
+ IL_0007: blt.s IL_0017
+
+ IL_0009: ldloc.1
+ IL_000a: call void [mscorlib]System.Console::WriteLine(int32)
+ IL_000f: ldloc.1
+ IL_0010: ldc.i4.2
+ IL_0011: add
+ IL_0012: stloc.1
+ IL_0013: ldloc.1
+ IL_0014: ldloc.0
+ IL_0015: ble.s IL_0009
+
+ IL_0017: ret
+ }""" ]
+
+ []
+ let ``Strided integer for loops with constant negative step should be optimized``() =
+ FSharp """
+module ForLoops
+
+let loop2 () =
+ for i in 10 .. -2 .. 1 do
+ System.Console.WriteLine i
+ """
+ |> compile
+ |> shouldSucceed
+ |> verifyIL ["""
+ .method public static void loop2() cil managed
+ {
+
+ .maxstack 4
+ .locals init (int32 V_0,
+ int32 V_1)
+ IL_0000: ldc.i4.s 10
+ IL_0002: stloc.1
+ IL_0003: ldc.i4.1
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: ldloc.1
+ IL_0007: bgt.s IL_0017
+
+ IL_0009: ldloc.1
+ IL_000a: call void [mscorlib]System.Console::WriteLine(int32)
+ IL_000f: ldloc.1
+ IL_0010: ldc.i4.2
+ IL_0011: sub
+ IL_0012: stloc.1
+ IL_0013: ldloc.1
+ IL_0014: ldloc.0
+ IL_0015: bge.s IL_0009
+
+ IL_0017: ret
+ }""" ]
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
index a899d457f86..966dfab7ce3 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
+++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
@@ -175,6 +175,7 @@
+
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ConstStepForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ConstStepForLoops.fs
new file mode 100644
index 00000000000..c04630841ec
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ConstStepForLoops.fs
@@ -0,0 +1,498 @@
+
+let ``test -20`` n m =
+ let expected = seq { n .. -20 .. m }
+ let actual = ResizeArray()
+ for i in n .. -20 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -20`` n m |> not then
+ failwith $"FAILURE: {n} .. -20 .. {m}"
+
+let ``test -19`` n m =
+ let expected = seq { n .. -19 .. m }
+ let actual = ResizeArray()
+ for i in n .. -19 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -19`` n m |> not then
+ failwith $"FAILURE: {n} .. -19 .. {m}"
+
+let ``test -18`` n m =
+ let expected = seq { n .. -18 .. m }
+ let actual = ResizeArray()
+ for i in n .. -18 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -18`` n m |> not then
+ failwith $"FAILURE: {n} .. -18 .. {m}"
+
+let ``test -17`` n m =
+ let expected = seq { n .. -17 .. m }
+ let actual = ResizeArray()
+ for i in n .. -17 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -17`` n m |> not then
+ failwith $"FAILURE: {n} .. -17 .. {m}"
+
+let ``test -16`` n m =
+ let expected = seq { n .. -16 .. m }
+ let actual = ResizeArray()
+ for i in n .. -16 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -16`` n m |> not then
+ failwith $"FAILURE: {n} .. -16 .. {m}"
+
+let ``test -15`` n m =
+ let expected = seq { n .. -15 .. m }
+ let actual = ResizeArray()
+ for i in n .. -15 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -15`` n m |> not then
+ failwith $"FAILURE: {n} .. -15 .. {m}"
+
+let ``test -14`` n m =
+ let expected = seq { n .. -14 .. m }
+ let actual = ResizeArray()
+ for i in n .. -14 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -14`` n m |> not then
+ failwith $"FAILURE: {n} .. -14 .. {m}"
+
+let ``test -13`` n m =
+ let expected = seq { n .. -13 .. m }
+ let actual = ResizeArray()
+ for i in n .. -13 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -13`` n m |> not then
+ failwith $"FAILURE: {n} .. -13 .. {m}"
+
+let ``test -12`` n m =
+ let expected = seq { n .. -12 .. m }
+ let actual = ResizeArray()
+ for i in n .. -12 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -12`` n m |> not then
+ failwith $"FAILURE: {n} .. -12 .. {m}"
+
+let ``test -11`` n m =
+ let expected = seq { n .. -11 .. m }
+ let actual = ResizeArray()
+ for i in n .. -11 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -11`` n m |> not then
+ failwith $"FAILURE: {n} .. -11 .. {m}"
+
+let ``test -10`` n m =
+ let expected = seq { n .. -10 .. m }
+ let actual = ResizeArray()
+ for i in n .. -10 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -10`` n m |> not then
+ failwith $"FAILURE: {n} .. -10 .. {m}"
+
+let ``test -9`` n m =
+ let expected = seq { n .. -9 .. m }
+ let actual = ResizeArray()
+ for i in n .. -9 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -9`` n m |> not then
+ failwith $"FAILURE: {n} .. -9 .. {m}"
+
+let ``test -8`` n m =
+ let expected = seq { n .. -8 .. m }
+ let actual = ResizeArray()
+ for i in n .. -8 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -8`` n m |> not then
+ failwith $"FAILURE: {n} .. -8 .. {m}"
+
+let ``test -7`` n m =
+ let expected = seq { n .. -7 .. m }
+ let actual = ResizeArray()
+ for i in n .. -7 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -7`` n m |> not then
+ failwith $"FAILURE: {n} .. -7 .. {m}"
+
+let ``test -6`` n m =
+ let expected = seq { n .. -6 .. m }
+ let actual = ResizeArray()
+ for i in n .. -6 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -6`` n m |> not then
+ failwith $"FAILURE: {n} .. -6 .. {m}"
+
+let ``test -5`` n m =
+ let expected = seq { n .. -5 .. m }
+ let actual = ResizeArray()
+ for i in n .. -5 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -5`` n m |> not then
+ failwith $"FAILURE: {n} .. -5 .. {m}"
+
+let ``test -4`` n m =
+ let expected = seq { n .. -4 .. m }
+ let actual = ResizeArray()
+ for i in n .. -4 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -4`` n m |> not then
+ failwith $"FAILURE: {n} .. -4 .. {m}"
+
+let ``test -3`` n m =
+ let expected = seq { n .. -3 .. m }
+ let actual = ResizeArray()
+ for i in n .. -3 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -3`` n m |> not then
+ failwith $"FAILURE: {n} .. -3 .. {m}"
+
+let ``test -2`` n m =
+ let expected = seq { n .. -2 .. m }
+ let actual = ResizeArray()
+ for i in n .. -2 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -2`` n m |> not then
+ failwith $"FAILURE: {n} .. -2 .. {m}"
+
+let ``test -1`` n m =
+ let expected = seq { n .. -1 .. m }
+ let actual = ResizeArray()
+ for i in n .. -1 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test -1`` n m |> not then
+ failwith $"FAILURE: {n} .. -1 .. {m}"
+
+let ``test 1`` n m =
+ let expected = seq { n .. 1 .. m }
+ let actual = ResizeArray()
+ for i in n .. 1 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 1`` n m |> not then
+ failwith $"FAILURE: {n} .. 1 .. {m}"
+
+let ``test 2`` n m =
+ let expected = seq { n .. 2 .. m }
+ let actual = ResizeArray()
+ for i in n .. 2 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 2`` n m |> not then
+ failwith $"FAILURE: {n} .. 2 .. {m}"
+
+let ``test 3`` n m =
+ let expected = seq { n .. 3 .. m }
+ let actual = ResizeArray()
+ for i in n .. 3 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 3`` n m |> not then
+ failwith $"FAILURE: {n} .. 3 .. {m}"
+
+let ``test 4`` n m =
+ let expected = seq { n .. 4 .. m }
+ let actual = ResizeArray()
+ for i in n .. 4 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 4`` n m |> not then
+ failwith $"FAILURE: {n} .. 4 .. {m}"
+
+let ``test 5`` n m =
+ let expected = seq { n .. 5 .. m }
+ let actual = ResizeArray()
+ for i in n .. 5 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 5`` n m |> not then
+ failwith $"FAILURE: {n} .. 5 .. {m}"
+
+let ``test 6`` n m =
+ let expected = seq { n .. 6 .. m }
+ let actual = ResizeArray()
+ for i in n .. 6 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 6`` n m |> not then
+ failwith $"FAILURE: {n} .. 6 .. {m}"
+
+let ``test 7`` n m =
+ let expected = seq { n .. 7 .. m }
+ let actual = ResizeArray()
+ for i in n .. 7 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 7`` n m |> not then
+ failwith $"FAILURE: {n} .. 7 .. {m}"
+
+let ``test 8`` n m =
+ let expected = seq { n .. 8 .. m }
+ let actual = ResizeArray()
+ for i in n .. 8 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 8`` n m |> not then
+ failwith $"FAILURE: {n} .. 8 .. {m}"
+
+let ``test 9`` n m =
+ let expected = seq { n .. 9 .. m }
+ let actual = ResizeArray()
+ for i in n .. 9 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 9`` n m |> not then
+ failwith $"FAILURE: {n} .. 9 .. {m}"
+
+let ``test 10`` n m =
+ let expected = seq { n .. 10 .. m }
+ let actual = ResizeArray()
+ for i in n .. 10 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 10`` n m |> not then
+ failwith $"FAILURE: {n} .. 10 .. {m}"
+
+let ``test 11`` n m =
+ let expected = seq { n .. 11 .. m }
+ let actual = ResizeArray()
+ for i in n .. 11 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 11`` n m |> not then
+ failwith $"FAILURE: {n} .. 11 .. {m}"
+
+let ``test 12`` n m =
+ let expected = seq { n .. 12 .. m }
+ let actual = ResizeArray()
+ for i in n .. 12 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 12`` n m |> not then
+ failwith $"FAILURE: {n} .. 12 .. {m}"
+
+let ``test 13`` n m =
+ let expected = seq { n .. 13 .. m }
+ let actual = ResizeArray()
+ for i in n .. 13 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 13`` n m |> not then
+ failwith $"FAILURE: {n} .. 13 .. {m}"
+
+let ``test 14`` n m =
+ let expected = seq { n .. 14 .. m }
+ let actual = ResizeArray()
+ for i in n .. 14 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 14`` n m |> not then
+ failwith $"FAILURE: {n} .. 14 .. {m}"
+
+let ``test 15`` n m =
+ let expected = seq { n .. 15 .. m }
+ let actual = ResizeArray()
+ for i in n .. 15 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 15`` n m |> not then
+ failwith $"FAILURE: {n} .. 15 .. {m}"
+
+let ``test 16`` n m =
+ let expected = seq { n .. 16 .. m }
+ let actual = ResizeArray()
+ for i in n .. 16 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 16`` n m |> not then
+ failwith $"FAILURE: {n} .. 16 .. {m}"
+
+let ``test 17`` n m =
+ let expected = seq { n .. 17 .. m }
+ let actual = ResizeArray()
+ for i in n .. 17 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 17`` n m |> not then
+ failwith $"FAILURE: {n} .. 17 .. {m}"
+
+let ``test 18`` n m =
+ let expected = seq { n .. 18 .. m }
+ let actual = ResizeArray()
+ for i in n .. 18 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 18`` n m |> not then
+ failwith $"FAILURE: {n} .. 18 .. {m}"
+
+let ``test 19`` n m =
+ let expected = seq { n .. 19 .. m }
+ let actual = ResizeArray()
+ for i in n .. 19 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 19`` n m |> not then
+ failwith $"FAILURE: {n} .. 19 .. {m}"
+
+let ``test 20`` n m =
+ let expected = seq { n .. 20 .. m }
+ let actual = ResizeArray()
+ for i in n .. 20 .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+for n = -20 to 20 do
+ for m = -20 to 20 do
+ if ``test 20`` n m |> not then
+ failwith $"FAILURE: {n} .. 20 .. {m}"
+
+// Generation Code:
+// [ -20..-1 ] @ [ 1..20 ]
+// |> List.map (fun step ->
+// $"""
+// let ``test {step}`` n m =
+// let expected = seq {{ n .. {step} .. m }}
+// let actual = ResizeArray()
+// for i in n .. {step} .. m do
+// actual.Add i
+// Seq.forall2 (=) actual expected
+//
+// for n = -20 to 20 do
+// for m = -20 to 20 do
+// if ``test {step}`` n m |> not then
+// failwith $"FAILURE: {{n}} .. {step} .. {{m}}"
+// """)
+// |> List.reduce (+)
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
new file mode 100644
index 00000000000..e00cb510af9
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace FSharp.Compiler.ComponentTests.Miscellaneous
+
+open Xunit
+open FSharp.Test
+open FSharp.Test.Compiler
+
+module OptimizedForLoops =
+
+ []
+ let ``Optimized variable step for loops should match OperatorIntrinsics RangeInt32 behavior`` compilation =
+ compilation
+ |> compileExeAndRun
+ |> shouldSucceed
+
+ []
+ let ``Optimized constant step loops should match OperatorIntrinsics RangeInt32 behavior`` compilation =
+ compilation
+ |> compileExeAndRun
+ |> shouldSucceed
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/VariableStepForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/VariableStepForLoops.fs
new file mode 100644
index 00000000000..9b1ee755931
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/VariableStepForLoops.fs
@@ -0,0 +1,18 @@
+// 1020100 test cases
+let test n step m =
+ let expected = seq { n .. step .. m}
+ let actual = ResizeArray()
+ for i in n .. step .. m do
+ actual.Add i
+ Seq.forall2 (=) actual expected
+
+let ns = [ -50 .. 50 ]
+let ms = [ -50 .. 50 ]
+let steps = [ -50 .. -1 ] @ [ 1 .. 50 ]
+
+for n in ns do
+ for step in steps do
+ for m in ms do
+ let res = test n step m
+ if not res then
+ failwith $"FAILED CASE: {n} .. {step} .. {m}"
\ No newline at end of file
From 02bd0f9658db8fc8e36850b5302056f1398fb2d4 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Tue, 26 Jul 2022 16:52:03 -0700
Subject: [PATCH 02/15] run fantomas
---
src/Compiler/CodeGen/IlxGen.fs | 54 +++++++++++++------------
src/Compiler/TypedTree/TypedTreeOps.fsi | 3 +-
2 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs
index 90d6b2dd696..219549230b5 100644
--- a/src/Compiler/CodeGen/IlxGen.fs
+++ b/src/Compiler/CodeGen/IlxGen.fs
@@ -2998,9 +2998,12 @@ and GenExprAux (cenv: cenv) (cgbuf: CodeGenBuffer) eenv expr (sequel: sequel) =
GenWhileLoop cenv cgbuf eenv (sp, e1, e2, m) sequel
| TOp.IntegerForLoop (spFor, spTo, dir),
[ Expr.Lambda (_, _, _, [ _ ], e1, _, _); Expr.Lambda (_, _, _, [ _ ], e2, _, _); Expr.Lambda (_, _, _, [ v ], e3, _, _) ],
- [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, mkZero g (range()), m) sequel
- | TOp.IntegerForLoop(spFor, spTo, dir),
- [ Expr.Lambda(_, _, _, [ _ ], e1, _, _); Expr.Lambda (_, _, _, [ _ ], e2, _, _); Expr.Lambda (_, _, _, [ v ], e3, _, _); Expr.Lambda (_, _, _, [ _ ], e4, _, _) ],
+ [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, mkZero g (range ()), m) sequel
+ | TOp.IntegerForLoop (spFor, spTo, dir),
+ [ Expr.Lambda (_, _, _, [ _ ], e1, _, _)
+ Expr.Lambda (_, _, _, [ _ ], e2, _, _)
+ Expr.Lambda (_, _, _, [ v ], e3, _, _)
+ Expr.Lambda (_, _, _, [ _ ], e4, _, _) ],
[] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, e4, m) sequel
| TOp.TryFinally (spTry, spFinally),
[ Expr.Lambda (_, _, _, [ _ ], e1, _, _); Expr.Lambda (_, _, _, [ _ ], e2, _, _) ],
@@ -4898,7 +4901,7 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
let stepConst =
match stepExpr with
- | Expr.Const(Const.Int32 i, _, _) when i <> 0 -> Some i
+ | Expr.Const (Const.Int32 i, _, _) when i <> 0 -> Some i
| _ -> None
let finishIdx, stepIdx, eenvinner =
@@ -4915,6 +4918,7 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
if not stepByOne && Option.isNone stepConst then
let v2, _realloc, eenvinner =
AllocLocal cenv cgbuf eenvinner true (vName, g.ilg.typ_Int32, false) (start, finish)
+
v, v2, eenvinner
else
v, -1, eenvinner
@@ -4930,19 +4934,19 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
GenExpr cenv cgbuf eenv e1 Continue
GenStoreVal cgbuf eenvinner m v
- match dir, stepConst with
+ match dir, stepConst with
| FSharpForLoopWithStep, None ->
// Throw invalidarg at runtime if step is 0.
// Emulates behavior of the RangeInt32 enumerator that this replaces.
GenExpr cenv cgbuf eenvinner stepExpr Continue
EmitSetLocal cgbuf stepIdx
EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
-
+
let notZero = CG.GenerateDelayMark cgbuf "notZero"
CG.EmitInstr cgbuf (pop 1) Push0 (I_brcmp(BI_brtrue, notZero.CodeLabel))
let arg1 = mkString g stepExpr.Range (SR.GetString "StepCannotBeZero")
- let arg2 = mkString g stepExpr.Range "step"
+ let arg2 = mkString g stepExpr.Range "step"
let invalidArgExpr = MakeArgumentExnExpr cenv eenv (arg1, arg2, stepExpr.Range)
GenExpr cenv cgbuf eenvinner invalidArgExpr Continue
CG.EmitInstr cgbuf (pop 1) Push0 I_throw
@@ -4956,23 +4960,20 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- match dir with
- | FSharpForLoopUp ->
- CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, finish.CodeLabel))
- | FSharpForLoopDown ->
- CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
+ match dir with
+ | FSharpForLoopUp -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, finish.CodeLabel))
+ | FSharpForLoopDown -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
| FSharpForLoopWithStep ->
match stepConst with
- | Some stepC ->
- CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp((if stepC > 0 then BI_blt else BI_bgt), finish.CodeLabel))
+ | Some stepC -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp((if stepC > 0 then BI_blt else BI_bgt), finish.CodeLabel))
| None ->
let testPassed = CG.GenerateDelayMark cgbuf "testPassed"
CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, testPassed.CodeLabel))
-
+
EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 0)
CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, inner.CodeLabel))
-
+
CG.SetMarkToHere cgbuf testPassed
EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
@@ -4982,8 +4983,7 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 0)
CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bge, finish.CodeLabel))
- | CSharpForLoopUp ->
- CG.EmitInstr cgbuf (pop 0) Push0 (I_br test.CodeLabel)
+ | CSharpForLoopUp -> CG.EmitInstr cgbuf (pop 0) Push0 (I_br test.CodeLabel)
cgbuf.EmitStartOfHiddenCode()
@@ -4996,22 +4996,22 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
// v++ or v--
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- match dir with
+ match dir with
| FSharpForLoopUp
| FSharpForLoopDown
| CSharpForLoopUp ->
CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
| FSharpForLoopWithStep _ ->
- match stepConst with
- | Some sc ->
+ match stepConst with
+ | Some sc ->
let pos = sc > 0
CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 (if pos then sc else -sc))
CG.EmitInstr cgbuf (pop 1) Push0 (if pos then AI_add else AI_sub)
| None ->
EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
CG.EmitInstr cgbuf (pop 1) Push0 AI_add
-
+
GenStoreVal cgbuf eenvinner m v
// .test
@@ -5029,19 +5029,20 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- match dir with
+ match dir with
| FSharpForLoopUp
| FSharpForLoopDown ->
EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
+
CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_bne_un, inner.CodeLabel) ])
|> GenSequel cenv eenv.cloc cgbuf
| FSharpForLoopWithStep _ ->
EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
- match stepConst with
+ match stepConst with
| Some sc ->
let pos = sc > 0
CmpThenBrOrContinue(pop 2, [ I_brcmp((if pos then BI_ble else BI_bge), inner.CodeLabel) ])
@@ -5480,7 +5481,10 @@ and MakeArgumentExnExpr cenv eenv (messageExpr, argNameExpr, m) =
let g = cenv.g
let ety = mkAppTy (g.FindSysTyconRef [ "System" ] "ArgumentException") []
let ilTy = GenType cenv m eenv.tyenv ety
- let mref = mkILCtorMethSpecForTy(ilTy, [ g.ilg.typ_String; g.ilg.typ_String ]).MethodRef
+
+ let mref =
+ mkILCtorMethSpecForTy(ilTy, [ g.ilg.typ_String; g.ilg.typ_String ]).MethodRef
+
Expr.Op(TOp.ILCall(false, false, false, true, NormalValUse, false, false, mref, [], [], [ ety ]), [], [ messageExpr; argNameExpr ], m)
and GenTraitCall (cenv: cenv) cgbuf eenv (traitInfo: TraitConstraintInfo, argExprs, m) expr sequel =
diff --git a/src/Compiler/TypedTree/TypedTreeOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.fsi
index df72560e744..8ca9233a41d 100755
--- a/src/Compiler/TypedTree/TypedTreeOps.fsi
+++ b/src/Compiler/TypedTree/TypedTreeOps.fsi
@@ -2582,7 +2582,8 @@ val (|WhileExpr|_|): Expr -> (DebugPointAtWhile * SpecialWhileLoopMarker * Expr
/// Recognise an integer for-loop expression
val (|IntegerForLoopExpr|_|):
- Expr -> (DebugPointAtFor * DebugPointAtInOrTo * ForLoopStyle * Expr * Expr * Val * Expr * Expr option * range) option
+ Expr ->
+ (DebugPointAtFor * DebugPointAtInOrTo * ForLoopStyle * Expr * Expr * Val * Expr * Expr option * range) option
/// Recognise a try-with expression
val (|TryWithExpr|_|):
From 86de1fd22744a39f37761dbe02f4a5be1c45813f Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Wed, 27 Jul 2022 23:10:55 -0700
Subject: [PATCH 03/15] add benchmark
---
.../MicroPerf/Benchmarks.fs | 2 +-
.../MicroPerf/ForLoops.fs | 24 +++++++++++++++++++
.../MicroPerf/MicroPerf.fsproj | 1 +
3 files changed, 26 insertions(+), 1 deletion(-)
create mode 100644 tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/ForLoops.fs
diff --git a/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/Benchmarks.fs b/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/Benchmarks.fs
index 366efa97439..dc24a3087de 100644
--- a/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/Benchmarks.fs
+++ b/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/Benchmarks.fs
@@ -14,5 +14,5 @@ module Main =
printfn "Running benchmarks..."
//let results = BenchmarkRunner.Run()
//let results = BenchmarkRunner.Run()
- let results = BenchmarkRunner.Run()
+ let results = BenchmarkRunner.Run()
0
diff --git a/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/ForLoops.fs b/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/ForLoops.fs
new file mode 100644
index 00000000000..759ae985f78
--- /dev/null
+++ b/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/ForLoops.fs
@@ -0,0 +1,24 @@
+module ForLoops
+
+open BenchmarkDotNet.Attributes
+open BenchmarkDotNet.Diagnosers
+open System.Runtime.CompilerServices
+
+[]
+[]
+type ForLoopBenchmark() =
+
+ []
+ member val Start = 0 with get, set
+
+ []
+ member val Finish = 0 with get, set
+
+ []
+ member val Step = 0 with get, set
+
+ []
+ member this.Benchmark() =
+ let mutable x = 0
+ for i in this.Start .. this.Finish .. this.Step do
+ x <- i
diff --git a/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/MicroPerf.fsproj b/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/MicroPerf.fsproj
index 9b89d243beb..fca34b31a17 100644
--- a/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/MicroPerf.fsproj
+++ b/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/MicroPerf.fsproj
@@ -28,6 +28,7 @@
+
From 96fed0eb1b8a7a2b5c68c934fcaf92ccb6740dff Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Thu, 28 Jul 2022 14:09:46 -0700
Subject: [PATCH 04/15] update quotations
* adds new active pattern to match int32 range step for loops
* existing Expr structure changed, no longer backed by an enumerator
* updates test, existing check changed to int64 instead of int32
---
src/Compiler/Checking/PostInferenceChecks.fs | 4 +++
src/Compiler/Checking/QuotationTranslator.fs | 3 ++
src/Compiler/TypedTree/QuotationPickler.fs | 2 ++
src/Compiler/TypedTree/QuotationPickler.fsi | 2 ++
src/FSharp.Core/quotations.fs | 35 +++++++++++++++++---
src/FSharp.Core/quotations.fsi | 10 ++++++
tests/fsharp/core/quotes/test.fsx | 14 ++++++--
7 files changed, 63 insertions(+), 7 deletions(-)
diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs
index 62889308edb..c150c64054b 100644
--- a/src/Compiler/Checking/PostInferenceChecks.fs
+++ b/src/Compiler/Checking/PostInferenceChecks.fs
@@ -1454,6 +1454,10 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr =
CheckTypeInstNoByrefs cenv env m tyargs
CheckExprsNoByRefLike cenv env [e1;e2;e3]
+ | TOp.IntegerForLoop _, _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _);Expr.Lambda (_, _, _, [_], e3, _, _);Expr.Lambda (_, _, _, [_], e4, _, _)] ->
+ CheckTypeInstNoByrefs cenv env m tyargs
+ CheckExprsNoByRefLike cenv env [e1;e2;e3;e4]
+
| TOp.TryWith _, [_], [Expr.Lambda (_, _, _, [_], e1, _, _); Expr.Lambda (_, _, _, [_], _e2, _, _); Expr.Lambda (_, _, _, [_], e3, _, _)] ->
CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/catch can be a byref
ctorLimitedZoneCheck()
diff --git a/src/Compiler/Checking/QuotationTranslator.fs b/src/Compiler/Checking/QuotationTranslator.fs
index 089de7b4a7f..64072ddfe9c 100644
--- a/src/Compiler/Checking/QuotationTranslator.fs
+++ b/src/Compiler/Checking/QuotationTranslator.fs
@@ -665,6 +665,9 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP.
| FSharpForLoopUp -> QP.mkIntegerForLoop(ConvExpr cenv env lim0, ConvExpr cenv env lim1, ConvExpr cenv env body)
| _ -> wfail(Error(FSComp.SR.crefQuotationsCantContainDescendingForLoops(), m))
+ | TOp.IntegerForLoop (_, _, _), [], [Expr.Lambda (_, _, _, [_], lim0, _, _);Expr.Lambda (_, _, _, [_], lim1, _, _);body; Expr.Lambda (_, _, _, [_], step, _, _)] ->
+ QP.mkIntegerForLoopWithStep(ConvExpr cenv env lim0, ConvExpr cenv env lim1, ConvExpr cenv env body, ConvExpr cenv env step)
+
| TOp.ILCall (_, _, _, isCtor, valUseFlag, isProperty, _, ilMethRef, enclTypeInst, methInst, _), [], callArgs ->
let parentTyconR = ConvILTypeRefUnadjusted cenv m ilMethRef.DeclaringTypeRef
let isNewObj = isCtor || (match valUseFlag with CtorValUsedAsSuperInit | CtorValUsedAsSelfInit -> true | _ -> false)
diff --git a/src/Compiler/TypedTree/QuotationPickler.fs b/src/Compiler/TypedTree/QuotationPickler.fs
index 4c613f007d2..678da2d64c0 100644
--- a/src/Compiler/TypedTree/QuotationPickler.fs
+++ b/src/Compiler/TypedTree/QuotationPickler.fs
@@ -210,6 +210,8 @@ let mkSequential (e1, e2) = CombExpr(SeqOp, [], [e1;e2])
let mkIntegerForLoop (x1, x2, x3) = CombExpr(ForLoopOp, [], [x1;x2;x3])
+let mkIntegerForLoopWithStep (x1, x2, x3, x4) = CombExpr(ForLoopOp, [], [x1;x2;x3;x4])
+
let mkWhileLoop (e1, e2) = CombExpr(WhileLoopOp, [], [e1;e2])
let mkTryFinally(e1, e2) = CombExpr(TryFinallyOp, [], [e1;e2])
diff --git a/src/Compiler/TypedTree/QuotationPickler.fsi b/src/Compiler/TypedTree/QuotationPickler.fsi
index 648e9d0acf6..2cd9995daf5 100644
--- a/src/Compiler/TypedTree/QuotationPickler.fsi
+++ b/src/Compiler/TypedTree/QuotationPickler.fsi
@@ -141,6 +141,8 @@ val mkSequential: ExprData * ExprData -> ExprData
val mkIntegerForLoop: ExprData * ExprData * ExprData -> ExprData
+val mkIntegerForLoopWithStep: ExprData * ExprData * ExprData * ExprData -> ExprData
+
val mkWhileLoop: ExprData * ExprData -> ExprData
val mkTryFinally: ExprData * ExprData -> ExprData
diff --git a/src/FSharp.Core/quotations.fs b/src/FSharp.Core/quotations.fs
index 44c625de5f5..424b15f4a84 100644
--- a/src/FSharp.Core/quotations.fs
+++ b/src/FSharp.Core/quotations.fs
@@ -422,6 +422,8 @@ and [] Expr(
| CombTerm (AddressSetOp, args) -> combL "AddressSet" (exprs args)
| CombTerm (ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)) ]) ->
combL "ForIntegerRangeLoop" [ varL v; expr e1; expr e2; expr e3 ]
+ | CombTerm (ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)); step ]) ->
+ combL "ForIntegerRangeLoop" [ varL v; expr e1; expr step; expr e2; expr e3 ]
| CombTerm (WhileLoopOp, args) -> combL "WhileLoop" (exprs args)
| CombTerm (TryFinallyOp, args) -> combL "TryFinally" (exprs args)
| CombTerm (TryWithOp, [ e1; Lambda (v1, e2); Lambda (v2, e3) ]) ->
@@ -554,6 +556,11 @@ module Patterns =
| CombTerm (k, [ x1; x2; x3 ]) -> Some(k, x1, x2, x3)
| _ -> None
+ let (|Comb4|_|) (E x) =
+ match x with
+ | CombTerm (k, [ x1; x2; x3; x4 ]) -> Some(k, x1, x2, x3, x4)
+ | _ -> None
+
[]
let (|Var|_|) (E x) =
match x with
@@ -722,6 +729,12 @@ module Patterns =
| Comb3 (ForIntegerRangeLoopOp, e1, e2, Lambda (v, e3)) -> Some(v, e1, e2, e3)
| _ -> None
+ []
+ let (|ForIntegerRangeLoopWithStep|_|) input =
+ match input with
+ | Comb4 (ForIntegerRangeLoopOp, e1, e2, Lambda (v, e3), step) -> Some(v, e1, step, e2, e3)
+ | _ -> None
+
[]
let (|WhileLoop|_|) input =
match input with
@@ -970,6 +983,9 @@ module Patterns =
let mkFE3 op (x, y, z) =
E(CombTerm(op, [ (x :> Expr); (y :> Expr); (z :> Expr) ]))
+ let mkFE4 op (x, y, z, a) =
+ E(CombTerm(op, [ (x :> Expr); (y :> Expr); (z :> Expr); (a :> Expr) ]))
+
let mkOp v () =
v
@@ -1346,11 +1362,16 @@ module Patterns =
| true -> mkFEN (StaticMethodCallWOp(minfo, minfoW, nWitnesses)) args
| false -> invalidArg "minfo" (SR.GetString(SR.QnonStaticNoReceiverObject))
- let mkForLoop (v: Var, lowerBound, upperBound, body) =
+ let mkForLoop (v: Var, lowerBound, step, upperBound, body) =
+ checkTypesSR (typeof) (v.Type) "for" (SR.GetString(SR.QtmmLoopBodyMustBeLambdaTakingInteger))
checkTypesSR (typeof) (typeOf lowerBound) "lowerBound" (SR.GetString(SR.QtmmLowerUpperBoundMustBeInt))
checkTypesSR (typeof) (typeOf upperBound) "upperBound" (SR.GetString(SR.QtmmLowerUpperBoundMustBeInt))
- checkTypesSR (typeof) (v.Type) "for" (SR.GetString(SR.QtmmLoopBodyMustBeLambdaTakingInteger))
- mkFE3 ForIntegerRangeLoopOp (lowerBound, upperBound, mkLambda (v, body))
+ match step with
+ | Some stepExpr ->
+ checkTypesSR (typeof) (typeOf stepExpr) "step" (SR.GetString(SR.QtmmLoopBodyMustBeLambdaTakingInteger))
+ mkFE4 ForIntegerRangeLoopOp (lowerBound, stepExpr, upperBound, mkLambda (v, body))
+ | None ->
+ mkFE3 ForIntegerRangeLoopOp (lowerBound, upperBound, mkLambda (v, body))
let mkWhileLoop (guard, body) =
checkTypesSR (typeof) (typeOf guard) "guard" (SR.GetString(SR.QtmmGuardMustBeBool))
@@ -2630,7 +2651,10 @@ type Expr with
mkIfThenElse (guard, thenExpr, elseExpr)
static member ForIntegerRangeLoop(loopVariable, start: Expr, endExpr: Expr, body: Expr) =
- mkForLoop (loopVariable, start, endExpr, body)
+ mkForLoop (loopVariable, start, None, endExpr, body)
+
+ static member ForIntegerRangeLoop(loopVariable, start: Expr, step: Expr, endExpr: Expr, body: Expr) =
+ mkForLoop (loopVariable, start, Some step, endExpr, body)
static member FieldGet(fieldInfo: FieldInfo) =
checkNonNull "fieldInfo" fieldInfo
@@ -3034,7 +3058,8 @@ module ExprShape =
| AddressOfOp, [ e1 ] -> mkAddressOf e1
| VarSetOp, [ E (VarTerm v); e ] -> mkVarSet (v, e)
| AddressSetOp, [ e1; e2 ] -> mkAddressSet (e1, e2)
- | ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)) ] -> mkForLoop (v, e1, e2, e3)
+ | ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)) ] -> mkForLoop (v, e1, None, e2, e3)
+ | ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)); e4 ] -> mkForLoop (v, e1, Some e4, e2, e3)
| WhileLoopOp, [ e1; e2 ] -> mkWhileLoop (e1, e2)
| TryFinallyOp, [ e1; e2 ] -> mkTryFinally (e1, e2)
| TryWithOp, [ e1; Lambda (v1, e2); Lambda (v2, e3) ] -> mkTryWith (e1, v1, e2, v2, e3)
diff --git a/src/FSharp.Core/quotations.fsi b/src/FSharp.Core/quotations.fsi
index 5ec624e1438..fa4455a05bb 100644
--- a/src/FSharp.Core/quotations.fsi
+++ b/src/FSharp.Core/quotations.fsi
@@ -1439,6 +1439,16 @@ module Patterns =
[]
val (|ForIntegerRangeLoop|_|): input: Expr -> (Var * Expr * Expr * Expr) option
+ /// An active pattern to recognize expressions that represent loops over integer ranges with non-one step
+ ///
+ /// The input expression to match against.
+ ///
+ /// When successful, the pattern binds the value, start, step, finish and body of the input expression
+ ///
+ ///
+ []
+ val (|ForIntegerRangeLoopWithStep|_|): input: Expr -> (Var * Expr * Expr * Expr * Expr) option
+
/// An active pattern to recognize expressions that represent while loops
///
/// The input expression to match against.
diff --git a/tests/fsharp/core/quotes/test.fsx b/tests/fsharp/core/quotes/test.fsx
index cc85cf23ad6..a262f970e70 100644
--- a/tests/fsharp/core/quotes/test.fsx
+++ b/tests/fsharp/core/quotes/test.fsx
@@ -125,6 +125,7 @@ module TypedTest = begin
test "check AndAlso - encoded" ((<@ true && false @> |> (function IfThenElse(Bool(true),Bool(false),Bool(false)) -> true | _ -> false)))
test "check OrElse - encoded" ((<@ true || false @> |> (function IfThenElse(Bool(true),Bool(true),Bool(false)) -> true | _ -> false)))
+ test "check ForIntegerRangeLoopWithStep" (<@ for i in 1..2..10 do printf "hello" @> |> (function ForIntegerRangeLoopWithStep(v,Int32(1),Int32(2),Int32(10),b) -> true | _ -> false))
test "check ForIntegerRangeLoop" (<@ for i = 1 to 10 do printf "hello" @> |> (function ForIntegerRangeLoop(v,Int32(1),Int32(10),b) -> true | _ -> false))
test "check ForIntegerRangeLoop" (<@ for i in 1 .. 10 do printf "hello" @> |> (function ForIntegerRangeLoop(v,Int32(1),Int32(10),b) -> true | _ -> false))
@@ -137,7 +138,7 @@ module TypedTest = begin
test "check ForEachInList" (<@ for i in "123" do printf "hello" @> |> (function ForEachShape(_) -> true | _ -> false))
test "check ForEachInString" (<@ for i in [1;2;3] do printf "hello" @> |> (function ForEachShape(_) -> true | _ -> false))
// A slight non orthogonality is that all other 'for' loops go to (quite complex) the desugared form
- test "check Other Loop" (<@ for i in 1 .. 2 .. 10 do printf "hello" @> |> (function Let(v,_,b) -> true | _ -> false))
+ test "check Other Loop" (<@ for i in 1L .. 2L .. 10L do printf "hello" @> |> (function Let(v,_,b) -> true | _ -> false))
test "check Other Loop" (<@ for i in 1L .. 10L do printf "hello" @> |> (function Let(v,_,b) -> true | _ -> false))
let mutable mutableX = 1
@@ -1617,11 +1618,20 @@ module MoreQuotationsTests =
Call (None, Reraise, [])))))"""
let t14 = <@@ try failwith "test" with _ when true -> 0 @@>
- checkStrings "vwewvwewe13" (sprintf "%A" t14)
+ checkStrings "vwewvwewe14" (sprintf "%A" t14)
"""TryWith (Call (None, FailWith, [Value ("test")]), matchValue,
IfThenElse (Value (true), Value (1), Value (0)), matchValue,
IfThenElse (Value (true), Value (0), Call (None, Reraise, [])))"""
+ let t15 = <@@ for i in 1..2..10 do printfn $"{i}" @@>
+ checkStrings "vwewvwewe15" (sprintf "%A" t15)
+ """ForIntegerRangeLoop (i, Value (1), Value (2), Value (10),
+ Call (None, PrintFormatLine,
+ [Coerce (NewObject (PrintfFormat`5, Value ("%P()"),
+ NewArray (Object,
+ Call (None, Box, [i])),
+ Value ()), PrintfFormat`4)]))"""
+
let _ = <@@ let x : int option = None in x.IsSome @@> |> checkQuoteString "fqekhec1" """Let (x, NewUnionCase (None), Call (None, get_IsSome, [x]))"""
let _ = <@@ let x : int option = None in x.IsNone @@> |> checkQuoteString "fqekhec2" """Let (x, NewUnionCase (None), Call (None, get_IsNone, [x]))"""
let _ = <@@ let x : int option = None in x.Value @@> |> checkQuoteString "fqekhec3" """Let (x, NewUnionCase (None), PropertyGet (Some (x), Value, []))"""
From 5b76d5716c7c6338ffda60d10175216e760f2b0e Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Thu, 28 Jul 2022 16:31:14 -0700
Subject: [PATCH 05/15] improve il generation
* even smaller and faster generated il code
* ran fantomas
---
src/Compiler/CodeGen/IlxGen.fs | 27 +++++----------------------
src/FSharp.Core/quotations.fs | 4 ++--
2 files changed, 7 insertions(+), 24 deletions(-)
diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs
index 219549230b5..6c025db60c0 100644
--- a/src/Compiler/CodeGen/IlxGen.fs
+++ b/src/Compiler/CodeGen/IlxGen.fs
@@ -4957,32 +4957,15 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
if isFSharpStyle then
GenExpr cenv cgbuf eenvinner e2 Continue
EmitSetLocal cgbuf finishIdx
- EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
- GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
-
- match dir with
- | FSharpForLoopUp -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, finish.CodeLabel))
- | FSharpForLoopDown -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
- | FSharpForLoopWithStep ->
- match stepConst with
- | Some stepC -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp((if stepC > 0 then BI_blt else BI_bgt), finish.CodeLabel))
- | None ->
- let testPassed = CG.GenerateDelayMark cgbuf "testPassed"
- CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, testPassed.CodeLabel))
- EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
- CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 0)
- CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, inner.CodeLabel))
-
- CG.SetMarkToHere cgbuf testPassed
+ if stepByOne then
EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
-
- EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
- CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 0)
- CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bge, finish.CodeLabel))
+ match dir with
+ | FSharpForLoopUp -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, finish.CodeLabel))
+ | FSharpForLoopDown -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
+ | FSharpForLoopWithStep
| CSharpForLoopUp -> CG.EmitInstr cgbuf (pop 0) Push0 (I_br test.CodeLabel)
cgbuf.EmitStartOfHiddenCode()
diff --git a/src/FSharp.Core/quotations.fs b/src/FSharp.Core/quotations.fs
index 424b15f4a84..67e2eeab46e 100644
--- a/src/FSharp.Core/quotations.fs
+++ b/src/FSharp.Core/quotations.fs
@@ -1366,12 +1366,12 @@ module Patterns =
checkTypesSR (typeof) (v.Type) "for" (SR.GetString(SR.QtmmLoopBodyMustBeLambdaTakingInteger))
checkTypesSR (typeof) (typeOf lowerBound) "lowerBound" (SR.GetString(SR.QtmmLowerUpperBoundMustBeInt))
checkTypesSR (typeof) (typeOf upperBound) "upperBound" (SR.GetString(SR.QtmmLowerUpperBoundMustBeInt))
+
match step with
| Some stepExpr ->
checkTypesSR (typeof) (typeOf stepExpr) "step" (SR.GetString(SR.QtmmLoopBodyMustBeLambdaTakingInteger))
mkFE4 ForIntegerRangeLoopOp (lowerBound, stepExpr, upperBound, mkLambda (v, body))
- | None ->
- mkFE3 ForIntegerRangeLoopOp (lowerBound, upperBound, mkLambda (v, body))
+ | None -> mkFE3 ForIntegerRangeLoopOp (lowerBound, upperBound, mkLambda (v, body))
let mkWhileLoop (guard, body) =
checkTypesSR (typeof) (typeOf guard) "guard" (SR.GetString(SR.QtmmGuardMustBeBool))
From d771c5b4fac7a7589d51d5dfd3bbc75dfcf70b68 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Thu, 28 Jul 2022 16:50:08 -0700
Subject: [PATCH 06/15] Update SurfaceArea.fs
---
tests/FSharp.Core.UnitTests/SurfaceArea.fs | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/FSharp.Core.UnitTests/SurfaceArea.fs b/tests/FSharp.Core.UnitTests/SurfaceArea.fs
index c214e76daf7..164b2c98972 100644
--- a/tests/FSharp.Core.UnitTests/SurfaceArea.fs
+++ b/tests/FSharp.Core.UnitTests/SurfaceArea.fs
@@ -2440,6 +2440,7 @@ Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1
Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`4[Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr]] ForIntegerRangeLoopPattern(Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`5[Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr],System.Reflection.MethodInfo,System.Reflection.MethodInfo,Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]]] CallWithWitnessesPattern(Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`5[Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr]] TryWithPattern(Microsoft.FSharp.Quotations.FSharpExpr)
+Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`5[Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr]] ForIntegerRangeLoopWithStepPattern(Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Type] DefaultValuePattern(Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Reflection.FSharpReflectionExtensions: Boolean FSharpType.IsExceptionRepresentation.Static(System.Type, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
Microsoft.FSharp.Reflection.FSharpReflectionExtensions: Boolean FSharpType.IsRecord.Static(System.Type, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
From 88895955d9f0545ca44e3044ee4436c0b2d0cee9 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Thu, 28 Jul 2022 21:45:07 -0700
Subject: [PATCH 07/15] baseline tests
---
.../EmittedIL/ForLoop/ForLoop.fs | 179 ++----------------
.../EmittedIL/ForLoop/ForLoopWithStep1.fsx | 3 +
.../ForLoopWithStep1.fsx.il.net472.debug.bsl | 139 ++++++++++++++
...ForLoopWithStep1.fsx.il.net472.release.bsl | 149 +++++++++++++++
.../ForLoopWithStep1.fsx.il.netcore.debug.bsl | 139 ++++++++++++++
...orLoopWithStep1.fsx.il.netcore.release.bsl | 149 +++++++++++++++
.../EmittedIL/ForLoop/ForLoopWithStep2.fsx | 3 +
.../ForLoopWithStep2.fsx.il.net472.debug.bsl | 113 +++++++++++
...ForLoopWithStep2.fsx.il.net472.release.bsl | 123 ++++++++++++
.../ForLoopWithStep2.fsx.il.netcore.debug.bsl | 113 +++++++++++
...orLoopWithStep2.fsx.il.netcore.release.bsl | 123 ++++++++++++
.../EmittedIL/ForLoop/ForLoopWithStep3.fsx | 3 +
.../ForLoopWithStep3.fsx.il.net472.debug.bsl | 113 +++++++++++
...ForLoopWithStep3.fsx.il.net472.release.bsl | 123 ++++++++++++
.../ForLoopWithStep3.fsx.il.netcore.debug.bsl | 113 +++++++++++
...orLoopWithStep3.fsx.il.netcore.release.bsl | 123 ++++++++++++
16 files changed, 1547 insertions(+), 161 deletions(-)
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.net472.debug.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.net472.release.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.netcore.debug.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.netcore.release.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.debug.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.release.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.debug.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.release.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.debug.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.release.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.debug.bsl
create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.release.bsl
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoop.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoop.fs
index ac54111a66c..03b9e1596db 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoop.fs
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoop.fs
@@ -69,6 +69,24 @@ module ForLoop =
let ``NoIEnumerable03_fsx`` compilation =
compilation
|> verifyCompilation
+
+ // SOURCE=ForLoopWithStep1.fsx SCFLAGS="-a -g --optimize+" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd ForLoopWithStep1.dll" # ForLoopWithStep1.fsx
+ []
+ let ``ForLoopWithStep1_fsx`` compilation =
+ compilation
+ |> verifyCompilation
+
+ // SOURCE=ForLoopWithStep2.fsx SCFLAGS="-a -g --optimize+" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd ForLoopWithStep2.dll" # ForLoopWithStep2.fsx
+ []
+ let ``ForLoopWithStep2_fsx`` compilation =
+ compilation
+ |> verifyCompilation
+
+ // SOURCE=ForLoopWithStep3.fsx SCFLAGS="-a -g --optimize+" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd ForLoopWithStep3.dll" # ForLoopWithStep3.fsx
+ []
+ let ``ForLoopWithStep3_fsx`` compilation =
+ compilation
+ |> verifyCompilation
// SOURCE=NonTrivialBranchingBindingInEnd01.fs SCFLAGS="--optimize+" # NonTrivialBranchingBindingInEnd01.fs --optimize+
[]
@@ -129,164 +147,3 @@ module ForLoop =
let ``NonTrivialBranchingBindingInEnd05_fs_nonopt`` compilation =
compilation
|> verifyCompilation
-
- []
- let ``Strided integer for loops should not allocate a RangeInt32 enumerator``() =
- FSharp """
-module ForLoops
-
-let loop1 () =
- let s = System.Random().Next(2, 2) // avoid constant step optimization
- for i in 0..s..10 do
- System.Console.WriteLine i
- """
- |> compile
- |> shouldSucceed
- |> verifyIL ["""
- .method public static void loop1() cil managed
- {
-
- .maxstack 5
- .locals init (int32 V_0,
- int32 V_1,
- int32 V_2,
- int32 V_3)
- IL_0000: newobj instance void [mscorlib]System.Random::.ctor()
- IL_0005: ldc.i4.2
- IL_0006: ldc.i4.2
- IL_0007: callvirt instance int32 [mscorlib]System.Random::Next(int32,
- int32)
- IL_000c: stloc.0
- IL_000d: ldc.i4.0
- IL_000e: stloc.3
- IL_000f: ldloc.0
- IL_0010: stloc.2
- IL_0011: ldloc.2
- IL_0012: brtrue.s IL_0024
-
- IL_0014: ldstr "The step of a range cannot be zero."
- IL_0019: ldstr "step"
- IL_001e: newobj instance void [mscorlib]System.ArgumentException::.ctor(string,
- string)
- IL_0023: throw
-
- IL_0024: ldc.i4.s 10
- IL_0026: stloc.1
- IL_0027: ldloc.1
- IL_0028: ldloc.3
- IL_0029: blt.s IL_002f
-
- IL_002b: ldloc.2
- IL_002c: ldc.i4.0
- IL_002d: bgt.s IL_0037
-
- IL_002f: ldloc.1
- IL_0030: ldloc.3
- IL_0031: bgt.s IL_0051
-
- IL_0033: ldloc.2
- IL_0034: ldc.i4.0
- IL_0035: bge.s IL_0051
-
- IL_0037: ldloc.3
- IL_0038: call void [mscorlib]System.Console::WriteLine(int32)
- IL_003d: ldloc.3
- IL_003e: ldloc.2
- IL_003f: add
- IL_0040: stloc.3
- IL_0041: ldloc.3
- IL_0042: ldloc.1
- IL_0043: ble.s IL_0049
-
- IL_0045: ldloc.2
- IL_0046: ldc.i4.0
- IL_0047: bgt.s IL_0051
-
- IL_0049: ldloc.3
- IL_004a: ldloc.1
- IL_004b: bge.s IL_0037
-
- IL_004d: ldloc.2
- IL_004e: ldc.i4.0
- IL_004f: bge.s IL_0037
-
- IL_0051: ret
- }""" ]
-
- []
- let ``Strided integer for loops with constant step should be optimized``() =
- FSharp """
-module ForLoops
-
-let loop2 () =
- for i in 0..2..10 do
- System.Console.WriteLine i
- """
- |> compile
- |> shouldSucceed
- |> verifyIL ["""
- .method public static void loop2() cil managed
- {
-
- .maxstack 4
- .locals init (int32 V_0,
- int32 V_1)
- IL_0000: ldc.i4.0
- IL_0001: stloc.1
- IL_0002: ldc.i4.s 10
- IL_0004: stloc.0
- IL_0005: ldloc.0
- IL_0006: ldloc.1
- IL_0007: blt.s IL_0017
-
- IL_0009: ldloc.1
- IL_000a: call void [mscorlib]System.Console::WriteLine(int32)
- IL_000f: ldloc.1
- IL_0010: ldc.i4.2
- IL_0011: add
- IL_0012: stloc.1
- IL_0013: ldloc.1
- IL_0014: ldloc.0
- IL_0015: ble.s IL_0009
-
- IL_0017: ret
- }""" ]
-
- []
- let ``Strided integer for loops with constant negative step should be optimized``() =
- FSharp """
-module ForLoops
-
-let loop2 () =
- for i in 10 .. -2 .. 1 do
- System.Console.WriteLine i
- """
- |> compile
- |> shouldSucceed
- |> verifyIL ["""
- .method public static void loop2() cil managed
- {
-
- .maxstack 4
- .locals init (int32 V_0,
- int32 V_1)
- IL_0000: ldc.i4.s 10
- IL_0002: stloc.1
- IL_0003: ldc.i4.1
- IL_0004: stloc.0
- IL_0005: ldloc.0
- IL_0006: ldloc.1
- IL_0007: bgt.s IL_0017
-
- IL_0009: ldloc.1
- IL_000a: call void [mscorlib]System.Console::WriteLine(int32)
- IL_000f: ldloc.1
- IL_0010: ldc.i4.2
- IL_0011: sub
- IL_0012: stloc.1
- IL_0013: ldloc.1
- IL_0014: ldloc.0
- IL_0015: bge.s IL_0009
-
- IL_0017: ret
- }""" ]
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx
new file mode 100644
index 00000000000..9a4d317cbd4
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx
@@ -0,0 +1,3 @@
+let loop n step m =
+ for i in n..step..m do
+ printfn $"{i}"
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.net472.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.net472.debug.bsl
new file mode 100644
index 00000000000..f1245289b99
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.net472.debug.bsl
@@ -0,0 +1,139 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly ForLoopWithStep1
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep1
+{
+ // Offset: 0x00000000 Length: 0x00000256
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep1 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep1
+{
+ // Offset: 0x00000260 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep1 created
+}
+.module ForLoopWithStep1.exe
+// MVID: {62E36119-6AFE-A894-A745-03831961E362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000001D0F2FE0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep1
+ extends [mscorlib]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(int32 n,
+ int32 step,
+ int32 m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 03 00 00 00 01 00 00 00 01 00 00 00 01 00
+ 00 00 00 00 )
+ // Code size 84 (0x54)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1,
+ int32 V_2)
+ IL_0000: ldarg.0
+ IL_0001: stloc.2
+ IL_0002: ldarg.1
+ IL_0003: stloc.1
+ IL_0004: ldloc.1
+ IL_0005: brtrue.s IL_0017
+
+ IL_0007: ldstr "The step of a range cannot be zero."
+ IL_000c: ldstr "step"
+ IL_0011: newobj instance void [mscorlib]System.ArgumentException::.ctor(string,
+ string)
+ IL_0016: throw
+
+ IL_0017: ldarg.2
+ IL_0018: stloc.0
+ IL_0019: br.s IL_0043
+
+ IL_001b: ldstr "%P()"
+ IL_0020: ldc.i4.1
+ IL_0021: newarr [mscorlib]System.Object
+ IL_0026: dup
+ IL_0027: ldc.i4.0
+ IL_0028: ldloc.2
+ IL_0029: box [mscorlib]System.Int32
+ IL_002e: stelem [mscorlib]System.Object
+ IL_0033: ldnull
+ IL_0034: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [mscorlib]System.Type[])
+ IL_0039: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_003e: pop
+ IL_003f: ldloc.2
+ IL_0040: ldloc.1
+ IL_0041: add
+ IL_0042: stloc.2
+ IL_0043: ldloc.2
+ IL_0044: ldloc.0
+ IL_0045: ble.s IL_004b
+
+ IL_0047: ldloc.1
+ IL_0048: ldc.i4.0
+ IL_0049: bgt.s IL_0053
+
+ IL_004b: ldloc.2
+ IL_004c: ldloc.0
+ IL_004d: bge.s IL_001b
+
+ IL_004f: ldloc.1
+ IL_0050: ldc.i4.0
+ IL_0051: bge.s IL_001b
+
+ IL_0053: ret
+ } // end of method ForLoopWithStep1::loop
+
+} // end of class ForLoopWithStep1
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep1$fsx
+ extends [mscorlib]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep1$fsx::main@
+
+} // end of class ''.$ForLoopWithStep1$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Debug\net472\tests\EmittedIL\ForLoop\ForLoopWithStep1_fsx\ForLoopWithStep1.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.net472.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.net472.release.bsl
new file mode 100644
index 00000000000..85a66424b26
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.net472.release.bsl
@@ -0,0 +1,149 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern netstandard
+{
+ .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q
+ .ver 2:0:0:0
+}
+.assembly ForLoopWithStep1
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep1
+{
+ // Offset: 0x00000000 Length: 0x0000025A
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep1 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep1
+{
+ // Offset: 0x00000260 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep1 created
+}
+.module ForLoopWithStep1.exe
+// MVID: {62E35ED9-6AFE-A894-A745-0383D95EE362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000001F9D8160000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep1
+ extends [mscorlib]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(int32 n,
+ int32 step,
+ int32 m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 03 00 00 00 01 00 00 00 01 00 00 00 01 00
+ 00 00 00 00 )
+ // Code size 91 (0x5b)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1,
+ int32 V_2,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_3)
+ IL_0000: ldarg.0
+ IL_0001: stloc.2
+ IL_0002: ldarg.1
+ IL_0003: stloc.1
+ IL_0004: ldloc.1
+ IL_0005: brtrue.s IL_0017
+
+ IL_0007: ldstr "The step of a range cannot be zero."
+ IL_000c: ldstr "step"
+ IL_0011: newobj instance void [mscorlib]System.ArgumentException::.ctor(string,
+ string)
+ IL_0016: throw
+
+ IL_0017: ldarg.2
+ IL_0018: stloc.0
+ IL_0019: br.s IL_004a
+
+ IL_001b: ldstr "%P()"
+ IL_0020: ldc.i4.1
+ IL_0021: newarr [mscorlib]System.Object
+ IL_0026: dup
+ IL_0027: ldc.i4.0
+ IL_0028: ldloc.2
+ IL_0029: box [mscorlib]System.Int32
+ IL_002e: stelem [mscorlib]System.Object
+ IL_0033: ldnull
+ IL_0034: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [mscorlib]System.Type[])
+ IL_0039: stloc.3
+ IL_003a: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out()
+ IL_003f: ldloc.3
+ IL_0040: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [mscorlib]System.IO.TextWriter,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_0045: pop
+ IL_0046: ldloc.2
+ IL_0047: ldloc.1
+ IL_0048: add
+ IL_0049: stloc.2
+ IL_004a: ldloc.2
+ IL_004b: ldloc.0
+ IL_004c: ble.s IL_0052
+
+ IL_004e: ldloc.1
+ IL_004f: ldc.i4.0
+ IL_0050: bgt.s IL_005a
+
+ IL_0052: ldloc.2
+ IL_0053: ldloc.0
+ IL_0054: bge.s IL_001b
+
+ IL_0056: ldloc.1
+ IL_0057: ldc.i4.0
+ IL_0058: bge.s IL_001b
+
+ IL_005a: ret
+ } // end of method ForLoopWithStep1::loop
+
+} // end of class ForLoopWithStep1
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep1$fsx
+ extends [mscorlib]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep1$fsx::main@
+
+} // end of class ''.$ForLoopWithStep1$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Release\net472\tests\EmittedIL\ForLoop\ForLoopWithStep1_fsx\ForLoopWithStep1.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.netcore.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.netcore.debug.bsl
new file mode 100644
index 00000000000..134e9cea8c6
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.netcore.debug.bsl
@@ -0,0 +1,139 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern System.Runtime
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly ForLoopWithStep1
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep1
+{
+ // Offset: 0x00000000 Length: 0x00000256
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep1 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep1
+{
+ // Offset: 0x00000260 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep1 created
+}
+.module ForLoopWithStep1.exe
+// MVID: {62E35B4D-9D48-2410-A745-03834D5BE362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x00000227076D0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep1
+ extends [System.Runtime]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(int32 n,
+ int32 step,
+ int32 m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 03 00 00 00 01 00 00 00 01 00 00 00 01 00
+ 00 00 00 00 )
+ // Code size 84 (0x54)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1,
+ int32 V_2)
+ IL_0000: ldarg.0
+ IL_0001: stloc.2
+ IL_0002: ldarg.1
+ IL_0003: stloc.1
+ IL_0004: ldloc.1
+ IL_0005: brtrue.s IL_0017
+
+ IL_0007: ldstr "The step of a range cannot be zero."
+ IL_000c: ldstr "step"
+ IL_0011: newobj instance void [System.Runtime]System.ArgumentException::.ctor(string,
+ string)
+ IL_0016: throw
+
+ IL_0017: ldarg.2
+ IL_0018: stloc.0
+ IL_0019: br.s IL_0043
+
+ IL_001b: ldstr "%P()"
+ IL_0020: ldc.i4.1
+ IL_0021: newarr [System.Runtime]System.Object
+ IL_0026: dup
+ IL_0027: ldc.i4.0
+ IL_0028: ldloc.2
+ IL_0029: box [System.Runtime]System.Int32
+ IL_002e: stelem [System.Runtime]System.Object
+ IL_0033: ldnull
+ IL_0034: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [System.Runtime]System.Type[])
+ IL_0039: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_003e: pop
+ IL_003f: ldloc.2
+ IL_0040: ldloc.1
+ IL_0041: add
+ IL_0042: stloc.2
+ IL_0043: ldloc.2
+ IL_0044: ldloc.0
+ IL_0045: ble.s IL_004b
+
+ IL_0047: ldloc.1
+ IL_0048: ldc.i4.0
+ IL_0049: bgt.s IL_0053
+
+ IL_004b: ldloc.2
+ IL_004c: ldloc.0
+ IL_004d: bge.s IL_001b
+
+ IL_004f: ldloc.1
+ IL_0050: ldc.i4.0
+ IL_0051: bge.s IL_001b
+
+ IL_0053: ret
+ } // end of method ForLoopWithStep1::loop
+
+} // end of class ForLoopWithStep1
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep1$fsx
+ extends [System.Runtime]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep1$fsx::main@
+
+} // end of class ''.$ForLoopWithStep1$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Debug\net6.0\tests\EmittedIL\ForLoop\ForLoopWithStep1_fsx\ForLoopWithStep1.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.netcore.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.netcore.release.bsl
new file mode 100644
index 00000000000..64420a510e6
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep1.fsx.il.netcore.release.bsl
@@ -0,0 +1,149 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern System.Runtime
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern netstandard
+{
+ .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q
+ .ver 2:1:0:0
+}
+.assembly ForLoopWithStep1
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep1
+{
+ // Offset: 0x00000000 Length: 0x0000025A
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep1 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep1
+{
+ // Offset: 0x00000260 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep1 created
+}
+.module ForLoopWithStep1.exe
+// MVID: {62E352C7-7C41-2A5C-A745-0383C752E362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000001BCADDE0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep1
+ extends [System.Runtime]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(int32 n,
+ int32 step,
+ int32 m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 03 00 00 00 01 00 00 00 01 00 00 00 01 00
+ 00 00 00 00 )
+ // Code size 91 (0x5b)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1,
+ int32 V_2,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_3)
+ IL_0000: ldarg.0
+ IL_0001: stloc.2
+ IL_0002: ldarg.1
+ IL_0003: stloc.1
+ IL_0004: ldloc.1
+ IL_0005: brtrue.s IL_0017
+
+ IL_0007: ldstr "The step of a range cannot be zero."
+ IL_000c: ldstr "step"
+ IL_0011: newobj instance void [System.Runtime]System.ArgumentException::.ctor(string,
+ string)
+ IL_0016: throw
+
+ IL_0017: ldarg.2
+ IL_0018: stloc.0
+ IL_0019: br.s IL_004a
+
+ IL_001b: ldstr "%P()"
+ IL_0020: ldc.i4.1
+ IL_0021: newarr [System.Runtime]System.Object
+ IL_0026: dup
+ IL_0027: ldc.i4.0
+ IL_0028: ldloc.2
+ IL_0029: box [System.Runtime]System.Int32
+ IL_002e: stelem [System.Runtime]System.Object
+ IL_0033: ldnull
+ IL_0034: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [System.Runtime]System.Type[])
+ IL_0039: stloc.3
+ IL_003a: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out()
+ IL_003f: ldloc.3
+ IL_0040: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [System.Runtime]System.IO.TextWriter,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_0045: pop
+ IL_0046: ldloc.2
+ IL_0047: ldloc.1
+ IL_0048: add
+ IL_0049: stloc.2
+ IL_004a: ldloc.2
+ IL_004b: ldloc.0
+ IL_004c: ble.s IL_0052
+
+ IL_004e: ldloc.1
+ IL_004f: ldc.i4.0
+ IL_0050: bgt.s IL_005a
+
+ IL_0052: ldloc.2
+ IL_0053: ldloc.0
+ IL_0054: bge.s IL_001b
+
+ IL_0056: ldloc.1
+ IL_0057: ldc.i4.0
+ IL_0058: bge.s IL_001b
+
+ IL_005a: ret
+ } // end of method ForLoopWithStep1::loop
+
+} // end of class ForLoopWithStep1
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep1$fsx
+ extends [System.Runtime]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep1$fsx::main@
+
+} // end of class ''.$ForLoopWithStep1$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Release\net6.0\tests\EmittedIL\ForLoop\ForLoopWithStep1_fsx\ForLoopWithStep1.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx
new file mode 100644
index 00000000000..86c2d919a63
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx
@@ -0,0 +1,3 @@
+let loop n m =
+ for i in n..2..m do
+ printfn $"{i}"
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.debug.bsl
new file mode 100644
index 00000000000..dc959e2e433
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.debug.bsl
@@ -0,0 +1,113 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly ForLoopWithStep2
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep2
+{
+ // Offset: 0x00000000 Length: 0x00000245
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep2 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep2
+{
+ // Offset: 0x00000250 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep2 created
+}
+.module ForLoopWithStep2.exe
+// MVID: {62E36119-8E23-B794-A745-03831961E362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x00000187F2490000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep2
+ extends [mscorlib]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(int32 n,
+ int32 m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
+ // Code size 51 (0x33)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1)
+ IL_0000: ldarg.0
+ IL_0001: stloc.1
+ IL_0002: ldarg.1
+ IL_0003: stloc.0
+ IL_0004: br.s IL_002e
+
+ IL_0006: ldstr "%P()"
+ IL_000b: ldc.i4.1
+ IL_000c: newarr [mscorlib]System.Object
+ IL_0011: dup
+ IL_0012: ldc.i4.0
+ IL_0013: ldloc.1
+ IL_0014: box [mscorlib]System.Int32
+ IL_0019: stelem [mscorlib]System.Object
+ IL_001e: ldnull
+ IL_001f: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [mscorlib]System.Type[])
+ IL_0024: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_0029: pop
+ IL_002a: ldloc.1
+ IL_002b: ldc.i4.2
+ IL_002c: add
+ IL_002d: stloc.1
+ IL_002e: ldloc.1
+ IL_002f: ldloc.0
+ IL_0030: ble.s IL_0006
+
+ IL_0032: ret
+ } // end of method ForLoopWithStep2::loop
+
+} // end of class ForLoopWithStep2
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep2$fsx
+ extends [mscorlib]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep2$fsx::main@
+
+} // end of class ''.$ForLoopWithStep2$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Debug\net472\tests\EmittedIL\ForLoop\ForLoopWithStep2_fsx\ForLoopWithStep2.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.release.bsl
new file mode 100644
index 00000000000..a41f694687f
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.release.bsl
@@ -0,0 +1,123 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern netstandard
+{
+ .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q
+ .ver 2:0:0:0
+}
+.assembly ForLoopWithStep2
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep2
+{
+ // Offset: 0x00000000 Length: 0x00000249
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep2 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep2
+{
+ // Offset: 0x00000250 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep2 created
+}
+.module ForLoopWithStep2.exe
+// MVID: {62E35ED9-8E23-B794-A745-0383D95EE362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x00000271B3BF0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep2
+ extends [mscorlib]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(int32 n,
+ int32 m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
+ // Code size 58 (0x3a)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_2)
+ IL_0000: ldarg.0
+ IL_0001: stloc.1
+ IL_0002: ldarg.1
+ IL_0003: stloc.0
+ IL_0004: br.s IL_0035
+
+ IL_0006: ldstr "%P()"
+ IL_000b: ldc.i4.1
+ IL_000c: newarr [mscorlib]System.Object
+ IL_0011: dup
+ IL_0012: ldc.i4.0
+ IL_0013: ldloc.1
+ IL_0014: box [mscorlib]System.Int32
+ IL_0019: stelem [mscorlib]System.Object
+ IL_001e: ldnull
+ IL_001f: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [mscorlib]System.Type[])
+ IL_0024: stloc.2
+ IL_0025: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out()
+ IL_002a: ldloc.2
+ IL_002b: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [mscorlib]System.IO.TextWriter,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_0030: pop
+ IL_0031: ldloc.1
+ IL_0032: ldc.i4.2
+ IL_0033: add
+ IL_0034: stloc.1
+ IL_0035: ldloc.1
+ IL_0036: ldloc.0
+ IL_0037: ble.s IL_0006
+
+ IL_0039: ret
+ } // end of method ForLoopWithStep2::loop
+
+} // end of class ForLoopWithStep2
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep2$fsx
+ extends [mscorlib]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep2$fsx::main@
+
+} // end of class ''.$ForLoopWithStep2$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Release\net472\tests\EmittedIL\ForLoop\ForLoopWithStep2_fsx\ForLoopWithStep2.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.debug.bsl
new file mode 100644
index 00000000000..75aa1cfc8b4
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.debug.bsl
@@ -0,0 +1,113 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern System.Runtime
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly ForLoopWithStep2
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep2
+{
+ // Offset: 0x00000000 Length: 0x00000245
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep2 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep2
+{
+ // Offset: 0x00000250 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep2 created
+}
+.module ForLoopWithStep2.exe
+// MVID: {62E35B4D-0BEB-9A4A-A745-03834D5BE362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000002629F980000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep2
+ extends [System.Runtime]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(int32 n,
+ int32 m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
+ // Code size 51 (0x33)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1)
+ IL_0000: ldarg.0
+ IL_0001: stloc.1
+ IL_0002: ldarg.1
+ IL_0003: stloc.0
+ IL_0004: br.s IL_002e
+
+ IL_0006: ldstr "%P()"
+ IL_000b: ldc.i4.1
+ IL_000c: newarr [System.Runtime]System.Object
+ IL_0011: dup
+ IL_0012: ldc.i4.0
+ IL_0013: ldloc.1
+ IL_0014: box [System.Runtime]System.Int32
+ IL_0019: stelem [System.Runtime]System.Object
+ IL_001e: ldnull
+ IL_001f: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [System.Runtime]System.Type[])
+ IL_0024: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_0029: pop
+ IL_002a: ldloc.1
+ IL_002b: ldc.i4.2
+ IL_002c: add
+ IL_002d: stloc.1
+ IL_002e: ldloc.1
+ IL_002f: ldloc.0
+ IL_0030: ble.s IL_0006
+
+ IL_0032: ret
+ } // end of method ForLoopWithStep2::loop
+
+} // end of class ForLoopWithStep2
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep2$fsx
+ extends [System.Runtime]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep2$fsx::main@
+
+} // end of class ''.$ForLoopWithStep2$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Debug\net6.0\tests\EmittedIL\ForLoop\ForLoopWithStep2_fsx\ForLoopWithStep2.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.release.bsl
new file mode 100644
index 00000000000..d037f9b4563
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.release.bsl
@@ -0,0 +1,123 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern System.Runtime
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern netstandard
+{
+ .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q
+ .ver 2:1:0:0
+}
+.assembly ForLoopWithStep2
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep2
+{
+ // Offset: 0x00000000 Length: 0x00000249
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep2 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep2
+{
+ // Offset: 0x00000250 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep2 created
+}
+.module ForLoopWithStep2.exe
+// MVID: {62E352C7-65F8-C026-A745-0383C752E362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000002B014A70000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep2
+ extends [System.Runtime]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(int32 n,
+ int32 m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
+ // Code size 58 (0x3a)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_2)
+ IL_0000: ldarg.0
+ IL_0001: stloc.1
+ IL_0002: ldarg.1
+ IL_0003: stloc.0
+ IL_0004: br.s IL_0035
+
+ IL_0006: ldstr "%P()"
+ IL_000b: ldc.i4.1
+ IL_000c: newarr [System.Runtime]System.Object
+ IL_0011: dup
+ IL_0012: ldc.i4.0
+ IL_0013: ldloc.1
+ IL_0014: box [System.Runtime]System.Int32
+ IL_0019: stelem [System.Runtime]System.Object
+ IL_001e: ldnull
+ IL_001f: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [System.Runtime]System.Type[])
+ IL_0024: stloc.2
+ IL_0025: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out()
+ IL_002a: ldloc.2
+ IL_002b: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [System.Runtime]System.IO.TextWriter,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_0030: pop
+ IL_0031: ldloc.1
+ IL_0032: ldc.i4.2
+ IL_0033: add
+ IL_0034: stloc.1
+ IL_0035: ldloc.1
+ IL_0036: ldloc.0
+ IL_0037: ble.s IL_0006
+
+ IL_0039: ret
+ } // end of method ForLoopWithStep2::loop
+
+} // end of class ForLoopWithStep2
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep2$fsx
+ extends [System.Runtime]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep2$fsx::main@
+
+} // end of class ''.$ForLoopWithStep2$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Release\net6.0\tests\EmittedIL\ForLoop\ForLoopWithStep2_fsx\ForLoopWithStep2.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx
new file mode 100644
index 00000000000..f33ce6d3bc6
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx
@@ -0,0 +1,3 @@
+let loop n m =
+ for i in 10..-3..-2 do
+ printfn $"{i}"
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.debug.bsl
new file mode 100644
index 00000000000..b9cb8f4713f
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.debug.bsl
@@ -0,0 +1,113 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly ForLoopWithStep3
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep3
+{
+ // Offset: 0x00000000 Length: 0x00000264
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep3 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep3
+{
+ // Offset: 0x00000268 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep3 created
+}
+.module ForLoopWithStep3.exe
+// MVID: {62E36119-5EC8-08E2-A745-03831961E362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000002872C9E0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep3
+ extends [mscorlib]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(!!a n,
+ !!b m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
+ // Code size 53 (0x35)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1)
+ IL_0000: ldc.i4.s 10
+ IL_0002: stloc.1
+ IL_0003: ldc.i4.s -2
+ IL_0005: stloc.0
+ IL_0006: br.s IL_0030
+
+ IL_0008: ldstr "%P()"
+ IL_000d: ldc.i4.1
+ IL_000e: newarr [mscorlib]System.Object
+ IL_0013: dup
+ IL_0014: ldc.i4.0
+ IL_0015: ldloc.1
+ IL_0016: box [mscorlib]System.Int32
+ IL_001b: stelem [mscorlib]System.Object
+ IL_0020: ldnull
+ IL_0021: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [mscorlib]System.Type[])
+ IL_0026: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_002b: pop
+ IL_002c: ldloc.1
+ IL_002d: ldc.i4.3
+ IL_002e: sub
+ IL_002f: stloc.1
+ IL_0030: ldloc.1
+ IL_0031: ldloc.0
+ IL_0032: bge.s IL_0008
+
+ IL_0034: ret
+ } // end of method ForLoopWithStep3::loop
+
+} // end of class ForLoopWithStep3
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep3$fsx
+ extends [mscorlib]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep3$fsx::main@
+
+} // end of class ''.$ForLoopWithStep3$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Debug\net472\tests\EmittedIL\ForLoop\ForLoopWithStep3_fsx\ForLoopWithStep3.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.release.bsl
new file mode 100644
index 00000000000..50e4838adfa
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.release.bsl
@@ -0,0 +1,123 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern netstandard
+{
+ .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q
+ .ver 2:0:0:0
+}
+.assembly ForLoopWithStep3
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep3
+{
+ // Offset: 0x00000000 Length: 0x00000268
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep3 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep3
+{
+ // Offset: 0x00000270 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep3 created
+}
+.module ForLoopWithStep3.exe
+// MVID: {62E35ED9-5EC8-08E2-A745-0383D95EE362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000001DEBDF10000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep3
+ extends [mscorlib]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(!!a n,
+ !!b m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
+ // Code size 60 (0x3c)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_2)
+ IL_0000: ldc.i4.s 10
+ IL_0002: stloc.1
+ IL_0003: ldc.i4.s -2
+ IL_0005: stloc.0
+ IL_0006: br.s IL_0037
+
+ IL_0008: ldstr "%P()"
+ IL_000d: ldc.i4.1
+ IL_000e: newarr [mscorlib]System.Object
+ IL_0013: dup
+ IL_0014: ldc.i4.0
+ IL_0015: ldloc.1
+ IL_0016: box [mscorlib]System.Int32
+ IL_001b: stelem [mscorlib]System.Object
+ IL_0020: ldnull
+ IL_0021: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [mscorlib]System.Type[])
+ IL_0026: stloc.2
+ IL_0027: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out()
+ IL_002c: ldloc.2
+ IL_002d: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [mscorlib]System.IO.TextWriter,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_0032: pop
+ IL_0033: ldloc.1
+ IL_0034: ldc.i4.3
+ IL_0035: sub
+ IL_0036: stloc.1
+ IL_0037: ldloc.1
+ IL_0038: ldloc.0
+ IL_0039: bge.s IL_0008
+
+ IL_003b: ret
+ } // end of method ForLoopWithStep3::loop
+
+} // end of class ForLoopWithStep3
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep3$fsx
+ extends [mscorlib]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep3$fsx::main@
+
+} // end of class ''.$ForLoopWithStep3$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Release\net472\tests\EmittedIL\ForLoop\ForLoopWithStep3_fsx\ForLoopWithStep3.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.debug.bsl
new file mode 100644
index 00000000000..418ece31504
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.debug.bsl
@@ -0,0 +1,113 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern System.Runtime
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly ForLoopWithStep3
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep3
+{
+ // Offset: 0x00000000 Length: 0x00000264
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep3 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep3
+{
+ // Offset: 0x00000268 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep3 created
+}
+.module ForLoopWithStep3.exe
+// MVID: {62E35B4D-8E9F-8EFA-A745-03834D5BE362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000002B1E0100000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep3
+ extends [System.Runtime]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(!!a n,
+ !!b m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
+ // Code size 53 (0x35)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1)
+ IL_0000: ldc.i4.s 10
+ IL_0002: stloc.1
+ IL_0003: ldc.i4.s -2
+ IL_0005: stloc.0
+ IL_0006: br.s IL_0030
+
+ IL_0008: ldstr "%P()"
+ IL_000d: ldc.i4.1
+ IL_000e: newarr [System.Runtime]System.Object
+ IL_0013: dup
+ IL_0014: ldc.i4.0
+ IL_0015: ldloc.1
+ IL_0016: box [System.Runtime]System.Int32
+ IL_001b: stelem [System.Runtime]System.Object
+ IL_0020: ldnull
+ IL_0021: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [System.Runtime]System.Type[])
+ IL_0026: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_002b: pop
+ IL_002c: ldloc.1
+ IL_002d: ldc.i4.3
+ IL_002e: sub
+ IL_002f: stloc.1
+ IL_0030: ldloc.1
+ IL_0031: ldloc.0
+ IL_0032: bge.s IL_0008
+
+ IL_0034: ret
+ } // end of method ForLoopWithStep3::loop
+
+} // end of class ForLoopWithStep3
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep3$fsx
+ extends [System.Runtime]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep3$fsx::main@
+
+} // end of class ''.$ForLoopWithStep3$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Debug\net6.0\tests\EmittedIL\ForLoop\ForLoopWithStep3_fsx\ForLoopWithStep3.res
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.release.bsl
new file mode 100644
index 00000000000..d959bd83ffc
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.release.bsl
@@ -0,0 +1,123 @@
+
+// Microsoft (R) .NET IL Disassembler. Version 5.0.0-preview.7.20364.11
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern System.Runtime
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern FSharp.Core
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
+ .ver 6:0:0:0
+}
+.assembly extern netstandard
+{
+ .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q
+ .ver 2:1:0:0
+}
+.assembly ForLoopWithStep3
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
+ int32,
+ int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 00 00 00 00 00 )
+
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.mresource public FSharpSignatureData.ForLoopWithStep3
+{
+ // Offset: 0x00000000 Length: 0x00000268
+ // WARNING: managed resource file FSharpSignatureData.ForLoopWithStep3 created
+}
+.mresource public FSharpOptimizationData.ForLoopWithStep3
+{
+ // Offset: 0x00000270 Length: 0x0000007B
+ // WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep3 created
+}
+.module ForLoopWithStep3.exe
+// MVID: {62E352C7-B005-C4DD-A745-0383C752E362}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x000001C4DA720000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public abstract auto ansi sealed ForLoopWithStep3
+ extends [System.Runtime]System.Object
+{
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
+ .method public static void loop(!!a n,
+ !!b m) cil managed
+ {
+ .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
+ // Code size 60 (0x3c)
+ .maxstack 7
+ .locals init (int32 V_0,
+ int32 V_1,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4 V_2)
+ IL_0000: ldc.i4.s 10
+ IL_0002: stloc.1
+ IL_0003: ldc.i4.s -2
+ IL_0005: stloc.0
+ IL_0006: br.s IL_0037
+
+ IL_0008: ldstr "%P()"
+ IL_000d: ldc.i4.1
+ IL_000e: newarr [System.Runtime]System.Object
+ IL_0013: dup
+ IL_0014: ldc.i4.0
+ IL_0015: ldloc.1
+ IL_0016: box [System.Runtime]System.Int32
+ IL_001b: stelem [System.Runtime]System.Object
+ IL_0020: ldnull
+ IL_0021: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string,
+ object[],
+ class [System.Runtime]System.Type[])
+ IL_0026: stloc.2
+ IL_0027: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out()
+ IL_002c: ldloc.2
+ IL_002d: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter(class [System.Runtime]System.IO.TextWriter,
+ class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4)
+ IL_0032: pop
+ IL_0033: ldloc.1
+ IL_0034: ldc.i4.3
+ IL_0035: sub
+ IL_0036: stloc.1
+ IL_0037: ldloc.1
+ IL_0038: ldloc.0
+ IL_0039: bge.s IL_0008
+
+ IL_003b: ret
+ } // end of method ForLoopWithStep3::loop
+
+} // end of class ForLoopWithStep3
+
+.class private abstract auto ansi sealed ''.$ForLoopWithStep3$fsx
+ extends [System.Runtime]System.Object
+{
+ .method public static void main@() cil managed
+ {
+ .entrypoint
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method $ForLoopWithStep3$fsx::main@
+
+} // end of class ''.$ForLoopWithStep3$fsx
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file C:\Users\albert\fsharp\artifacts\bin\FSharp.Compiler.ComponentTests\Release\net6.0\tests\EmittedIL\ForLoop\ForLoopWithStep3_fsx\ForLoopWithStep3.res
From 65e6553f88af6ed9835eb38619ff6cfbed535d7d Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Sat, 20 Aug 2022 22:05:58 -0700
Subject: [PATCH 08/15] test near integer max
---
.../Miscellaneous/ConstStepForLoops.fs | 177 +++++++++---------
.../Miscellaneous/NearMaxForLoops.fs | 32 ++++
.../Miscellaneous/OptimizedForLoops.fs | 6 +
.../Miscellaneous/VariableStepForLoops.fs | 4 +-
4 files changed, 128 insertions(+), 91 deletions(-)
create mode 100644 tests/FSharp.Compiler.ComponentTests/Miscellaneous/NearMaxForLoops.fs
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ConstStepForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ConstStepForLoops.fs
index c04630841ec..6ec18828fce 100644
--- a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ConstStepForLoops.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ConstStepForLoops.fs
@@ -1,498 +1,497 @@
-
-let ``test -20`` n m =
+let ``test -20`` n m =
let expected = seq { n .. -20 .. m }
let actual = ResizeArray()
for i in n .. -20 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -20`` n m |> not then
- failwith $"FAILURE: {n} .. -20 .. {m}"
+ failwith $"FAILURE: {n} .. -20 .. {m}"
let ``test -19`` n m =
let expected = seq { n .. -19 .. m }
let actual = ResizeArray()
for i in n .. -19 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
-
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
+
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -19`` n m |> not then
- failwith $"FAILURE: {n} .. -19 .. {m}"
+ failwith $"FAILURE: {n} .. -19 .. {m}"
let ``test -18`` n m =
let expected = seq { n .. -18 .. m }
let actual = ResizeArray()
for i in n .. -18 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -18`` n m |> not then
- failwith $"FAILURE: {n} .. -18 .. {m}"
+ failwith $"FAILURE: {n} .. -18 .. {m}"
let ``test -17`` n m =
let expected = seq { n .. -17 .. m }
let actual = ResizeArray()
for i in n .. -17 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -17`` n m |> not then
- failwith $"FAILURE: {n} .. -17 .. {m}"
+ failwith $"FAILURE: {n} .. -17 .. {m}"
let ``test -16`` n m =
let expected = seq { n .. -16 .. m }
let actual = ResizeArray()
for i in n .. -16 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -16`` n m |> not then
- failwith $"FAILURE: {n} .. -16 .. {m}"
+ failwith $"FAILURE: {n} .. -16 .. {m}"
let ``test -15`` n m =
let expected = seq { n .. -15 .. m }
let actual = ResizeArray()
for i in n .. -15 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -15`` n m |> not then
- failwith $"FAILURE: {n} .. -15 .. {m}"
+ failwith $"FAILURE: {n} .. -15 .. {m}"
let ``test -14`` n m =
let expected = seq { n .. -14 .. m }
let actual = ResizeArray()
for i in n .. -14 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -14`` n m |> not then
- failwith $"FAILURE: {n} .. -14 .. {m}"
+ failwith $"FAILURE: {n} .. -14 .. {m}"
let ``test -13`` n m =
let expected = seq { n .. -13 .. m }
let actual = ResizeArray()
for i in n .. -13 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -13`` n m |> not then
- failwith $"FAILURE: {n} .. -13 .. {m}"
+ failwith $"FAILURE: {n} .. -13 .. {m}"
let ``test -12`` n m =
let expected = seq { n .. -12 .. m }
let actual = ResizeArray()
for i in n .. -12 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -12`` n m |> not then
- failwith $"FAILURE: {n} .. -12 .. {m}"
+ failwith $"FAILURE: {n} .. -12 .. {m}"
let ``test -11`` n m =
let expected = seq { n .. -11 .. m }
let actual = ResizeArray()
for i in n .. -11 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -11`` n m |> not then
- failwith $"FAILURE: {n} .. -11 .. {m}"
+ failwith $"FAILURE: {n} .. -11 .. {m}"
let ``test -10`` n m =
let expected = seq { n .. -10 .. m }
let actual = ResizeArray()
for i in n .. -10 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -10`` n m |> not then
- failwith $"FAILURE: {n} .. -10 .. {m}"
+ failwith $"FAILURE: {n} .. -10 .. {m}"
let ``test -9`` n m =
let expected = seq { n .. -9 .. m }
let actual = ResizeArray()
for i in n .. -9 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -9`` n m |> not then
- failwith $"FAILURE: {n} .. -9 .. {m}"
+ failwith $"FAILURE: {n} .. -9 .. {m}"
let ``test -8`` n m =
let expected = seq { n .. -8 .. m }
let actual = ResizeArray()
for i in n .. -8 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -8`` n m |> not then
- failwith $"FAILURE: {n} .. -8 .. {m}"
+ failwith $"FAILURE: {n} .. -8 .. {m}"
let ``test -7`` n m =
let expected = seq { n .. -7 .. m }
let actual = ResizeArray()
for i in n .. -7 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -7`` n m |> not then
- failwith $"FAILURE: {n} .. -7 .. {m}"
+ failwith $"FAILURE: {n} .. -7 .. {m}"
let ``test -6`` n m =
let expected = seq { n .. -6 .. m }
let actual = ResizeArray()
for i in n .. -6 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -6`` n m |> not then
- failwith $"FAILURE: {n} .. -6 .. {m}"
+ failwith $"FAILURE: {n} .. -6 .. {m}"
let ``test -5`` n m =
let expected = seq { n .. -5 .. m }
let actual = ResizeArray()
for i in n .. -5 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -5`` n m |> not then
- failwith $"FAILURE: {n} .. -5 .. {m}"
+ failwith $"FAILURE: {n} .. -5 .. {m}"
let ``test -4`` n m =
let expected = seq { n .. -4 .. m }
let actual = ResizeArray()
for i in n .. -4 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -4`` n m |> not then
- failwith $"FAILURE: {n} .. -4 .. {m}"
+ failwith $"FAILURE: {n} .. -4 .. {m}"
let ``test -3`` n m =
let expected = seq { n .. -3 .. m }
let actual = ResizeArray()
for i in n .. -3 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -3`` n m |> not then
- failwith $"FAILURE: {n} .. -3 .. {m}"
+ failwith $"FAILURE: {n} .. -3 .. {m}"
let ``test -2`` n m =
let expected = seq { n .. -2 .. m }
let actual = ResizeArray()
for i in n .. -2 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -2`` n m |> not then
- failwith $"FAILURE: {n} .. -2 .. {m}"
+ failwith $"FAILURE: {n} .. -2 .. {m}"
let ``test -1`` n m =
let expected = seq { n .. -1 .. m }
let actual = ResizeArray()
for i in n .. -1 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test -1`` n m |> not then
- failwith $"FAILURE: {n} .. -1 .. {m}"
+ failwith $"FAILURE: {n} .. -1 .. {m}"
let ``test 1`` n m =
let expected = seq { n .. 1 .. m }
let actual = ResizeArray()
for i in n .. 1 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 1`` n m |> not then
- failwith $"FAILURE: {n} .. 1 .. {m}"
+ failwith $"FAILURE: {n} .. 1 .. {m}"
let ``test 2`` n m =
let expected = seq { n .. 2 .. m }
let actual = ResizeArray()
for i in n .. 2 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 2`` n m |> not then
- failwith $"FAILURE: {n} .. 2 .. {m}"
+ failwith $"FAILURE: {n} .. 2 .. {m}"
let ``test 3`` n m =
let expected = seq { n .. 3 .. m }
let actual = ResizeArray()
for i in n .. 3 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 3`` n m |> not then
- failwith $"FAILURE: {n} .. 3 .. {m}"
+ failwith $"FAILURE: {n} .. 3 .. {m}"
let ``test 4`` n m =
let expected = seq { n .. 4 .. m }
let actual = ResizeArray()
for i in n .. 4 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 4`` n m |> not then
- failwith $"FAILURE: {n} .. 4 .. {m}"
+ failwith $"FAILURE: {n} .. 4 .. {m}"
let ``test 5`` n m =
let expected = seq { n .. 5 .. m }
let actual = ResizeArray()
for i in n .. 5 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 5`` n m |> not then
- failwith $"FAILURE: {n} .. 5 .. {m}"
+ failwith $"FAILURE: {n} .. 5 .. {m}"
let ``test 6`` n m =
let expected = seq { n .. 6 .. m }
let actual = ResizeArray()
for i in n .. 6 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 6`` n m |> not then
- failwith $"FAILURE: {n} .. 6 .. {m}"
+ failwith $"FAILURE: {n} .. 6 .. {m}"
let ``test 7`` n m =
let expected = seq { n .. 7 .. m }
let actual = ResizeArray()
for i in n .. 7 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 7`` n m |> not then
- failwith $"FAILURE: {n} .. 7 .. {m}"
+ failwith $"FAILURE: {n} .. 7 .. {m}"
let ``test 8`` n m =
let expected = seq { n .. 8 .. m }
let actual = ResizeArray()
for i in n .. 8 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 8`` n m |> not then
- failwith $"FAILURE: {n} .. 8 .. {m}"
+ failwith $"FAILURE: {n} .. 8 .. {m}"
let ``test 9`` n m =
let expected = seq { n .. 9 .. m }
let actual = ResizeArray()
for i in n .. 9 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 9`` n m |> not then
- failwith $"FAILURE: {n} .. 9 .. {m}"
+ failwith $"FAILURE: {n} .. 9 .. {m}"
let ``test 10`` n m =
let expected = seq { n .. 10 .. m }
let actual = ResizeArray()
for i in n .. 10 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 10`` n m |> not then
- failwith $"FAILURE: {n} .. 10 .. {m}"
+ failwith $"FAILURE: {n} .. 10 .. {m}"
let ``test 11`` n m =
let expected = seq { n .. 11 .. m }
let actual = ResizeArray()
for i in n .. 11 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 11`` n m |> not then
- failwith $"FAILURE: {n} .. 11 .. {m}"
+ failwith $"FAILURE: {n} .. 11 .. {m}"
let ``test 12`` n m =
let expected = seq { n .. 12 .. m }
let actual = ResizeArray()
for i in n .. 12 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 12`` n m |> not then
- failwith $"FAILURE: {n} .. 12 .. {m}"
+ failwith $"FAILURE: {n} .. 12 .. {m}"
let ``test 13`` n m =
let expected = seq { n .. 13 .. m }
let actual = ResizeArray()
for i in n .. 13 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 13`` n m |> not then
- failwith $"FAILURE: {n} .. 13 .. {m}"
+ failwith $"FAILURE: {n} .. 13 .. {m}"
let ``test 14`` n m =
let expected = seq { n .. 14 .. m }
let actual = ResizeArray()
for i in n .. 14 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 14`` n m |> not then
- failwith $"FAILURE: {n} .. 14 .. {m}"
+ failwith $"FAILURE: {n} .. 14 .. {m}"
let ``test 15`` n m =
let expected = seq { n .. 15 .. m }
let actual = ResizeArray()
for i in n .. 15 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 15`` n m |> not then
- failwith $"FAILURE: {n} .. 15 .. {m}"
+ failwith $"FAILURE: {n} .. 15 .. {m}"
let ``test 16`` n m =
let expected = seq { n .. 16 .. m }
let actual = ResizeArray()
for i in n .. 16 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 16`` n m |> not then
- failwith $"FAILURE: {n} .. 16 .. {m}"
+ failwith $"FAILURE: {n} .. 16 .. {m}"
let ``test 17`` n m =
let expected = seq { n .. 17 .. m }
let actual = ResizeArray()
for i in n .. 17 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 17`` n m |> not then
- failwith $"FAILURE: {n} .. 17 .. {m}"
+ failwith $"FAILURE: {n} .. 17 .. {m}"
let ``test 18`` n m =
let expected = seq { n .. 18 .. m }
let actual = ResizeArray()
for i in n .. 18 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 18`` n m |> not then
- failwith $"FAILURE: {n} .. 18 .. {m}"
+ failwith $"FAILURE: {n} .. 18 .. {m}"
let ``test 19`` n m =
let expected = seq { n .. 19 .. m }
let actual = ResizeArray()
for i in n .. 19 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 19`` n m |> not then
- failwith $"FAILURE: {n} .. 19 .. {m}"
+ failwith $"FAILURE: {n} .. 19 .. {m}"
let ``test 20`` n m =
let expected = seq { n .. 20 .. m }
let actual = ResizeArray()
for i in n .. 20 .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
for n = -20 to 20 do
for m = -20 to 20 do
if ``test 20`` n m |> not then
- failwith $"FAILURE: {n} .. 20 .. {m}"
+ failwith $"FAILURE: {n} .. 20 .. {m}"
// Generation Code:
// [ -20..-1 ] @ [ 1..20 ]
-// |> List.map (fun step ->
+// |> List.map (fun step ->
// $"""
-// let ``test {step}`` n m =
+// let ``test {step}`` n m =
// let expected = seq {{ n .. {step} .. m }}
// let actual = ResizeArray()
// for i in n .. {step} .. m do
// actual.Add i
-// Seq.forall2 (=) actual expected
+// Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
//
-// for n = -20 to 20 do
-// for m = -20 to 20 do
-// if ``test {step}`` n m |> not then
+// for n = -20 to 20 do
+// for m = -20 to 20 do
+// if ``test {step}`` n m |> not then
// failwith $"FAILURE: {{n}} .. {step} .. {{m}}"
// """)
// |> List.reduce (+)
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/NearMaxForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/NearMaxForLoops.fs
new file mode 100644
index 00000000000..48cf6cebb54
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/NearMaxForLoops.fs
@@ -0,0 +1,32 @@
+open type System.Int32
+
+// Test looping behavior near Int32.MaxValue.
+
+let test n step m =
+ let expected = seq { n .. step .. m }
+ let actual = ResizeArray()
+ for i in n .. step .. m do
+ actual.Add i
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
+
+let ns = [ MaxValue - 10 .. MaxValue ]
+let ms = [ MaxValue - 10 .. MaxValue ]
+let steps = [ -25 .. -1 ] @ [ 1 .. 25 ]
+
+for n in ns do
+ for step in steps do
+ for m in ms do
+ let res = test n step m
+ if not res then
+ failwith $"FAILED CASE: {n} .. {step} .. {m}"
+
+do
+ let n = MaxValue - 1
+ let m = MaxValue
+ let expected = seq { n .. 10 .. m }
+ let actual = ResizeArray()
+ for i in n .. 10 .. m do
+ actual.Add i
+ let res = Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
+ if not res then
+ failwith $"FAILED CASE: {n} .. 10 .. {m}"
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
index e00cb510af9..67420d5a103 100644
--- a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
@@ -16,6 +16,12 @@ module OptimizedForLoops =
[]
let ``Optimized constant step loops should match OperatorIntrinsics RangeInt32 behavior`` compilation =
+ compilation
+ |> compileExeAndRun
+ |> shouldSucceed
+
+ []
+ let ``Optimized loops with values near Int32 MaxValue should match OperatorIntrinsics RangeInt32 behavior`` compilation =
compilation
|> compileExeAndRun
|> shouldSucceed
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/VariableStepForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/VariableStepForLoops.fs
index 9b1ee755931..ec4d1c99972 100644
--- a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/VariableStepForLoops.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/VariableStepForLoops.fs
@@ -1,10 +1,10 @@
// 1020100 test cases
let test n step m =
- let expected = seq { n .. step .. m}
+ let expected = seq { n .. step .. m }
let actual = ResizeArray()
for i in n .. step .. m do
actual.Add i
- Seq.forall2 (=) actual expected
+ Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
let ns = [ -50 .. 50 ]
let ms = [ -50 .. 50 ]
From aa39f2b3a8b81545391b2211850c43ca70e0c2d3 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Sun, 21 Aug 2022 20:43:16 -0700
Subject: [PATCH 09/15] fix integer overflow with constant step for loops
---
src/Compiler/CodeGen/IlxGen.fs | 12 +++--
.../Miscellaneous/NearMaxForLoops.fs | 48 +++++++++++++++----
2 files changed, 47 insertions(+), 13 deletions(-)
diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs
index 6c025db60c0..5b0de837c49 100644
--- a/src/Compiler/CodeGen/IlxGen.fs
+++ b/src/Compiler/CodeGen/IlxGen.fs
@@ -5003,8 +5003,8 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
// FSharpForLoopUp: if v <> e2 + 1 then goto .inner
// FSharpForLoopDown: if v <> e2 - 1 then goto .inner
// FSharpForLoopWithStep: if (step > 0 && v <= e2) || (step < 0 && v >= e2) then goto .inner (variable step)
- // FSharpForLoopWithStep: if v <= e2 then goto .inner (constant step > 0)
- // FSharpForLoopWithStep: if v >= e2 then goto .inner (constant step < 0)
+ // FSharpForLoopWithStep: if v <= e2 && v >= e1 then goto .inner (constant step > 0)
+ // FSharpForLoopWithStep: if v >= e2 && v <= e1 then goto .inner (constant step < 0)
// CSharpStyle: if v < e2 then goto .inner
match spTo with
| DebugPointAtInOrTo.Yes spStart -> CG.EmitDebugPoint cgbuf spStart
@@ -5023,13 +5023,19 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
|> GenSequel cenv eenv.cloc cgbuf
| FSharpForLoopWithStep _ ->
- EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
match stepConst with
| Some sc ->
let pos = sc > 0
+
+ GenExpr cenv cgbuf eenv e1 Continue
+ CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp((if pos then BI_blt else BI_bgt), finish.CodeLabel))
+
+ GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
+ EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
CmpThenBrOrContinue(pop 2, [ I_brcmp((if pos then BI_ble else BI_bge), inner.CodeLabel) ])
| None ->
+ EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
let testPassed = CG.GenerateDelayMark cgbuf "testPassed"
CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_ble, testPassed.CodeLabel))
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/NearMaxForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/NearMaxForLoops.fs
index 48cf6cebb54..ed8018429c0 100644
--- a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/NearMaxForLoops.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/NearMaxForLoops.fs
@@ -1,6 +1,6 @@
open type System.Int32
-// Test looping behavior near Int32.MaxValue.
+// Test looping behavior near Int32.MaxValue and Int32.MinValue.
let test n step m =
let expected = seq { n .. step .. m }
@@ -9,18 +9,34 @@ let test n step m =
actual.Add i
Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
-let ns = [ MaxValue - 10 .. MaxValue ]
-let ms = [ MaxValue - 10 .. MaxValue ]
-let steps = [ -25 .. -1 ] @ [ 1 .. 25 ]
+do
+ // Variable step overflow.
+ let ns = [ MaxValue - 10 .. MaxValue ]
+ let ms = [ MaxValue - 10 .. MaxValue ]
+ let steps = [ -25 .. -1 ] @ [ 1 .. 25 ]
+
+ for n in ns do
+ for step in steps do
+ for m in ms do
+ let res = test n step m
+ if not res then
+ failwith $"FAILED CASE: {n} .. {step} .. {m}"
+
+do
+ // Variable step underflow.
+ let ns = [ MinValue .. MinValue + 10 ]
+ let ms = [ MinValue .. MinValue + 10 ]
+ let steps = [ -25 .. -1 ] @ [ 1 .. 25 ]
-for n in ns do
- for step in steps do
- for m in ms do
- let res = test n step m
- if not res then
- failwith $"FAILED CASE: {n} .. {step} .. {m}"
+ for n in ns do
+ for step in steps do
+ for m in ms do
+ let res = test n step m
+ if not res then
+ failwith $"FAILED CASE: {n} .. {step} .. {m}"
do
+ // Constant step overflow.
let n = MaxValue - 1
let m = MaxValue
let expected = seq { n .. 10 .. m }
@@ -30,3 +46,15 @@ do
let res = Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
if not res then
failwith $"FAILED CASE: {n} .. 10 .. {m}"
+
+do
+ // Constant step underflow.
+ let n = MinValue + 1
+ let m = MinValue
+ let expected = seq { n .. -10 .. m }
+ let actual = ResizeArray()
+ for i in n .. -10 .. m do
+ actual.Add i
+ let res = Seq.length expected = actual.Count && Seq.forall2 (=) actual expected
+ if not res then
+ failwith $"FAILED CASE: {n} .. -10 .. {m}"
\ No newline at end of file
From 606e15d3bd2302d79e77710bde1d5167adf7e381 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Sun, 21 Aug 2022 22:28:53 -0700
Subject: [PATCH 10/15] update baselines
---
.../ForLoopWithStep2.fsx.il.net472.debug.bsl | 16 ++++++++++------
.../ForLoopWithStep2.fsx.il.net472.release.bsl | 16 ++++++++++------
.../ForLoopWithStep2.fsx.il.netcore.debug.bsl | 16 ++++++++++------
.../ForLoopWithStep2.fsx.il.netcore.release.bsl | 16 ++++++++++------
.../ForLoopWithStep3.fsx.il.net472.debug.bsl | 16 ++++++++++------
.../ForLoopWithStep3.fsx.il.net472.release.bsl | 16 ++++++++++------
.../ForLoopWithStep3.fsx.il.netcore.debug.bsl | 16 ++++++++++------
.../ForLoopWithStep3.fsx.il.netcore.release.bsl | 16 ++++++++++------
8 files changed, 80 insertions(+), 48 deletions(-)
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.debug.bsl
index dc959e2e433..e221474be66 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.debug.bsl
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.debug.bsl
@@ -37,13 +37,13 @@
// WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep2 created
}
.module ForLoopWithStep2.exe
-// MVID: {62E36119-8E23-B794-A745-03831961E362}
+// MVID: {630305ED-8E23-B794-A745-0383ED050363}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x00000187F2490000
+// Image base: 0x00000198DED80000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -56,7 +56,7 @@
int32 m) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
- // Code size 51 (0x33)
+ // Code size 55 (0x37)
.maxstack 7
.locals init (int32 V_0,
int32 V_1)
@@ -85,10 +85,14 @@
IL_002c: add
IL_002d: stloc.1
IL_002e: ldloc.1
- IL_002f: ldloc.0
- IL_0030: ble.s IL_0006
+ IL_002f: ldarg.0
+ IL_0030: blt.s IL_0036
- IL_0032: ret
+ IL_0032: ldloc.1
+ IL_0033: ldloc.0
+ IL_0034: ble.s IL_0006
+
+ IL_0036: ret
} // end of method ForLoopWithStep2::loop
} // end of class ForLoopWithStep2
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.release.bsl
index a41f694687f..efe71bc40b0 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.release.bsl
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.net472.release.bsl
@@ -42,13 +42,13 @@
// WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep2 created
}
.module ForLoopWithStep2.exe
-// MVID: {62E35ED9-8E23-B794-A745-0383D95EE362}
+// MVID: {63030EDE-8E23-B794-A745-0383DE0E0363}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x00000271B3BF0000
+// Image base: 0x0000024EE9640000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -61,7 +61,7 @@
int32 m) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
- // Code size 58 (0x3a)
+ // Code size 62 (0x3e)
.maxstack 7
.locals init (int32 V_0,
int32 V_1,
@@ -95,10 +95,14 @@
IL_0033: add
IL_0034: stloc.1
IL_0035: ldloc.1
- IL_0036: ldloc.0
- IL_0037: ble.s IL_0006
+ IL_0036: ldarg.0
+ IL_0037: blt.s IL_003d
- IL_0039: ret
+ IL_0039: ldloc.1
+ IL_003a: ldloc.0
+ IL_003b: ble.s IL_0006
+
+ IL_003d: ret
} // end of method ForLoopWithStep2::loop
} // end of class ForLoopWithStep2
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.debug.bsl
index 75aa1cfc8b4..ebf5374dbe4 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.debug.bsl
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.debug.bsl
@@ -37,13 +37,13 @@
// WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep2 created
}
.module ForLoopWithStep2.exe
-// MVID: {62E35B4D-0BEB-9A4A-A745-03834D5BE362}
+// MVID: {6303023F-4ACD-7CD9-A745-03833F020363}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x000002629F980000
+// Image base: 0x0000020734F80000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -56,7 +56,7 @@
int32 m) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
- // Code size 51 (0x33)
+ // Code size 55 (0x37)
.maxstack 7
.locals init (int32 V_0,
int32 V_1)
@@ -85,10 +85,14 @@
IL_002c: add
IL_002d: stloc.1
IL_002e: ldloc.1
- IL_002f: ldloc.0
- IL_0030: ble.s IL_0006
+ IL_002f: ldarg.0
+ IL_0030: blt.s IL_0036
- IL_0032: ret
+ IL_0032: ldloc.1
+ IL_0033: ldloc.0
+ IL_0034: ble.s IL_0006
+
+ IL_0036: ret
} // end of method ForLoopWithStep2::loop
} // end of class ForLoopWithStep2
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.release.bsl
index d037f9b4563..3fe2c3cce18 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.release.bsl
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep2.fsx.il.netcore.release.bsl
@@ -42,13 +42,13 @@
// WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep2 created
}
.module ForLoopWithStep2.exe
-// MVID: {62E352C7-65F8-C026-A745-0383C752E362}
+// MVID: {6302FED2-D2CD-892C-A745-0383D2FE0263}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x000002B014A70000
+// Image base: 0x0000022B4DB70000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -61,7 +61,7 @@
int32 m) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
- // Code size 58 (0x3a)
+ // Code size 62 (0x3e)
.maxstack 7
.locals init (int32 V_0,
int32 V_1,
@@ -95,10 +95,14 @@
IL_0033: add
IL_0034: stloc.1
IL_0035: ldloc.1
- IL_0036: ldloc.0
- IL_0037: ble.s IL_0006
+ IL_0036: ldarg.0
+ IL_0037: blt.s IL_003d
- IL_0039: ret
+ IL_0039: ldloc.1
+ IL_003a: ldloc.0
+ IL_003b: ble.s IL_0006
+
+ IL_003d: ret
} // end of method ForLoopWithStep2::loop
} // end of class ForLoopWithStep2
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.debug.bsl
index b9cb8f4713f..fd971d2b7ed 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.debug.bsl
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.debug.bsl
@@ -37,13 +37,13 @@
// WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep3 created
}
.module ForLoopWithStep3.exe
-// MVID: {62E36119-5EC8-08E2-A745-03831961E362}
+// MVID: {630305ED-5EC8-08E2-A745-0383ED050363}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x000002872C9E0000
+// Image base: 0x000002A50BC20000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -56,7 +56,7 @@
!!b m) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
- // Code size 53 (0x35)
+ // Code size 58 (0x3a)
.maxstack 7
.locals init (int32 V_0,
int32 V_1)
@@ -85,10 +85,14 @@
IL_002e: sub
IL_002f: stloc.1
IL_0030: ldloc.1
- IL_0031: ldloc.0
- IL_0032: bge.s IL_0008
+ IL_0031: ldc.i4.s 10
+ IL_0033: bgt.s IL_0039
- IL_0034: ret
+ IL_0035: ldloc.1
+ IL_0036: ldloc.0
+ IL_0037: bge.s IL_0008
+
+ IL_0039: ret
} // end of method ForLoopWithStep3::loop
} // end of class ForLoopWithStep3
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.release.bsl
index 50e4838adfa..18f2f4df458 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.release.bsl
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.net472.release.bsl
@@ -42,13 +42,13 @@
// WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep3 created
}
.module ForLoopWithStep3.exe
-// MVID: {62E35ED9-5EC8-08E2-A745-0383D95EE362}
+// MVID: {63030EDE-5EC8-08E2-A745-0383DE0E0363}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x000001DEBDF10000
+// Image base: 0x000001FCDB5E0000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -61,7 +61,7 @@
!!b m) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
- // Code size 60 (0x3c)
+ // Code size 65 (0x41)
.maxstack 7
.locals init (int32 V_0,
int32 V_1,
@@ -95,10 +95,14 @@
IL_0035: sub
IL_0036: stloc.1
IL_0037: ldloc.1
- IL_0038: ldloc.0
- IL_0039: bge.s IL_0008
+ IL_0038: ldc.i4.s 10
+ IL_003a: bgt.s IL_0040
- IL_003b: ret
+ IL_003c: ldloc.1
+ IL_003d: ldloc.0
+ IL_003e: bge.s IL_0008
+
+ IL_0040: ret
} // end of method ForLoopWithStep3::loop
} // end of class ForLoopWithStep3
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.debug.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.debug.bsl
index 418ece31504..1c403e9ed20 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.debug.bsl
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.debug.bsl
@@ -37,13 +37,13 @@
// WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep3 created
}
.module ForLoopWithStep3.exe
-// MVID: {62E35B4D-8E9F-8EFA-A745-03834D5BE362}
+// MVID: {6303023F-ADEE-FD5D-A745-03833F020363}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x000002B1E0100000
+// Image base: 0x0000021B405D0000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -56,7 +56,7 @@
!!b m) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
- // Code size 53 (0x35)
+ // Code size 58 (0x3a)
.maxstack 7
.locals init (int32 V_0,
int32 V_1)
@@ -85,10 +85,14 @@
IL_002e: sub
IL_002f: stloc.1
IL_0030: ldloc.1
- IL_0031: ldloc.0
- IL_0032: bge.s IL_0008
+ IL_0031: ldc.i4.s 10
+ IL_0033: bgt.s IL_0039
- IL_0034: ret
+ IL_0035: ldloc.1
+ IL_0036: ldloc.0
+ IL_0037: bge.s IL_0008
+
+ IL_0039: ret
} // end of method ForLoopWithStep3::loop
} // end of class ForLoopWithStep3
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.release.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.release.bsl
index d959bd83ffc..8b00e7bb935 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.release.bsl
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/ForLoopWithStep3.fsx.il.netcore.release.bsl
@@ -42,13 +42,13 @@
// WARNING: managed resource file FSharpOptimizationData.ForLoopWithStep3 created
}
.module ForLoopWithStep3.exe
-// MVID: {62E352C7-B005-C4DD-A745-0383C752E362}
+// MVID: {6302FED2-9A4D-1590-A745-0383D2FE0263}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x000001C4DA720000
+// Image base: 0x000001AC54900000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -61,7 +61,7 @@
!!b m) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 )
- // Code size 60 (0x3c)
+ // Code size 65 (0x41)
.maxstack 7
.locals init (int32 V_0,
int32 V_1,
@@ -95,10 +95,14 @@
IL_0035: sub
IL_0036: stloc.1
IL_0037: ldloc.1
- IL_0038: ldloc.0
- IL_0039: bge.s IL_0008
+ IL_0038: ldc.i4.s 10
+ IL_003a: bgt.s IL_0040
- IL_003b: ret
+ IL_003c: ldloc.1
+ IL_003d: ldloc.0
+ IL_003e: bge.s IL_0008
+
+ IL_0040: ret
} // end of method ForLoopWithStep3::loop
} // end of class ForLoopWithStep3
From c1c6bc467a420c519dc5ee652eb1a338f2c20422 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Mon, 22 Aug 2022 09:05:13 -0700
Subject: [PATCH 11/15] test for loops in task
---
.../Miscellaneous/ForLoopsInTasks.fs | 16 ++++++++++++++++
.../Miscellaneous/OptimizedForLoops.fs | 6 ++++++
2 files changed, 22 insertions(+)
create mode 100644 tests/FSharp.Compiler.ComponentTests/Miscellaneous/ForLoopsInTasks.fs
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ForLoopsInTasks.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ForLoopsInTasks.fs
new file mode 100644
index 00000000000..b7639ad264f
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/ForLoopsInTasks.fs
@@ -0,0 +1,16 @@
+let mutable v = 0
+
+let incr () =
+ task {
+ System.Threading.Interlocked.Increment(&v) |> ignore
+ }
+
+let t () =
+ task {
+ for i in 1 .. 10 .. 1000 do
+ do! incr ()
+ }
+t().Wait()
+
+if v <> 100 then
+ failwith $"Expected: 100; got: {v}"
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
index 67420d5a103..d88dc275972 100644
--- a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/OptimizedForLoops.fs
@@ -22,6 +22,12 @@ module OptimizedForLoops =
[]
let ``Optimized loops with values near Int32 MaxValue should match OperatorIntrinsics RangeInt32 behavior`` compilation =
+ compilation
+ |> compileExeAndRun
+ |> shouldSucceed
+
+ []
+ let ``Optimized loops should work with resumable code`` compilation =
compilation
|> compileExeAndRun
|> shouldSucceed
\ No newline at end of file
From e1dc3c71d37a7423ae173680f4e416199a8a0511 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Mon, 22 Aug 2022 13:19:11 -0700
Subject: [PATCH 12/15] Update TheBigFileOfDebugStepping.fsx
---
.../TheBigFileOfDebugStepping.fsx | 194 ++++++++++++++++++
1 file changed, 194 insertions(+)
diff --git a/tests/walkthroughs/DebugStepping/TheBigFileOfDebugStepping.fsx b/tests/walkthroughs/DebugStepping/TheBigFileOfDebugStepping.fsx
index 59e13687105..5c902b3669d 100644
--- a/tests/walkthroughs/DebugStepping/TheBigFileOfDebugStepping.fsx
+++ b/tests/walkthroughs/DebugStepping/TheBigFileOfDebugStepping.fsx
@@ -190,6 +190,19 @@ let ListExpressionSteppingTest8 () =
yield x
]
+let ListExpressionSteppingTest9 () =
+ [ for x in 1..2..4 do
+ match x with
+ | 1 ->
+ printfn "hello"
+ yield x
+ | 3 ->
+ printfn "hello"
+ yield x
+ | _ ->
+ yield x
+ ]
+
let SeqExpressionSteppingTest1 () =
seq { yield 1 }
@@ -842,6 +855,7 @@ ListExpressionSteppingTest5()
ListExpressionSteppingTest6()
ListExpressionSteppingTest7()
ListExpressionSteppingTest8()
+ListExpressionSteppingTest9()
SeqExpressionSteppingTest1()|> Seq.length
SeqExpressionSteppingTest2()|> Seq.length
SeqExpressionSteppingTest3()|> Seq.length
@@ -1072,6 +1086,24 @@ module ForLoopRegularCode =
printfn $"hello, x = {x}"
printfn $"hello, x = {x}"
+ let testSimpleForEachIntRangeLoopWithVariableStepAndOneStatement (start, step, stop) =
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+
+ let testSimpleForEachIntRangeLoopWithVariableStepAndTwoStatements (start, step, stop) =
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+
+ let testSimpleForEachIntRangeLoopWithConstantStepAndOneStatement (start, stop) =
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+
+ let testSimpleForEachIntRangeLoopWithConstantStepAndTwoStatements (start, stop) =
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+
let testSimpleForEachIntLoopWithOneStatement (start, stop) =
for x = start to stop do
printfn $"hello, x = {x}"
@@ -1102,6 +1134,10 @@ module ForLoopRegularCode =
testSimpleForEachIntRangeLoopWithTwoStatements (1, 3)
testSimpleForEachIntRangeLoopDownWithOneStatement (1, 3)
testSimpleForEachIntRangeLoopDownWithTwoStatements (1, 3)
+ testSimpleForEachIntRangeLoopWithVariableStepAndOneStatement (1, 3, 10)
+ testSimpleForEachIntRangeLoopWithVariableStepAndTwoStatements (1, 3, 10)
+ testSimpleForEachIntRangeLoopWithConstantStepAndOneStatement (1, 10)
+ testSimpleForEachIntRangeLoopWithConstantStepAndTwoStatements (1, 10)
testSimpleForEachIntLoopWithOneStatement (1, 3)
testSimpleForEachIntLoopWithTwoStatements (1, 3)
testSimpleForEachIntLoopDownWithOneStatement (1, 3)
@@ -1175,6 +1211,24 @@ module ForLoopInGeneratedList =
printfn $"hello, x = {x}"
yield x + 1 ]
+ let testSimpleListEachIntRangeLoopWithVariableStepAndOneStatement (start, step, stop) =
+ [ for x in start .. step .. stop do
+ yield x + 1 ]
+
+ let testSimpleListEachIntRangeLoopWithVariableStepAndTwoStatements (start, step, stop) =
+ [ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ yield x + 1 ]
+
+ let testSimpleListEachIntRangeLoopWithConstantStepAndOneStatement (start, stop) =
+ [ for x in start .. 3 .. stop do
+ yield x + 1 ]
+
+ let testSimpleListEachIntRangeLoopWithConstantStepAndTwoStatements (start, stop) =
+ [ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ yield x + 1 ]
+
let testSimpleListEachIntLoopWithOneStatement (start, stop) =
[ for x = start to stop do
yield x + 1 ]
@@ -1205,6 +1259,10 @@ module ForLoopInGeneratedList =
testSimpleListEachIntRangeLoopWithTwoStatements (1, 3)
testSimpleListEachIntRangeLoopDownWithOneStatement (1, 3)
testSimpleListEachIntRangeLoopDownWithTwoStatements (1, 3)
+ testSimpleListEachIntRangeLoopWithVariableStepAndOneStatement (1, 3, 10)
+ testSimpleListEachIntRangeLoopWithVariableStepAndTwoStatements (1, 3, 10)
+ testSimpleListEachIntRangeLoopWithConstantStepAndOneStatement (1, 10)
+ testSimpleListEachIntRangeLoopWithConstantStepAndTwoStatements (1, 10)
testSimpleListEachIntLoopWithOneStatement (1, 3)
testSimpleListEachIntLoopWithTwoStatements (1, 3)
testSimpleListEachIntLoopDownWithOneStatement (1, 3)
@@ -1317,6 +1375,36 @@ module ForLoopTaskCode =
return 1
}
+ let testSimpleTaskEachIntRangeLoopDownWithVariableStepAndOneStatement (start, step, stop) =
+ task {
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleTaskEachIntRangeLoopDownWithVariableStepAndTwoStatements (start, step, stop) =
+ task {
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleTaskEachIntRangeLoopDownWithConstantStepAndOneStatement (start, stop) =
+ task {
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleTaskEachIntRangeLoopDownWithConstantStepAndTwoStatements (start, stop) =
+ task {
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
let testSimpleTaskEachIntLoopWithOneStatement (start, stop) =
task {
for x = start to stop do
@@ -1359,6 +1447,10 @@ module ForLoopTaskCode =
testSimpleTaskEachIntRangeLoopWithTwoStatements (1, 3) |> fun t -> t.Result
testSimpleTaskEachIntRangeLoopDownWithOneStatement (1, 3) |> fun t -> t.Result
testSimpleTaskEachIntRangeLoopDownWithTwoStatements (1, 3) |> fun t -> t.Result
+ testSimpleTaskEachIntRangeLoopDownWithVariableStepAndOneStatement (1, 3, 10) |> fun t -> t.Result
+ testSimpleTaskEachIntRangeLoopDownWithVariableStepAndTwoStatements (1, 3, 10) |> fun t -> t.Result
+ testSimpleTaskEachIntRangeLoopDownWithConstantStepAndOneStatement (1, 10) |> fun t -> t.Result
+ testSimpleTaskEachIntRangeLoopDownWithConstantStepAndTwoStatements (1, 10) |> fun t -> t.Result
testSimpleTaskEachIntLoopWithOneStatement (1, 3) |> fun t -> t.Result
testSimpleTaskEachIntLoopWithTwoStatements (1, 3) |> fun t -> t.Result
testSimpleTaskEachIntLoopDownWithOneStatement (1, 3) |> fun t -> t.Result
@@ -1475,6 +1567,36 @@ module ForLoopSeqCode =
yield 1
}
+ let testSimpleSeqEachIntRangeLoopDownWithVariableStepAndOneStatement (start, step, stop) =
+ seq {
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ yield 1
+ }
+
+ let testSimpleSeqEachIntRangeLoopDownWithVariableStepAndTwoStatements (start, step, stop) =
+ seq {
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+ yield 1
+ }
+
+ let testSimpleSeqEachIntRangeLoopDownWithConstantStepAndOneStatement (start, stop) =
+ seq {
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ yield 1
+ }
+
+ let testSimpleSeqEachIntRangeLoopDownWithConstantStepAndTwoStatements (start, stop) =
+ seq {
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+ yield 1
+ }
+
let testSimpleSeqEachIntLoopWithOneStatement (start, stop) =
seq {
for x = start to stop do
@@ -1517,6 +1639,10 @@ module ForLoopSeqCode =
testSimpleSeqEachIntRangeLoopWithTwoStatements (1, 3) |> Seq.toList
testSimpleSeqEachIntRangeLoopDownWithOneStatement (1, 3) |> Seq.toList
testSimpleSeqEachIntRangeLoopDownWithTwoStatements (1, 3) |> Seq.toList
+ testSimpleSeqEachIntRangeLoopDownWithVariableStepAndOneStatement (1, 3, 10) |> Seq.toList
+ testSimpleSeqEachIntRangeLoopDownWithVariableStepAndTwoStatements (1, 3, 10) |> Seq.toList
+ testSimpleSeqEachIntRangeLoopDownWithConstantStepAndOneStatement (1, 10) |> Seq.toList
+ testSimpleSeqEachIntRangeLoopDownWithConstantStepAndTwoStatements (1, 10) |> Seq.toList
testSimpleSeqEachIntLoopWithOneStatement (1, 3) |> Seq.toList
testSimpleSeqEachIntLoopWithTwoStatements (1, 3) |> Seq.toList
testSimpleSeqEachIntLoopDownWithOneStatement (1, 3) |> Seq.toList
@@ -1633,6 +1759,36 @@ module ForLoopAsyncCode =
return 1
}
+ let testSimpleAsyncEachIntRangeLoopDownWithVariableStepAndOneStatement (start, step, stop) =
+ async {
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleAsyncEachIntRangeLoopDownWithVariableStepAndTwoStatements (start, step, stop) =
+ async {
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleAsyncEachIntRangeLoopDownWithConstantStepAndOneStatement (start, stop) =
+ async {
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleAsyncEachIntRangeLoopDownWithConstantStepAndTwoStatements (start, stop) =
+ async {
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
let testSimpleAsyncEachIntLoopWithOneStatement (start, stop) =
async {
for x = start to stop do
@@ -1675,6 +1831,10 @@ module ForLoopAsyncCode =
testSimpleAsyncEachIntRangeLoopWithTwoStatements (1, 3) |> Async.RunSynchronously
testSimpleAsyncEachIntRangeLoopDownWithOneStatement (1, 3) |> Async.RunSynchronously
testSimpleAsyncEachIntRangeLoopDownWithTwoStatements (1, 3) |> Async.RunSynchronously
+ testSimpleAsyncEachIntRangeLoopDownWithVariableStepAndOneStatement (1, 3, 10) |> Async.RunSynchronously
+ testSimpleAsyncEachIntRangeLoopDownWithVariableStepAndTwoStatements (1, 3, 10) |> Async.RunSynchronously
+ testSimpleAsyncEachIntRangeLoopDownWithConstantStepAndOneStatement (1, 10) |> Async.RunSynchronously
+ testSimpleAsyncEachIntRangeLoopDownWithConstantStepAndTwoStatements (1, 10) |> Async.RunSynchronously
testSimpleAsyncEachIntLoopWithOneStatement (1, 3) |> Async.RunSynchronously
testSimpleAsyncEachIntLoopWithTwoStatements (1, 3) |> Async.RunSynchronously
testSimpleAsyncEachIntLoopDownWithOneStatement (1, 3) |> Async.RunSynchronously
@@ -2021,6 +2181,36 @@ module ForLoopCancellableCode =
return 1
}
+ let testSimpleCancellableEachIntRangeLoopDownWithVariableStepAndOneStatement (start, step, stop) =
+ cancellable {
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleCancellableEachIntRangeLoopDownWithVariableStepAndTwoStatements (start, step, stop) =
+ cancellable {
+ for x in start .. step .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleCancellableEachIntRangeLoopDownWithConstantStepAndOneStatement (start, stop) =
+ cancellable {
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
+ let testSimpleCancellableEachIntRangeLoopDownWithConstantStepAndTwoStatements (start, stop) =
+ cancellable {
+ for x in start .. 3 .. stop do
+ printfn $"hello, x = {x}"
+ printfn $"hello, x = {x}"
+ return 1
+ }
+
let testSimpleCancellableEachIntLoopWithOneStatement (start, stop) =
cancellable {
for x = start to stop do
@@ -2063,6 +2253,10 @@ module ForLoopCancellableCode =
testSimpleCancellableEachIntRangeLoopWithTwoStatements (1, 3) |> Cancellable.runWithoutCancellation
testSimpleCancellableEachIntRangeLoopDownWithOneStatement (1, 3) |> Cancellable.runWithoutCancellation
testSimpleCancellableEachIntRangeLoopDownWithTwoStatements (1, 3) |> Cancellable.runWithoutCancellation
+ testSimpleCancellableEachIntRangeLoopDownWithVariableStepAndOneStatement (1, 3, 10) |> Cancellable.runWithoutCancellation
+ testSimpleCancellableEachIntRangeLoopDownWithVariableStepAndTwoStatements (1, 3, 10) |> Cancellable.runWithoutCancellation
+ testSimpleCancellableEachIntRangeLoopDownWithConstantStepAndOneStatement (1, 10) |> Cancellable.runWithoutCancellation
+ testSimpleCancellableEachIntRangeLoopDownWithConstantStepAndTwoStatements (1, 10) |> Cancellable.runWithoutCancellation
testSimpleCancellableEachIntLoopWithOneStatement (1, 3) |> Cancellable.runWithoutCancellation
testSimpleCancellableEachIntLoopWithTwoStatements (1, 3) |> Cancellable.runWithoutCancellation
testSimpleCancellableEachIntLoopDownWithOneStatement (1, 3) |> Cancellable.runWithoutCancellation
From 0b936437fe1bd9be7d6cd568cedf976a9be54d03 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Mon, 22 Aug 2022 21:59:51 -0700
Subject: [PATCH 13/15] new benchmarks
---
.../CompiledCodeBenchmarks/MicroPerf/ForLoops.fs | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/ForLoops.fs b/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/ForLoops.fs
index 759ae985f78..0c4e0dd034c 100644
--- a/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/ForLoops.fs
+++ b/tests/benchmarks/CompiledCodeBenchmarks/MicroPerf/ForLoops.fs
@@ -11,14 +11,20 @@ type ForLoopBenchmark() =
[]
member val Start = 0 with get, set
- []
+ []
member val Finish = 0 with get, set
[]
member val Step = 0 with get, set
[]
- member this.Benchmark() =
+ member this.VariableStep() =
let mutable x = 0
- for i in this.Start .. this.Finish .. this.Step do
+ for i in this.Start .. this.Step .. this.Finish do
+ x <- i
+
+ []
+ member this.ConstantStep() =
+ let mutable x = 0
+ for i in this.Start .. 10 .. this.Finish do
x <- i
From 5d4441da74a5044f0608ae293456600a405d517f Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Wed, 24 Aug 2022 13:18:00 -0700
Subject: [PATCH 14/15] move optimizations out of type checking
---
src/Compiler/Checking/CheckExpressions.fs | 23 ++---
src/Compiler/Checking/PostInferenceChecks.fs | 7 +-
src/Compiler/Checking/QuotationTranslator.fs | 3 -
src/Compiler/CodeGen/IlxGen.fs | 92 ++++++++++----------
src/Compiler/TypedTree/QuotationPickler.fs | 2 -
src/Compiler/TypedTree/QuotationPickler.fsi | 2 -
src/Compiler/TypedTree/TypedTree.fs | 3 -
src/Compiler/TypedTree/TypedTree.fsi | 3 -
src/Compiler/TypedTree/TypedTreeOps.fs | 2 +-
src/Compiler/TypedTree/TypedTreePickle.fs | 4 +-
src/FSharp.Core/quotations.fs | 34 ++------
src/FSharp.Core/quotations.fsi | 10 ---
tests/FSharp.Core.UnitTests/SurfaceArea.fs | 1 -
tests/fsharp/core/quotes/test.fsx | 13 +--
14 files changed, 64 insertions(+), 135 deletions(-)
diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs
index 14df201309a..2261a77d407 100644
--- a/src/Compiler/Checking/CheckExpressions.fs
+++ b/src/Compiler/Checking/CheckExpressions.fs
@@ -7559,12 +7559,7 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s
// optimize 'for i in n .. m do'
| Expr.App (Expr.Val (vref, _, _), _, [tyarg], [startExpr;finishExpr], _)
when valRefEq g vref g.range_op_vref && typeEquiv g tyarg g.int_ty ->
- (g.int32_ty, (fun _ x -> x), id, Choice1Of4 (startExpr, finishExpr))
-
- // optimize 'for i in n .. step .. m do'
- | Expr.App(Expr.Val(vref, _, _), _, [ tyarg; stepTyarg ], [ startExpr; stepExpr; finishExpr ], _)
- when valRefEq g vref g.range_step_op_vref && typeEquiv g tyarg g.int_ty && typeEquiv g stepTyarg g.int_ty ->
- (g.int32_ty, (fun _ x -> x), id, Choice2Of4(startExpr, stepExpr, finishExpr))
+ (g.int32_ty, (fun _ x -> x), id, Choice1Of3 (startExpr, finishExpr))
// optimize 'for i in arr do'
| _ when isArray1DTy g enumExprTy ->
@@ -7579,7 +7574,7 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s
let overallExprFixup overallExpr = mkLet spForBind mFor arrVar enumExpr overallExpr
// Ask for a loop over integers for the given range
- (elemTy, bodyExprFixup, overallExprFixup, Choice3Of4 (idxVar, mkZero g mFor, mkDecr g mFor (mkLdlen g mFor arrExpr)))
+ (elemTy, bodyExprFixup, overallExprFixup, Choice2Of3 (idxVar, mkZero g mFor, mkDecr g mFor (mkLdlen g mFor arrExpr)))
| _ ->
// try optimize 'for i in span do' for span or readonlyspan
@@ -7604,13 +7599,13 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s
let getLengthCallExpr, _ = BuildMethodCall tcVal g cenv.amap PossiblyMutates mWholeExpr true getLengthMethInfo ValUseFlag.NormalValUse [] [ spanExpr ] [] None
// Ask for a loop over integers for the given range
- (elemTy, bodyExprFixup, overallExprFixup, Choice3Of4 (idxVar, mkZero g mFor, mkDecr g mFor getLengthCallExpr))
+ (elemTy, bodyExprFixup, overallExprFixup, Choice2Of3 (idxVar, mkZero g mFor, mkDecr g mFor getLengthCallExpr))
| _ ->
let enumerableVar, enumerableExprInVar = mkCompGenLocal mEnumExpr "inputSequence" enumExprTy
let enumeratorVar, enumeratorExpr, _, enumElemTy, getEnumExpr, getEnumTy, guardExpr, _, currentExpr =
AnalyzeArbitraryExprAsEnumerable cenv env true mEnumExpr enumExprTy enumerableExprInVar
- (enumElemTy, (fun _ x -> x), id, Choice4Of4(enumerableVar, enumeratorVar, enumeratorExpr, getEnumExpr, getEnumTy, guardExpr, currentExpr))
+ (enumElemTy, (fun _ x -> x), id, Choice3Of3(enumerableVar, enumeratorVar, enumeratorExpr, getEnumExpr, getEnumTy, guardExpr, currentExpr))
let pat, _, vspecs, envinner, tpenv =
let env = { env with eIsControlFlow = false }
@@ -7648,19 +7643,15 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s
match iterationTechnique with
// Build iteration as a for loop
- | Choice1Of4(startExpr, finishExpr) ->
+ | Choice1Of3(startExpr, finishExpr) ->
mkFastForLoop g (spFor, spIn, mWholeExpr, elemVar, startExpr, true, finishExpr, bodyExpr)
- // Build iteration as a for loop with step value
- | Choice2Of4(startExpr, stepExpr, finishExpr) ->
- mkIntegerForLoopWithStep g (spFor, spIn, elemVar, startExpr, stepExpr, finishExpr, bodyExpr, mWholeExpr)
-
// Build iteration as a for loop with a specific index variable that is not the same as the elemVar
- | Choice3Of4(idxVar, startExpr, finishExpr) ->
+ | Choice2Of3(idxVar, startExpr, finishExpr) ->
mkFastForLoop g (DebugPointAtFor.No, spIn, mWholeExpr, idxVar, startExpr, true, finishExpr, bodyExpr)
// Build iteration as a while loop with a try/finally disposal
- | Choice4Of4(enumerableVar, enumeratorVar, _, getEnumExpr, _, guardExpr, currentExpr) ->
+ | Choice3Of3(enumerableVar, enumeratorVar, _, getEnumExpr, _, guardExpr, currentExpr) ->
// This compiled for must be matched EXACTLY by CompiledForEachExpr
mkLet spForBind mFor enumerableVar enumExpr
diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs
index 35f5ccf48c6..5f609356965 100644
--- a/src/Compiler/Checking/PostInferenceChecks.fs
+++ b/src/Compiler/Checking/PostInferenceChecks.fs
@@ -1060,10 +1060,9 @@ and TryCheckResumableCodeConstructs cenv env expr : bool =
true
// Integer for-loops are allowed but their bodies are not currently resumable
- | IntegerForLoopExpr (_sp1, _sp2, _style, e1, e2, v, e3, e4, _m) ->
+ | IntegerForLoopExpr (_sp1, _sp2, _style, e1, e2, v, e3, _, _m) ->
CheckExprNoByrefs cenv { env with resumableCode = Resumable.None } e1
CheckExprNoByrefs cenv { env with resumableCode = Resumable.None } e2
- Option.iter (CheckExprNoByrefs cenv { env with resumableCode = Resumable.None }) e4
BindVal cenv env v
CheckExprNoByrefs cenv { env with resumableCode = Resumable.None } e3
true
@@ -1454,10 +1453,6 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr =
CheckTypeInstNoByrefs cenv env m tyargs
CheckExprsNoByRefLike cenv env [e1;e2;e3]
- | TOp.IntegerForLoop _, _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _);Expr.Lambda (_, _, _, [_], e3, _, _);Expr.Lambda (_, _, _, [_], e4, _, _)] ->
- CheckTypeInstNoByrefs cenv env m tyargs
- CheckExprsNoByRefLike cenv env [e1;e2;e3;e4]
-
| TOp.TryWith _, [_], [Expr.Lambda (_, _, _, [_], e1, _, _); Expr.Lambda (_, _, _, [_], _e2, _, _); Expr.Lambda (_, _, _, [_], e3, _, _)] ->
CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/catch can be a byref
ctorLimitedZoneCheck()
diff --git a/src/Compiler/Checking/QuotationTranslator.fs b/src/Compiler/Checking/QuotationTranslator.fs
index 107781eca72..80c7e52e7bf 100644
--- a/src/Compiler/Checking/QuotationTranslator.fs
+++ b/src/Compiler/Checking/QuotationTranslator.fs
@@ -665,9 +665,6 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP.
| FSharpForLoopUp -> QP.mkIntegerForLoop(ConvExpr cenv env lim0, ConvExpr cenv env lim1, ConvExpr cenv env body)
| _ -> wfail(Error(FSComp.SR.crefQuotationsCantContainDescendingForLoops(), m))
- | TOp.IntegerForLoop (_, _, _), [], [Expr.Lambda (_, _, _, [_], lim0, _, _);Expr.Lambda (_, _, _, [_], lim1, _, _);body; Expr.Lambda (_, _, _, [_], step, _, _)] ->
- QP.mkIntegerForLoopWithStep(ConvExpr cenv env lim0, ConvExpr cenv env lim1, ConvExpr cenv env body, ConvExpr cenv env step)
-
| TOp.ILCall (_, _, _, isCtor, valUseFlag, isProperty, _, ilMethRef, enclTypeInst, methInst, _), [], callArgs ->
let parentTyconR = ConvILTypeRefUnadjusted cenv m ilMethRef.DeclaringTypeRef
let isNewObj = isCtor || (match valUseFlag with CtorValUsedAsSuperInit | CtorValUsedAsSelfInit -> true | _ -> false)
diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs
index aa1393b7fd2..fb8a19805d1 100644
--- a/src/Compiler/CodeGen/IlxGen.fs
+++ b/src/Compiler/CodeGen/IlxGen.fs
@@ -3014,13 +3014,13 @@ and GenExprAux (cenv: cenv) (cgbuf: CodeGenBuffer) eenv expr (sequel: sequel) =
GenWhileLoop cenv cgbuf eenv (sp, e1, e2, m) sequel
| TOp.IntegerForLoop (spFor, spTo, dir),
[ Expr.Lambda (_, _, _, [ _ ], e1, _, _); Expr.Lambda (_, _, _, [ _ ], e2, _, _); Expr.Lambda (_, _, _, [ v ], e3, _, _) ],
- [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, mkZero g (range ()), m) sequel
+ [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, None, m) sequel
| TOp.IntegerForLoop (spFor, spTo, dir),
[ Expr.Lambda (_, _, _, [ _ ], e1, _, _)
Expr.Lambda (_, _, _, [ _ ], e2, _, _)
Expr.Lambda (_, _, _, [ v ], e3, _, _)
Expr.Lambda (_, _, _, [ _ ], e4, _, _) ],
- [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, e4, m) sequel
+ [] -> GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, e3, Some e4, m) sequel
| TOp.TryFinally (spTry, spFinally),
[ Expr.Lambda (_, _, _, [ _ ], e1, _, _); Expr.Lambda (_, _, _, [ _ ], e2, _, _) ],
[ resTy ] -> GenTryFinally cenv cgbuf eenv (e1, e2, m, resTy, spTry, spFinally) sequel
@@ -4895,7 +4895,7 @@ and GenTryFinally cenv cgbuf eenv (bodyExpr, handlerExpr, m, resTy, spTry, spFin
// Generate for-loop
//--------------------------------------------------------------------------
-and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, stepExpr, m) sequel =
+and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, stepExpr: Expr option, m) sequel =
let eenv = SetIsInLoop true eenv
let g = cenv.g
@@ -4912,16 +4912,16 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
let test = CG.GenerateDelayMark cgbuf "for_test"
let stack, eenvinner = EmitSaveStack cenv cgbuf eenv m (start, finish)
- let stepByOne, isFSharpStyle, isUp =
- match dir with
- | FSharpForLoopUp -> true, true, true
- | FSharpForLoopDown -> true, true, false
- | FSharpForLoopWithStep _ -> false, true, true
- | CSharpForLoopUp -> true, false, true
+ let isFSharpStyle, isUp =
+ match stepExpr, dir with
+ | Some _, _ -> true, true
+ | None, FSharpForLoopUp -> true, true
+ | None, FSharpForLoopDown -> true, false
+ | None, CSharpForLoopUp -> false, true
let stepConst =
match stepExpr with
- | Expr.Const (Const.Int32 i, _, _) when i <> 0 -> Some i
+ | Some(Expr.Const (Const.Int32 i, _, _)) when i <> 0 -> Some i
| _ -> None
let finishIdx, stepIdx, eenvinner =
@@ -4935,7 +4935,7 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
let v, _realloc, eenvinner =
AllocLocal cenv cgbuf eenvinner true (vName, g.ilg.typ_Int32, false) (start, finish)
- if not stepByOne && Option.isNone stepConst then
+ if stepExpr.IsSome && stepConst.IsNone then
let v2, _realloc, eenvinner =
AllocLocal cenv cgbuf eenvinner true (vName, g.ilg.typ_Int32, false) (start, finish)
@@ -4954,20 +4954,20 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
GenExpr cenv cgbuf eenv e1 Continue
GenStoreVal cgbuf eenvinner m v
- match dir, stepConst with
- | FSharpForLoopWithStep, None ->
+ match stepExpr, stepConst with
+ | Some step, None ->
// Throw invalidarg at runtime if step is 0.
// Emulates behavior of the RangeInt32 enumerator that this replaces.
- GenExpr cenv cgbuf eenvinner stepExpr Continue
+ GenExpr cenv cgbuf eenvinner step Continue
EmitSetLocal cgbuf stepIdx
EmitGetLocal cgbuf g.ilg.typ_Int32 stepIdx
let notZero = CG.GenerateDelayMark cgbuf "notZero"
CG.EmitInstr cgbuf (pop 1) Push0 (I_brcmp(BI_brtrue, notZero.CodeLabel))
- let arg1 = mkString g stepExpr.Range (SR.GetString "StepCannotBeZero")
- let arg2 = mkString g stepExpr.Range "step"
- let invalidArgExpr = MakeArgumentExnExpr cenv eenv (arg1, arg2, stepExpr.Range)
+ let arg1 = mkString g step.Range (SR.GetString "StepCannotBeZero")
+ let arg2 = mkString g step.Range "step"
+ let invalidArgExpr = MakeArgumentExnExpr cenv eenv (arg1, arg2, step.Range)
GenExpr cenv cgbuf eenvinner invalidArgExpr Continue
CG.EmitInstr cgbuf (pop 1) Push0 I_throw
@@ -4978,15 +4978,15 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
GenExpr cenv cgbuf eenvinner e2 Continue
EmitSetLocal cgbuf finishIdx
- if stepByOne then
+ if stepExpr.IsNone then
EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- match dir with
- | FSharpForLoopUp -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, finish.CodeLabel))
- | FSharpForLoopDown -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
- | FSharpForLoopWithStep
- | CSharpForLoopUp -> CG.EmitInstr cgbuf (pop 0) Push0 (I_br test.CodeLabel)
+ match stepExpr, dir with
+ | Some _, _
+ | None, CSharpForLoopUp -> CG.EmitInstr cgbuf (pop 0) Push0 (I_br test.CodeLabel)
+ | None, FSharpForLoopUp -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_blt, finish.CodeLabel))
+ | None, FSharpForLoopDown -> CG.EmitInstr cgbuf (pop 2) Push0 (I_brcmp(BI_bgt, finish.CodeLabel))
cgbuf.EmitStartOfHiddenCode()
@@ -4999,13 +4999,15 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
// v++ or v--
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- match dir with
- | FSharpForLoopUp
- | FSharpForLoopDown
- | CSharpForLoopUp ->
- CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
- CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
- | FSharpForLoopWithStep _ ->
+ match stepExpr with
+ | None ->
+ match dir with
+ | FSharpForLoopUp
+ | FSharpForLoopDown
+ | CSharpForLoopUp ->
+ CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
+ CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
+ | Some _ ->
match stepConst with
| Some sc ->
let pos = sc > 0
@@ -5032,18 +5034,21 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- match dir with
- | FSharpForLoopUp
- | FSharpForLoopDown ->
- EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
- CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
- CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
-
- CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_bne_un, inner.CodeLabel) ])
- |> GenSequel cenv eenv.cloc cgbuf
-
- | FSharpForLoopWithStep _ ->
-
+ match stepExpr with
+ | None ->
+ match dir with
+ | FSharpForLoopUp
+ | FSharpForLoopDown ->
+ EmitGetLocal cgbuf g.ilg.typ_Int32 finishIdx
+ CG.EmitInstr cgbuf (pop 0) (Push [ g.ilg.typ_Int32 ]) (mkLdcInt32 1)
+ CG.EmitInstr cgbuf (pop 1) Push0 (if isUp then AI_add else AI_sub)
+
+ CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_bne_un, inner.CodeLabel) ])
+ |> GenSequel cenv eenv.cloc cgbuf
+ | CSharpForLoopUp ->
+ CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_blt, inner.CodeLabel) ])
+ |> GenExpr cenv cgbuf eenv e2
+ | Some _ ->
match stepConst with
| Some sc ->
let pos = sc > 0
@@ -5073,9 +5078,6 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_bge, inner.CodeLabel) ])
|> GenSequel cenv eenv.cloc cgbuf
- | CSharpForLoopUp ->
- CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_blt, inner.CodeLabel) ])
- |> GenExpr cenv cgbuf eenv e2
// .finish - loop-exit here
CG.SetMarkToHere cgbuf finish
diff --git a/src/Compiler/TypedTree/QuotationPickler.fs b/src/Compiler/TypedTree/QuotationPickler.fs
index 678da2d64c0..4c613f007d2 100644
--- a/src/Compiler/TypedTree/QuotationPickler.fs
+++ b/src/Compiler/TypedTree/QuotationPickler.fs
@@ -210,8 +210,6 @@ let mkSequential (e1, e2) = CombExpr(SeqOp, [], [e1;e2])
let mkIntegerForLoop (x1, x2, x3) = CombExpr(ForLoopOp, [], [x1;x2;x3])
-let mkIntegerForLoopWithStep (x1, x2, x3, x4) = CombExpr(ForLoopOp, [], [x1;x2;x3;x4])
-
let mkWhileLoop (e1, e2) = CombExpr(WhileLoopOp, [], [e1;e2])
let mkTryFinally(e1, e2) = CombExpr(TryFinallyOp, [], [e1;e2])
diff --git a/src/Compiler/TypedTree/QuotationPickler.fsi b/src/Compiler/TypedTree/QuotationPickler.fsi
index 2cd9995daf5..648e9d0acf6 100644
--- a/src/Compiler/TypedTree/QuotationPickler.fsi
+++ b/src/Compiler/TypedTree/QuotationPickler.fsi
@@ -141,8 +141,6 @@ val mkSequential: ExprData * ExprData -> ExprData
val mkIntegerForLoop: ExprData * ExprData * ExprData -> ExprData
-val mkIntegerForLoopWithStep: ExprData * ExprData * ExprData * ExprData -> ExprData
-
val mkWhileLoop: ExprData * ExprData -> ExprData
val mkTryFinally: ExprData * ExprData -> ExprData
diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs
index 935d59cc883..c060e9ef2df 100644
--- a/src/Compiler/TypedTree/TypedTree.fs
+++ b/src/Compiler/TypedTree/TypedTree.fs
@@ -5018,9 +5018,6 @@ type ForLoopStyle =
/// Evaluate start and end once, loop down
| FSharpForLoopDown
- /// Evaluate start, step, and end once
- | FSharpForLoopWithStep
-
/// Evaluate start once and end multiple times, loop up
| CSharpForLoopUp
diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi
index e7845842290..d55e5e40706 100644
--- a/src/Compiler/TypedTree/TypedTree.fsi
+++ b/src/Compiler/TypedTree/TypedTree.fsi
@@ -3674,9 +3674,6 @@ type ForLoopStyle =
/// Evaluate start type end once, loop down
| FSharpForLoopDown
- /// Evaluate start, step, and end once
- | FSharpForLoopWithStep
-
/// Evaluate start once type end multiple times, loop up
| CSharpForLoopUp
diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs
index e08c93d99b5..90f416f51b7 100644
--- a/src/Compiler/TypedTree/TypedTreeOps.fs
+++ b/src/Compiler/TypedTree/TypedTreeOps.fs
@@ -1522,7 +1522,7 @@ let mkIntegerForLoop (g: TcGlobals) (spFor, spIn, v, startExpr, dir, finishExpr,
Expr.Op (TOp.IntegerForLoop (spFor, spIn, dir), [], [mkDummyLambda g (startExpr, g.int_ty) ;mkDummyLambda g (finishExpr, g.int_ty);mkLambda bodyExpr.Range v (bodyExpr, g.unit_ty)], m)
let mkIntegerForLoopWithStep (g: TcGlobals) (spFor, spIn, v, startExpr, stepExpr: Expr, finishExpr, bodyExpr: Expr, m) =
- Expr.Op (TOp.IntegerForLoop (spFor, spIn, FSharpForLoopWithStep), [], [mkDummyLambda g (startExpr, g.int_ty) ;mkDummyLambda g (finishExpr, g.int_ty);mkLambda bodyExpr.Range v (bodyExpr, g.unit_ty); mkDummyLambda g (stepExpr, g.int_ty)], m)
+ Expr.Op (TOp.IntegerForLoop (spFor, spIn, FSharpForLoopUp), [], [mkDummyLambda g (startExpr, g.int_ty) ;mkDummyLambda g (finishExpr, g.int_ty);mkLambda bodyExpr.Range v (bodyExpr, g.unit_ty); mkDummyLambda g (stepExpr, g.int_ty)], m)
let mkTryWith g (bodyExpr, filterVal, filterExpr: Expr, handlerVal, handlerExpr: Expr, m, ty, spTry, spWith) =
Expr.Op (TOp.TryWith (spTry, spWith), [ty], [mkDummyLambda g (bodyExpr, ty);mkLambda filterExpr.Range filterVal (filterExpr, ty);mkLambda handlerExpr.Range handlerVal (handlerExpr, ty)], m)
diff --git a/src/Compiler/TypedTree/TypedTreePickle.fs b/src/Compiler/TypedTree/TypedTreePickle.fs
index 56c71d1f279..c367865dbc2 100644
--- a/src/Compiler/TypedTree/TypedTreePickle.fs
+++ b/src/Compiler/TypedTree/TypedTreePickle.fs
@@ -2531,7 +2531,7 @@ and p_op x st =
-> p_byte 18 st; p_tup11 p_bool p_bool p_bool p_bool p_vrefFlags p_bool p_bool p_ILMethodRef p_tys p_tys p_tys (a1, a2, a3, a4, a5, a7, a8, a9, b, c, d) st
| TOp.Array -> p_byte 19 st
| TOp.While _ -> p_byte 20 st
- | TOp.IntegerForLoop (_, _, dir) -> p_byte 21 st; p_int (match dir with FSharpForLoopUp -> 0 | CSharpForLoopUp -> 1 | FSharpForLoopDown -> 2 | FSharpForLoopWithStep -> 3) st
+ | TOp.IntegerForLoop (_, _, dir) -> p_byte 21 st; p_int (match dir with FSharpForLoopUp -> 0 | CSharpForLoopUp -> 1 | FSharpForLoopDown -> 2) st
| TOp.Bytes bytes -> p_byte 22 st; p_bytes bytes st
| TOp.TryWith _ -> p_byte 23 st
| TOp.TryFinally _ -> p_byte 24 st
@@ -2596,7 +2596,7 @@ and u_op st =
TOp.ILCall (a1, a2, a3, a4, a5, a7, a8, a9, b, c, d)
| 19 -> TOp.Array
| 20 -> TOp.While (DebugPointAtWhile.No, NoSpecialWhileLoopMarker)
- | 21 -> let dir = match u_int st with 0 -> FSharpForLoopUp | 1 -> CSharpForLoopUp | 2 -> FSharpForLoopDown | 3 -> FSharpForLoopWithStep | _ -> failwith "unknown for loop"
+ | 21 -> let dir = match u_int st with 0 -> FSharpForLoopUp | 1 -> CSharpForLoopUp | 2 -> FSharpForLoopDown | _ -> failwith "unknown for loop"
TOp.IntegerForLoop (DebugPointAtFor.No, DebugPointAtInOrTo.No, dir)
| 22 -> TOp.Bytes (u_bytes st)
| 23 -> TOp.TryWith (DebugPointAtTry.No, DebugPointAtWith.No)
diff --git a/src/FSharp.Core/quotations.fs b/src/FSharp.Core/quotations.fs
index 67e2eeab46e..7e6f8b5a95e 100644
--- a/src/FSharp.Core/quotations.fs
+++ b/src/FSharp.Core/quotations.fs
@@ -422,8 +422,6 @@ and [] Expr(
| CombTerm (AddressSetOp, args) -> combL "AddressSet" (exprs args)
| CombTerm (ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)) ]) ->
combL "ForIntegerRangeLoop" [ varL v; expr e1; expr e2; expr e3 ]
- | CombTerm (ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)); step ]) ->
- combL "ForIntegerRangeLoop" [ varL v; expr e1; expr step; expr e2; expr e3 ]
| CombTerm (WhileLoopOp, args) -> combL "WhileLoop" (exprs args)
| CombTerm (TryFinallyOp, args) -> combL "TryFinally" (exprs args)
| CombTerm (TryWithOp, [ e1; Lambda (v1, e2); Lambda (v2, e3) ]) ->
@@ -556,11 +554,6 @@ module Patterns =
| CombTerm (k, [ x1; x2; x3 ]) -> Some(k, x1, x2, x3)
| _ -> None
- let (|Comb4|_|) (E x) =
- match x with
- | CombTerm (k, [ x1; x2; x3; x4 ]) -> Some(k, x1, x2, x3, x4)
- | _ -> None
-
[]
let (|Var|_|) (E x) =
match x with
@@ -729,12 +722,6 @@ module Patterns =
| Comb3 (ForIntegerRangeLoopOp, e1, e2, Lambda (v, e3)) -> Some(v, e1, e2, e3)
| _ -> None
- []
- let (|ForIntegerRangeLoopWithStep|_|) input =
- match input with
- | Comb4 (ForIntegerRangeLoopOp, e1, e2, Lambda (v, e3), step) -> Some(v, e1, step, e2, e3)
- | _ -> None
-
[]
let (|WhileLoop|_|) input =
match input with
@@ -983,9 +970,6 @@ module Patterns =
let mkFE3 op (x, y, z) =
E(CombTerm(op, [ (x :> Expr); (y :> Expr); (z :> Expr) ]))
- let mkFE4 op (x, y, z, a) =
- E(CombTerm(op, [ (x :> Expr); (y :> Expr); (z :> Expr); (a :> Expr) ]))
-
let mkOp v () =
v
@@ -1362,16 +1346,12 @@ module Patterns =
| true -> mkFEN (StaticMethodCallWOp(minfo, minfoW, nWitnesses)) args
| false -> invalidArg "minfo" (SR.GetString(SR.QnonStaticNoReceiverObject))
- let mkForLoop (v: Var, lowerBound, step, upperBound, body) =
+ let mkForLoop (v: Var, lowerBound, upperBound, body) =
checkTypesSR (typeof) (v.Type) "for" (SR.GetString(SR.QtmmLoopBodyMustBeLambdaTakingInteger))
checkTypesSR (typeof) (typeOf lowerBound) "lowerBound" (SR.GetString(SR.QtmmLowerUpperBoundMustBeInt))
checkTypesSR (typeof) (typeOf upperBound) "upperBound" (SR.GetString(SR.QtmmLowerUpperBoundMustBeInt))
-
- match step with
- | Some stepExpr ->
- checkTypesSR (typeof) (typeOf stepExpr) "step" (SR.GetString(SR.QtmmLoopBodyMustBeLambdaTakingInteger))
- mkFE4 ForIntegerRangeLoopOp (lowerBound, stepExpr, upperBound, mkLambda (v, body))
- | None -> mkFE3 ForIntegerRangeLoopOp (lowerBound, upperBound, mkLambda (v, body))
+ checkTypesSR (typeof) (v.Type) "for" (SR.GetString(SR.QtmmLoopBodyMustBeLambdaTakingInteger))
+ mkFE3 ForIntegerRangeLoopOp (lowerBound, upperBound, mkLambda (v, body))
let mkWhileLoop (guard, body) =
checkTypesSR (typeof) (typeOf guard) "guard" (SR.GetString(SR.QtmmGuardMustBeBool))
@@ -2651,10 +2631,7 @@ type Expr with
mkIfThenElse (guard, thenExpr, elseExpr)
static member ForIntegerRangeLoop(loopVariable, start: Expr, endExpr: Expr, body: Expr) =
- mkForLoop (loopVariable, start, None, endExpr, body)
-
- static member ForIntegerRangeLoop(loopVariable, start: Expr, step: Expr, endExpr: Expr, body: Expr) =
- mkForLoop (loopVariable, start, Some step, endExpr, body)
+ mkForLoop (loopVariable, start, endExpr, body)
static member FieldGet(fieldInfo: FieldInfo) =
checkNonNull "fieldInfo" fieldInfo
@@ -3058,8 +3035,7 @@ module ExprShape =
| AddressOfOp, [ e1 ] -> mkAddressOf e1
| VarSetOp, [ E (VarTerm v); e ] -> mkVarSet (v, e)
| AddressSetOp, [ e1; e2 ] -> mkAddressSet (e1, e2)
- | ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)) ] -> mkForLoop (v, e1, None, e2, e3)
- | ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)); e4 ] -> mkForLoop (v, e1, Some e4, e2, e3)
+ | ForIntegerRangeLoopOp, [ e1; e2; E (LambdaTerm (v, e3)) ] -> mkForLoop (v, e1, e2, e3)
| WhileLoopOp, [ e1; e2 ] -> mkWhileLoop (e1, e2)
| TryFinallyOp, [ e1; e2 ] -> mkTryFinally (e1, e2)
| TryWithOp, [ e1; Lambda (v1, e2); Lambda (v2, e3) ] -> mkTryWith (e1, v1, e2, v2, e3)
diff --git a/src/FSharp.Core/quotations.fsi b/src/FSharp.Core/quotations.fsi
index fa4455a05bb..5ec624e1438 100644
--- a/src/FSharp.Core/quotations.fsi
+++ b/src/FSharp.Core/quotations.fsi
@@ -1439,16 +1439,6 @@ module Patterns =
[]
val (|ForIntegerRangeLoop|_|): input: Expr -> (Var * Expr * Expr * Expr) option
- /// An active pattern to recognize expressions that represent loops over integer ranges with non-one step
- ///
- /// The input expression to match against.
- ///
- /// When successful, the pattern binds the value, start, step, finish and body of the input expression
- ///
- ///
- []
- val (|ForIntegerRangeLoopWithStep|_|): input: Expr -> (Var * Expr * Expr * Expr * Expr) option
-
/// An active pattern to recognize expressions that represent while loops
///
/// The input expression to match against.
diff --git a/tests/FSharp.Core.UnitTests/SurfaceArea.fs b/tests/FSharp.Core.UnitTests/SurfaceArea.fs
index c6a09b6181a..51de2a7a3ff 100644
--- a/tests/FSharp.Core.UnitTests/SurfaceArea.fs
+++ b/tests/FSharp.Core.UnitTests/SurfaceArea.fs
@@ -2440,7 +2440,6 @@ Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1
Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`4[Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr]] ForIntegerRangeLoopPattern(Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`5[Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr],System.Reflection.MethodInfo,System.Reflection.MethodInfo,Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]]] CallWithWitnessesPattern(Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`5[Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr]] TryWithPattern(Microsoft.FSharp.Quotations.FSharpExpr)
-Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`5[Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr]] ForIntegerRangeLoopWithStepPattern(Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Type] DefaultValuePattern(Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Reflection.FSharpReflectionExtensions: Boolean FSharpType.IsExceptionRepresentation.Static(System.Type, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
Microsoft.FSharp.Reflection.FSharpReflectionExtensions: Boolean FSharpType.IsRecord.Static(System.Type, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
diff --git a/tests/fsharp/core/quotes/test.fsx b/tests/fsharp/core/quotes/test.fsx
index a262f970e70..f8c005fe6e7 100644
--- a/tests/fsharp/core/quotes/test.fsx
+++ b/tests/fsharp/core/quotes/test.fsx
@@ -125,8 +125,6 @@ module TypedTest = begin
test "check AndAlso - encoded" ((<@ true && false @> |> (function IfThenElse(Bool(true),Bool(false),Bool(false)) -> true | _ -> false)))
test "check OrElse - encoded" ((<@ true || false @> |> (function IfThenElse(Bool(true),Bool(true),Bool(false)) -> true | _ -> false)))
- test "check ForIntegerRangeLoopWithStep" (<@ for i in 1..2..10 do printf "hello" @> |> (function ForIntegerRangeLoopWithStep(v,Int32(1),Int32(2),Int32(10),b) -> true | _ -> false))
-
test "check ForIntegerRangeLoop" (<@ for i = 1 to 10 do printf "hello" @> |> (function ForIntegerRangeLoop(v,Int32(1),Int32(10),b) -> true | _ -> false))
test "check ForIntegerRangeLoop" (<@ for i in 1 .. 10 do printf "hello" @> |> (function ForIntegerRangeLoop(v,Int32(1),Int32(10),b) -> true | _ -> false))
// In this example, the types of the start and end points are not known at the point the loop
@@ -138,7 +136,7 @@ module TypedTest = begin
test "check ForEachInList" (<@ for i in "123" do printf "hello" @> |> (function ForEachShape(_) -> true | _ -> false))
test "check ForEachInString" (<@ for i in [1;2;3] do printf "hello" @> |> (function ForEachShape(_) -> true | _ -> false))
// A slight non orthogonality is that all other 'for' loops go to (quite complex) the desugared form
- test "check Other Loop" (<@ for i in 1L .. 2L .. 10L do printf "hello" @> |> (function Let(v,_,b) -> true | _ -> false))
+ test "check Other Loop" (<@ for i in 1 .. 2 .. 10 do printf "hello" @> |> (function Let(v,_,b) -> true | _ -> false))
test "check Other Loop" (<@ for i in 1L .. 10L do printf "hello" @> |> (function Let(v,_,b) -> true | _ -> false))
let mutable mutableX = 1
@@ -1623,15 +1621,6 @@ module MoreQuotationsTests =
IfThenElse (Value (true), Value (1), Value (0)), matchValue,
IfThenElse (Value (true), Value (0), Call (None, Reraise, [])))"""
- let t15 = <@@ for i in 1..2..10 do printfn $"{i}" @@>
- checkStrings "vwewvwewe15" (sprintf "%A" t15)
- """ForIntegerRangeLoop (i, Value (1), Value (2), Value (10),
- Call (None, PrintFormatLine,
- [Coerce (NewObject (PrintfFormat`5, Value ("%P()"),
- NewArray (Object,
- Call (None, Box, [i])),
- Value ()), PrintfFormat`4)]))"""
-
let _ = <@@ let x : int option = None in x.IsSome @@> |> checkQuoteString "fqekhec1" """Let (x, NewUnionCase (None), Call (None, get_IsSome, [x]))"""
let _ = <@@ let x : int option = None in x.IsNone @@> |> checkQuoteString "fqekhec2" """Let (x, NewUnionCase (None), Call (None, get_IsNone, [x]))"""
let _ = <@@ let x : int option = None in x.Value @@> |> checkQuoteString "fqekhec3" """Let (x, NewUnionCase (None), PropertyGet (Some (x), Value, []))"""
From 76f22dfd93f6d1cd18a53de63bf14e6e74711c97 Mon Sep 17 00:00:00 2001
From: albert-du <52804499+albert-du@users.noreply.github.com>
Date: Wed, 24 Aug 2022 13:37:20 -0700
Subject: [PATCH 15/15] formatting
---
src/Compiler/Checking/CheckExpressions.fsi | 1 -
src/Compiler/CodeGen/IlxGen.fs | 7 +++----
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/Compiler/Checking/CheckExpressions.fsi b/src/Compiler/Checking/CheckExpressions.fsi
index 3b70a5caa1e..0bbaca89177 100644
--- a/src/Compiler/Checking/CheckExpressions.fsi
+++ b/src/Compiler/Checking/CheckExpressions.fsi
@@ -126,7 +126,6 @@ val TcFieldInit: range -> ILFieldInit -> Const
val LightweightTcValForUsingInBuildMethodCall:
g: TcGlobals -> vref: ValRef -> vrefFlags: ValUseFlag -> vrefTypeInst: TTypes -> m: range -> Expr * TType
-
/// Indicates whether a syntactic type is allowed to include new type variables
/// not declared anywhere, e.g. `let f (x: 'T option) = x.Value`
type ImplicitlyBoundTyparsAllowed =
diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs
index fb8a19805d1..4994564a954 100644
--- a/src/Compiler/CodeGen/IlxGen.fs
+++ b/src/Compiler/CodeGen/IlxGen.fs
@@ -4921,7 +4921,7 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
let stepConst =
match stepExpr with
- | Some(Expr.Const (Const.Int32 i, _, _)) when i <> 0 -> Some i
+ | Some (Expr.Const (Const.Int32 i, _, _)) when i <> 0 -> Some i
| _ -> None
let finishIdx, stepIdx, eenvinner =
@@ -4999,7 +4999,7 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
// v++ or v--
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- match stepExpr with
+ match stepExpr with
| None ->
match dir with
| FSharpForLoopUp
@@ -5034,7 +5034,7 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
GenGetLocalVal cenv cgbuf eenvinner e2.Range v None
- match stepExpr with
+ match stepExpr with
| None ->
match dir with
| FSharpForLoopUp
@@ -5078,7 +5078,6 @@ and GenIntegerForLoop cenv cgbuf eenv (spFor, spTo, v, e1, dir, e2, loopBody, st
CmpThenBrOrContinue(pop 2, [ I_brcmp(BI_bge, inner.CodeLabel) ])
|> GenSequel cenv eenv.cloc cgbuf
-
// .finish - loop-exit here
CG.SetMarkToHere cgbuf finish