diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index a74ba5bc7fa..cfca8482bbe 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -1331,6 +1331,7 @@ fn connect_expression<'eng: 'cfg, 'cfg>( )?; } + let mut args_diverge = false; // we evaluate every one of the function arguments for (_name, arg) in arguments { let span = arg.span.clone(); @@ -1345,6 +1346,13 @@ fn connect_expression<'eng: 'cfg, 'cfg>( span, options, )?; + + if type_engine + .get(arg.return_type) + .is_uninhabited(engines.te(), engines.de()) + { + args_diverge = true; + } } options.force_struct_fields_connection = force_struct_fields_connection; @@ -1363,16 +1371,20 @@ fn connect_expression<'eng: 'cfg, 'cfg>( } } } - // the exit points get connected to an exit node for the application - if !is_external { - if let Some(exit_node) = exit_node { - graph.add_edge(fn_exit_point, exit_node, "".into()); - Ok(vec![exit_node]) + if args_diverge { + Ok(vec![]) + } else { + // the exit points get connected to an exit node for the application + if !is_external { + if let Some(exit_node) = exit_node { + graph.add_edge(fn_exit_point, exit_node, "".into()); + Ok(vec![exit_node]) + } else { + Ok(vec![fn_exit_point]) + } } else { - Ok(vec![fn_exit_point]) + Ok(vec![fn_entrypoint]) } - } else { - Ok(vec![fn_entrypoint]) } } LazyOperator { lhs, rhs, .. } => { @@ -1711,9 +1723,17 @@ fn connect_expression<'eng: 'cfg, 'cfg>( elem_type: _, contents, } => { + let mut element_diverge = false; let nodes = contents .iter() .map(|elem| { + if !element_diverge + && type_engine + .get(elem.return_type) + .is_uninhabited(engines.te(), engines.de()) + { + element_diverge = true + } connect_expression( engines, &elem.expression, @@ -1727,7 +1747,11 @@ fn connect_expression<'eng: 'cfg, 'cfg>( ) }) .collect::, _>>()?; - Ok(nodes.concat()) + if element_diverge { + Ok(vec![]) + } else { + Ok(nodes.concat()) + } } ArrayIndex { prefix, index } => { let prefix_idx = connect_expression( @@ -1843,13 +1867,15 @@ fn connect_expression<'eng: 'cfg, 'cfg>( let while_loop_exit = graph.add_node("while loop exit".to_string().into()); - // it is possible for a whole while loop to be skipped so add edge from - // beginning of while loop straight to exit - graph.add_edge( - entry, - while_loop_exit, - "condition is initially false".into(), - ); + if !matches!(*type_engine.get(condition.return_type), TypeInfo::Never) { + // it is possible for a whole while loop to be skipped so add edge from + // beginning of while loop straight to exit + graph.add_edge( + entry, + while_loop_exit, + "condition is initially false".into(), + ); + } let mut leaves = vec![entry]; // handle the condition of the loop @@ -2087,6 +2113,7 @@ fn connect_enum_instantiation<'eng: 'cfg, 'cfg>( graph.add_edge(*leaf, enum_instantiation_entry_idx, "".into()); } + let mut is_variant_unreachable = false; // add edge from the entry of the enum instantiation to the body of the instantiation if let Some(instantiator) = contents { let instantiator_contents = connect_expression( @@ -2100,13 +2127,23 @@ fn connect_enum_instantiation<'eng: 'cfg, 'cfg>( enum_decl.span.clone(), options, )?; + if engines + .te() + .get(instantiator.return_type) + .is_uninhabited(engines.te(), engines.de()) + { + is_variant_unreachable = true; + } + for leaf in instantiator_contents { graph.add_edge(leaf, enum_instantiation_exit_idx, "".into()); } } graph.add_edge(decl_ix, variant_index, "".into()); - graph.add_edge(variant_index, enum_instantiation_exit_idx, "".into()); + if !is_variant_unreachable { + graph.add_edge(variant_index, enum_instantiation_exit_idx, "".into()); + } Ok(vec![enum_instantiation_exit_idx]) } diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index fa897f02733..e1b5fe88f9d 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -1013,6 +1013,7 @@ impl TypeInfo { let id_uninhabited = |id| type_engine.get(id).is_uninhabited(type_engine, decl_engine); match self { + TypeInfo::Never => true, TypeInfo::Enum(decl_ref) => decl_engine .get_enum(decl_ref) .variants @@ -1027,6 +1028,13 @@ impl TypeInfo { .iter() .any(|field_type| id_uninhabited(field_type.type_id)), TypeInfo::Array(elem_ty, length) => length.val() > 0 && id_uninhabited(elem_ty.type_id), + TypeInfo::Ptr(ty) => id_uninhabited(ty.type_id), + TypeInfo::Alias { name: _, ty } => id_uninhabited(ty.type_id), + TypeInfo::Slice(ty) => id_uninhabited(ty.type_id), + TypeInfo::Ref { + to_mutable_value: _, + referenced_type, + } => id_uninhabited(referenced_type.type_id), _ => false, } } diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index a9f9506d374..71562a7fb1b 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -299,6 +299,8 @@ impl TestContext { run_and_capture_output(|| harness::compile_to_bytes(&name, &run_config)).await; *output = out; + check_file_checker(checker, &name, output)?; + let compiled = result?; let compiled = match compiled { diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/return_in_strange_positions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/return_in_strange_positions/src/main.sw index 29362150164..60570e9442f 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/return_in_strange_positions/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/return_in_strange_positions/src/main.sw @@ -48,7 +48,7 @@ fn in_length_2_array_first() -> u64 { fn in_length_2_array_second() -> u64 { let _ = [0, return]; - 145 // TODO: Missing unreachable warning + 145 } fn in_tuple() -> u64 { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/break_in_strange_positions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/break_in_strange_positions/test.toml index 3e8a6c1d354..3005fe97091 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/break_in_strange_positions/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/break_in_strange_positions/test.toml @@ -1,4 +1,4 @@ category = "run" expected_result = { action = "return", value = 8193 } validate_abi = true -expected_warnings = 26 +expected_warnings = 33 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/continue_in_strange_positions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/continue_in_strange_positions/test.toml index b914ad4ca6a..79b6421e7fc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/continue_in_strange_positions/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/continue_in_strange_positions/test.toml @@ -1,4 +1,4 @@ category = "run" expected_result = { action = "return", value = 8193 } validate_abi = true -expected_warnings = 25 +expected_warnings = 31 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/diverging_exprs/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/diverging_exprs/test.toml index 915f7efb4b4..8930e0622aa 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/diverging_exprs/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/diverging_exprs/test.toml @@ -1,4 +1,4 @@ category = "run" expected_result = { action = "return", value = 42 } validate_abi = true -expected_warnings = 27 +expected_warnings = 31 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/implicit_casting/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/implicit_casting/test.toml index 6225d0880ca..7bbc428caf0 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/implicit_casting/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/implicit_casting/test.toml @@ -2,10 +2,3 @@ category = "run" expected_result = { action = "return", value = 42 } validate_abi = true -# check: let _a: Result = Ok(5); -# nextln: $()This cast, from integer type of width sixty four to integer type of width thirty two, will lose precision. - -# check: let _b: MyStruct = MyStruct{ a:5 }; -# nextln: $()This cast, from integer type of width sixty four to integer type of width thirty two, will lose precision. - -expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/return_in_strange_positions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/return_in_strange_positions/src/main.sw index 2c3ec216638..ba0fcbd8ef1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/return_in_strange_positions/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/return_in_strange_positions/src/main.sw @@ -20,34 +20,34 @@ pub enum Enum_multivariant { fn in_init() -> u64 { let _ = return 42; - 45 + 045 } fn in_array() -> u64 { let _ = [return 42, return 43]; - 145 + 1450 } // Arrays of length 1 are treated differently fn in_length_1_array() -> u64 { let _ = [return 42]; - 145 + 1451 } // The first element of an array is treated differently fn in_length_2_array_first() -> u64 { let _ = [return 42, 0]; - 145 + 1452 } // The first element of an array is treated differently fn in_length_2_array_second() -> u64 { let _ = [0, return 42]; - 145 // TODO: Missing unreachable warning + 1453 } fn in_tuple() -> u64 { @@ -90,19 +90,19 @@ fn in_while_condition() -> u64 { break; }; - 745 // TODO: Missing unreachable warning + 745 } fn in_enum() -> u64 { let _ = Enum::A((return 42, return 43)); - 845 // TODO: Missing unreachable warning + 845 } fn in_enum_multivariant() -> u64 { let _ = Enum_multivariant::B((return 42, return 43)); - 945 // TODO: Missing unreachable warning + 945 } fn helper_fun(x : u64, y : u64) -> u64 { @@ -112,7 +112,7 @@ fn helper_fun(x : u64, y : u64) -> u64 { fn in_fun_arg() -> u64 { let _ = helper_fun(return 42, return 43); - 1045 // TODO: Missing unreachable warning + 1045 } fn in_lazy_and() -> u64 { @@ -128,11 +128,11 @@ fn in_lazy_or() -> u64 { } fn in_match_scrutinee() -> u64 { - match return 42 { + let _ = match return 42 { _ => 5411, - } + }; - 1145 + 1345 } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/return_in_strange_positions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/return_in_strange_positions/test.toml index 868bbd25b90..9e1db8de1ce 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/return_in_strange_positions/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/return_in_strange_positions/test.toml @@ -1,4 +1,67 @@ category = "run" expected_result = { action = "return", value = 8193 } validate_abi = true -expected_warnings = 17 +expected_warnings = 22 + +#check: $()045 +#nextln: $()This code is unreachable. + +#check: $()1450 +#nextln: $()This code is unreachable. + +#check: $()1451 +#nextln: $()This code is unreachable. + +#check: $()1452 +#nextln: $()This code is unreachable. + +#check: $()1453 +#nextln: $()This code is unreachable. + +#check: $()245 +#nextln: $()This code is unreachable. + +#check: $()345 +#nextln: $()This code is unreachable. + +#check: $()445 +#nextln: $()This code is unreachable. + +#check: $()545 +#nextln: $()This code is unreachable. + +#check: $()543 +#nextln: $()This code is unreachable. + +#check: $()345 +#nextln: $()This code is unreachable. + +#check: $()645 +#nextln: $()This code is unreachable. + +# check: $()745 +# nextln: $()This code is unreachable. + +#check: $()845 +#nextln: $()This code is unreachable. + +#check: $()945 +#nextln: $()This code is unreachable. + +#check: $()1045 +#nextln: $()This code is unreachable. + +#check: $()1145 +#nextln: $()This code is unreachable. + +#check: $()1245 +#nextln: $()This code is unreachable. + +#check: $()let _ = match return 42 { +#check: $()}; +#nextln: $()This code is unreachable. +#nextln: $() +#nextln: $()1345 + +#check: $()1345 +#nextln: $()This code is unreachable. \ No newline at end of file