Skip to content

Commit 15c05bd

Browse files
authored
Merge pull request #17723 from dotnet/merges/main-to-release/dev17.12
Merge main to release/dev17.12
2 parents 1518498 + 81cfc4d commit 15c05bd

File tree

9 files changed

+2175
-772
lines changed

9 files changed

+2175
-772
lines changed

docs/release-notes/.FSharp.Compiler.Service/9.0.100.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* Fix IsUnionCaseTester throwing for non-methods/properties [#17301](https://github.com/dotnet/fsharp/pull/17634)
1919
* Consider `open type` used when the type is an enum and any of the enum cases is used unqualified. ([PR #17628](https://github.com/dotnet/fsharp/pull/17628))
2020
* Guard for possible StackOverflowException when typechecking non recursive modules and namespaces ([PR #17654](https://github.com/dotnet/fsharp/pull/17654))
21+
* Fixes for the optimization of simple mappings in array and list comprehensions. ([Issue #17708](https://github.com/dotnet/fsharp/issues/17708), [PR #17711](https://github.com/dotnet/fsharp/pull/17711))
2122

2223
### Added
2324

eng/common/internal/Tools.csproj

+25
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,31 @@
66
<AutomaticallyUseReferenceAssemblyPackages>false</AutomaticallyUseReferenceAssemblyPackages>
77
<BuildWithNetFrameworkHostedCompiler>false</BuildWithNetFrameworkHostedCompiler>
88
</PropertyGroup>
9+
<!-- BEGIN workaround for https://github.com/dotnet/sdk/issues/43339; remove after updated to VS 17.12, future 17.11 patch or when arcade ships the the same workaround -->
10+
<Target Name="WorkaroundDotnetSdk43339" BeforeTargets="ResolvePackageAssets" Condition=" '$(MSBuildRuntimeType)' == 'Full' and $([MSBuild]::VersionLessThan($(MSBuildVersion), 17.12.0))">
11+
<PrimeSystemTextJson804 />
12+
</Target>
13+
<UsingTask
14+
TaskName="PrimeSystemTextJson804"
15+
TaskFactory="RoslynCodeTaskFactory"
16+
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
17+
<Task>
18+
<Code Type="Fragment" Language="cs">
19+
<![CDATA[
20+
try
21+
{
22+
System.Reflection.Assembly.LoadFrom(@"$(MicrosoftNETBuildTasksDirectoryRoot)\..\..\..\DotnetTools\dotnet-format\BuildHost-net472\System.Text.Json.dll");
23+
}
24+
catch
25+
{
26+
// Best effort: if something moves in the SDK don't break the build.
27+
}
28+
]]>
29+
</Code>
30+
</Task>
31+
</UsingTask>
32+
<!-- END workaround for https://github.com/dotnet/sdk/issues/43339 -->
33+
934
<ItemGroup>
1035
<!-- Clear references, the SDK may add some depending on UsuingToolXxx settings, but we only want to restore the following -->
1136
<PackageReference Remove="@(PackageReference)"/>

src/Compiler/Checking/Expressions/CheckExpressions.fs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7530,9 +7530,9 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn
75307530
let concatenableExprs = if canLower then concatenable [] fillExprs parts else []
75317531

75327532
match concatenableExprs with
7533-
| [p1; p2; p3; p4] -> mkStaticCall_String_Concat4 g m p1 p2 p3 p4, tpenv
7534-
| [p1; p2; p3] -> mkStaticCall_String_Concat3 g m p1 p2 p3, tpenv
7535-
| [p1; p2] -> mkStaticCall_String_Concat2 g m p1 p2, tpenv
7533+
| [p1; p2; p3; p4] -> TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env m (fun () -> mkStaticCall_String_Concat4 g m p1 p2 p3 p4, tpenv)
7534+
| [p1; p2; p3] -> TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env m (fun () -> mkStaticCall_String_Concat3 g m p1 p2 p3, tpenv)
7535+
| [p1; p2] -> TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env m (fun () -> mkStaticCall_String_Concat2 g m p1 p2, tpenv)
75367536
| [p1] -> p1, tpenv
75377537
| _ ->
75387538

src/Compiler/Optimize/LowerComputedCollections.fs

+63-50
Original file line numberDiff line numberDiff line change
@@ -373,60 +373,70 @@ module Array =
373373
else any ilTy
374374

375375
/// Makes the equivalent of an inlined call to Array.map.
376-
let mkMap g m (mBody, _spFor, _spIn, mFor, mIn, spInWhile) srcArray srcIlTy destIlTy overallElemTy loopVal body =
377-
let len = mkLdlen g mIn srcArray
378-
let arrayTy = mkArrayType g overallElemTy
379-
380-
/// (# "newarr !0" type ('T) count : 'T array #)
381-
let array =
382-
mkAsmExpr
383-
(
384-
[I_newarr (ILArrayShape.SingleDimensional, destIlTy)],
385-
[],
386-
[len],
387-
[arrayTy],
388-
m
389-
)
390-
391-
let ldelem = mkIlInstr g I_ldelem (fun ilTy -> I_ldelem_any (ILArrayShape.SingleDimensional, ilTy)) srcIlTy
392-
let stelem = mkIlInstr g I_stelem (fun ilTy -> I_stelem_any (ILArrayShape.SingleDimensional, ilTy)) destIlTy
393-
394-
let mapping =
395-
mkCompGenLetIn m (nameof array) arrayTy array (fun (_, array) ->
396-
mkCompGenLetMutableIn mFor "i" g.int32_ty (mkTypedZero g mIn g.int32_ty) (fun (iVal, i) ->
397-
let body =
398-
// Rebind the loop val to pull directly from the source array.
399-
let body = mkInvisibleLet mBody loopVal (mkAsmExpr ([ldelem], [], [srcArray; i], [loopVal.val_type], mBody)) body
400-
401-
// destArray[i] <- body srcArray[i]
402-
let setArrSubI = mkAsmExpr ([stelem], [], [array; i; body], [], mIn)
403-
404-
// i <- i + 1
405-
let incrI = mkValSet mIn (mkLocalValRef iVal) (mkAsmExpr ([AI_add], [], [i; mkTypedOne g mIn g.int32_ty], [g.int32_ty], mIn))
406-
407-
mkSequential mIn setArrSubI incrI
408-
409-
let guard = mkILAsmClt g mFor i (mkLdlen g mFor array)
376+
let mkMap g m (mBody, _spFor, _spIn, mFor, mIn, spInWhile) srcArray srcIlTy destIlTy overallElemTy (loopVal: Val) body =
377+
mkCompGenLetIn m (nameof srcArray) (tyOfExpr g srcArray) srcArray (fun (_, srcArray) ->
378+
let len = mkLdlen g mIn srcArray
379+
let arrayTy = mkArrayType g overallElemTy
380+
381+
/// (# "newarr !0" type ('T) count : 'T array #)
382+
let array =
383+
mkAsmExpr
384+
(
385+
[I_newarr (ILArrayShape.SingleDimensional, destIlTy)],
386+
[],
387+
[len],
388+
[arrayTy],
389+
m
390+
)
410391

411-
let loop =
412-
mkWhile
413-
g
414-
(
415-
spInWhile,
416-
NoSpecialWhileLoopMarker,
417-
guard,
418-
body,
419-
mIn
420-
)
392+
let ldelem = mkIlInstr g I_ldelem (fun ilTy -> I_ldelem_any (ILArrayShape.SingleDimensional, ilTy)) srcIlTy
393+
let stelem = mkIlInstr g I_stelem (fun ilTy -> I_stelem_any (ILArrayShape.SingleDimensional, ilTy)) destIlTy
421394

422-
// while i < array.Length do <body> done
423-
// array
424-
mkSequential m loop array
395+
let mapping =
396+
mkCompGenLetIn m (nameof array) arrayTy array (fun (_, array) ->
397+
mkCompGenLetMutableIn mFor "i" g.int32_ty (mkTypedZero g mIn g.int32_ty) (fun (iVal, i) ->
398+
let body =
399+
// If the loop val is used in the loop body,
400+
// rebind it to pull directly from the source array.
401+
// Otherwise, don't bother reading from the source array at all.
402+
let body =
403+
let freeLocals = (freeInExpr CollectLocals body).FreeLocals
404+
405+
if freeLocals.Contains loopVal then
406+
mkInvisibleLet mBody loopVal (mkAsmExpr ([ldelem], [], [srcArray; i], [loopVal.val_type], mBody)) body
407+
else
408+
body
409+
410+
// destArray[i] <- body srcArray[i]
411+
let setArrSubI = mkAsmExpr ([stelem], [], [array; i; body], [], mIn)
412+
413+
// i <- i + 1
414+
let incrI = mkValSet mIn (mkLocalValRef iVal) (mkAsmExpr ([AI_add], [], [i; mkTypedOne g mIn g.int32_ty], [g.int32_ty], mIn))
415+
416+
mkSequential mIn setArrSubI incrI
417+
418+
let guard = mkILAsmClt g mFor i (mkLdlen g mFor array)
419+
420+
let loop =
421+
mkWhile
422+
g
423+
(
424+
spInWhile,
425+
NoSpecialWhileLoopMarker,
426+
guard,
427+
body,
428+
mIn
429+
)
430+
431+
// while i < array.Length do <body> done
432+
// array
433+
mkSequential m loop array
434+
)
425435
)
426-
)
427436

428-
// Add a debug point at the `for`, before anything gets evaluated.
429-
Expr.DebugPoint (DebugPointAtLeafExpr.Yes mFor, mapping)
437+
// Add a debug point at the `for`, before anything gets evaluated.
438+
Expr.DebugPoint (DebugPointAtLeafExpr.Yes mFor, mapping)
439+
)
430440

431441
/// Whether to check for overflow when converting a value to a native int.
432442
[<NoEquality; NoComparison>]
@@ -558,6 +568,9 @@ let (|SingleYield|_|) g expr : Expr voption =
558568
| Expr.Sequential (expr1, DebugPoints (body, debug), kind, m) ->
559569
loop body (cont << fun body -> Expr.Sequential (expr1, debug body, kind, m))
560570

571+
| Expr.Match (debugPoint, mInput, decision, [|TTarget (boundVals, DebugPoints (SeqSingleton g body, debug), isStateVarFlags)|], mFull, exprType) ->
572+
ValueSome (cont (Expr.Match (debugPoint, mInput, decision, [|TTarget (boundVals, debug body, isStateVarFlags)|], mFull, exprType)))
573+
561574
| SeqSingleton g body ->
562575
ValueSome (cont body)
563576

tests/FSharp.Compiler.ComponentTests/EmittedIL/ComputedCollections/ForXInArray_ToArray.fs

+14
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,17 @@ let f8 f g (array: int array) = [|let y = f () in let z = g () in for x in array
2121
let f9 f g (array: int array) = [|let y = f () in g (); for x in array -> x + y|]
2222
let f10 f g (array: int array) = [|f (); g (); for x in array -> x|]
2323
let f11 f g (array: int array) = [|f (); let y = g () in for x in array -> x + y|]
24+
let f12 (f: unit -> int array) y = [|for x in f () -> x + y|]
25+
26+
// https://github.com/dotnet/fsharp/issues/17708
27+
// Don't read or rebind the loop variable when it is not in scope in the body.
28+
let ``for _ in Array.groupBy id [||] do ...`` () = [|for _ in Array.groupBy id [||] do 0|]
29+
let ``for _ | _ in Array.groupBy id [||] do ...`` () = [|for _ | _ in Array.groupBy id [||] do 0|]
30+
let ``for _ & _ in Array.groupBy id [||] do ...`` () = [|for _ & _ in Array.groupBy id [||] do 0|]
31+
let ``for _, _group in Array.groupBy id [||] do ...`` () = [|for _, _group in Array.groupBy id [||] do 0|]
32+
let ``for _, group in Array.groupBy id [||] do ...`` () = [|for _, group in Array.groupBy id [||] do group.Length|]
33+
let ``for 1 | 2 | _ in ...`` () = [|for 1 | 2 | _ in [||] do 0|]
34+
let ``for Failure _ | _ in ...`` () = [|for Failure _ | _ in [||] do 0|]
35+
let ``for true | false in ...`` () = [|for true | false in [||] do 0|]
36+
let ``for true | _ in ...`` () = [|for true | _ in [||] do 0|]
37+
let ``for _ | true in ...`` () = [|for _ | true in [||] do 0|]

0 commit comments

Comments
 (0)