Skip to content

Commit e428ee9

Browse files
authored
Fix panic when interpreter has unbound names in Adaptive/Base (#2691)
Fixes #2689
1 parent 9284f42 commit e428ee9

File tree

5 files changed

+119
-25
lines changed

5 files changed

+119
-25
lines changed

source/compiler/qsc/src/interpret/tests.rs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ mod given_interpreter {
167167
}
168168

169169
#[test]
170-
fn invalid_statements_and_unbound_vars_return_error() {
170+
fn invalid_statements_and_unbound_vars_return_error_on_immutable_usage() {
171171
let mut interpreter = get_interpreter();
172172

173173
let (result, output) = line(&mut interpreter, "let y = x;");
@@ -193,6 +193,87 @@ mod given_interpreter {
193193
);
194194
}
195195

196+
#[test]
197+
fn invalid_statements_and_unbound_vars_return_error_on_mutable_update() {
198+
let mut interpreter = get_interpreter();
199+
200+
let (result, output) = line(&mut interpreter, "mutable y = x;");
201+
is_only_error(
202+
&result,
203+
&output,
204+
&expect![[r#"
205+
name error: `x` not found
206+
[line_0] [x]
207+
type error: insufficient type information to infer type
208+
[line_0] [y]
209+
"#]],
210+
);
211+
212+
let (result, output) = line(&mut interpreter, "y = 3");
213+
is_only_error(
214+
&result,
215+
&output,
216+
&expect![[r#"
217+
cannot update immutable variable
218+
[line_1] [y]
219+
"#]],
220+
);
221+
}
222+
223+
#[test]
224+
fn invalid_statements_and_unbound_vars_return_error_on_immutable_usage_with_rca() {
225+
let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
226+
227+
let (result, output) = line(&mut interpreter, "let y = x;");
228+
is_only_error(
229+
&result,
230+
&output,
231+
&expect![[r#"
232+
name error: `x` not found
233+
[line_0] [x]
234+
type error: insufficient type information to infer type
235+
[line_0] [y]
236+
"#]],
237+
);
238+
239+
let (result, output) = line(&mut interpreter, "y");
240+
is_only_error(
241+
&result,
242+
&output,
243+
&expect![[r#"
244+
runtime error: name is not bound
245+
[line_1] [y]
246+
"#]],
247+
);
248+
}
249+
250+
#[test]
251+
fn invalid_statements_and_unbound_vars_return_error_on_mutable_update_with_rca() {
252+
let mut interpreter = get_interpreter_with_capabilities(TargetCapabilityFlags::empty());
253+
254+
let (result, output) = line(&mut interpreter, "mutable y = x;");
255+
is_only_error(
256+
&result,
257+
&output,
258+
&expect![[r#"
259+
name error: `x` not found
260+
[line_0] [x]
261+
type error: insufficient type information to infer type
262+
[line_0] [y]
263+
"#]],
264+
);
265+
266+
let (result, output) = line(&mut interpreter, "y = 3");
267+
is_only_error(
268+
&result,
269+
&output,
270+
&expect![[r#"
271+
cannot update immutable variable
272+
[line_1] [y]
273+
"#]],
274+
);
275+
}
276+
196277
#[test]
197278
fn failing_statements_return_early_error() {
198279
let mut interpreter = get_interpreter();

source/compiler/qsc_rca/src/applications.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -605,9 +605,27 @@ impl LocalsComputeKindMap {
605605
self.0.get(local_var_id)
606606
}
607607

608-
pub fn get_local_compute_kind(&self, local_var_id: LocalVarId) -> &LocalComputeKind {
609-
self.find_local_compute_kind(local_var_id)
610-
.expect("local compute kind does not exist")
608+
pub fn get_or_init_local_compute_kind(
609+
&mut self,
610+
local_var_id: LocalVarId,
611+
local_kind: LocalKind,
612+
compute_kind: ComputeKind,
613+
) -> &LocalComputeKind {
614+
if self.0.contains_key(local_var_id) {
615+
self.0.get(local_var_id).expect("local should exist")
616+
} else {
617+
self.0.insert(
618+
local_var_id,
619+
LocalComputeKind {
620+
local: Local {
621+
var: local_var_id,
622+
kind: local_kind,
623+
},
624+
compute_kind,
625+
},
626+
);
627+
self.0.get(local_var_id).expect("local should exist")
628+
}
611629
}
612630

613631
pub fn insert(&mut self, local_var_id: LocalVarId, value: LocalComputeKind) {

source/compiler/qsc_rca/src/common.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use std::{
2222
#[derive(Clone, Debug)]
2323
pub struct Local {
2424
pub var: LocalVarId,
25-
pub ty: Ty,
2625
pub kind: LocalKind,
2726
}
2827

@@ -57,7 +56,6 @@ pub fn initialize_locals_map(input_params: &Vec<InputParam>) -> FxHashMap<LocalV
5756
id,
5857
Local {
5958
var: id,
60-
ty: param.ty.clone(),
6159
kind: LocalKind::InputParam(param.index),
6260
},
6361
);

source/compiler/qsc_rca/src/core.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,7 @@ impl<'a> Analyzer<'a> {
468468
self.get_current_application_instance()
469469
.locals_map
470470
.find_local_compute_kind(local_var_id)
471-
.expect("local should have been processed before this")
472-
.compute_kind
471+
.map_or(ComputeKind::Classical, |v| v.compute_kind)
473472
.value_kind_or_default(ValueKind::Element(RuntimeKind::Static))
474473
})
475474
.chain(self.derive_arg_value_kinds(&arg_exprs))
@@ -1091,10 +1090,10 @@ impl<'a> Analyzer<'a> {
10911090
// Gather the current compute kind of the local.
10921091
Res::Local(local_var_id) => {
10931092
let application_instance = self.get_current_application_instance();
1094-
let local_compute_kind = application_instance
1093+
application_instance
10951094
.locals_map
1096-
.get_local_compute_kind(*local_var_id);
1097-
local_compute_kind.compute_kind
1095+
.find_local_compute_kind(*local_var_id)
1096+
.map_or(ComputeKind::Classical, |v| v.compute_kind)
10981097
}
10991098
Res::Err => panic!("unexpected error resolution"),
11001099
}
@@ -1332,15 +1331,13 @@ impl<'a> Analyzer<'a> {
13321331

13331332
fn bind_compute_kind_to_ident(
13341333
&mut self,
1335-
pat: &Pat,
13361334
ident: &Ident,
13371335
local_kind: LocalKind,
13381336
compute_kind: ComputeKind,
13391337
) {
13401338
let application_instance = self.get_current_application_instance_mut();
13411339
let local = Local {
13421340
var: ident.id,
1343-
ty: pat.ty.clone(),
13441341
kind: local_kind,
13451342
};
13461343
let local_compute_kind = LocalComputeKind {
@@ -1369,7 +1366,7 @@ impl<'a> Analyzer<'a> {
13691366
let application_instance = self.get_current_application_instance();
13701367
let expr_compute_kind = *application_instance.get_expr_compute_kind(expr_id);
13711368
let bound_compute_kind = ComputeKind::map_to_type(expr_compute_kind, &pat.ty);
1372-
self.bind_compute_kind_to_ident(pat, ident, local_kind, bound_compute_kind);
1369+
self.bind_compute_kind_to_ident(ident, local_kind, bound_compute_kind);
13731370
}
13741371
PatKind::Tuple(pats) => match &expr.kind {
13751372
ExprKind::Tuple(exprs) => {
@@ -1403,7 +1400,7 @@ impl<'a> Analyzer<'a> {
14031400
let application_instance = self.get_current_application_instance();
14041401
let expr_compute_kind = *application_instance.get_expr_compute_kind(expr_id);
14051402
let bound_compute_kind = ComputeKind::map_to_type(expr_compute_kind, &pat.ty);
1406-
self.bind_compute_kind_to_ident(pat, ident, local_kind, bound_compute_kind);
1403+
self.bind_compute_kind_to_ident(ident, local_kind, bound_compute_kind);
14071404
}
14081405
PatKind::Tuple(pats) => {
14091406
for pat_id in pats {
@@ -1569,10 +1566,14 @@ impl<'a> Analyzer<'a> {
15691566
// The updated compute kind is the aggregation of the compute kind of the local variable and the
15701567
// assigned value.
15711568
// Start by initializing the updated compute kind with the compute kind of the local variable.
1572-
let application_instance = self.get_current_application_instance();
1569+
let application_instance = self.get_current_application_instance_mut();
15731570
let local_var_compute_kind = application_instance
15741571
.locals_map
1575-
.get_local_compute_kind(*local_var_id);
1572+
.get_or_init_local_compute_kind(
1573+
*local_var_id,
1574+
LocalKind::Mutable,
1575+
ComputeKind::Classical,
1576+
);
15761577
let mut updated_compute_kind = local_var_compute_kind.compute_kind;
15771578

15781579
// Since the local variable compute kind is what will be updated, the value kind must match the local
@@ -1582,16 +1583,14 @@ impl<'a> Analyzer<'a> {
15821583
// a UDT variable field since we do not track individual UDT fields).
15831584
let value_expr_compute_kind =
15841585
*application_instance.get_expr_compute_kind(value_expr_id);
1585-
let assigned_compute_kind = ComputeKind::map_to_type(
1586-
value_expr_compute_kind,
1587-
&local_var_compute_kind.local.ty,
1588-
);
1586+
let assigned_compute_kind =
1587+
ComputeKind::map_to_type(value_expr_compute_kind, &assignee_expr.ty);
15891588
updated_compute_kind = updated_compute_kind.aggregate(assigned_compute_kind);
15901589

15911590
// If a local is updated within a dynamic scope, the updated value of the local variable should be
15921591
// dynamic and additional runtime features may apply.
15931592
if !application_instance.active_dynamic_scopes.is_empty() {
1594-
let local_type = &local_var_compute_kind.local.ty;
1593+
let local_type = &assignee_expr.ty;
15951594
let mut dynamic_value_kind = ValueKind::new_dynamic_from_type(local_type);
15961595
let mut dynamic_runtime_features =
15971596
derive_runtime_features_for_value_kind_associated_to_type(
@@ -1621,7 +1620,7 @@ impl<'a> Analyzer<'a> {
16211620
updated_quantum_properties.runtime_features |=
16221621
derive_runtime_features_for_value_kind_associated_to_type(
16231622
value_kind,
1624-
&local_var_compute_kind.local.ty,
1623+
&assignee_expr.ty,
16251624
);
16261625
}
16271626

@@ -2551,7 +2550,6 @@ fn derive_specialization_controls(
25512550
match &pat.kind {
25522551
PatKind::Bind(ident) => Some(Local {
25532552
var: ident.id,
2554-
ty: pat.ty.clone(),
25552553
kind: LocalKind::SpecInput,
25562554
}),
25572555
PatKind::Discard => None, // Nothing to bind to.

source/compiler/qsc_rca/src/cycle_detection.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ impl<'a> CycleDetector<'a> {
5959
ident.id,
6060
Local {
6161
var: ident.id,
62-
ty: pat.ty.clone(),
6362
kind,
6463
},
6564
);

0 commit comments

Comments
 (0)