RCA: Bool/Int result of an intrinsic function (e.g. `read_loss` behind `MResetZChecked`) is treated as constant; heralded code is dropped
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 35/100
Research direction
Start by tracing how RCA assigns value kinds to intrinsic function results, especially when an argument is dynamic but constant; the issue identifies __quantum__rt__read_loss, MResetZChecked, and @SimulatableIntrinsic as affected paths. Use the M3 repro to check whether the heralded X remains in QIR under Adaptive_RI and Adaptive_RIF, and compare with the listed panic cases. Done means runtime Bool and Int results stay dynamic through control flow and mutable reads across the reported profiles.
Written by the indexing model from the issue text.
Description
Summary
RCA gives the output of every intrinsic function the kind Dynamic { value_kind: Constant } when an argument is dynamic but "constant", which is the kind a measured Result has. This covers __quantum__rt__read_loss, which is behind the public MResetZChecked and IsLossResult, and user @SimulatableIntrinsic functions. The returned Bool/Int is a runtime value. Because RCA does not mark it Variable, an if on it opens no dynamic scope, and a mutable set inside stays Static. Partial evaluation still branches at run time, but later folds reads of that mutable at compile time. The effects are:
- the QIR records a constant instead of the runtime value;
- heralded gates are removed;
- three different panics occur in partial evaluation and RIR.
Affected profiles:
MResetZChecked: Adaptive_RI and Adaptive_RIF. On Adaptive the programs happen to give the right value: the mutable is kept in a stack variable and the comparison is computed at run time.- Direct
read_losscall or a user intrinsic: Adaptive_RI, Adaptive_RIF and Adaptive.
At the end of this issue there is a question for the RCA owners about the right rule.
Minimal repro
M3, heralded correction dropped (Main()). The X(t), applied only when q was not lost, is removed from the QIR on Adaptive_RI/RIF:
import Std.Measurement.*;
operation Main() : (Bool, Result) {
use (q, t) = (Qubit(), Qubit());
let (_, lost) = MResetZChecked(q);
mutable n = 0;
if not lost { set n = 5; }
if n == 5 { X(t); }
(lost, MResetZ(t))
}
M1, wrong value on every shot where the qubit is not lost (Main(), Adaptive_RI/RIF):
import Std.Measurement.*;
operation Main() : (Result, Bool) {
use q = Qubit();
let (r, lost) = MResetZChecked(q);
mutable y = 0;
if lost { set y = 1; }
(r, y == 0)
}
M4, a user intrinsic, wrong on all three profiles (Main()):
@SimulatableIntrinsic()
function IsOneExt(r : Result) : Bool { r == One }
operation Main() : Bool {
use q = Qubit();
X(q);
mutable n = 0;
if IsOneExt(MResetZ(q)) { set n = 5; }
n == 5
}
Other variants (same cause), with the entry point used:
// M2: direct read_loss call, wrong on all three profiles; Main()
import QIR.Runtime.__quantum__rt__read_loss;
operation Main() : Bool {
use q = Qubit();
let lost = __quantum__rt__read_loss(MResetZ(q));
mutable y = 0;
if lost { set y = 1; }
y == 0
}
// P1: panic, counting the shots that were not lost; Main()
import Std.Measurement.*;
operation Main() : Int {
use q = Qubit();
let (_, lost) = MResetZChecked(q);
mutable good = 0;
if not lost { set good += 1; }
good + 0
}
// P2: panic, an intrinsic Int used as an array index; Main()
@SimulatableIntrinsic()
function CountExt(r : Result) : Int { r == One ? 1 | 0 }
operation Main() : Int {
use q = Qubit();
X(q);
let k = CountExt(MResetZ(q));
let arr = [10, 20, 30];
arr[k]
}
More variants of the same family:
M5: anorwhose left operand is a loss flag. This has the shape of #3976, but #3977 alone does not fix it (see below).M6: a nestedifon a negated loss flag.math_dcandmath_dc_dbl: the value passed throughMaxIorIntAsDoublebefore the test.P1b: a loss count in aforloop.P3: the count used as a range bound.
Sources of the other variants
// M5; Main()
import QIR.Runtime.__quantum__rt__read_loss;
operation Main() : (Int, Bool) {
use q = Qubit();
let lost = __quantum__rt__read_loss(MResetZ(q));
mutable n = 0;
let _ = lost or { set n = 6; true };
(n, n == 6)
}
// M6; Prog(true)
import Std.Measurement.*;
import QIR.Runtime.__quantum__rt__read_loss;
operation Prog(x0 : Bool) : (Result, Int, Bool) {
use (q0, q1) = (Qubit(), Qubit());
if x0 { X(q0); }
let r = MResetZ(q0);
mutable zo = -1;
mutable bo = false;
if r == One {
let x = not __quantum__rt__read_loss(MResetZ(q1));
mutable z = 0;
if x { set z = 1; }
set zo = z;
set bo = z == 1;
}
(r, zo, bo)
}
// math_dc; Main() (math_dc_dbl: `let d = IntAsDouble(CountExt(MResetZ(q)));` and `if d > 0.5`)
import Std.Math.*;
import Std.Convert.*;
@SimulatableIntrinsic()
function CountExt(r : Result) : Int { r == One ? 1 | 0 }
operation Main() : Bool {
use q = Qubit();
X(q);
let k = CountExt(MResetZ(q));
let m = MaxI(k, 0);
mutable n = 0;
if m == 1 { set n = 5; }
n == 5
}
// P1b; Main()
import Std.Measurement.*;
operation Main() : Int {
use qs = Qubit[2];
mutable good = 0;
for q in qs {
let (_, lost) = MResetZChecked(q);
if not lost { set good += 1; }
}
good
}
// P3; Main()
import Std.Measurement.*;
operation Main() : (Result, Result) {
use (q, t) = (Qubit(), Qubit());
X(q);
let (r, lost) = MResetZChecked(q);
mutable n = 0;
if not lost { set n = 1; }
for _ in 1..n { X(t); }
(r, MResetZ(t))
}
The script is a variant of check.py from #4001 (python check_new3.py prog.qs "Main()"; needs pip install qdk qirrunner). qir-runner 0.9.7 cannot link __quantum__rt__read_loss or user intrinsics, so the script gives them bodies before running the QIR:
read_lossreturnsfalse, meaning no loss, as in the simulator.IsOneExtandCountExtread the measured result.
The wrong answers do not depend on these stubs: for M1, M2 and M4 the QIR records the constant false directly (shown after the table).
check_new3.py
import re
import sys
import qirrunner
from qdk import Context, TargetProfile
# qir-runner 0.9.7 cannot link __quantum__rt__read_loss or user intrinsics, so
# give them bodies before running: read_loss returns false (no loss, as in the
# simulator); the test intrinsics IsOneExt/CountExt read the measured result.
STUBS = {
"__quantum__rt__read_loss": "ret i1 false",
"IsOneExt": "%v = call i1 @__quantum__qis__read_result__body(PTR %a0)\n ret i1 %v",
"CountExt": "%v = call i1 @__quantum__qis__read_result__body(PTR %a0)\n"
" %w = zext i1 %v to i64\n ret i64 %w",
}
def stub(qir):
ptr = "%Result*" if "%Result*" in qir else "ptr"
for name, body in STUBS.items():
m = re.search(rf"^declare (?:zeroext )?(i1|i64) @{name}\(([^)]*)\).*$", qir, re.M)
if m:
fn = f"define {m[1]} @{name}({m[2]} %a0) {{\n {body.replace('PTR', ptr)}\n}}"
qir = qir[: m.start()] + fn + qir[m.end() :]
if "read_result" in body and "declare i1 @__quantum__qis__read_result" not in qir:
qir += f"\ndeclare i1 @__quantum__qis__read_result__body({ptr})\n"
return qir
src, entry = open(sys.argv[1]).read(), sys.argv[2]
sim = Context(target_profile=TargetProfile.Unrestricted)
sim.eval(src)
print("simulator:", sim.run(entry, 1)[0])
for p in ["Adaptive_RI", "Adaptive_RIF", "Adaptive"]:
try:
ctx = Context(target_profile=getattr(TargetProfile, p))
ctx.eval(src)
qir = str(ctx.compile(entry))
except BaseException as e: # panics surface as PanicException
print(f"{p}: {type(e).__name__}: {str(e).splitlines()[0]}")
continue
x_gates = len(re.findall(r"call void @__quantum__qis__x__body", qir))
with open("prog.ll", "w") as f:
f.write(stub(qir))
out = qirrunner.OutputHandler()
try:
qirrunner.run("prog.ll", shots=1, output_fn=out.handle)
except BaseException as e:
print(f"{p}: qir-runner error: {str(e).splitlines()[0]}")
continue
lines = [l for l in out.get_output().splitlines() if l.startswith("OUTPUT")]
print(f"{p}:", " ".join(lines), f"[x__body calls in QIR: {x_gates}]")
Expected vs actual
On main 1b8de0d17 (identical, line for line, on the earlier main commits a90b8f777 and 48449939c and on open PR #3902 577dc9382):
| Program | Simulator (expected) | Adaptive_RI / RIF | Adaptive |
|---|---|---|---|
M3 heralded X (main repro) |
(false, One) |
(false, Zero), no X in QIR |
(false, One) (correct) |
M1 MResetZChecked |
(Zero, true) |
(Zero, false) |
(Zero, true) (correct) |
| M4 user intrinsic | true |
false |
false |
M2 direct read_loss |
true |
false |
false |
M5 or with loss left operand |
(6, true) |
(6, false) |
(6, false) |
M6 nested, Prog(true) |
(One, 1, true) |
(One, 1, false) |
(One, 1, false) |
MaxI / IntAsDouble |
true |
false |
false |
| P1 / P1b count of non-lost | 1 / 2 |
panic value is not addable: Var |
1 / 2 (correct) |
P2 intrinsic Int as index |
20 |
panic Unexpected advanced instruction at BlockId(0), instruction 4 |
20 (correct) |
| P3 count as range bound | (One, One) |
panic value should be Int, got Var |
UseOfDynamicRange (rejected) |
Script output (qir-runner 0.9.7, 1 shot each)
### M3 Main()
simulator: (False, One)
Adaptive_RI: OUTPUT TUPLE 2 0_t OUTPUT BOOL false 1_t0b OUTPUT RESULT 0 2_t1r [x__body calls in QIR: 0]
Adaptive_RIF: OUTPUT TUPLE 2 0_t OUTPUT BOOL false 1_t0b OUTPUT RESULT 0 2_t1r [x__body calls in QIR: 0]
Adaptive: OUTPUT TUPLE 2 0_t OUTPUT BOOL false 1_t0b OUTPUT RESULT 1 2_t1r [x__body calls in QIR: 1]
### M1 Main()
simulator: (Zero, True)
Adaptive_RI: OUTPUT TUPLE 2 0_t OUTPUT RESULT 0 1_t0r OUTPUT BOOL false 2_t1b [x__body calls in QIR: 0]
Adaptive_RIF: OUTPUT TUPLE 2 0_t OUTPUT RESULT 0 1_t0r OUTPUT BOOL false 2_t1b [x__body calls in QIR: 0]
Adaptive: OUTPUT TUPLE 2 0_t OUTPUT RESULT 0 1_t0r OUTPUT BOOL true 2_t1b [x__body calls in QIR: 0]
### M2 Main()
simulator: True
Adaptive_RI: OUTPUT BOOL false 0_b [x__body calls in QIR: 0]
Adaptive_RIF: OUTPUT BOOL false 0_b [x__body calls in QIR: 0]
Adaptive: OUTPUT BOOL false 0_b [x__body calls in QIR: 0]
### M4 Main()
simulator: True
Adaptive_RI: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
Adaptive_RIF: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
Adaptive: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
### M5 Main()
simulator: (6, True)
Adaptive_RI: OUTPUT TUPLE 2 0_t OUTPUT INT 6 1_t0i OUTPUT BOOL false 2_t1b [x__body calls in QIR: 0]
Adaptive_RIF: OUTPUT TUPLE 2 0_t OUTPUT INT 6 1_t0i OUTPUT BOOL false 2_t1b [x__body calls in QIR: 0]
Adaptive: OUTPUT TUPLE 2 0_t OUTPUT INT 6 1_t0i OUTPUT BOOL false 2_t1b [x__body calls in QIR: 0]
### M6 Prog(true)
simulator: (One, 1, True)
Adaptive_RI: OUTPUT TUPLE 3 0_t OUTPUT RESULT 1 1_t0r OUTPUT INT 1 2_t1i OUTPUT BOOL false 3_t2b [x__body calls in QIR: 1]
Adaptive_RIF: OUTPUT TUPLE 3 0_t OUTPUT RESULT 1 1_t0r OUTPUT INT 1 2_t1i OUTPUT BOOL false 3_t2b [x__body calls in QIR: 1]
Adaptive: OUTPUT TUPLE 3 0_t OUTPUT RESULT 1 1_t0r OUTPUT INT 1 2_t1i OUTPUT BOOL false 3_t2b [x__body calls in QIR: 1]
### math_dc Main()
simulator: True
Adaptive_RI: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
Adaptive_RIF: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
Adaptive: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
### math_dc_dbl Main()
simulator: True
Adaptive_RI: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
Adaptive_RIF: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
Adaptive: OUTPUT BOOL false 0_b [x__body calls in QIR: 1]
### P1 Main()
simulator: 1
Adaptive_RI: PanicException: value is not addable: Var
Adaptive_RIF: PanicException: value is not addable: Var
Adaptive: OUTPUT INT 1 0_i [x__body calls in QIR: 0]
### P1b Main()
simulator: 2
Adaptive_RI: PanicException: value is not addable: Var
Adaptive_RIF: PanicException: value is not addable: Var
Adaptive: OUTPUT INT 2 0_i [x__body calls in QIR: 0]
### P2 Main()
simulator: 20
Adaptive_RI: PanicException: Unexpected advanced instruction at BlockId(0), instruction 4
Adaptive_RIF: PanicException: Unexpected advanced instruction at BlockId(0), instruction 4
Adaptive: OUTPUT INT 20 0_i [x__body calls in QIR: 1]
### P3 Main()
simulator: (One, One)
Adaptive_RI: PanicException: value should be Int, got Var
Adaptive_RIF: PanicException: value should be Int, got Var
Adaptive: QSharpError: Qdk.Qsc.CapabilitiesCk.UseOfDynamicRange (https://aka.ms/qdk.qir#use-of-dynamic-range)
Stub-independent evidence: the argument of bool_record_output in the compiled QIR, before any stub:
M1 Adaptive_RI: bool_record_output argument = ['i1 zeroext false']
M1 Adaptive_RIF: bool_record_output argument = ['i1 zeroext false']
M1 Adaptive: bool_record_output argument = ['i1 zeroext %var_5']
M2 (all three): bool_record_output argument = ['i1 zeroext false']
M4 (all three): bool_record_output argument = ['i1 zeroext false']
For M1, the QIR does branch on %var_0 = call i1 @__quantum__rt__read_loss(...), and it builds a phi for y. It then records the literal false for y == 0 instead of using that phi.
The same shows in the RIR that partial evaluation produces, before any QIR or SSA pass (M2's shape, on main):
Block 0:Block:
Call id(1), args( Pointer, )
Call id(2), args( Qubit(0), Result(0), )
Variable(0, Boolean) = Call id(3), args( Result(0), )
Variable(1, Boolean) = Store Variable(0, Boolean)
Variable(2, Integer) = Store Integer(0)
Branch Variable(1, Boolean), 2, 1
Block 1:Block:
Call id(4), args( Bool(false), Tag(0, 3), )
Return Integer(0)
Block 2:Block:
Variable(2, Integer) = Store Integer(1)
Jump(1)
The branch on read_loss is emitted and block 2 stores 1 into y, but block 1 records the folded Bool(false). In RCA, __quantum__rt__read_loss(M(q)) and a user IsOneExt(M(q)) both get value_kind: Constant.
Root cause
derive_intrinsic_function_application_generator_setgives an intrinsic function's output the "constant" applicationDynamic { runtime_features: empty, value_kind: Constant }when its argument is dynamic but constant (qsc_rca/src/core.rs#L2562-L2620; theconstantarm is lines 2604–2607). A measuredResultis such an argument. Intrinsic and@SimulatableIntrinsiccallables reach this path throughanalyze_intrinsic_callable(core.rs#L1509).- Intrinsic operations do it differently: their output is
Variableunless it isUnit,QubitorResult(core.rs#L2644-L2653). analyze_expr_ifpushes a dynamic scope only for aVariablecondition (core.rs#L771-L778). Sosetinsideif lost { … }leaves the mutable Static.- Partial evaluation evaluates the condition and emits a runtime branch (
qsc_partial_eval/src/lib.rs#L2530-L2538). It then evaluates the Static uses after the merge classically. This produces the literalfalsein the QIR, the foldedn == 5, and the panics when a Static use meets a runtimeVar. - Because the kind carries no runtime-feature flags, capability checks are bypassed as well:
math_dc_dblcompiles a runtimeDoublecomparison on Adaptive_RI (and gives the wrong answer), where the same comparison on aVariablevalue is rejected withUseOfDynamicDouble;- P2 indexes an array with a runtime
Inton Adaptive_RI/RIF, whereUseOfDynamicIndexis expected; it panics in RIR instead.
- The RCA side is confirmed by tests, and the folding of the Static uses by the RIR above; the exact code path inside
qsc_partial_evalis from reading.
History (from earlier runs on these commits):
| Version | M1, M2 | M3, M4, M6 | M5 |
|---|---|---|---|
95c039f (before #3885) |
wrong | ok | ok |
45d8e3038 (#3885) |
wrong | wrong | ok |
96388a0da (#3887) and later |
wrong | wrong | wrong |
At 95c039f the path not taken was already wrong; #3885 moved the error to the taken path. The family therefore predates #3885 and #3887, and reverting either would not fix it. Loss support (read_loss, MResetZChecked, IsLossResult) arrived in #2567.
Possible fixes
- Proposal: in
derive_intrinsic_function_application_generator_set, give theconstantparameter application the output kindVariable(by type, withValueKind::new_variable_from_type) unless the output type isUnit,QubitorResult. This is the rule intrinsic operations already use. A function of a measuredResultis a runtime value, even though theResultitself is a static ID. - Push a dynamic scope in
analyze_expr_iffor any non-Static condition, not onlyVariableones. This fixes theifshapes only. The capability checks ofmath_dc_dbl, P2 and P3 would still be bypassed, because the value itself would still beConstant. - Make partial evaluation reject (
Error::Unexpected) a runtime fork on a condition that RCA did not classify asVariable, as it already does forwhile. This turns wrong answers into compile errors but does not make the programs compile.
Why option 1 seems right.
- It makes RCA agree with what partial evaluation does. The
Resultargument reaches partial evaluation as aResultID, whichis_static_valuetreats as not static (qsc_partial_eval/src/lib.rs#L5021-L5032). So the call is emitted to the target and returns a fresh runtime variable (eval_expr_call_to_intrinsic, same file, L1892-L2041). Option 1 gives that variable the RCA kindVariable. - It changes behaviour only where an intrinsic function gets a
Resultargument. From reading:derive_arg_compute_kinds(core.rs#L1665-L1691) turns every dynamic-constant argument that is not aResult(or array) intoStaticbefore the application is computed, so the changedconstantarm is reached only forResult-typed arguments (and for captured lambda arguments, which skip that step). Array parameters use a different application, which is unchanged. In particular, the math intrinsics (Cos,Sqrt,IntAsDouble, …) never take aResult, so their behaviour does not change. This was checked with a probe that passes an operation'sDoubleresult toCos: the output is the same on main and with the fix.
Prototype of option 1 (on main a90b8f777; qsc_rca and qsc_partial_eval are unchanged on main 1b8de0d17): the core.rs change plus 3 new tests, which all fail without the change:
qsc_rcatests::calls::check_rca_for_call_to_intrinsic_function_with_measured_result_argument(user@SimulatableIntrinsicfunction) andcheck_rca_for_call_to_read_loss_with_measured_result_argument: the call is nowvalue_kind: Variable(wasConstant).qsc_partial_evaltests::intrinsics::branch_on_read_loss_of_measured_result_keeps_dynamic_value_of_mutable: block 1 now loadsy, compares it with0and records that variable, instead ofBool(false).
Existing tests that change: 16 qsc_rca tests in tests/intrinsics.rs (check_rca_for_{arc_cos, arc_sin, arc_tan, arc_tan_2, begin_estimate_caching, cos, cosh, int_as_big_int, int_as_double, log, sin, sinh, sqrt, tan, tanh, truncate}). They print each intrinsic function's generator set. The whole change is 18 lines, each constant: … value_kind: Constant becoming value_kind: Variable (ArcTan2 and BeginEstimateCaching have 2 parameters). This is exactly the changed arm, and, as argued above, it is not reached for these functions' parameter types. No other expectation changes.
Results with option 1, with a qdk wheel built from the prototype:
| Program | Main (1b8de0d17) |
With option 1 |
|---|---|---|
M1, M2, M3, M4, M6, math_dc |
wrong (as in the table) | correct on Adaptive_RI, Adaptive_RIF and Adaptive |
| P1, P1b | panic on Adaptive_RI/RIF | correct (1, 2) on all three |
math_dc_dbl |
wrong on all three | UseOfDynamicDouble on Adaptive_RI; correct on Adaptive_RIF, Adaptive |
| P2 | panic on Adaptive_RI/RIF | UseOfDynamicIndex on Adaptive_RI/RIF; 20 on Adaptive (unchanged) |
| P3 | panic on Adaptive_RI/RIF | UseOfDynamicRange on all three (Adaptive unchanged) |
M5 (or with loss flag) |
wrong on all three | still wrong: (6, false); needs #3977 as well |
The rejections are the expected capability errors for a runtime Double, a runtime index and a runtime range on these profiles. With the prototype, cargo test of qsc_rca, qsc_partial_eval, qsc_passes and qsc_codegen passes, and clippy (-D warnings) and cargo fmt are clean.
Relation to #3977. With #3977 alone (head 6228ff9ee), all 12 programs behave as on main, M5 included. With #3977 plus option 1, M5 is correct on all three profiles ((6, true)) and the other rows are as with option 1 alone; cargo test of qsc_codegen, qsc_partial_eval, qsc_passes and qsc_rca (254, 426, 475, 317 passed) and qsc --lib (494 passed, 1 ignored) pass, and clippy and fmt are clean. So this bug is independent of #3976, and M5 needs both fixes.
Not covered by option 1: an Int returned by a user operation (operation GetK(q : Qubit) : Int { X(q); X(q); 1 }) passed to a user intrinsic function. It is wrong (false, expected true) on Adaptive_RI/RIF both on main and with option 1. RCA gives PosExt(GetK(q)) the kind value_kind: Constant, because derive_arg_compute_kinds turns the non-Result argument into Static. But partial evaluation still emits a runtime call to PosExt and branches on its result. From reading, the cause is that partial evaluation folds intrinsic functions only for a fixed list of names (the math functions, IntAsDouble, …) and emits a call for every other intrinsic function, whatever its arguments. With a literal argument (PosExt(1)) the program is rejected with PartialEval.EvaluationFailed on main and with option 1, so only the "dynamic but constant" argument is miscompiled. A complete fix would also make RCA classify any call to an intrinsic function that partial evaluation does not fold as Variable when the call is dynamic. We did not prototype this.
How it was found
While proving properties of a formal model of the lowering: the proof needed the invariant "a Dynamic(Constant) value never hides a runtime Bool/Int", and its counterexample turned out to be reachable in qdk through intrinsic functions. Random differential testing did not find it: our generator's only runtime Bool is MResetZ(q) == One, and it has no intrinsic calls.
Related issues
- #3283 (closed): "Arguments that are 'Dynamic Constant' treated as 'Static' across callable boundaries". It is the same kind confusion, but at a different site: callable arguments, not intrinsic-function outputs.
- #3610 (open): "Add PEEK_LOSS functionality to Q# / QASM", for loss-checking APIs. Programs using it will meet this bug.
- #3750 (closed):
Result.Lossin callable-object compiles. This is a different bug. - #3976 / #3977: M5 has the
and/orshape, but needs this fix as well. - No existing issue found for this bug. Searches: "MResetZChecked", "read_loss", "IsLossResult", "SimulatableIntrinsic", "intrinsic function constant", "Dynamic Constant", "value is not addable", "Unexpected advanced instruction", "value should be Int, got Var".
Question for the RCA owners
Option 1 changes RCA's rule for intrinsic functions: their output on a dynamic-constant argument (a measured Result) becomes Variable, as is already the rule for intrinsic operations. This changes the printed generator sets in 16 tests in qsc_rca/src/tests/intrinsics.rs (Constant → Variable in the constant application of Cos, IntAsDouble, …); from reading, behaviour changes only for Result arguments.
Is that the rule you want? Or would you prefer option 2 (a dynamic scope for any non-Static if condition) or option 3 (partial evaluation rejects such forks)? Also, the variant with an operation's Int result passed to a user intrinsic function is not fixed by any of these; should it be tracked in this issue? I will open the PR once you confirm.
- Dominant language
- Rust
- Stars
- 1k
- Forks
- 219
- Avg merge
- 3d 19h
- Merged PRs (30d)
- 93
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/qdk
-
bug needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
[Samples] Investigate redundant CheckMay be free again @theARCania claimed this 41 days ago, and no pull request is open. Openenhancement good first issue low-priority
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
microsoft/qdk#1933 · 4 comments ·
Maintainers usually reply within 1 day
-
Fuzz: "" (ubuntu-latest)Possibly taken @swernli claimed this today. Openbug
microsoft/qdk#4019 · 1 assignee ·
Maintainers usually reply within 1 day
-
RCA: `set () = { … }` drops its value's dynamic kind; code is lostPossibly taken @domorale claimed this 1 day ago. Openbug needs triage
Difficulty 4/5 3-5 days Newbie friendliness 20/100
Maintainers usually reply within 1 day
-
FIR `tuple_decompose`: `{ set p = new P { … } }` (an assignment without a semicolon) panics with `LocalVarId consistency: … not bound`Possibly taken @domorale claimed this 1 day ago. Openbug needs triage
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
foxglove/mcap#1907 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 66/100
Maintainers usually reply within 1 day
-
good first issue help wanted r-feature
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
servo/rust-smallvec#792 ·
Maintainers usually reply within 1 day
-
A-Unicode C-bug P-low
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
rust-lang/rustfmt#7210 · 1 comment ·
Maintainers usually reply within 1 day
-
callTracer with withLog: true includes logs from a reverted top-level call (diverges from geth)Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
paradigmxyz/revm-inspectors#570 ·
Maintainers usually reply within 1 day