Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ impl Elaborator<'_> {
}

if i + 1 == statements.len() {
block_type = if is_break_or_continue { Type::Unit } else { stmt_type };
block_type = stmt_type;
}
}

Expand Down
4 changes: 1 addition & 3 deletions compiler/noirc_frontend/src/elaborator/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,6 @@ impl Elaborator<'_> {
self.current_loop = Some(Loop { is_for: true, has_break: false });
self.push_scope();

// TODO: For loop variables are currently mutable by default since we haven't
// yet implemented syntax for them to be optionally mutable.
let kind = DefinitionKind::Local(None);
let identifier = self.add_variable_decl(
identifier, false, // mutable
Expand Down Expand Up @@ -346,7 +344,7 @@ impl Elaborator<'_> {
}

let expr = if is_break { HirStatement::Break } else { HirStatement::Continue };
(expr, self.interner.next_type_variable())
(expr, Type::Unit)
}

fn get_lvalue_error_info(&self, lvalue: &HirLValue) -> (DefinitionId, String, Location) {
Expand Down
140 changes: 140 additions & 0 deletions compiler/noirc_frontend/src/tests/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,62 @@ fn resolve_for_expr_incl() {
assert_no_errors(src);
}

#[test]
fn for_loop_empty_range() {
let src = r#"
fn main() {
let mut x = 0;
for _i in 0..0 {
x = 1;
}
assert(x == 0);
}
"#;
assert_no_errors(src);
}

#[test]
fn for_loop_backwards_range() {
let src = r#"
fn main() {
let mut x = 0;
for _i in 10..5 {
x = 1;
}
assert(x == 0);
}
"#;
assert_no_errors(src);
}

#[test]
fn for_loop_single_elem_inclusive_max_value() {
let src = r#"
fn main() {
let mut count = 0;
for i in 4294967295..=4294967295 {
count += 1;
let _x: u32 = i;
}
assert(count == 1);
}
"#;
assert_no_errors(src);
}

#[test]
fn for_loop_mutate_induction_var() {
let src = r#"
fn main() {
for i in 0..10 {
i = 5;
^ Variable `i` must be mutable to be assigned to
}
}
"#;
check_errors(src);
}

#[test]
fn break_and_continue_outside_loop() {
let src = r#"
Expand Down Expand Up @@ -138,6 +194,56 @@ fn errors_on_loop_without_break_with_nested_loop() {
check_errors(src);
}

#[test]
fn break_in_nested_and_outer_loops() {
let src = r#"
unconstrained fn main() {
let mut x = 1;
loop {
x += 1;
loop {
x += 2;
break; // Breaks from nested loop only
}
if x > 2 {
break; // Breaks from outer loop
}
}
}
"#;
assert_no_errors(src);
}

#[test]
fn continue_in_loop() {
let src = r#"
unconstrained fn main() {
let mut x = 0;
loop {
x += 1;
if x < 5 {
continue;
}
break;
}

for i in 0..10 {
if i == 5 {
continue;
}
}

while x > 0 {
x -= 1;
if x == 3 {
continue;
}
}
}
"#;
assert_no_errors(src);
}

#[test]
fn errors_if_for_body_type_is_not_unit() {
let src = r#"
Expand Down Expand Up @@ -190,3 +296,37 @@ fn overflowing_int_in_for_loop() {
"#;
check_errors(src);
}

#[test]
fn break_type_mismatch() {
let src = r#"
unconstrained fn main() {
loop {
if true {
break;
} else {
5
^ Expected type (), found type Field
};
}
}
"#;
check_errors(src);
}

#[test]
fn continue_type_mismatch() {
let src = r#"
unconstrained fn main() {
for _ in 0..1 {
if true {
continue;
} else {
5
^ Expected type (), found type Field
}
}
}
"#;
check_errors(src);
}
Loading