Skip to content

Commit 91c296d

Browse files
authored
Fix explicit types in for loops (#2440)
This fixes a long hidden bug where using explicit types in a for loop (technically supported because the loop binding variable is parsed as a pattern just like bindings for let-stmts and callable params) would cause the type for the binding to be unknown and propagate as an error type through the code.
1 parent 2fe6296 commit 91c296d

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

compiler/qsc_frontend/src/resolve.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,7 @@ impl With<'_> {
12901290
/// Apply `f` to self while a pattern's constituent identifiers are in scope. Removes those
12911291
/// identifiers from the scope after `f`.
12921292
fn with_pat(&mut self, span: Span, kind: ScopeKind, pat: &ast::Pat, f: impl FnOnce(&mut Self)) {
1293+
self.visit_pat(pat);
12931294
self.with_scope(span, kind, |visitor| {
12941295
// The bindings are valid from the beginning of the scope
12951296
visitor.resolver.bind_pat(pat, span.lo);

compiler/qsc_frontend/src/resolve/tests.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,30 @@ fn for_loop_var() {
15891589
);
15901590
}
15911591

1592+
#[test]
1593+
fn for_loop_explicit_type() {
1594+
check(
1595+
indoc! {"
1596+
namespace Foo {
1597+
function A() : Unit {
1598+
for i : Int in 0..9 {
1599+
let _ = i;
1600+
}
1601+
}
1602+
}
1603+
"},
1604+
&expect![[r#"
1605+
namespace namespace3 {
1606+
function item1() : Unit {
1607+
for local14 : Int in 0..9 {
1608+
let _ = local14;
1609+
}
1610+
}
1611+
}
1612+
"#]],
1613+
);
1614+
}
1615+
15921616
#[test]
15931617
fn repeat_until() {
15941618
check(

compiler/qsc_frontend/src/typeck/tests.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,53 @@ fn return_semi() {
242242
);
243243
}
244244

245+
#[test]
246+
fn explicit_type_in_let_binding() {
247+
check(
248+
"",
249+
"{ let x : Int = 4; }",
250+
&expect![[r##"
251+
#1 0-20 "{ let x : Int = 4; }" : Unit
252+
#2 0-20 "{ let x : Int = 4; }" : Unit
253+
#4 6-13 "x : Int" : Int
254+
#9 16-17 "4" : Int
255+
"##]],
256+
);
257+
}
258+
259+
#[test]
260+
fn incorrect_explicit_type_in_let_binding_error() {
261+
check(
262+
"",
263+
"{ let x : Int = 4.0; }",
264+
&expect![[r##"
265+
#1 0-22 "{ let x : Int = 4.0; }" : Unit
266+
#2 0-22 "{ let x : Int = 4.0; }" : Unit
267+
#4 6-13 "x : Int" : Int
268+
#9 16-19 "4.0" : Double
269+
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 16, hi: 19 }))))
270+
"##]],
271+
);
272+
}
273+
274+
#[test]
275+
fn incorrect_explicit_type_in_let_binding_used_later_correctly() {
276+
check(
277+
"",
278+
"{ let x : Int = 4.0; x + 1}",
279+
&expect![[r##"
280+
#1 0-27 "{ let x : Int = 4.0; x + 1}" : Int
281+
#2 0-27 "{ let x : Int = 4.0; x + 1}" : Int
282+
#4 6-13 "x : Int" : Int
283+
#9 16-19 "4.0" : Double
284+
#11 21-26 "x + 1" : Int
285+
#12 21-22 "x" : Int
286+
#15 25-26 "1" : Int
287+
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 16, hi: 19 }))))
288+
"##]],
289+
);
290+
}
291+
245292
#[test]
246293
fn return_var() {
247294
check(
@@ -929,6 +976,41 @@ fn for_loop_body_should_be_unit_error() {
929976
);
930977
}
931978

979+
#[test]
980+
fn for_loop_correct_explicit_type_works() {
981+
check(
982+
"",
983+
"for i : Int in 0..1 { i; }",
984+
&expect![[r##"
985+
#1 0-26 "for i : Int in 0..1 { i; }" : Unit
986+
#2 4-11 "i : Int" : Int
987+
#7 15-19 "0..1" : Range
988+
#8 15-16 "0" : Int
989+
#9 18-19 "1" : Int
990+
#10 20-26 "{ i; }" : Unit
991+
#12 22-23 "i" : Int
992+
"##]],
993+
);
994+
}
995+
996+
#[test]
997+
fn for_loop_incorrect_explicit_type_error() {
998+
check(
999+
"",
1000+
"for i : Double in 0..1 { i; }",
1001+
&expect![[r##"
1002+
#1 0-29 "for i : Double in 0..1 { i; }" : Unit
1003+
#2 4-14 "i : Double" : Double
1004+
#7 18-22 "0..1" : Range
1005+
#8 18-19 "0" : Int
1006+
#9 21-22 "1" : Int
1007+
#10 23-29 "{ i; }" : Unit
1008+
#12 25-26 "i" : Double
1009+
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 18, hi: 22 }))))
1010+
"##]],
1011+
);
1012+
}
1013+
9321014
#[test]
9331015
fn repeat_loop_non_bool_condition_error() {
9341016
check(

0 commit comments

Comments
 (0)