Skip to content

Commit

Permalink
Fix bug which created dead and incorrectly typed blocks into IR, trig…
Browse files Browse the repository at this point in the history
…gering a verification failure. (FuelLabs#3210)

If both arms of an `if` (or all arms of a `match` which are converted to
`if`s) were terminated with `return` then we still created a merge block
with an unknown arg, which ended up being dead code and incorrectly
typed.
  • Loading branch information
otrho authored Nov 1, 2022
1 parent 04a61e1 commit 10b6c44
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 6 deletions.
17 changes: 11 additions & 6 deletions sway-core/src/ir_generation/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,17 @@ fn compile_fn_with_args(
let mut compiler = FnCompiler::new(context, module, func, returns_by_ref, logged_types_map);
let mut ret_val = compiler.compile_code_block(context, md_mgr, body)?;

// Special case: if the return type is unit but the return value type is not, then we have an
// implicit return from the last expression in the code block having a semi-colon. This isn't
// codified in the AST explicitly so we need to make a unit to return here.
if ret_type.eq(context, &Type::Unit) && !matches!(ret_val.get_type(context), Some(Type::Unit)) {
ret_val = Constant::get_unit(context);
}
// Special case: sometimes the returned value at the end of the function block is hacked
// together and is invalid. This can happen with diverging control flow or with implicit
// returns. We can double check here and make sure the return value type is correct.
ret_val = match ret_val.get_type(context) {
Some(ret_val_type) if ret_type.eq(context, &ret_val_type.strip_ptr_type(context)) => {
ret_val
}

// Mismatched or unavailable type. Set ret_val to a correctly typed Undef.
_otherwise => Value::new_constant(context, Constant::get_undef(ret_type)),
};

// Another special case: if the last expression in a function is a return then we don't want to
// add another implicit return instruction here, as `ret_val` will be unit regardless of the
Expand Down
7 changes: 7 additions & 0 deletions sway-ir/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ impl Constant {
}
}

pub fn get_undef(ty: Type) -> Self {
Constant {
ty,
value: ConstantValue::Undef,
}
}

pub fn get_unit(context: &mut Context) -> Value {
Value::new_constant(context, Constant::new_unit())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
target
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[package]]
name = 'core'
source = 'path+from-root-3F456608F1F32854'

[[package]]
name = 'match_expressions_explicit_rets'
source = 'root'
dependencies = ['core']
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "match_expressions_explicit_rets"
implicit-std = false

[dependencies]
core = { path = "../../../../../../../sway-lib-core" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
script;

// Explicit returns from each arm of a match expression. Was causing mistyped dead IR to be
// generated.

fn main() -> bool {
match true {
true => {
return true;
},
false => {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
category = "run"
expected_result = { action = "return", value = 1 }
validate_abi = false

0 comments on commit 10b6c44

Please sign in to comment.