mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker, cgen: fix aliased optional or result fn call (#16908)
This commit is contained in:
parent
ed0500dcfd
commit
241109516f
@ -923,13 +923,20 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to
|
|||||||
// return the actual type of the expression, once the optional is handled
|
// return the actual type of the expression, once the optional is handled
|
||||||
fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Type {
|
fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Type {
|
||||||
if expr is ast.CallExpr {
|
if expr is ast.CallExpr {
|
||||||
if expr.return_type.has_flag(.optional) || expr.return_type.has_flag(.result) {
|
mut expr_ret_type := expr.return_type
|
||||||
return_modifier_kind := if expr.return_type.has_flag(.optional) {
|
if expr_ret_type != 0 && c.table.sym(expr_ret_type).kind == .alias {
|
||||||
|
unaliased_ret_type := c.table.unaliased_type(expr_ret_type)
|
||||||
|
if unaliased_ret_type.has_flag(.optional) || unaliased_ret_type.has_flag(.result) {
|
||||||
|
expr_ret_type = unaliased_ret_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if expr_ret_type.has_flag(.optional) || expr_ret_type.has_flag(.result) {
|
||||||
|
return_modifier_kind := if expr_ret_type.has_flag(.optional) {
|
||||||
'an option'
|
'an option'
|
||||||
} else {
|
} else {
|
||||||
'a result'
|
'a result'
|
||||||
}
|
}
|
||||||
return_modifier := if expr.return_type.has_flag(.optional) { '?' } else { '!' }
|
return_modifier := if expr_ret_type.has_flag(.optional) { '?' } else { '!' }
|
||||||
if expr.or_block.kind == .absent {
|
if expr.or_block.kind == .absent {
|
||||||
if c.inside_defer {
|
if c.inside_defer {
|
||||||
c.error('${expr.name}() returns ${return_modifier_kind}, so it should have an `or {}` block at the end',
|
c.error('${expr.name}() returns ${return_modifier_kind}, so it should have an `or {}` block at the end',
|
||||||
@ -939,7 +946,7 @@ fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Typ
|
|||||||
expr.pos)
|
expr.pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.check_or_expr(expr.or_block, ret_type, expr.return_type)
|
c.check_or_expr(expr.or_block, ret_type, expr_ret_type)
|
||||||
}
|
}
|
||||||
return ret_type.clear_flag(.optional).clear_flag(.result)
|
return ret_type.clear_flag(.optional).clear_flag(.result)
|
||||||
} else if expr.or_block.kind == .block {
|
} else if expr.or_block.kind == .block {
|
||||||
@ -2329,6 +2336,12 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
|
|||||||
}
|
}
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
mut ret_type := c.call_expr(mut node)
|
mut ret_type := c.call_expr(mut node)
|
||||||
|
if ret_type != 0 && c.table.sym(ret_type).kind == .alias {
|
||||||
|
unaliased_type := c.table.unaliased_type(ret_type)
|
||||||
|
if unaliased_type.has_flag(.optional) || unaliased_type.has_flag(.result) {
|
||||||
|
ret_type = unaliased_type
|
||||||
|
}
|
||||||
|
}
|
||||||
if !ret_type.has_flag(.optional) && !ret_type.has_flag(.result) {
|
if !ret_type.has_flag(.optional) && !ret_type.has_flag(.result) {
|
||||||
if node.or_block.kind == .block {
|
if node.or_block.kind == .block {
|
||||||
c.error('unexpected `or` block, the function `${node.name}` does neither return an optional nor a result',
|
c.error('unexpected `or` block, the function `${node.name}` does neither return an optional nor a result',
|
||||||
|
@ -12,6 +12,12 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
|||||||
}
|
}
|
||||||
c.expected_type = c.table.cur_fn.return_type
|
c.expected_type = c.table.cur_fn.return_type
|
||||||
mut expected_type := c.unwrap_generic(c.expected_type)
|
mut expected_type := c.unwrap_generic(c.expected_type)
|
||||||
|
if expected_type != 0 && c.table.sym(expected_type).kind == .alias {
|
||||||
|
unaliased_type := c.table.unaliased_type(expected_type)
|
||||||
|
if unaliased_type.has_flag(.optional) || unaliased_type.has_flag(.result) {
|
||||||
|
expected_type = unaliased_type
|
||||||
|
}
|
||||||
|
}
|
||||||
expected_type_sym := c.table.sym(expected_type)
|
expected_type_sym := c.table.sym(expected_type)
|
||||||
if node.exprs.len > 0 && c.table.cur_fn.return_type == ast.void_type {
|
if node.exprs.len > 0 && c.table.cur_fn.return_type == ast.void_type {
|
||||||
c.error('unexpected argument, current function does not return anything', node.exprs[0].pos())
|
c.error('unexpected argument, current function does not return anything', node.exprs[0].pos())
|
||||||
|
6
vlib/v/checker/tests/aliased_optional_fn_call_err.out
Normal file
6
vlib/v/checker/tests/aliased_optional_fn_call_err.out
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
vlib/v/checker/tests/aliased_optional_fn_call_err.vv:8:10: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
|
||||||
|
6 |
|
||||||
|
7 | fn main(){
|
||||||
|
8 | println(foo())
|
||||||
|
| ~~~~~
|
||||||
|
9 | }
|
9
vlib/v/checker/tests/aliased_optional_fn_call_err.vv
Normal file
9
vlib/v/checker/tests/aliased_optional_fn_call_err.vv
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
type OptStr = ?string
|
||||||
|
|
||||||
|
fn foo() OptStr{
|
||||||
|
return 'abc'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
println(foo())
|
||||||
|
}
|
@ -4485,14 +4485,21 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
|||||||
|
|
||||||
// got to do a correct check for multireturn
|
// got to do a correct check for multireturn
|
||||||
sym := g.table.sym(g.fn_decl.return_type)
|
sym := g.table.sym(g.fn_decl.return_type)
|
||||||
|
mut fn_ret_type := g.fn_decl.return_type
|
||||||
|
if sym.kind == .alias {
|
||||||
|
unaliased_type := g.table.unaliased_type(fn_ret_type)
|
||||||
|
if unaliased_type.has_flag(.optional) || unaliased_type.has_flag(.result) {
|
||||||
|
fn_ret_type = unaliased_type
|
||||||
|
}
|
||||||
|
}
|
||||||
fn_return_is_multi := sym.kind == .multi_return
|
fn_return_is_multi := sym.kind == .multi_return
|
||||||
fn_return_is_optional := g.fn_decl.return_type.has_flag(.optional)
|
fn_return_is_optional := fn_ret_type.has_flag(.optional)
|
||||||
fn_return_is_result := g.fn_decl.return_type.has_flag(.result)
|
fn_return_is_result := fn_ret_type.has_flag(.result)
|
||||||
mut has_semicolon := false
|
mut has_semicolon := false
|
||||||
if node.exprs.len == 0 {
|
if node.exprs.len == 0 {
|
||||||
g.write_defer_stmts_when_needed()
|
g.write_defer_stmts_when_needed()
|
||||||
if fn_return_is_optional || fn_return_is_result {
|
if fn_return_is_optional || fn_return_is_result {
|
||||||
styp := g.typ(g.fn_decl.return_type)
|
styp := g.typ(fn_ret_type)
|
||||||
g.writeln('return (${styp}){0};')
|
g.writeln('return (${styp}){0};')
|
||||||
} else {
|
} else {
|
||||||
if g.is_autofree {
|
if g.is_autofree {
|
||||||
@ -4504,7 +4511,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
tmpvar := g.new_tmp_var()
|
tmpvar := g.new_tmp_var()
|
||||||
ret_typ := g.typ(g.unwrap_generic(g.fn_decl.return_type))
|
ret_typ := g.typ(g.unwrap_generic(fn_ret_type))
|
||||||
mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0
|
mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0
|
||||||
|| g.cur_lock.lockeds.len > 0
|
|| g.cur_lock.lockeds.len > 0
|
||||||
// handle promoting none/error/function returning _option'
|
// handle promoting none/error/function returning _option'
|
||||||
@ -4516,7 +4523,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
|||||||
if g.fn_decl != unsafe { nil } && g.fn_decl.is_test {
|
if g.fn_decl != unsafe { nil } && g.fn_decl.is_test {
|
||||||
test_error_var := g.new_tmp_var()
|
test_error_var := g.new_tmp_var()
|
||||||
g.write('${ret_typ} ${test_error_var} = ')
|
g.write('${ret_typ} ${test_error_var} = ')
|
||||||
g.gen_optional_error(g.fn_decl.return_type, node.exprs[0])
|
g.gen_optional_error(fn_ret_type, node.exprs[0])
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
g.write_defer_stmts_when_needed()
|
g.write_defer_stmts_when_needed()
|
||||||
g.gen_failing_return_error_for_test_fn(node, test_error_var)
|
g.gen_failing_return_error_for_test_fn(node, test_error_var)
|
||||||
@ -4527,7 +4534,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
|||||||
} else {
|
} else {
|
||||||
g.write('return ')
|
g.write('return ')
|
||||||
}
|
}
|
||||||
g.gen_optional_error(g.fn_decl.return_type, node.exprs[0])
|
g.gen_optional_error(fn_ret_type, node.exprs[0])
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
if use_tmp_var {
|
if use_tmp_var {
|
||||||
g.write_defer_stmts_when_needed()
|
g.write_defer_stmts_when_needed()
|
||||||
@ -4544,7 +4551,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
|||||||
if g.fn_decl != unsafe { nil } && g.fn_decl.is_test {
|
if g.fn_decl != unsafe { nil } && g.fn_decl.is_test {
|
||||||
test_error_var := g.new_tmp_var()
|
test_error_var := g.new_tmp_var()
|
||||||
g.write('${ret_typ} ${test_error_var} = ')
|
g.write('${ret_typ} ${test_error_var} = ')
|
||||||
g.gen_result_error(g.fn_decl.return_type, node.exprs[0])
|
g.gen_result_error(fn_ret_type, node.exprs[0])
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
g.write_defer_stmts_when_needed()
|
g.write_defer_stmts_when_needed()
|
||||||
g.gen_failing_return_error_for_test_fn(node, test_error_var)
|
g.gen_failing_return_error_for_test_fn(node, test_error_var)
|
||||||
@ -4555,7 +4562,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
|||||||
} else {
|
} else {
|
||||||
g.write('return ')
|
g.write('return ')
|
||||||
}
|
}
|
||||||
g.gen_result_error(g.fn_decl.return_type, node.exprs[0])
|
g.gen_result_error(fn_ret_type, node.exprs[0])
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
if use_tmp_var {
|
if use_tmp_var {
|
||||||
g.write_defer_stmts_when_needed()
|
g.write_defer_stmts_when_needed()
|
||||||
@ -4686,16 +4693,16 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fn_return_is_optional && !expr_type_is_opt && return_sym.name != c.option_name {
|
if fn_return_is_optional && !expr_type_is_opt && return_sym.name != c.option_name {
|
||||||
styp := g.base_type(g.fn_decl.return_type)
|
styp := g.base_type(fn_ret_type)
|
||||||
g.writeln('${ret_typ} ${tmpvar};')
|
g.writeln('${ret_typ} ${tmpvar};')
|
||||||
g.write('_option_ok(&(${styp}[]) { ')
|
g.write('_option_ok(&(${styp}[]) { ')
|
||||||
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
if !fn_ret_type.is_ptr() && node.types[0].is_ptr() {
|
||||||
if !(node.exprs[0] is ast.Ident && !g.is_amp) {
|
if !(node.exprs[0] is ast.Ident && !g.is_amp) {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, expr in node.exprs {
|
for i, expr in node.exprs {
|
||||||
g.expr_with_cast(expr, node.types[i], g.fn_decl.return_type.clear_flag(.optional).clear_flag(.result))
|
g.expr_with_cast(expr, node.types[i], fn_ret_type.clear_flag(.optional).clear_flag(.result))
|
||||||
if i < node.exprs.len - 1 {
|
if i < node.exprs.len - 1 {
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
}
|
}
|
||||||
@ -4715,16 +4722,16 @@ fn (mut g Gen) return_stmt(node ast.Return) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fn_return_is_result && !expr_type_is_result && return_sym.name != c.result_name {
|
if fn_return_is_result && !expr_type_is_result && return_sym.name != c.result_name {
|
||||||
styp := g.base_type(g.fn_decl.return_type)
|
styp := g.base_type(fn_ret_type)
|
||||||
g.writeln('${ret_typ} ${tmpvar};')
|
g.writeln('${ret_typ} ${tmpvar};')
|
||||||
g.write('_result_ok(&(${styp}[]) { ')
|
g.write('_result_ok(&(${styp}[]) { ')
|
||||||
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
if !fn_ret_type.is_ptr() && node.types[0].is_ptr() {
|
||||||
if !(node.exprs[0] is ast.Ident && !g.is_amp) {
|
if !(node.exprs[0] is ast.Ident && !g.is_amp) {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, expr in node.exprs {
|
for i, expr in node.exprs {
|
||||||
g.expr_with_cast(expr, node.types[i], g.fn_decl.return_type.clear_flag(.result))
|
g.expr_with_cast(expr, node.types[i], fn_ret_type.clear_flag(.result))
|
||||||
if i < node.exprs.len - 1 {
|
if i < node.exprs.len - 1 {
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
}
|
}
|
||||||
|
@ -684,6 +684,12 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||||||
tmp_opt := if gen_or || gen_keep_alive { g.new_tmp_var() } else { '' }
|
tmp_opt := if gen_or || gen_keep_alive { g.new_tmp_var() } else { '' }
|
||||||
if gen_or || gen_keep_alive {
|
if gen_or || gen_keep_alive {
|
||||||
mut ret_typ := node.return_type
|
mut ret_typ := node.return_type
|
||||||
|
if g.table.sym(ret_typ).kind == .alias {
|
||||||
|
unaliased_type := g.table.unaliased_type(ret_typ)
|
||||||
|
if unaliased_type.has_flag(.optional) || unaliased_type.has_flag(.result) {
|
||||||
|
ret_typ = unaliased_type
|
||||||
|
}
|
||||||
|
}
|
||||||
styp := g.typ(ret_typ)
|
styp := g.typ(ret_typ)
|
||||||
if gen_or && !is_gen_or_and_assign_rhs {
|
if gen_or && !is_gen_or_and_assign_rhs {
|
||||||
cur_line = g.go_before_stmt(0)
|
cur_line = g.go_before_stmt(0)
|
||||||
@ -713,7 +719,13 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||||||
}
|
}
|
||||||
if gen_or {
|
if gen_or {
|
||||||
g.or_block(tmp_opt, node.or_block, node.return_type)
|
g.or_block(tmp_opt, node.or_block, node.return_type)
|
||||||
unwrapped_typ := node.return_type.clear_flag(.optional).clear_flag(.result)
|
mut unwrapped_typ := node.return_type.clear_flag(.optional).clear_flag(.result)
|
||||||
|
if g.table.sym(unwrapped_typ).kind == .alias {
|
||||||
|
unaliased_type := g.table.unaliased_type(unwrapped_typ)
|
||||||
|
if unaliased_type.has_flag(.optional) || unaliased_type.has_flag(.result) {
|
||||||
|
unwrapped_typ = unaliased_type.clear_flag(.optional).clear_flag(.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
unwrapped_styp := g.typ(unwrapped_typ)
|
unwrapped_styp := g.typ(unwrapped_typ)
|
||||||
if g.infix_left_var_name.len > 0 {
|
if g.infix_left_var_name.len > 0 {
|
||||||
g.indent--
|
g.indent--
|
||||||
|
11
vlib/v/tests/aliased_optional_fn_call_test.v
Normal file
11
vlib/v/tests/aliased_optional_fn_call_test.v
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
type OptStr = ?string
|
||||||
|
|
||||||
|
fn foo() OptStr {
|
||||||
|
return 'abc'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_aliased_optional_fn_call() {
|
||||||
|
ret := foo()?
|
||||||
|
println(ret)
|
||||||
|
assert ret == 'abc'
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user