diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 5c444bd4fd3..e3beae168a3 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -1,5 +1,6 @@ ### Fixed * Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877)) +* Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280)) * Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)== * Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238)) * Cancellable: only cancel on OCE with own token ([PR #18277](https://github.com/dotnet/fsharp/pull/18277)) diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index d2af320b8de..27e80d396be 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4273,6 +4273,19 @@ type UnionCaseRef = override x.ToString() = x.CaseName +let findLogicalFieldIndexOfRecordField (tcref:TyconRef) (id:string) = + let arr = tcref.AllFieldsArray + + // We are skipping compiler generated fields such as "init@5" from index calculation + let rec go originalIdx skippedItems = + if originalIdx >= arr.Length then error(InternalError(sprintf "field %s not found in type %s" id tcref.LogicalName, tcref.Range)) + else + let currentItem = arr[originalIdx] + if currentItem.LogicalName = id then (originalIdx-skippedItems) + else go (originalIdx + 1) (skippedItems + (if currentItem.IsCompilerGenerated && currentItem.IsStatic then 1 else 0)) + + go 0 0 + /// Represents a reference to a field in a record, class or struct [] type RecdFieldRef = @@ -4316,11 +4329,8 @@ type RecdFieldRef = member x.Index = let (RecdFieldRef(tcref, id)) = x - try - // REVIEW: this could be faster, e.g. by storing the index in the NameMap - tcref.AllFieldsArray |> Array.findIndex (fun rfspec -> rfspec.LogicalName = id) - with :? KeyNotFoundException -> - error(InternalError(sprintf "field %s not found in type %s" id tcref.LogicalName, tcref.Range)) + findLogicalFieldIndexOfRecordField tcref id + [] member x.DebugText = x.ToString() diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/RecordOptimizerRegression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/RecordOptimizerRegression.fs new file mode 100644 index 00000000000..1ecbe38c6f8 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/RecordOptimizerRegression.fs @@ -0,0 +1,14 @@ +module Test + +// https://github.com/dotnet/fsharp/issues/18165 + +type FooBar = + { xyz : string } + static let staticLet = 1 + +let doThing (foo : FooBar) = + let bar = { foo with xyz = foo.xyz } + let baz = { bar with xyz = bar.xyz } + printf "%O" baz + +doThing { xyz = "" } \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/StaticLetInUnionsAndRecords.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/StaticLetInUnionsAndRecords.fs index 17c7c03c808..5ce43b8db72 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/StaticLetInUnionsAndRecords.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/StaticLet/StaticLetInUnionsAndRecords.fs @@ -95,6 +95,16 @@ init R 2 1 2""" +[] +let ``Static let - record optimizer regression`` compilation = + compilation + |> withOptimize + |> verifyCompileAndRun + |> shouldSucceed + |> withStdOutContains """{ xyz = "" }""" + + + [] let ``Static let - lowercase DU`` compilation = compilation