diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 90d41fbf19b..7e03c3bf43e 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -370,6 +370,7 @@ impl PartialEqWithEngines for IntrinsicFunctionExpression { pub struct WhileLoopExpression { pub condition: Box, pub body: CodeBlock, + pub is_desugared_for_loop: bool, } impl EqWithEngines for WhileLoopExpression {} diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 3d6204c46ce..3d4d5259ec1 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -506,9 +506,18 @@ impl ty::TyExpression { arguments, span, ), - ExpressionKind::WhileLoop(WhileLoopExpression { condition, body }) => { - Self::type_check_while_loop(handler, ctx.by_ref(), condition, body, span) - } + ExpressionKind::WhileLoop(WhileLoopExpression { + condition, + body, + is_desugared_for_loop, + }) => Self::type_check_while_loop( + handler, + ctx.by_ref(), + condition, + body, + *is_desugared_for_loop, + span, + ), ExpressionKind::ForLoop(ForLoopExpression { desugared }) => { Self::type_check_for_loop(handler, ctx.by_ref(), desugared) } @@ -2131,6 +2140,7 @@ impl ty::TyExpression { mut ctx: TypeCheckContext, condition: &Expression, body: &CodeBlock, + is_desugared_for_loop: bool, span: Span, ) -> Result { let type_engine = ctx.engines.te(); @@ -2144,11 +2154,17 @@ impl ty::TyExpression { }; let unit_ty = type_engine.id_of_unit(); - let mut ctx = ctx.with_type_annotation(unit_ty).with_help_text( - "A while loop's loop body cannot implicitly return a value. Try \ + let mut ctx = ctx + .with_type_annotation(unit_ty) + .with_help_text(if is_desugared_for_loop { + "A for loop's loop body cannot implicitly return a value. Try \ assigning it to a mutable variable declared outside of the loop \ - instead.", - ); + instead." + } else { + "A while loop's loop body cannot implicitly return a value. Try \ + assigning it to a mutable variable declared outside of the loop \ + instead." + }); let typed_body = ty::TyCodeBlock::type_check(handler, ctx.by_ref(), body, false)?; let exp = ty::TyExpression { diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index fd3fb725089..cf3f8daab71 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -2131,6 +2131,7 @@ fn expr_to_expression( kind: ExpressionKind::WhileLoop(WhileLoopExpression { condition: Box::new(expr_to_expression(context, handler, engines, *condition)?), body: braced_code_block_contents_to_code_block(context, handler, engines, block)?, + is_desugared_for_loop: false, }), span, }, @@ -3278,6 +3279,7 @@ fn for_expr_to_expression( span: Span::dummy(), }), body: while_body, + is_desugared_for_loop: true, }), span: Span::dummy(), }), diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock new file mode 100644 index 00000000000..cc167580e1e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-FF35018BB7DF2595" + +[[package]] +name = "for_loop_error" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-FF35018BB7DF2595" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml new file mode 100644 index 00000000000..700b97ff4e3 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +name = "for_loop_error" +entry = "main.sw" + +[dependencies] +std = { path = "../../../reduced_std_libs/sway-lib-std-vec" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json new file mode 100644 index 00000000000..0637a088a01 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw new file mode 100644 index 00000000000..5c3f883c10d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw @@ -0,0 +1,12 @@ +script; + +fn main() { + let mut v : Vec = Vec::new(); + v.push(1); + v.push(2); + v.push(3); + for elem in v.iter() { + log(elem); + 3 + }; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml new file mode 100644 index 00000000000..e738a23e98e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml @@ -0,0 +1,13 @@ +category = "fail" + +# check: $()3 +# nextln: $()Mismatched types. +# nextln: $()expected: () +# nextln: $()found: numeric. +# nextln: $()Implicit return must match up with block's type. + +# check: $()3 +# nextln: $()Mismatched types. +# nextln: $()expected: () +# nextln: $()found: numeric. +# nextln: $()A for loop's loop body cannot implicitly return a value. Try assigning it to a mutable variable declared outside of the loop instead. \ No newline at end of file