checker,cgen: allow result if guard (#14474)

Daniel Däschle 2022-05-20 18:34:53 +02:00 committed by Jef Roosens
parent ec5ccb2995
commit 53bc4c80d4
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
5 changed files with 33 additions and 12 deletions

View File

@ -2150,25 +2150,25 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
c.inside_if_guard = true c.inside_if_guard = true
node.expr_type = c.expr(node.expr) node.expr_type = c.expr(node.expr)
c.inside_if_guard = old_inside_if_guard c.inside_if_guard = old_inside_if_guard
if !node.expr_type.has_flag(.optional) { if !node.expr_type.has_flag(.optional) && !node.expr_type.has_flag(.result) {
mut no_opt := true mut no_opt_or_res := true
match mut node.expr { match mut node.expr {
ast.IndexExpr { ast.IndexExpr {
no_opt = false no_opt_or_res = false
node.expr_type = node.expr_type.set_flag(.optional) node.expr_type = node.expr_type.set_flag(.optional)
node.expr.is_option = true node.expr.is_option = true
} }
ast.PrefixExpr { ast.PrefixExpr {
if node.expr.op == .arrow { if node.expr.op == .arrow {
no_opt = false no_opt_or_res = false
node.expr_type = node.expr_type.set_flag(.optional) node.expr_type = node.expr_type.set_flag(.optional)
node.expr.is_option = true node.expr.is_option = true
} }
} }
else {} else {}
} }
if no_opt { if no_opt_or_res {
c.error('expression should return an option', node.expr.pos()) c.error('expression should either return an option or a result', node.expr.pos())
} }
} }
return ast.bool_type return ast.bool_type
@ -2676,7 +2676,7 @@ pub fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
} }
} }
} else { } else {
typ = obj.expr.expr_type.clear_flag(.optional) typ = obj.expr.expr_type.clear_flag(.optional).clear_flag(.result)
} }
} else { } else {
typ = c.expr(obj.expr) typ = c.expr(obj.expr)

View File

@ -80,7 +80,7 @@ pub fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
// } // }
array_info := type_sym.array_info() array_info := type_sym.array_info()
node.elem_type = array_info.elem_type node.elem_type = array_info.elem_type
// clear optional flag incase of: `fn opt_arr ?[]int { return [] }` // clear optional flag incase of: `fn opt_arr() ?[]int { return [] }`
return if c.expected_type.has_flag(.shared_f) { return if c.expected_type.has_flag(.shared_f) {
c.expected_type.clear_flag(.shared_f).deref() c.expected_type.clear_flag(.shared_f).deref()
} else { } else {

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/expression_should_return_an_option.vv:28:10: error: expression should return an option vlib/v/checker/tests/expression_should_return_an_option.vv:28:10: error: expression should either return an option or a result
26 | } 26 | }
27 | // should be an checker error: 27 | // should be an checker error:
28 | if x := return_string() { 28 | if x := return_string() {

View File

@ -132,11 +132,19 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
var_name = g.new_tmp_var() var_name = g.new_tmp_var()
guard_vars[i] = var_name // for `else` guard_vars[i] = var_name // for `else`
g.tmp_count-- g.tmp_count--
g.writeln('if (${var_name}.state == 0) {') if branch.cond.expr_type.has_flag(.optional) {
g.writeln('if (${var_name}.state == 0) {')
} else if branch.cond.expr_type.has_flag(.result) {
g.writeln('if (!${var_name}.is_error) {')
}
} else { } else {
g.write('if ($var_name = ') g.write('if ($var_name = ')
g.expr(branch.cond.expr) g.expr(branch.cond.expr)
g.writeln(', ${var_name}.state == 0) {') if branch.cond.expr_type.has_flag(.optional) {
g.writeln(', ${var_name}.state == 0) {')
} else if branch.cond.expr_type.has_flag(.result) {
g.writeln(', !${var_name}.is_error) {')
}
} }
if short_opt || branch.cond.vars[0].name != '_' { if short_opt || branch.cond.vars[0].name != '_' {
base_type := g.base_type(branch.cond.expr_type) base_type := g.base_type(branch.cond.expr_type)

View File

@ -81,3 +81,16 @@ fn return_reference_type(path string) !&string {
str := '' str := ''
return &str return &str
} }
fn read() !string {
return ''
}
fn test_results_if_guard() {
if fcontent := read() {
assert fcontent == ''
assert '$fcontent' == ''
return
}
assert false
}