checker: allow but deprecate propagating result as option (#14500)
parent
7f03b89611
commit
5e95bdc451
|
@ -940,9 +940,13 @@ pub fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_re
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
if !expr_return_type.has_flag(.optional) {
|
if !expr_return_type.has_flag(.optional) {
|
||||||
|
if expr_return_type.has_flag(.result) {
|
||||||
|
c.warn('propagating a result like an option is deprecated, use `foo()!` instead of `foo()?`', node.pos)
|
||||||
|
} else {
|
||||||
c.error('to propagate an option, the call must also return an optional type',
|
c.error('to propagate an option, the call must also return an optional type',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if node.kind == .propagate_result {
|
if node.kind == .propagate_result {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/propagate_option_with_result_err.vv:6:7: error: to propagate an option, the call must also return an optional type
|
vlib/v/checker/tests/propagate_option_with_result_err.vv:6:7: warning: propagating a result like an option is deprecated, use `foo()!` instead of `foo()?`
|
||||||
4 |
|
4 |
|
||||||
5 | fn bar() ?string {
|
5 | fn bar() ?string {
|
||||||
6 | foo()?
|
6 | foo()?
|
||||||
|
|
|
@ -5212,6 +5212,36 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.or_expr_return_type = ast.void_type
|
g.or_expr_return_type = ast.void_type
|
||||||
|
} else if or_block.kind == .propagate_result
|
||||||
|
|| (or_block.kind == .propagate_option && return_type.has_flag(.result)) {
|
||||||
|
if g.file.mod.name == 'main' && (isnil(g.fn_decl) || g.fn_decl.is_main) {
|
||||||
|
// In main(), an `opt()!` call is sugar for `opt() or { panic(err) }`
|
||||||
|
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
|
||||||
|
if g.pref.is_debug {
|
||||||
|
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
|
||||||
|
g.writeln('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), $err_msg);')
|
||||||
|
} else {
|
||||||
|
g.writeln('\tpanic_result_not_set($err_msg);')
|
||||||
|
}
|
||||||
|
} else if !isnil(g.fn_decl) && g.fn_decl.is_test {
|
||||||
|
g.gen_failing_error_propagation_for_test_fn(or_block, cvar_name)
|
||||||
|
} else {
|
||||||
|
// In ordinary functions, `opt()!` call is sugar for:
|
||||||
|
// `opt() or { return err }`
|
||||||
|
// Since we *do* return, first we have to ensure that
|
||||||
|
// the defered statements are generated.
|
||||||
|
g.write_defer_stmts()
|
||||||
|
// Now that option types are distinct we need a cast here
|
||||||
|
if g.fn_decl.return_type == ast.void_type {
|
||||||
|
g.writeln('\treturn;')
|
||||||
|
} else {
|
||||||
|
styp := g.typ(g.fn_decl.return_type)
|
||||||
|
err_obj := g.new_tmp_var()
|
||||||
|
g.writeln('\t$styp $err_obj;')
|
||||||
|
g.writeln('\tmemcpy(&$err_obj, &$cvar_name, sizeof($c.result_name));')
|
||||||
|
g.writeln('\treturn $err_obj;')
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if or_block.kind == .propagate_option {
|
} else if or_block.kind == .propagate_option {
|
||||||
if g.file.mod.name == 'main' && (isnil(g.fn_decl) || g.fn_decl.is_main) {
|
if g.file.mod.name == 'main' && (isnil(g.fn_decl) || g.fn_decl.is_main) {
|
||||||
// In main(), an `opt()?` call is sugar for `opt() or { panic(err) }`
|
// In main(), an `opt()?` call is sugar for `opt() or { panic(err) }`
|
||||||
|
@ -5241,35 +5271,6 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
|
||||||
g.writeln('\treturn $err_obj;')
|
g.writeln('\treturn $err_obj;')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if or_block.kind == .propagate_result {
|
|
||||||
if g.file.mod.name == 'main' && (isnil(g.fn_decl) || g.fn_decl.is_main) {
|
|
||||||
// In main(), an `opt()!` call is sugar for `opt() or { panic(err) }`
|
|
||||||
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
|
|
||||||
if g.pref.is_debug {
|
|
||||||
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
|
|
||||||
g.writeln('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), $err_msg);')
|
|
||||||
} else {
|
|
||||||
g.writeln('\tpanic_result_not_set($err_msg);')
|
|
||||||
}
|
|
||||||
} else if !isnil(g.fn_decl) && g.fn_decl.is_test {
|
|
||||||
g.gen_failing_error_propagation_for_test_fn(or_block, cvar_name)
|
|
||||||
} else {
|
|
||||||
// In ordinary functions, `opt()!` call is sugar for:
|
|
||||||
// `opt() or { return err }`
|
|
||||||
// Since we *do* return, first we have to ensure that
|
|
||||||
// the defered statements are generated.
|
|
||||||
g.write_defer_stmts()
|
|
||||||
// Now that option types are distinct we need a cast here
|
|
||||||
if g.fn_decl.return_type == ast.void_type {
|
|
||||||
g.writeln('\treturn;')
|
|
||||||
} else {
|
|
||||||
styp := g.typ(g.fn_decl.return_type)
|
|
||||||
err_obj := g.new_tmp_var()
|
|
||||||
g.writeln('\t$styp $err_obj;')
|
|
||||||
g.writeln('\tmemcpy(&$err_obj, &$cvar_name, sizeof($c.result_name));')
|
|
||||||
g.writeln('\treturn $err_obj;')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
g.set_current_pos_as_last_stmt_pos()
|
g.set_current_pos_as_last_stmt_pos()
|
||||||
|
|
Loading…
Reference in New Issue