diff --git a/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/lit_abort.exp b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/lit_abort.exp new file mode 100644 index 0000000000000..fc5a4436b29d4 --- /dev/null +++ b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/lit_abort.exp @@ -0,0 +1 @@ +processed 3 tasks diff --git a/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/lit_abort.move b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/lit_abort.move new file mode 100644 index 0000000000000..111d0963957b4 --- /dev/null +++ b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/lit_abort.move @@ -0,0 +1,19 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public fun from_index(index: u64): u64 { + match (index) { + 0 => 1, + 1 => 2, + 2 => 3, + _ => abort 0, + } + } + + public fun run() { + assert!(from_index(2) == 3) + } +} + +//# run 0x42::m::run diff --git a/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/struct_abort.exp b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/struct_abort.exp new file mode 100644 index 0000000000000..fc5a4436b29d4 --- /dev/null +++ b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/struct_abort.exp @@ -0,0 +1 @@ +processed 3 tasks diff --git a/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/struct_abort.move b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/struct_abort.move new file mode 100644 index 0000000000000..c3d9bf35fa146 --- /dev/null +++ b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/struct_abort.move @@ -0,0 +1,19 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public struct S has drop { x: u64 } + + public fun from_index(s: S): u64 { + match (s) { + S { x: 0} => 1, + _ => abort 0, + } + } + + public fun run() { + assert!(from_index(S { x: 0 }) == 1) + } +} + +//# run 0x42::m::run diff --git a/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_abort.exp b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_abort.exp new file mode 100644 index 0000000000000..fc5a4436b29d4 --- /dev/null +++ b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_abort.exp @@ -0,0 +1 @@ +processed 3 tasks diff --git a/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_abort.move b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_abort.move new file mode 100644 index 0000000000000..58a37086695b9 --- /dev/null +++ b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_abort.move @@ -0,0 +1,17 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public fun test(value: bool): u64 { + match (value) { + true => abort 0, + false => 0, + } + } + + public fun run() { + assert!(test(false) == 0) + } +} + +//# run 0x42::m::run diff --git a/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_nested_abort.exp b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_nested_abort.exp new file mode 100644 index 0000000000000..fc5a4436b29d4 --- /dev/null +++ b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_nested_abort.exp @@ -0,0 +1 @@ +processed 3 tasks diff --git a/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_nested_abort.move b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_nested_abort.move new file mode 100644 index 0000000000000..8449e4e069a9e --- /dev/null +++ b/external-crates/move/crates/move-compiler-transactional-tests/tests/matching/true_false_nested_abort.move @@ -0,0 +1,17 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public fun test(value: bool): u64 { + match (value) { + true => match (value) { true => abort 0, false => abort 0 }, + false => match (value) { true => abort 0, false => 1 }, + } + } + + public fun run() { + assert!(test(false) == 1) + } +} + +//# run 0x42::m::run diff --git a/external-crates/move/crates/move-compiler/src/hlir/detect_dead_code.rs b/external-crates/move/crates/move-compiler/src/hlir/detect_dead_code.rs index df536f57c9a7a..881be586e4a47 100644 --- a/external-crates/move/crates/move-compiler/src/hlir/detect_dead_code.rs +++ b/external-crates/move/crates/move-compiler/src/hlir/detect_dead_code.rs @@ -309,8 +309,10 @@ fn tail(context: &mut Context, e: &T::Exp) -> Option { }; let conseq_flow = tail(context, conseq); let alt_flow = tail(context, alt); + if matches!(ty, sp!(_, N::Type_::Unit | N::Type_::Anything)) { + return None; + }; match (conseq_flow, alt_flow) { - _ if matches!(ty, sp!(_, N::Type_::Unit)) => None, (Some(cflow), Some(aflow)) => { if cflow.value == aflow.value { context.report_tail_error(sp(*eloc, cflow.value)); @@ -340,6 +342,13 @@ fn tail(context: &mut Context, e: &T::Exp) -> Option { tail(context, &arm.rhs) }) .collect::>(); + if matches!(ty, sp!(_, N::Type_::Unit | N::Type_::Anything)) + || arms.value.iter().all(|sp!(_, arm)| { + matches!(arm.rhs.ty, sp!(_, N::Type_::Unit | N::Type_::Anything)) + }) + { + return None; + }; if arm_somes.iter().all(|arm_opt| arm_opt.is_some()) { for arm_opt in arm_somes { let sp!(aloc, arm_error) = arm_opt.unwrap(); diff --git a/external-crates/move/crates/move-compiler/src/hlir/match_compilation.rs b/external-crates/move/crates/move-compiler/src/hlir/match_compilation.rs index df12006c03ad6..2ffad708230e8 100644 --- a/external-crates/move/crates/move-compiler/src/hlir/match_compilation.rs +++ b/external-crates/move/crates/move-compiler/src/hlir/match_compilation.rs @@ -592,11 +592,11 @@ fn resolve_result( let true_arm = resolve_result(context, init_subject, true_arm_result); let false_arm = resolve_result(context, init_subject, false_arm_result); - let result_type = true_arm.ty.clone(); + let result_ty = context.output_type().clone(); make_copy_bindings( bindings, - make_if_else(lit_subject, true_arm, false_arm, result_type), + make_if_else(lit_subject, true_arm, false_arm, result_ty), ) } WorkResult::LiteralSwitch { @@ -622,7 +622,7 @@ fn resolve_result( let work_result = context.work_result(result_ndx); let match_arm = resolve_result(context, init_subject, work_result); let test_exp = make_lit_test(lit_subject.clone(), key); - let result_ty = out_exp.ty.clone(); + let result_ty = context.output_type().clone(); out_exp = make_if_else(test_exp, match_arm, out_exp, result_ty); } make_copy_bindings(bindings, out_exp) diff --git a/external-crates/move/crates/move-compiler/tests/linter/move_2024/unneeded_return_branch.exp b/external-crates/move/crates/move-compiler/tests/linter/move_2024/unneeded_return_branch.exp index dc2b298b92718..c6b514b6023e4 100644 --- a/external-crates/move/crates/move-compiler/tests/linter/move_2024/unneeded_return_branch.exp +++ b/external-crates/move/crates/move-compiler/tests/linter/move_2024/unneeded_return_branch.exp @@ -6,14 +6,6 @@ warning[Lint W04004]: unneeded return │ = This warning can be suppressed with '#[allow(lint(unneeded_return))]' applied to the 'module' or module member ('const', 'fun', or 'struct') -warning[W09005]: dead or unreachable code - ┌─ tests/linter/move_2024/unneeded_return_branch.move:5:35 - │ -5 │ if (cond) { return 5 } else { abort ZERO } - │ ^^^^^^^^^^ Unreachable code. This statement (and any following statements) will not be executed. - │ - = This warning can be suppressed with '#[allow(dead_code)]' applied to the 'module' or module member ('const', 'fun', or 'struct') - warning[Lint W04004]: unneeded return ┌─ tests/linter/move_2024/unneeded_return_branch.move:9:17 │ @@ -97,14 +89,6 @@ warning[Lint W04004]: unneeded return │ = This warning can be suppressed with '#[allow(lint(unneeded_return))]' applied to the 'module' or module member ('const', 'fun', or 'struct') -warning[W09005]: dead or unreachable code - ┌─ tests/linter/move_2024/unneeded_return_branch.move:53:18 - │ -53 │ E::V1 => abort ZERO, - │ ^^^^^^^^^^ Unreachable code. This statement (and any following statements) will not be executed. - │ - = This warning can be suppressed with '#[allow(dead_code)]' applied to the 'module' or module member ('const', 'fun', or 'struct') - warning[Lint W04004]: unneeded return ┌─ tests/linter/move_2024/unneeded_return_branch.move:58:5 │ diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/hlir/abort_pair.exp b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/abort_pair.exp new file mode 100644 index 0000000000000..11213a0f76c3a --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/abort_pair.exp @@ -0,0 +1,8 @@ +warning[W09005]: dead or unreachable code + ┌─ tests/move_2024/hlir/abort_pair.move:4:6 + │ +4 │ (abort 0, abort 0) + │ ^^^^^^^ Expected a value. Any code surrounding or after this expression will not be reached + │ + = This warning can be suppressed with '#[allow(dead_code)]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/hlir/abort_pair.move b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/abort_pair.move new file mode 100644 index 0000000000000..f416443e6b3f4 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/abort_pair.move @@ -0,0 +1,5 @@ +module 0x42::m; + +public fun test(): (u64, u64) { + (abort 0, abort 0) +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/hlir/determine_error.move b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/determine_error.move new file mode 100644 index 0000000000000..3837f8d4c83a5 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/determine_error.move @@ -0,0 +1,5 @@ +module 0x42::m; + +public fun report_from_value(code: u64) { + if (code < 10) abort 0 else abort 1 +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort.move b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort.move new file mode 100644 index 0000000000000..13eecec8415de --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort.move @@ -0,0 +1,9 @@ +module 0x42::m; + +fun test() { + if (true) { + if (true) abort 0 else abort 0 + } else { + if (true) abort 0 else abort 0 + } +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort_statement.exp b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort_statement.exp new file mode 100644 index 0000000000000..bfba37c67fe59 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort_statement.exp @@ -0,0 +1,16 @@ +warning[W09005]: dead or unreachable code + ┌─ tests/move_2024/hlir/nested_if_abort_statement.move:5:9 + │ +5 │ if (true) abort 0 else abort 0 + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Expected a value. Any code surrounding or after this expression will not be reached + │ + = This warning can be suppressed with '#[allow(dead_code)]' applied to the 'module' or module member ('const', 'fun', or 'struct') + +warning[W09005]: dead or unreachable code + ┌─ tests/move_2024/hlir/nested_if_abort_statement.move:7:9 + │ +7 │ if (true) abort 0 else abort 0 + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Expected a value. Any code surrounding or after this expression will not be reached + │ + = This warning can be suppressed with '#[allow(dead_code)]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort_statement.move b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort_statement.move new file mode 100644 index 0000000000000..112fe2d7381db --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/nested_if_abort_statement.move @@ -0,0 +1,10 @@ +module 0x42::m; + +fun test(): u64 { + let x: u64 = if (true) { + if (true) abort 0 else abort 0 + } else { + if (true) abort 0 else abort 0 + }; + x +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/hlir/true_false_nested_abort.move b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/true_false_nested_abort.move new file mode 100644 index 0000000000000..8449e4e069a9e --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/hlir/true_false_nested_abort.move @@ -0,0 +1,17 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public fun test(value: bool): u64 { + match (value) { + true => match (value) { true => abort 0, false => abort 0 }, + false => match (value) { true => abort 0, false => 1 }, + } + } + + public fun run() { + assert!(test(false) == 1) + } +} + +//# run 0x42::m::run diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/matching/lit_abort.move b/external-crates/move/crates/move-compiler/tests/move_2024/matching/lit_abort.move new file mode 100644 index 0000000000000..111d0963957b4 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/matching/lit_abort.move @@ -0,0 +1,19 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public fun from_index(index: u64): u64 { + match (index) { + 0 => 1, + 1 => 2, + 2 => 3, + _ => abort 0, + } + } + + public fun run() { + assert!(from_index(2) == 3) + } +} + +//# run 0x42::m::run diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/matching/struct_abort.move b/external-crates/move/crates/move-compiler/tests/move_2024/matching/struct_abort.move new file mode 100644 index 0000000000000..c3d9bf35fa146 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/matching/struct_abort.move @@ -0,0 +1,19 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public struct S has drop { x: u64 } + + public fun from_index(s: S): u64 { + match (s) { + S { x: 0} => 1, + _ => abort 0, + } + } + + public fun run() { + assert!(from_index(S { x: 0 }) == 1) + } +} + +//# run 0x42::m::run diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/matching/true_false_abort.move b/external-crates/move/crates/move-compiler/tests/move_2024/matching/true_false_abort.move new file mode 100644 index 0000000000000..58a37086695b9 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/matching/true_false_abort.move @@ -0,0 +1,17 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public fun test(value: bool): u64 { + match (value) { + true => abort 0, + false => 0, + } + } + + public fun run() { + assert!(test(false) == 0) + } +} + +//# run 0x42::m::run diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/matching/true_false_nested_abort.move b/external-crates/move/crates/move-compiler/tests/move_2024/matching/true_false_nested_abort.move new file mode 100644 index 0000000000000..8449e4e069a9e --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/matching/true_false_nested_abort.move @@ -0,0 +1,17 @@ +//# init --edition 2024.beta + +//# publish +module 0x42::m { + public fun test(value: bool): u64 { + match (value) { + true => match (value) { true => abort 0, false => abort 0 }, + false => match (value) { true => abort 0, false => 1 }, + } + } + + public fun run() { + assert!(test(false) == 1) + } +} + +//# run 0x42::m::run