Copy-and-update of a let mutable struct record loses the unchanged fields

Aperta
#5,253 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
65/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
fsharp, javascript
Ambito
compilers

Direzione di ricerca

Start from the copy-and-update ({ mark with S = ... }) case in the compiler, where a let mutable local of a [<Struct>] record is wrapped in an FSharpRef and the unchanged fields are read from the wrapper. Reproduce with the Mark example in the issue and compare the emitted JavaScript with the non-struct output, which reads mark.T directly. Done when the struct case emits mark.T and the sample prints 1 c; 2 c.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

When the source of a copy-and-update expression is a let mutable local of a [<Struct>] record type, the generated code wraps the local in an FSharpRef and reads the unchanged fields from the ref object, which doesn’t have them. Every field not named in the with comes out undefined. A reference record, or an immutable struct local, compiles correctly.

[<Struct>]
type Mark = { T: float; S: string }

let copies () =
    let mutable mark = { T = 1.0; S = "a" }
    let out = ResizeArray()

    for i in 1..2 do
        mark <- { T = float i; S = "b" }
        out.Add { mark with S = "c" }

    out |> Seq.map (fun m -> sprintf "%g %s" m.T m.S) |> String.concat "; "

printfn "%s" (copies ())

Under .NET 10, output is as expected 1 c; 2 c. For Fable 5.26.0, output is undefined c; undefined c. When [<Struct>] is removed from Mark, the correct result 1 c; 2 c will be emitted.

The emitted JavaScript reads the unchanged field from an FSharpRef wrapped around the local not from the local itself.

mark = (new Mark(i, "b"));
void (out.push(new Mark((new FSharpRef(() => mark, (v) => {
    mark = v; })).T, "c")));

FSharpRef exposes the value as .contents and has no T accessor, hence the field is undefined. Without [<Struct>] the same line is new Mark(mark.T, "c").

Lingua principale
F#
Stelle
3.2k
Fork
335
Merge medio
18h 11m
PR unite (30g)
152

Preparare l'ambiente

Apri in Codespaces

Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.

  • Nessun Dockerfile né file Docker Compose
  • Nessun modello di pull request
  • Nessuna guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di fable-compiler/Fable

Tutte le issue di fable-compiler/Fable

Issue simili

Altre issue su Compilers

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.