diff --git a/compiler/qsc_partial_eval/tests/bindings.rs b/compiler/qsc_partial_eval/tests/bindings.rs index 568dd0452b..c55f568255 100644 --- a/compiler/qsc_partial_eval/tests/bindings.rs +++ b/compiler/qsc_partial_eval/tests/bindings.rs @@ -397,3 +397,89 @@ fn mutable_int_binding_does_generate_store_instruction() { Jump(1)"#]], ); } + +#[test] +fn mutable_variable_in_outer_scope_set_to_mutable_from_inner_scope() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Int { + use q = Qubit(); + mutable i = 0; + if MResetZ(q) == One { + mutable j = 1; + set i = j; + } + else { + set i = 2; + } + return i; + } + } + "#, + }); + + let measurement_callable_id = CallableId(1); + assert_callable( + &program, + measurement_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: "#]], + ); + let read_result_callable_id = CallableId(2); + assert_callable( + &program, + read_result_callable_id, + &expect![[r#" + Callable: + name: __quantum__qis__read_result__body + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: "#]], + ); + let output_recording_callable_id = CallableId(3); + assert_callable( + &program, + output_recording_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__int_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: "#]], + ); + assert_blocks( + &program, + &expect![[r#" + Blocks: + Block 0:Block: + Variable(0, Integer) = Store Integer(0) + Call id(1), args( Qubit(0), Result(0), ) + Variable(1, Boolean) = Call id(2), args( Result(0), ) + Variable(2, Boolean) = Store Variable(1, Boolean) + Branch Variable(2, Boolean), 2, 3 + Block 1:Block: + Call id(3), args( Variable(0, Integer), Pointer, ) + Return + Block 2:Block: + Variable(3, Integer) = Store Integer(1) + Variable(0, Integer) = Store Integer(1) + Jump(1) + Block 3:Block: + Variable(0, Integer) = Store Integer(2) + Jump(1)"#]], + ); +} diff --git a/compiler/qsc_rir/src/passes/ssa_transform.rs b/compiler/qsc_rir/src/passes/ssa_transform.rs index 38be3936dc..040adad607 100644 --- a/compiler/qsc_rir/src/passes/ssa_transform.rs +++ b/compiler/qsc_rir/src/passes/ssa_transform.rs @@ -59,10 +59,10 @@ pub fn transform_to_ssa(program: &mut Program, preds: &IndexMap *operand, + None => { + // If the variable is not defined in this predecessor, it does not dominate this block. + // Assume it is not used and skip creating a phi node for this variable. If the variable is used, + // the ssa check will detect it and panic later. + continue 'var_loop; + } + }; pred_operand = pred_operand.mapped(pred_var_map); phi_args.push((pred_operand, *pred)); }