Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

RCA: `set () = { … }` drops its value's dynamic kind; code is lost

Aperta
#4,002 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@domorale ci sta già lavorando.

Dal 22/10/2026.

  • #4004 di @domorale — aperta

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
20/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Ferma
Stack tecnologico
rust
Ambito
compilers

Direzione di ricerca

Start with qsc_rca/src/core.rs, especially analyze_expr_assign around lines 149–171, and trace how assignment kinds are computed from the assignee and value. The issue reports that an open pull request (#4004) already addresses this bug. The described fix should restore dynamic features for assignments to (); the two repros should then produce 5 and true on Adaptive_RI, Adaptive_RIF, and Adaptive.

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

Descrizione

bug needs triage

Summary

RCA computes the kind of an assignment only from the locals it updates. set () = … updates no local, so the statement is Static even when its value contains measurement-dependent code. Partial evaluation then evaluates the block classically: a store into a mutable and gates inside the block are silently dropped. This gives wrong results on Adaptive_RI, Adaptive_RIF and Adaptive.

Minimal repro

operation Main() : Int {
    use q = Qubit();
    X(q);
    let d = MResetZ(q) == One;
    mutable z = 3;
    set () = { if d { set z = 5; } () };   // assigns nothing; means: if d { set z = 5; }
    return z;
}

Gate variant (the X(t) is dropped):

operation Main() : Bool {
    use (q, t) = (Qubit(), Qubit());
    X(q);
    let d = MResetZ(q) == One;
    set () = { if d { X(t); } () };
    return MResetZ(t) == One;
}

Run with python check.py prog.qs "Main()"; check.py is in #4001. It runs the program on the simulator, then compiles it for Adaptive_RI, Adaptive_RIF and Adaptive and runs the QIR with qir-runner, one shot each.

Expected vs actual

Program Simulator (expected) Adaptive_RI / Adaptive_RIF / Adaptive
store 5 3
gate variant true false

Output on main 1b8de0d17 (same on the earlier main commits a90b8f777 and 48449939c and on open PR #3902 577dc9382; qir-runner 0.9.7):

### store
simulator: 5
Adaptive_RI: OUTPUT	INT	3	0_i
Adaptive_RIF: OUTPUT	INT	3	0_i
Adaptive: OUTPUT	INT	3	0_i
### gate variant
simulator: True
Adaptive_RI: OUTPUT	BOOL	false	0_b
Adaptive_RIF: OUTPUT	BOOL	false	0_b
Adaptive: OUTPUT	BOOL	false	0_b

The results are the same with #3977 (head 6228ff9ee): that PR does not change this path.

Root cause

analyze_expr_assign builds the statement's kind only from update_locals_compute_kind, the kind of the locals in the assignee (qsc_rca/src/core.rs#L149-L171, lines 160–169). With the assignee (), no local is updated, so the value's runtime features are discarded and the statement is Static.

History (Adaptive_RI): at #3733 (95c039f4b) and #3885 (45d8e3038) both programs were rejected with PartialEval.EvaluationFailed; since #3887 (96388a0da) they compile and give the wrong answer.

Suggested fix

In analyze_expr_assign, also aggregate the value expression's runtime features into the assignment's kind. For an assignee without () parts this adds nothing new, since the value's kind already reaches the statement through the updated locals (reasoned; consistent with no existing expect-test changing); for () (or a tuple with a () element) it restores the value's dynamic features.

I have this implemented (9 lines in core.rs, plus tests) and will open a PR. With it, the repros give 5 and true on Adaptive_RI, Adaptive_RIF and Adaptive. It is independent of #3977 and merges with it without conflicts.

How it was found

While proving properties of a formal model of the lowering: the proof required the kind of an assignment to include the kind of its value. Random differential testing did not find it (our program generator has no set ()).

Related issues

  • No existing issue found. Searches: "set () unit", "unit tuple assignment", "assign to unit", "set () unit tuple", "assign unit tuple dynamic".
  • #3887: the partial-evaluation change after which these programs compile to wrong QIR instead of being rejected.
  • #3976 / #3977: a different RCA bug in the right operand of a dynamic and/or; #3977 does not fix this one.
Lingua principale
Rust
Stelle
1k
Fork
219
Merge medio
3g 19h
PR unite (30g)
92

Preparare l'ambiente

Apri in Codespaces

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

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 microsoft/qdk

Tutte le issue di microsoft/qdk

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.