Record spreads: { ...expr }, { ...ty } - #18927
Conversation
❗ Release notes requiredYou can open this PR in browser to add release notes: open in github.dev
|
|
Amazing work! I was literally asking @edgarfgp a few days ago if we had something like |
|
@brianrourkeboll Great to see work starting in this direction! |
e66b7a6 to
c61dbf4
Compare
6dd4f0b to
d181c97
Compare
b43fc1d to
46998d6
Compare
|
I believe the state of the art so far has indeed been to duplicate the .bsl files due to it. Brainstorming:
Right it is IlxGen which adds it conditionally, leading to differences in IL. Alternative approach which I see I have used at: Is to assert only a subset of the .bsl, not the full file (IMO this could be encoded into the framework if we want to - like a |
This is fine - we would only need a split if there is anything hinting a different decision path, such as ilimport, dependency on attributes, or ilxgen. Right now there is neither of that. We might later want an overall end to end scenario just as a smoke test for the desktop compiler, which is what is running in Visual Studio - more as a proof of overall stability. |
brianrourkeboll
left a comment
There was a problem hiding this comment.
Ha, these can go back.
86ff984 to
4817822
Compare
04e303a to
2f57763
Compare
In this test, I don't think I understand why the two synthesized fields should have distinct declaration locations. The current declaration location for both is [<Fact>]
let ``spread - synthesized fields have distinct DeclarationLocations`` () =
let _, checkResults =
getParseAndCheckResultsPreview """
type R1 = { A : int; B : int }
type R2 = { ...R1; C : int }
"""
let r2 = findSymbolByName "R2" checkResults :?> FSharpEntity
let r2A = r2.FSharpFields |> Seq.find (fun f -> f.Name = "A")
let r2B = r2.FSharpFields |> Seq.find (fun f -> f.Name = "B")
if getRangeCoords r2A.DeclarationLocation = getRangeCoords r2B.DeclarationLocation then
failwith $"Expected spread-synthesized fields A and B to have distinct DeclarationLocations, but both are %A{getRangeCoords r2A.DeclarationLocation}." |
95fcfda to
63d606a
Compare
{ ...expr }, { ...ty } for records{ ...expr }, { ...ty }
f344df1 to
1bc322b
Compare
|
@dsyme, @auduchinok: this and the RFC are ready for review, if you are interested in weighing in. |
1bc322b to
1c47d59
Compare

Description
Adds language support for record-to-record type and expression spreads.
This PR implements an independently useful record-to-record subset of the broader "spreads for F#" language suggestion: fsharp/fslang-suggestions#1253.
Checklist
...used in places that don't yet support it (e.g.,seq { ...xs })Feature overview
I hope that the tests can serve as a reasonable overview of the feature and its behavior. If you see any glaring omissions, or if the tests are unclear or incomplete, please let me know. (I see that I still need to add tests for coercions/conversions…)
Parsing & error recovery
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 46 to 244 in 1bc322b
Record type spreads: set algebra
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 247 to 400 in 1bc322b
Record type spreads: accessibility
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 402 to 428 in 1bc322b
Record type spreads: mutability
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 430 to 445 in 1bc322b
Record type spreads: generic type parameters
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 447 to 641 in 1bc322b
Record type spreads: non-record source (not allowed)
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 643 to 740 in 1bc322b
Record type spreads: members other than record fields
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 742 to 776 in 1bc322b
Record type spreads: recursion (cycles not allowed)
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 778 to 1002 in 1bc322b
Record type spreads: nullability
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1004 to 1020 in 1bc322b
Record type spreads: allowed (but not required) in signature files
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1022 to 1037 in 1bc322b
Record type spreads: structness depends on target type
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1039 to 1059 in 1bc322b
Anonymous record expression spreads: set algebra
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1062 to 1226 in 1bc322b
Anonymous record expression spreads: accessibility
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1228 to 1244 in 1bc322b
Anonymous record expression spreads: mutability
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1246 to 1264 in 1bc322b
Anonymous record expression spreads: generic type parameters
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1266 to 1321 in 1bc322b
Anonymous record expression spreads: non-record-source (not currently allowed)
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1323 to 1457 in 1bc322b
Anonymous record expression spreads: non-field members on record sources are ignored
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1459 to 1511 in 1bc322b
Anonymous record expression spreads: effects
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1513 to 1534 in 1bc322b
Anonymous record expression spreads: conversions and coercions
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1614 to 1650 in 1bc322b
Anonymous record expression spreads: nullability
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1652 to 1669 in 1bc322b
Anonymous record expression spreads: inference
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1671 to 1690 in 1bc322b
Anonymous record expression spreads: structness
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1692 to 1723 in 1bc322b
Anonymous record expression spreads: nested updates
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1725 to 1839 in 1bc322b
Nominal record expression spreads: set algebra
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 1842 to 2000 in 1bc322b
Nominal record expression spreads: accessibility
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2002 to 2020 in 1bc322b
Nominal record expression spreads: non-record source (not currently allowed)
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2022 to 2156 in 1bc322b
Nominal record expression spreads: non-field members on record sources are ignored
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2158 to 2209 in 1bc322b
Nominal record expression spreads: effects
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2211 to 2234 in 1bc322b
Nominal record expression spreads: conversions and coercions
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2236 to 2282 in 1bc322b
Nominal record expression spreads: nullability
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2284 to 2305 in 1bc322b
Nominal record expression spreads: target type inference
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2307 to 2367 in 1bc322b
Nominal record expression spreads: structness
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2369 to 2395 in 1bc322b
Nominal record expression spreads: nested updates
fsharp/tests/FSharp.Compiler.ComponentTests/Language/RecordSpreadsTests.fs
Lines 2417 to 2551 in 1bc322b