checker: allow but deprecate propagating result as option (#14500)

master
Daniel Däschle 2022-05-22 23:11:29 +02:00 committed by GitHub
parent 7f03b89611
commit 5e95bdc451
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 32 deletions

View File

@ -940,8 +940,12 @@ pub fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_re
node.pos)
}
if !expr_return_type.has_flag(.optional) {
c.error('to propagate an option, the call must also return an optional type',
node.pos)
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',
node.pos)
}
}
return
}

View File

@ -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 |
5 | fn bar() ?string {
6 | foo()?

View File

@ -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
} 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 {
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) }`
@ -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;')
}
}
} 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.set_current_pos_as_last_stmt_pos()