Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ast: add clear_option_and_result() and cleanup all the related calls #20443

Merged
merged 2 commits into from Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions vlib/v/ast/types.v
Expand Up @@ -389,6 +389,12 @@ pub fn (t Type) clear_flags(flags ...TypeFlag) Type {
}
}

// clear option and result flags
@[inline]
pub fn (t Type) clear_option_and_result() Type {
return u32(t) & ~0x0300_0000
}

// return true if `flag` is set on `t`
@[inline]
pub fn (t Type) has_flag(flag TypeFlag) bool {
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/check_types.v
Expand Up @@ -154,7 +154,7 @@ fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
&& expected.has_flag(.result)) {
// IError
return true
} else if !c.check_basic(got, expected.clear_flags(.option, .result)) {
} else if !c.check_basic(got, expected.clear_option_and_result()) {
return false
}
}
Expand Down
29 changes: 12 additions & 17 deletions vlib/v/checker/checker.v
Expand Up @@ -1271,22 +1271,20 @@ fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_return
return
}
mut last_stmt := node.stmts.last()
c.check_or_last_stmt(mut last_stmt, ret_type, expr_return_type.clear_flags(.option,
.result))
c.check_or_last_stmt(mut last_stmt, ret_type, expr_return_type.clear_option_and_result())
}

fn (mut c Checker) check_or_last_stmt(mut stmt ast.Stmt, ret_type ast.Type, expr_return_type ast.Type) {
if ret_type != ast.void_type {
match mut stmt {
ast.ExprStmt {
c.expected_type = ret_type
c.expected_or_type = ret_type.clear_flags(.option, .result)
c.expected_or_type = ret_type.clear_option_and_result()
last_stmt_typ := c.expr(mut stmt.expr)

if last_stmt_typ.has_flag(.option) || last_stmt_typ == ast.none_type {
if stmt.expr in [ast.Ident, ast.SelectorExpr, ast.CallExpr, ast.None, ast.CastExpr] {
expected_type_name := c.table.type_to_str(ret_type.clear_flags(.option,
.result))
expected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())
got_type_name := c.table.type_to_str(last_stmt_typ)
c.error('`or` block must provide a value of type `${expected_type_name}`, not `${got_type_name}`',
stmt.expr.pos())
Expand Down Expand Up @@ -1319,8 +1317,7 @@ fn (mut c Checker) check_or_last_stmt(mut stmt ast.Stmt, ret_type ast.Type, expr
}
return
}
expected_type_name := c.table.type_to_str(ret_type.clear_flags(.option,
.result))
expected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())
c.error('`or` block must provide a default value of type `${expected_type_name}`, or return/continue/break or call a [noreturn] function like panic(err) or exit(1)',
stmt.expr.pos())
} else {
Expand All @@ -1332,8 +1329,7 @@ fn (mut c Checker) check_or_last_stmt(mut stmt ast.Stmt, ret_type ast.Type, expr
return
}
type_name := c.table.type_to_str(last_stmt_typ)
expected_type_name := c.table.type_to_str(ret_type.clear_flags(.option,
.result))
expected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())
c.error('wrong return type `${type_name}` in the `or {}` block, expected `${expected_type_name}`',
stmt.expr.pos())
}
Expand All @@ -1347,8 +1343,7 @@ fn (mut c Checker) check_or_last_stmt(mut stmt ast.Stmt, ret_type ast.Type, expr
}
ast.Return {}
else {
expected_type_name := c.table.type_to_str(ret_type.clear_flags(.option,
.result))
expected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())
c.error('last statement in the `or {}` block should be an expression of type `${expected_type_name}` or exit parent scope',
stmt.pos)
}
Expand Down Expand Up @@ -1600,7 +1595,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
}
node.typ = field.typ
if node.or_block.kind == .block {
c.expected_or_type = node.typ.clear_flags(.option, .result)
c.expected_or_type = node.typ.clear_option_and_result()
c.stmts_ending_with_expression(mut node.or_block.stmts)
c.check_or_expr(node.or_block, node.typ, c.expected_or_type, node)
c.expected_or_type = ast.void_type
Expand Down Expand Up @@ -3500,7 +3495,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
c.error('cannot use `or {}` block on non-option variable', node.pos)
}
}
unwrapped_typ := typ.clear_flags(.option, .result)
unwrapped_typ := typ.clear_option_and_result()
c.expected_or_type = unwrapped_typ
c.stmts_ending_with_expression(mut node.or_expr.stmts)
c.check_or_expr(node.or_expr, typ, c.expected_or_type, node)
Expand Down Expand Up @@ -3574,7 +3569,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
}
}
} else {
typ = obj.expr.expr_type.clear_flags(.option, .result)
typ = obj.expr.expr_type.clear_option_and_result()
}
} else if obj.expr is ast.EmptyExpr {
c.error('invalid variable `${node.name}`', node.pos)
Expand Down Expand Up @@ -3609,7 +3604,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
node.pos)
}
}
unwrapped_typ := typ.clear_flags(.option, .result)
unwrapped_typ := typ.clear_option_and_result()
c.expected_or_type = unwrapped_typ
c.stmts_ending_with_expression(mut node.or_expr.stmts)
c.check_or_expr(node.or_expr, typ, c.expected_or_type, node)
Expand Down Expand Up @@ -3654,7 +3649,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {

if mut obj.expr is ast.CallExpr {
if obj.expr.or_block.kind != .absent {
typ = typ.clear_flags(.option, .result)
typ = typ.clear_option_and_result()
}
}
}
Expand All @@ -3667,7 +3662,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
node.obj = obj

if node.or_expr.kind != .absent {
unwrapped_typ := typ.clear_flags(.option, .result)
unwrapped_typ := typ.clear_option_and_result()
c.expected_or_type = unwrapped_typ
c.stmts_ending_with_expression(mut node.or_expr.stmts)
c.check_or_expr(node.or_expr, typ, c.expected_or_type, node)
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/containers.v
Expand Up @@ -132,7 +132,7 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
c.expected_type.clear_flag(.shared_f).deref()
} else {
c.expected_type
}.clear_flags(.option, .result)
}.clear_option_and_result()
}
// `[1,2,3]`
if node.exprs.len > 0 && node.elem_type == ast.void_type {
Expand Down Expand Up @@ -366,7 +366,7 @@ 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_flags(.option, .result)
node.typ = c.expected_type.clear_option_and_result()
node.key_type = info.key_type
node.value_type = info.value_type
return node.typ
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/fn.v
Expand Up @@ -504,7 +504,7 @@ fn (mut c Checker) anon_fn(mut node ast.AnonFn) ast.Type {
}
}
} else {
var.typ = parent_var.expr.expr_type.clear_flags(.option, .result)
var.typ = parent_var.expr.expr_type.clear_option_and_result()
}
} else {
var.typ = parent_var.typ
Expand Down Expand Up @@ -2644,7 +2644,7 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast
} else if !is_map && arg_expr.return_type != ast.bool_type {
if arg_expr.or_block.kind != .absent && (arg_expr.return_type.has_flag(.option)
|| arg_expr.return_type.has_flag(.result))
&& arg_expr.return_type.clear_flags(.option, .result) == ast.bool_type {
&& arg_expr.return_type.clear_option_and_result() == ast.bool_type {
return
}
c.error('type mismatch, `${arg_expr.name}` must return a bool', arg_expr.pos)
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/for.v
Expand Up @@ -120,7 +120,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_flags(.option, .result)
mut val_type := next_fn.return_type.clear_option_and_result()
if node.val_is_mut {
val_type = val_type.ref()
}
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/if.v
Expand Up @@ -70,7 +70,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
}
}
if mut branch.cond is ast.IfGuardExpr {
if branch.cond.expr_type.clear_flags(.option, .result) == ast.void_type
if branch.cond.expr_type.clear_option_and_result() == ast.void_type
&& !(branch.cond.vars.len == 1 && branch.cond.vars[0].name == '_') {
c.error('if guard expects non-propagate option or result', branch.pos)
continue
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/lambda_expr.v
Expand Up @@ -63,7 +63,7 @@ pub fn (mut c Checker) lambda_expr(mut node ast.LambdaExpr, exp_typ ast.Type) as

mut stmts := []ast.Stmt{}
mut has_return := false
if return_type.clear_flags(.option, .result) == ast.void_type {
if return_type.clear_option_and_result() == ast.void_type {
stmts << ast.ExprStmt{
pos: node.pos
expr: node.expr
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/assign.v
Expand Up @@ -775,7 +775,7 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ
mut mr_styp := g.typ(return_type.clear_flag(.result))
if node.right[0] is ast.CallExpr && node.right[0].or_block.kind != .absent {
is_option = false
mr_styp = g.typ(return_type.clear_flags(.option, .result))
mr_styp = g.typ(return_type.clear_option_and_result())
}
g.write('${mr_styp} ${mr_var_name} = ')
g.expr(node.right[0])
Expand Down
20 changes: 9 additions & 11 deletions vlib/v/gen/c/cgen.v
Expand Up @@ -1467,7 +1467,7 @@ pub fn (mut g Gen) write_typedef_types() {
g.type_definitions.writeln(def_str)
} else if !info.is_fn_ret && len.int() > 0 {
g.type_definitions.writeln('typedef ${fixed} ${styp} [${len}];')
base := g.typ(info.elem_type.clear_flags(.option, .result))
base := g.typ(info.elem_type.clear_option_and_result())
if info.elem_type.has_flag(.option) && base !in g.options_forward {
g.options_forward << base
} else if info.elem_type.has_flag(.result) && base !in g.results_forward {
Expand Down Expand Up @@ -3197,7 +3197,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_flags(.option, .result)
node.return_type.clear_option_and_result()
}
mut shared_styp := ''
if g.is_shared && !ret_type.has_flag(.shared_f) && !g.inside_or_block {
Expand Down Expand Up @@ -3694,7 +3694,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
g.or_block(tmp_var, node.or_block, node.typ)
g.write(stmt_str)
g.write(' ')
unwrapped_typ := node.typ.clear_flags(.option, .result)
unwrapped_typ := node.typ.clear_option_and_result()
unwrapped_styp := g.typ(unwrapped_typ)
g.write('(*(${unwrapped_styp}*)${tmp_var}.data)')
return
Expand Down Expand Up @@ -4713,11 +4713,11 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) {
}

fn (mut g Gen) concat_expr(node ast.ConcatExpr) {
mut styp := g.typ(node.return_type.clear_flags(.option, .result))
mut styp := g.typ(node.return_type.clear_option_and_result())
if g.inside_return {
styp = g.typ(g.fn_decl.return_type.clear_flags(.option, .result))
styp = g.typ(g.fn_decl.return_type.clear_option_and_result())
} else if g.inside_or_block {
styp = g.typ(g.or_expr_return_type.clear_flags(.option, .result))
styp = g.typ(g.or_expr_return_type.clear_option_and_result())
}
sym := g.table.sym(node.return_type)
is_multi := sym.kind == .multi_return
Expand Down Expand Up @@ -5209,8 +5209,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
if return_sym.kind == .array_fixed && expr !is ast.ArrayInit {
g.fixed_array_var_init(expr, (return_sym.info as ast.ArrayFixed).size)
} else {
g.expr_with_cast(expr, node.types[i], fn_ret_type.clear_flags(.option,
.result))
g.expr_with_cast(expr, node.types[i], fn_ret_type.clear_option_and_result())
}
if i < node.exprs.len - 1 {
g.write(', ')
Expand Down Expand Up @@ -6382,8 +6381,7 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
}
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_flags(.option,
.result))
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_option_and_result())
g.inside_opt_data = old_inside_opt_data
g.writeln(';')
g.stmt_path_pos.delete_last()
Expand Down Expand Up @@ -6419,7 +6417,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_flags(.option, .result)
g.or_expr_return_type = return_type.clear_option_and_result()
g.writeln('\tIError err = ${cvar_name}.err;')

g.inside_or_block = true
Expand Down
7 changes: 3 additions & 4 deletions vlib/v/gen/c/fn.v
Expand Up @@ -805,11 +805,11 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
}
if gen_or {
g.or_block(tmp_opt, node.or_block, node.return_type)
mut unwrapped_typ := node.return_type.clear_flags(.option, .result)
mut unwrapped_typ := node.return_type.clear_option_and_result()
if g.table.sym(unwrapped_typ).kind == .alias {
unaliased_type := g.table.unaliased_type(unwrapped_typ)
if unaliased_type.has_option_or_result() {
unwrapped_typ = unaliased_type.clear_flags(.option, .result)
unwrapped_typ = unaliased_type.clear_option_and_result()
}
}
mut unwrapped_styp := g.typ(unwrapped_typ)
Expand All @@ -824,8 +824,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
if !g.inside_const_opt_or_res {
if g.assign_ct_type != 0
&& node.or_block.kind in [.propagate_option, .propagate_result] {
unwrapped_styp = g.typ(g.assign_ct_type.derive(node.return_type).clear_flags(.option,
.result))
unwrapped_styp = g.typ(g.assign_ct_type.derive(node.return_type).clear_option_and_result())
}
if g.table.sym(node.return_type).kind == .array_fixed
&& unwrapped_styp.starts_with('_v_') {
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/orm.v
Expand Up @@ -38,7 +38,7 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
result_c_typ := g.typ(node.typ)
g.writeln('${result_c_typ} ${result_var};')
g.write_orm_select(node, connection_var_name, result_var)
unwrapped_c_typ := g.typ(node.typ.clear_flags(.result))
unwrapped_c_typ := g.typ(node.typ.clear_flag(.result))
g.write('${left} *(${unwrapped_c_typ}*)${result_var}.data')
}

Expand Down