1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

all: clean up optional and result handling (#16034)

This commit is contained in:
yuyi 2022-10-11 14:23:57 +08:00 committed by GitHub
parent 34d115d883
commit dab1c8a71d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 37 additions and 21 deletions

View File

@ -565,7 +565,7 @@ pub mut:
// returns TypeSymbol kind only if there are no type modifiers
pub fn (t &Table) type_kind(typ Type) Kind {
if typ.nr_muls() > 0 || typ.has_flag(.optional) {
if typ.nr_muls() > 0 || typ.has_flag(.optional) || typ.has_flag(.result) {
return Kind.placeholder
}
return t.sym(typ).kind
@ -862,7 +862,7 @@ pub fn (t &TypeSymbol) is_builtin() bool {
// type_size returns the size and alignment (in bytes) of `typ`, similarly to C's `sizeof()` and `alignof()`.
pub fn (t &Table) type_size(typ Type) (int, int) {
if typ.has_flag(.optional) {
if typ.has_flag(.optional) || typ.has_flag(.result) {
return t.type_size(ast.error_type_idx)
}
if typ.nr_muls() > 0 {

View File

@ -282,7 +282,7 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
sym := c.table.sym(c.expected_type)
if sym.kind == .map {
info := sym.map_info()
node.typ = c.expected_type.clear_flag(.optional)
node.typ = c.expected_type.clear_flag(.optional).clear_flag(.result)
node.key_type = info.key_type
node.value_type = info.value_type
return node.typ

View File

@ -120,6 +120,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
} else if multi_type.has_flag(.optional) {
c.error('option cannot be used in multi-return, return an option instead',
node.return_type_pos)
} else if multi_type.has_flag(.result) {
c.error('result cannot be used in multi-return, return a result instead',
node.return_type_pos)
} else if multi_sym.kind == .array_fixed {
c.error('fixed array cannot be used in multi-return', node.return_type_pos)
}
@ -208,8 +211,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.error('invalid use of reserved type `$param.name` as a parameter name',
param.pos)
}
if param.typ.has_flag(.optional) {
c.error('optional type argument is not supported currently', param.type_pos)
if param.typ.has_flag(.optional) || param.typ.has_flag(.result) {
c.error('optional or result type argument is not supported currently',
param.type_pos)
}
if !param.typ.is_ptr() { // value parameter, i.e. on stack - check for `[heap]`
arg_typ_sym := c.table.sym(param.typ)
@ -450,7 +454,7 @@ pub fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
c.inside_fn_arg = old_inside_fn_arg
// autofree: mark args that have to be freed (after saving them in tmp exprs)
free_tmp_arg_vars := c.pref.autofree && !c.is_builtin_mod && node.args.len > 0
&& !node.args[0].typ.has_flag(.optional)
&& !node.args[0].typ.has_flag(.optional) && !node.args[0].typ.has_flag(.result)
if free_tmp_arg_vars && !c.inside_const {
for i, arg in node.args {
if arg.typ != ast.string_type {
@ -471,7 +475,7 @@ pub fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
node.free_receiver = true
}
}
c.expected_or_type = node.return_type.clear_flag(.optional)
c.expected_or_type = node.return_type.clear_flag(.optional).clear_flag(.result)
c.stmts_ending_with_expression(node.or_block.stmts)
c.expected_or_type = ast.void_type
@ -1982,8 +1986,9 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast
if is_map && arg_expr.return_type in [ast.void_type, 0] {
c.error('type mismatch, `$arg_expr.name` does not return anything', arg_expr.pos)
} else if !is_map && arg_expr.return_type != ast.bool_type {
if arg_expr.or_block.kind != .absent && arg_expr.return_type.has_flag(.optional)
&& arg_expr.return_type.clear_flag(.optional) == ast.bool_type {
if arg_expr.or_block.kind != .absent && (arg_expr.return_type.has_flag(.optional)
|| arg_expr.return_type.has_flag(.result))
&& arg_expr.return_type.clear_flag(.optional).clear_flag(.result) == ast.bool_type {
return
}
c.error('type mismatch, `$arg_expr.name` must return a bool', arg_expr.pos)
@ -2116,6 +2121,9 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
if thread_ret_type.has_flag(.optional) {
c.error('`.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`.',
node.pos)
} else if thread_ret_type.has_flag(.result) {
c.error('`.wait()` cannot be called for an array when thread functions return results. Iterate over the arrays elements instead and handle each returned result with `or`.',
node.pos)
}
node.return_type = c.table.find_or_register_array(thread_ret_type)
} else {

View File

@ -103,7 +103,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
if next_fn.params.len != 1 {
c.error('iterator method `next()` must have 0 parameters', node.cond.pos())
}
mut val_type := next_fn.return_type.clear_flag(.optional)
mut val_type := next_fn.return_type.clear_flag(.optional).clear_flag(.result)
if node.val_is_mut {
val_type = val_type.ref()
}
@ -152,7 +152,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
if sym.kind == .string {
value_type = ast.u8_type
}
if value_type == ast.void_type || typ.has_flag(.optional) {
if value_type == ast.void_type || typ.has_flag(.optional) || typ.has_flag(.result) {
if typ != ast.void_type {
c.error('for in: cannot index `${c.table.type_to_str(typ)}`', node.cond.pos())
}

View File

@ -298,7 +298,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
left_name := c.table.type_to_str(unwrapped_left_type)
right_name := c.table.type_to_str(unwrapped_right_type)
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
} else if promoted_type.has_flag(.optional) {
} else if promoted_type.has_flag(.optional) || promoted_type.has_flag(.result) {
s := c.table.type_to_str(promoted_type)
c.error('`$node.op` cannot be used with `$s`', node.pos)
} else if promoted_type.is_float() {

View File

@ -270,6 +270,8 @@ fn (mut c Checker) resolve_generic_interface(typ ast.Type, interface_type ast.Ty
mut ret_typ := method.return_type
if imethod.return_type.has_flag(.optional) {
ret_typ = ret_typ.clear_flag(.optional)
} else if imethod.return_type.has_flag(.result) {
ret_typ = ret_typ.clear_flag(.result)
}
inferred_type = ret_typ
} else if imret_sym.info is ast.SumType && mret_sym.info is ast.SumType {

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/fn_arg_of_optional_err.vv:1:19: error: optional type argument is not supported currently
vlib/v/checker/tests/fn_arg_of_optional_err.vv:1:19: error: optional or result type argument is not supported currently
1 | fn optional_arg(x ?int) {
| ~~~~
2 | println('int type: $x')

View File

@ -3017,7 +3017,7 @@ fn (mut g Gen) expr(node_ ast.Expr) {
ret_type := if node.or_block.kind == .absent {
node.return_type
} else {
node.return_type.clear_flag(.optional)
node.return_type.clear_flag(.optional).clear_flag(.result)
}
mut shared_styp := ''
if g.is_shared && !ret_type.has_flag(.shared_f) && !g.inside_or_block {
@ -4429,7 +4429,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
}
}
for i, expr in node.exprs {
g.expr_with_cast(expr, node.types[i], g.fn_decl.return_type.clear_flag(.optional))
g.expr_with_cast(expr, node.types[i], g.fn_decl.return_type.clear_flag(.optional).clear_flag(.result))
if i < node.exprs.len - 1 {
g.write(', ')
}
@ -5389,7 +5389,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
}
}
if or_block.kind == .block {
g.or_expr_return_type = return_type.clear_flag(.optional)
g.or_expr_return_type = return_type.clear_flag(.optional).clear_flag(.result)
if g.inside_or_block {
g.writeln('\terr = ${cvar_name}.err;')
} else {
@ -5410,7 +5410,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
g.write('*($mr_styp*) ${cvar_name}.data = ')
old_inside_opt_data := g.inside_opt_data
g.inside_opt_data = true
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_flag(.optional))
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_flag(.optional).clear_flag(.result))
g.inside_opt_data = old_inside_opt_data
g.writeln(';')
g.stmt_path_pos.delete_last()

View File

@ -1358,7 +1358,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
g.writeln('));')
return
}
if g.is_autofree && !typ.has_flag(.optional) {
if g.is_autofree && !typ.has_flag(.optional) && !typ.has_flag(.result) {
// Create a temporary variable so that the value can be freed
tmp := g.new_tmp_var()
g.write('string $tmp = ')
@ -1499,7 +1499,8 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
// Create a temporary var before fn call for each argument in order to free it (only if it's a complex expression,
// like `foo(get_string())` or `foo(a + b)`
mut free_tmp_arg_vars := g.is_autofree && !g.is_builtin_mod && node.args.len > 0
&& !node.args[0].typ.has_flag(.optional) // TODO copy pasta checker.v
&& !node.args[0].typ.has_flag(.optional)
&& !node.args[0].typ.has_flag(.result) // TODO copy pasta checker.v
if !free_tmp_arg_vars {
return
}
@ -1600,6 +1601,11 @@ fn (mut g Gen) autofree_call_postgen(node_pos int) {
// TODO: free optionals
continue
}
is_result := obj.typ.has_flag(.result)
if is_result {
// TODO: free results
continue
}
if !obj.is_autofree_tmp {
continue
}

View File

@ -65,7 +65,7 @@ fn (mut g Gen) need_tmp_var_in_expr(expr ast.Expr) bool {
ast.ConcatExpr {
for val in expr.vals {
if val is ast.CallExpr {
if val.return_type.has_flag(.optional) {
if val.return_type.has_flag(.optional) || val.return_type.has_flag(.result) {
return true
}
}

View File

@ -181,7 +181,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
continue
}
field_name := c_name(field.name)
if field.typ.has_flag(.optional) {
if field.typ.has_flag(.optional) || field.typ.has_flag(.result) {
g.write('.$field_name = {EMPTY_STRUCT_INITIALIZATION},')
initialized = true
continue