diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 51ecdd505d..d1800650e6 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -354,10 +354,18 @@ pub fn (t Type) clear_flag(flag TypeFlag) Type { return int(t) & ~(1 << (int(flag) + 24)) } -// clear all flags +// clear all flags or multi flags [inline] -pub fn (t Type) clear_flags() Type { - return int(t) & 0xffffff +pub fn (t Type) clear_flags(flags ...TypeFlag) Type { + if flags.len == 0 { + return int(t) & 0xffffff + } else { + mut typ := int(t) + for flag in flags { + typ = typ & ~(1 << (int(flag) + 24)) + } + return typ + } } // return true if `flag` is set on `t` diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 33efba6dab..4727f9eeb9 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -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_flag(.option).clear_flag(.result)) { + } else if !c.check_basic(got, expected.clear_flags(.option, .result)) { return false } } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 10bf890dfa..aac14ace1c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1116,7 +1116,7 @@ fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_return return } last_stmt := node.stmts.last() - c.check_or_last_stmt(last_stmt, ret_type, expr_return_type.clear_flag(.option).clear_flag(.result)) + c.check_or_last_stmt(last_stmt, ret_type, expr_return_type.clear_flags(.option, .result)) } fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_return_type ast.Type) { @@ -1124,13 +1124,14 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret match stmt { ast.ExprStmt { c.expected_type = ret_type - c.expected_or_type = ret_type.clear_flag(.option).clear_flag(.result) + c.expected_or_type = ret_type.clear_flags(.option, .result) last_stmt_typ := c.expr(stmt.expr) if ret_type.has_flag(.option) && (last_stmt_typ.has_flag(.option) || last_stmt_typ == ast.none_type) { if stmt.expr in [ast.Ident, ast.SelectorExpr, ast.CallExpr, ast.None] { - expected_type_name := c.table.type_to_str(ret_type.clear_flag(.option).clear_flag(.result)) + expected_type_name := c.table.type_to_str(ret_type.clear_flags(.option, + .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()) @@ -1161,7 +1162,8 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret } return } - expected_type_name := c.table.type_to_str(ret_type.clear_flag(.option).clear_flag(.result)) + expected_type_name := c.table.type_to_str(ret_type.clear_flags(.option, + .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 { @@ -1173,7 +1175,8 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret return } type_name := c.table.type_to_str(last_stmt_typ) - expected_type_name := c.table.type_to_str(ret_type.clear_flag(.option).clear_flag(.result)) + expected_type_name := c.table.type_to_str(ret_type.clear_flags(.option, + .result)) c.error('wrong return type `${type_name}` in the `or {}` block, expected `${expected_type_name}`', stmt.expr.pos()) } @@ -1187,7 +1190,8 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret } ast.Return {} else { - expected_type_name := c.table.type_to_str(ret_type.clear_flag(.option).clear_flag(.result)) + expected_type_name := c.table.type_to_str(ret_type.clear_flags(.option, + .result)) c.error('last statement in the `or {}` block should be an expression of type `${expected_type_name}` or exit parent scope', stmt.pos) } @@ -1434,7 +1438,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_flag(.option).clear_flag(.result) + c.expected_or_type = node.typ.clear_flags(.option, .result) c.stmts_ending_with_expression(node.or_block.stmts) c.expected_or_type = ast.void_type } @@ -3179,7 +3183,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 := info.typ.clear_flag(.option).clear_flag(.result) + unwrapped_typ := info.typ.clear_flags(.option, .result) c.expected_or_type = unwrapped_typ c.stmts_ending_with_expression(node.or_expr.stmts) c.check_or_expr(node.or_expr, info.typ, c.expected_or_type, node) @@ -3245,7 +3249,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type { } } } else { - typ = obj.expr.expr_type.clear_flag(.option).clear_flag(.result) + typ = obj.expr.expr_type.clear_flags(.option, .result) } } else if obj.expr is ast.EmptyExpr { c.error('invalid variable `${node.name}`', node.pos) @@ -3278,7 +3282,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type { node.pos) } } - unwrapped_typ := typ.clear_flag(.option).clear_flag(.result) + unwrapped_typ := typ.clear_flags(.option, .result) c.expected_or_type = unwrapped_typ c.stmts_ending_with_expression(node.or_expr.stmts) c.check_or_expr(node.or_expr, typ, c.expected_or_type, node) @@ -3323,7 +3327,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_flag(.option).clear_flag(.result) + typ = typ.clear_flags(.option, .result) } } } diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 9a8654e8eb..e996bb6133 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -235,7 +235,7 @@ fn (mut c Checker) comptime_for(node ast.ComptimeFor) { unwrapped_expr_type := c.unwrap_generic(field.typ) tsym := c.table.sym(unwrapped_expr_type) - c.table.dumps[int(unwrapped_expr_type.clear_flag(.option).clear_flag(.result).clear_flag(.atomic_f))] = tsym.cname + c.table.dumps[int(unwrapped_expr_type.clear_flags(.option, .result, .atomic_f))] = tsym.cname } c.comptime_for_field_var = '' c.inside_comptime_for_field = false diff --git a/vlib/v/checker/containers.v b/vlib/v/checker/containers.v index 2306aa8266..1d1c81ee63 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -138,7 +138,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_flag(.option).clear_flag(.result) + }.clear_flags(.option, .result) } // [1,2,3] if node.exprs.len > 0 && node.elem_type == ast.void_type { @@ -299,7 +299,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_flag(.option).clear_flag(.result) + node.typ = c.expected_type.clear_flags(.option, .result) node.key_type = info.key_type node.value_type = info.value_type return node.typ diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index a4bfbdc37b..0079eb673a 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2285,7 +2285,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_flag(.option).clear_flag(.result) == ast.bool_type { + && arg_expr.return_type.clear_flags(.option, .result) == ast.bool_type { return } c.error('type mismatch, `${arg_expr.name}` must return a bool', arg_expr.pos) diff --git a/vlib/v/checker/for.v b/vlib/v/checker/for.v index 87abf3ffc7..fb789a7fc9 100644 --- a/vlib/v/checker/for.v +++ b/vlib/v/checker/for.v @@ -135,7 +135,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(.option).clear_flag(.result) + mut val_type := next_fn.return_type.clear_flags(.option, .result) if node.val_is_mut { val_type = val_type.ref() } diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 2dad0887dc..72c58e86de 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -71,7 +71,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_flag(.option).clear_flag(.result) == ast.void_type + if branch.cond.expr_type.clear_flags(.option, .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 diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 96fded29c4..49b4f413d5 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -705,7 +705,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] as ast.CallExpr).or_block.kind != .absent { is_option = false - mr_styp = g.typ(return_type.clear_flag(.option).clear_flag(.result)) + mr_styp = g.typ(return_type.clear_flags(.option, .result)) } g.write('${mr_styp} ${mr_var_name} = ') g.expr(node.right[0]) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index acd05280c2..57fb3ac3ba 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1388,7 +1388,7 @@ pub fn (mut g Gen) write_typedef_types() { g.type_definitions.writeln(def_str) } else { g.type_definitions.writeln('typedef ${fixed} ${styp} [${len}];') - base := g.typ(info.elem_type.clear_flag(.option).clear_flag(.result)) + base := g.typ(info.elem_type.clear_flags(.option, .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 { @@ -3031,7 +3031,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(.option).clear_flag(.result) + node.return_type.clear_flags(.option, .result) } mut shared_styp := '' if g.is_shared && !ret_type.has_flag(.shared_f) && !g.inside_or_block { @@ -3457,7 +3457,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_flag(.option).clear_flag(.result) + unwrapped_typ := node.typ.clear_flags(.option, .result) unwrapped_styp := g.typ(unwrapped_typ) g.write('(*(${unwrapped_styp}*)${tmp_var}.data)') return @@ -3817,7 +3817,7 @@ fn (mut g Gen) unlock_locks() { fn (mut g Gen) map_init(node ast.MapInit) { unwrap_key_typ := g.unwrap_generic(node.key_type) - unwrap_val_typ := g.unwrap_generic(node.value_type).clear_flag(.option).clear_flag(.result) + unwrap_val_typ := g.unwrap_generic(node.value_type).clear_flags(.option, .result) key_typ_str := g.typ(unwrap_key_typ) value_typ_str := g.typ(unwrap_val_typ) value_sym := g.table.sym(unwrap_val_typ) @@ -4288,11 +4288,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_flag(.option).clear_flag(.result)) + mut styp := g.typ(node.return_type.clear_flags(.option, .result)) if g.inside_return { - styp = g.typ(g.fn_decl.return_type.clear_flag(.option).clear_flag(.result)) + styp = g.typ(g.fn_decl.return_type.clear_flags(.option, .result)) } else if g.inside_or_block { - styp = g.typ(g.or_expr_return_type.clear_flag(.option).clear_flag(.result)) + styp = g.typ(g.or_expr_return_type.clear_flags(.option, .result)) } sym := g.table.sym(node.return_type) is_multi := sym.kind == .multi_return @@ -4761,7 +4761,8 @@ fn (mut g Gen) return_stmt(node ast.Return) { } } for i, expr in node.exprs { - g.expr_with_cast(expr, node.types[i], fn_ret_type.clear_flag(.option).clear_flag(.result)) + g.expr_with_cast(expr, node.types[i], fn_ret_type.clear_flags(.option, + .result)) if i < node.exprs.len - 1 { g.write(', ') } @@ -5830,7 +5831,8 @@ 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_flag(.option).clear_flag(.result)) + g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_flags(.option, + .result)) g.inside_opt_data = old_inside_opt_data g.writeln(';') g.stmt_path_pos.delete_last() @@ -5866,7 +5868,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(.option).clear_flag(.result) + g.or_expr_return_type = return_type.clear_flags(.option, .result) if g.inside_or_block { g.writeln('\terr = ${cvar_name}.err;') } else { diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index 31fc7396f9..8a0dd8f376 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -20,8 +20,8 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) { if node.expr is ast.Ident { // var if node.expr.info is ast.IdentVar && node.expr.language == .v { - name = g.typ(g.unwrap_generic(node.expr.info.typ.clear_flag(.shared_f).clear_flag(.result))).replace('*', - '') + name = g.typ(g.unwrap_generic(node.expr.info.typ.clear_flags(.shared_f, + .result))).replace('*', '') } } } @@ -32,14 +32,14 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) { if node.expr.field_expr.expr.name == g.comptime_for_field_var && node.expr.field_expr.field_name == 'name' { field, _ := g.get_comptime_selector_var_type(node.expr) - name = g.typ(g.unwrap_generic(field.typ.clear_flag(.shared_f).clear_flag(.result))) + name = g.typ(g.unwrap_generic(field.typ.clear_flags(.shared_f, .result))) expr_type = field.typ } } } } else if node.expr is ast.Ident && g.inside_comptime_for_field && g.is_comptime_var(node.expr) { expr_type = g.get_comptime_var_type(node.expr) - name = g.typ(g.unwrap_generic(expr_type.clear_flag(.shared_f).clear_flag(.result))).replace('*', + name = g.typ(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*', '') } @@ -83,7 +83,7 @@ fn (mut g Gen) dump_expr_definitions() { typ := ast.Type(dump_type) is_ptr := typ.is_ptr() deref, _ := deref_kind(str_method_expects_ptr, is_ptr, dump_type) - to_string_fn_name := g.get_str_fn(typ.clear_flag(.shared_f).clear_flag(.result)) + to_string_fn_name := g.get_str_fn(typ.clear_flags(.shared_f, .result)) ptr_asterisk := if is_ptr { '*'.repeat(typ.nr_muls()) } else { '' } mut str_dumparg_type := '' if dump_sym.kind == .none_ { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index c7558345cc..df5dfecc23 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -779,11 +779,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_flag(.option).clear_flag(.result) + mut unwrapped_typ := node.return_type.clear_flags(.option, .result) if g.table.sym(unwrapped_typ).kind == .alias { unaliased_type := g.table.unaliased_type(unwrapped_typ) if unaliased_type.has_flag(.option) || unaliased_type.has_flag(.result) { - unwrapped_typ = unaliased_type.clear_flag(.option).clear_flag(.result) + unwrapped_typ = unaliased_type.clear_flags(.option, .result) } } unwrapped_styp := g.typ(unwrapped_typ) diff --git a/vlib/v/gen/c/index.v b/vlib/v/gen/c/index.v index 501b25dbef..3221abed15 100644 --- a/vlib/v/gen/c/index.v +++ b/vlib/v/gen/c/index.v @@ -397,7 +397,7 @@ fn (mut g Gen) index_of_map(node ast.IndexExpr, sym ast.TypeSymbol) { if g.inside_return { g.typ(elem_type) } else { - g.typ(elem_type.clear_flag(.option).clear_flag(.result)) + g.typ(elem_type.clear_flags(.option, .result)) } } get_and_set_types := elem_sym.kind in [.struct_, .map, .array]