From edd56bc08049b9b62768fe1300045d9a061433fc Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Thu, 4 Jun 2020 22:38:54 +1000 Subject: [PATCH] table: allow type hold 8 flags at once --- vlib/v/checker/check_types.v | 2 +- vlib/v/checker/checker.v | 22 ++++++++++---------- vlib/v/gen/cgen.v | 32 ++++++++++++++--------------- vlib/v/gen/fn.v | 10 ++++----- vlib/v/gen/js/js.v | 2 +- vlib/v/table/atypes.v | 40 ++++++++++++++++++++---------------- vlib/v/table/table.v | 4 ++-- 7 files changed, 58 insertions(+), 54 deletions(-) diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index b87247606d..2525944ca1 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -19,7 +19,7 @@ pub fn (c &Checker) check_basic(got, expected table.Type) bool { // and the other is not, is this correct behaviour? return true } - if got_idx == table.none_type_idx && expected.flag_is(.optional) { + if got_idx == table.none_type_idx && expected.has_flag(.optional) { return true } // allow pointers to be initialized with 0. TODO: use none instead diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b7a64f4086..8a895d8057 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -826,7 +826,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { c.expected_type = exp_arg_typ got_arg_typ := c.expr(arg.expr) call_expr.args[i].typ = got_arg_typ - if method.is_variadic && got_arg_typ.flag_is(.variadic) && call_expr.args.len - + if method.is_variadic && got_arg_typ.has_flag(.variadic) && call_expr.args.len - 1 > i { c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos) } @@ -1027,7 +1027,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { call_expr.args[i].typ = typ typ_sym := c.table.get_type_symbol(typ) arg_typ_sym := c.table.get_type_symbol(arg.typ) - if f.is_variadic && typ.flag_is(.variadic) && call_expr.args.len - 1 > i { + if f.is_variadic && typ.has_flag(.variadic) && call_expr.args.len - 1 > i { c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos) } if arg.is_mut && !call_arg.is_mut { @@ -1100,7 +1100,7 @@ fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) table.Type { if expr is ast.CallExpr { call_expr := expr as ast.CallExpr - if call_expr.return_type.flag_is(.optional) { + if call_expr.return_type.has_flag(.optional) { if call_expr.or_block.kind == .absent { if ret_type != table.void_type { c.error('${call_expr.name}() returns an option, but you missed to add an `or {}` block to it', @@ -1110,7 +1110,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t c.check_or_expr(call_expr.or_block, ret_type) } // remove optional flag - return ret_type.set_flag(.unset) + return ret_type.clear_flag(.optional) } else if call_expr.or_block.kind == .block { c.error('unexpected `or` block, the function `$call_expr.name` does not return an optional', call_expr.pos) @@ -1124,7 +1124,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type) { if or_expr.kind == .propagate { - if !c.cur_fn.return_type.flag_is(.optional) && c.cur_fn.name != 'main' { + if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main' { c.error('to propagate the optional call, `${c.cur_fn.name}` must itself return an optional', or_expr.pos) } @@ -1193,7 +1193,7 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) table.T sym := c.table.get_type_symbol(c.unwrap_generic(typ)) field_name := selector_expr.field_name // variadic - if typ.flag_is(.variadic) { + if typ.has_flag(.variadic) { if field_name == 'len' { return table.int_type } @@ -1228,7 +1228,7 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) { } expected_type := c.expected_type expected_type_sym := c.table.get_type_symbol(expected_type) - exp_is_optional := expected_type.flag_is(.optional) + exp_is_optional := expected_type.has_flag(.optional) mut expected_types := [expected_type] if expected_type_sym.kind == .multi_return { mr_info := expected_type_sym.info as table.MultiReturn @@ -1258,8 +1258,8 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) { } for i, exp_type in expected_types { got_typ := got_types[i] - if got_typ.flag_is(.optional) && - (!exp_type.flag_is(.optional) || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) { + if got_typ.has_flag(.optional) && + (!exp_type.has_flag(.optional) || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) { pos := return_stmt.exprs[i].position() c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument', pos) } @@ -1977,7 +1977,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type { } typ = c.expr(it.expr) } - is_optional := typ.flag_is(.optional) + is_optional := typ.has_flag(.optional) ident.kind = .variable ident.info = ast.IdentVar{ typ: typ @@ -1993,7 +1993,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type { it.typ = typ // unwrap optional (`println(x)`) if is_optional { - return typ.set_flag(.unset) + return typ.clear_flag(.optional) } return typ } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 8d254f2564..33bcb69bb3 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -324,7 +324,7 @@ fn (g &Gen) typ(t table.Type) string { // T => int etc return g.typ(g.cur_generic_type) } - if t.flag_is(.optional) { + if t.has_flag(.optional) { // Register an optional if it's not registered yet return g.register_optional(t) } @@ -844,7 +844,7 @@ fn (mut g Gen) for_in(it ast.ForInStmt) { } g.stmts(it.stmts) g.writeln('}') - } else if it.cond_type.flag_is(.variadic) { + } else if it.cond_type.has_flag(.variadic) { g.writeln('// FOR IN cond_type/variadic') i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var } styp := g.typ(it.cond_type) @@ -901,7 +901,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type) got_deref_type := got_type.deref() deref_sym := g.table.get_type_symbol(got_deref_type) deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx] - got_is_opt := got_type.flag_is(.optional) + got_is_opt := got_type.has_flag(.optional) if deref_will_match || got_is_opt { g.write('*') } @@ -1015,7 +1015,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { 1 { // multi return // TODO Handle in if_expr - is_optional := return_type.flag_is(.optional) + is_optional := return_type.has_flag(.optional) mr_var_name := 'mr_$assign_stmt.pos.pos' mr_styp := g.typ(return_type) g.write('$mr_styp $mr_var_name = ') @@ -1289,7 +1289,7 @@ fn (mut g Gen) autofree_scope_vars(pos int) string { // continue // } v := *it - is_optional := v.typ.flag_is(.optional) + is_optional := v.typ.has_flag(.optional) if is_optional { // TODO: free optionals continue @@ -1644,7 +1644,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) { } else {} } - gen_or := is_call && return_type.flag_is(.optional) + gen_or := is_call && return_type.has_flag(.optional) tmp_opt := if gen_or { g.new_tmp_var() } else { '' } if gen_or { rstyp := g.typ(return_type) @@ -1662,7 +1662,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) { } } else { g.is_assign_lhs = true - if node.right_type.flag_is(.optional) { + if node.right_type.has_flag(.optional) { g.right_is_opt = true } mut str_add := false @@ -1719,7 +1719,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) { if gen_or { // g.write('/*777 $tmp_opt*/') g.or_block(tmp_opt, or_block, return_type) - unwrapped_type_str := g.typ(return_type.set_flag(.unset)) + unwrapped_type_str := g.typ(return_type.clear_flag(.optional)) ident := node.left as ast.Ident if ident.kind != .blank_ident && ident.info is ast.IdentVar { ident_var := ident.info as ast.IdentVar @@ -2207,7 +2207,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { if !is_range { sym := g.table.get_type_symbol(node.left_type) left_is_ptr := node.left_type.is_ptr() - if node.left_type.flag_is(.variadic) { + if node.left_type.has_flag(.variadic) { g.expr(node.left) g.write('.args') g.write('[') @@ -2339,7 +2339,7 @@ fn (mut g Gen) return_statement(node ast.Return) { // got to do a correct check for multireturn sym := g.table.get_type_symbol(g.fn_decl.return_type) fn_return_is_multi := sym.kind == .multi_return - fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional) + fn_return_is_optional := g.fn_decl.return_type.has_flag(.optional) // handle promoting none/error/function returning 'Option' if fn_return_is_optional { optional_none := node.exprs[0] is ast.None @@ -2418,7 +2418,7 @@ fn (mut g Gen) return_statement(node ast.Return) { // normal return return_sym := g.table.get_type_symbol(node.types[0]) // `return opt_ok(expr)` for functions that expect an optional - if fn_return_is_optional && !node.types[0].flag_is(.optional) && return_sym.name != + if fn_return_is_optional && !node.types[0].has_flag(.optional) && return_sym.name != 'Option' { styp := g.base_type(g.fn_decl.return_type) opt_type := g.typ(g.fn_decl.return_type) @@ -2631,7 +2631,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { // unions thould have exactly one explicit initializer continue } - if field.typ.flag_is(.optional) { + if field.typ.has_flag(.optional) { // TODO handle/require optionals in inits continue } @@ -2813,7 +2813,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) { // if this is the case then we are going to // buffer manip out in front of the struct // write the optional in and then continue - if field.typ.flag_is(.optional) { + if field.typ.has_flag(.optional) { // Dont use g.typ() here becuase it will register // optional and we dont want that last_text := g.type_definitions.after(start_pos).clone() @@ -3102,7 +3102,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool { sym := g.table.get_type_symbol(etype) sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() - if etype.flag_is(.variadic) { + if etype.has_flag(.variadic) { str_fn_name := g.gen_str_for_type(etype) g.write('${str_fn_name}(') g.expr(expr) @@ -3294,7 +3294,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table. expr_stmt := stmt as ast.ExprStmt g.stmt_path_pos << g.out.len g.write('*(${mr_styp}*) ${cvar_name}.data = ') - is_opt_call := expr_stmt.expr is ast.CallExpr && expr_stmt.typ.flag_is(.optional) + is_opt_call := expr_stmt.expr is ast.CallExpr && expr_stmt.typ.has_flag(.optional) if is_opt_call { g.write('*(${mr_styp}*) ') } @@ -3858,7 +3858,7 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string { } } // if varg, generate str for varg - if typ.flag_is(.variadic) { + if typ.has_flag(.variadic) { varg_already_generated_key := 'varg_$already_generated_key' if varg_already_generated_key !in g.str_types { g.gen_str_for_varg(styp, str_fn_name, sym_has_str_method) diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index be4116bed3..1e1b734421 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -430,7 +430,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { } g.expr(node.left) is_variadic := node.expected_arg_types.len > 0 && node.expected_arg_types[node.expected_arg_types.len - - 1].flag_is(.variadic) + 1].has_flag(.variadic) if node.args.len > 0 || is_variadic { g.write(', ') } @@ -523,7 +523,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { styp = styp.replace('*', '') } mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp) - if g.autofree && !typ.flag_is(.optional) { + if g.autofree && !typ.has_flag(.optional) { // Create a temporary variable so that the value can be freed tmp := g.new_tmp_var() // tmps << tmp @@ -565,7 +565,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { g.write('*') } g.expr(expr) - if !typ.flag_is(.variadic) && sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') { + if !typ.has_flag(.variadic) && sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') { g.write(', 0') // trailing 0 is initial struct indent count } } @@ -599,8 +599,8 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { } fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) { - is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].flag_is(.variadic) - is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic) + is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].has_flag(.variadic) + is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.has_flag(.variadic) gen_vargs := is_variadic && !is_forwarding_varg for i, arg in args { if gen_vargs && i == expected_types.len - 1 { diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index eebbec19b6..631fd7737f 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -908,7 +908,7 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) { g.inside_loop = false g.stmts(it.stmts) g.writeln('}') - } else if it.kind == .array || it.cond_type.flag_is(.variadic) { + } else if it.kind == .array || it.cond_type.has_flag(.variadic) { // `for num in nums {` i := if it.key_var == '' { g.new_tmp_var() } else { it.key_var } // styp := g.typ(it.val_type) diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 7d350791c1..d429df487f 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -36,8 +36,8 @@ pub mut: is_public bool } +// max of 8 pub enum TypeFlag { - unset optional variadic generic @@ -99,29 +99,33 @@ pub fn (t Type) deref() Type { return (((int(t) >> 24) & 0xff) << 24) | ((nr_muls - 1) << 16) | (u16(t) & 0xffff) } -// return the flag that is set on `t` -[inline] -pub fn (t Type) flag() TypeFlag { - return (int(t) >> 24) & 0xff -} - -// set the flag on `t` to `flag` and return it +// set `flag` on `t` and return `t` [inline] pub fn (t Type) set_flag(flag TypeFlag) Type { - return (int(flag) << 24) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff) + return ((((int(t) >> 24) & 0xff) | 1 << int(flag)) << 24) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff) } -// return true if the flag set on `t` is `flag` +// clear `flag` on `t` and return `t` +pub fn (t Type) clear_flag(flag TypeFlag) Type { + return (((((int(t) >> 24) & 0xff) & ~(1 << int(flag))) << 24) ) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff) +} + +// clear all flags +pub fn (t Type) clear_flags() Type { + return 0 | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff) +} + +// return true if `flag` is set in `t` [inline] -pub fn (t Type) flag_is(flag TypeFlag) bool { - return (int(t) >> 24) & 0xff == flag +pub fn (t Type) has_flag(flag TypeFlag) bool { + return (((int(t) >> 24) & 0xff) >> int(flag)) & 1 == 1 } // return new type with TypeSymbol idx set to `idx` [inline] pub fn new_type(idx int) Type { - if idx < 1 || idx > 65536 { - panic('new_type_id: idx must be between 1 & 65536') + if idx < 1 || idx > 65535 { + panic('new_type_id: idx must be between 1 & 65535') } return idx } @@ -129,8 +133,8 @@ pub fn new_type(idx int) Type { // return new type with TypeSymbol idx set to `idx` & nr_muls set to `nr_muls` [inline] pub fn new_type_ptr(idx, nr_muls int) Type { - if idx < 1 || idx > 65536 { - panic('new_type_ptr: idx must be between 1 & 65536') + if idx < 1 || idx > 65535 { + panic('new_type_ptr: idx must be between 1 & 65535') } if nr_muls < 0 || nr_muls > 255 { panic('new_type_ptr: nr_muls must be between 0 & 255') @@ -673,7 +677,7 @@ pub fn (table &Table) type_to_str(t Type) string { mut res := sym.name if sym.kind == .multi_return { res = '(' - if t.flag_is(.optional) { + if t.has_flag(.optional) { res = '?' + res } mr_info := sym.info as MultiReturn @@ -706,7 +710,7 @@ pub fn (table &Table) type_to_str(t Type) string { if nr_muls > 0 { res = strings.repeat(`&`, nr_muls) + res } - if t.flag_is(.optional) { + if t.has_flag(.optional) { if sym.kind == .void { res = '?' } else { diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index ae3540d63c..e10aec8f01 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -417,9 +417,9 @@ pub fn (mut t Table) add_placeholder_type(name string) int { [inline] pub fn (t &Table) value_type(typ Type) Type { typ_sym := t.get_type_symbol(typ) - if typ.flag_is(.variadic) { + if typ.has_flag(.variadic) { // ...string => string - return typ.set_flag(.unset) + return typ.clear_flag(.variadic) } if typ_sym.kind == .array { // Check index type