Skip to content

Commit 5ce894c

Browse files
authored
Allow implicit cast to non-const in binary exprs. (#2430)
This PR fixes an issue in casting where the following code was treated as an error. ``` int x = 5; int y = 2 * x; ``` The issue was that `2` is a constant, and the casting system wasn't allowing `x`, of type `int`, which isn't a constant to be cast to the type of `2`, which is `const int`. The fix consists in allowing the type of the binary expression as a whole to be demoted to a non-const type.
1 parent 2744b7c commit 5ce894c

File tree

3 files changed

+81
-13
lines changed

3 files changed

+81
-13
lines changed

compiler/qsc_qasm/src/semantic/tests/expression/binary/arithmetic_conversions.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,77 @@ fn left_shift_casts_rhs_to_uint() {
306306
"#]],
307307
);
308308
}
309+
310+
#[test]
311+
fn bin_op_with_const_lhs_and_non_const_rhs() {
312+
let source = "
313+
int x = 5;
314+
int y = 2 * x;
315+
";
316+
317+
check_stmt_kinds(
318+
source,
319+
&expect![[r#"
320+
ClassicalDeclarationStmt [9-19]:
321+
symbol_id: 8
322+
ty_span: [9-12]
323+
init_expr: Expr [17-18]:
324+
ty: int
325+
kind: Lit: Int(5)
326+
ClassicalDeclarationStmt [28-42]:
327+
symbol_id: 9
328+
ty_span: [28-31]
329+
init_expr: Expr [36-41]:
330+
ty: int
331+
kind: BinaryOpExpr:
332+
op: Mul
333+
lhs: Expr [36-37]:
334+
ty: const int
335+
kind: Lit: Int(2)
336+
rhs: Expr [40-41]:
337+
ty: int
338+
kind: SymbolId(8)
339+
"#]],
340+
);
341+
}
342+
343+
#[test]
344+
fn bin_op_with_const_lhs_and_non_const_rhs_sized() {
345+
let source = "
346+
int[32] x = 5;
347+
int[32] y = 2 * x;
348+
";
349+
350+
check_stmt_kinds(
351+
source,
352+
&expect![[r#"
353+
ClassicalDeclarationStmt [9-23]:
354+
symbol_id: 8
355+
ty_span: [9-16]
356+
init_expr: Expr [21-22]:
357+
ty: const int[32]
358+
kind: Lit: Int(5)
359+
ClassicalDeclarationStmt [32-50]:
360+
symbol_id: 9
361+
ty_span: [32-39]
362+
init_expr: Expr [44-49]:
363+
ty: int[32]
364+
kind: Cast [0-0]:
365+
ty: int[32]
366+
expr: Expr [44-49]:
367+
ty: int
368+
kind: BinaryOpExpr:
369+
op: Mul
370+
lhs: Expr [44-45]:
371+
ty: const int
372+
kind: Lit: Int(2)
373+
rhs: Expr [48-49]:
374+
ty: int
375+
kind: Cast [0-0]:
376+
ty: int
377+
expr: Expr [48-49]:
378+
ty: int[32]
379+
kind: SymbolId(8)
380+
"#]],
381+
);
382+
}

compiler/qsc_qasm/src/semantic/types.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,9 +712,13 @@ fn get_effective_width(lhs_ty: &Type, rhs_ty: &Type) -> Option<u32> {
712712
/// If the types are not compatible, the result is `Type::Void`.
713713
#[must_use]
714714
pub fn promote_types(lhs_ty: &Type, rhs_ty: &Type) -> Type {
715-
if types_equal_except_const(lhs_ty, rhs_ty) {
715+
if *lhs_ty == *rhs_ty {
716716
return lhs_ty.clone();
717717
}
718+
if types_equal_except_const(lhs_ty, rhs_ty) {
719+
// If one of the types is non-const, we return the type as non-const.
720+
return lhs_ty.as_non_const();
721+
}
718722
let ty = promote_types_symmetric(lhs_ty, rhs_ty);
719723
if ty != Type::Void {
720724
return ty;

compiler/qsc_qasm/src/tests/statement/const_eval.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,23 +1843,13 @@ fn binary_op_non_const_type_fails() {
18431843
let errs: Vec<_> = errs.iter().map(|e| format!("{e:?}")).collect();
18441844
let errs_string = errs.join("\n");
18451845
expect![[r#"
1846-
Qasm.Lowerer.CannotCast
1847-
1848-
x cannot cast expression of type int to type const int
1849-
,-[Test.qasm:4:17]
1850-
3 | int b = 3;
1851-
4 | int[a + b] x = 2;
1852-
: ^
1853-
5 |
1854-
`----
1855-
18561846
Qasm.Lowerer.ExprMustBeConst
18571847
18581848
x expression must be const
1859-
,-[Test.qasm:4:17]
1849+
,-[Test.qasm:4:13]
18601850
3 | int b = 3;
18611851
4 | int[a + b] x = 2;
1862-
: ^
1852+
: ^^^^^
18631853
5 |
18641854
`----
18651855
"#]]

0 commit comments

Comments
 (0)