diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index cb05a36f58bce9..dfc01eccdcf771 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -142,8 +142,8 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { && ((left.info as ast.IdentVar).share == .shared_t || left_type.has_flag(.shared_f)) && c.table.sym(left_type).kind in [.array, .map, .struct_] } - if c.inside_comptime_for_field && mut left is ast.ComptimeSelector { - left_type = c.comptime_fields_default_type + if c.comptime.comptime_for_field_var != '' && mut left is ast.ComptimeSelector { + left_type = c.comptime.comptime_for_field_type c.expected_type = c.unwrap_generic(left_type) } if node.right_types.len < node.left.len { // first type or multi return types added above @@ -183,7 +183,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { right_type = right_type.clear_flag(.option) } } else if right is ast.ComptimeSelector { - right_type = c.comptime_fields_default_type + right_type = c.comptime.comptime_for_field_type } if is_decl || is_shared_re_assign { // check generic struct init and return unwrap generic struct type @@ -351,12 +351,12 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { if right is ast.ComptimeSelector { if is_decl { left.obj.ct_type_var = .field_var - left.obj.typ = c.comptime_fields_default_type + left.obj.typ = c.comptime.comptime_for_field_type } } else if mut right is ast.Ident && right.obj is ast.Var && right.or_expr.kind == .absent { if (right.obj as ast.Var).ct_type_var != .no_comptime { - ctyp := c.get_comptime_var_type(right) + ctyp := c.comptime.get_comptime_var_type(right) if ctyp != ast.void_type { left.obj.ct_type_var = (right.obj as ast.Var).ct_type_var left.obj.typ = ctyp @@ -365,7 +365,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { } else if right is ast.DumpExpr && right.expr is ast.ComptimeSelector { left.obj.ct_type_var = .field_var - left.obj.typ = c.comptime_fields_default_type + left.obj.typ = c.comptime.comptime_for_field_type } } ast.GlobalField { @@ -766,8 +766,8 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', } } else { // allow `t.$(field.name) = 0` where `t.$(field.name)` is a enum - if c.inside_comptime_for_field && left is ast.ComptimeSelector { - field_sym := c.table.sym(c.unwrap_generic(c.comptime_fields_default_type)) + if c.comptime.comptime_for_field_var != '' && left is ast.ComptimeSelector { + field_sym := c.table.sym(c.unwrap_generic(c.comptime.comptime_for_field_type)) if field_sym.kind == .enum_ && !right_type.is_int() { c.error('enums can only be assigned `int` values', right.pos()) diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 7fe74e92d7df6a..27c412112159c7 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -235,7 +235,7 @@ fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, lan } if !expected.has_flag(.option) && got.has_flag(.option) && (arg.expr !is ast.Ident - || (arg.expr is ast.Ident && c.get_ct_type_var(arg.expr) != .field_var)) { + || (arg.expr is ast.Ident && c.comptime.get_ct_type_var(arg.expr) != .field_var)) { got_typ_str, expected_typ_str := c.get_string_names_of(got, expected) return error('cannot use `${got_typ_str}` as `${expected_typ_str}`, it must be unwrapped first') } @@ -919,9 +919,9 @@ fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr) { func_.name = '' idx := c.table.find_or_register_fn_type(func_, true, false) typ = ast.new_type(idx).derive(arg.typ) - } else if c.inside_comptime_for_field && sym.kind in [.struct_, .any] + } else if c.comptime.comptime_for_field_var != '' && sym.kind in [.struct_, .any] && arg.expr is ast.ComptimeSelector { - comptime_typ := c.get_comptime_selector_type(arg.expr, ast.void_type) + comptime_typ := c.comptime.get_comptime_selector_type(arg.expr, ast.void_type) if comptime_typ != ast.void_type { typ = comptime_typ if func.return_type.has_flag(.generic) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 1af632e137d71d..b41fc4419d94f4 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -12,6 +12,7 @@ import v.util.version import v.errors import v.pkgconfig import v.transformer +import v.comptime const int_min = int(0x80000000) const int_max = int(0x7FFFFFFF) @@ -82,7 +83,6 @@ pub mut: inside_fn_arg bool // `a`, `b` in `a.f(b)` inside_ct_attr bool // true inside `[if expr]` inside_x_is_type bool // true inside the Type expression of `if x is Type {` - inside_comptime_for_field bool inside_generic_struct_init bool cur_struct_generic_types []ast.Type cur_struct_concrete_types []ast.Type @@ -108,16 +108,8 @@ mut: loop_label string // set when inside a labelled for loop vweb_gen_types []ast.Type // vweb route checks timers &util.Timers = util.get_timers() - comptime_for_field_var string - comptime_for_variant_var string - comptime_fields_default_type ast.Type - comptime_fields_type map[string]ast.Type - comptime_for_field_value ast.StructField // value of the field variable - comptime_enum_field_value string // current enum value name - comptime_for_method string // $for method in T.methods {} - comptime_for_method_var string // $for method in T.methods {}; the variable name - comptime_for_method_ret_type ast.Type // $for method - current method.return_type field - comptime_values_stack []CurrentComptimeValues // stores the values from the above on each $for loop, to make nesting them easier + comptime_info_stack []comptime.ComptimeInfo // stores the values from the above on each $for loop, to make nesting them easier + comptime comptime.ComptimeInfo fn_scope &ast.Scope = unsafe { nil } main_fn_decl_node ast.FnDecl match_exhaustive_cutoff_limit int = 10 @@ -150,13 +142,18 @@ pub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker { $if time_checking ? { timers_should_print = true } - return &Checker{ + mut checker := &Checker{ table: table pref: pref_ timers: util.new_timers(should_print: timers_should_print, label: 'checker') match_exhaustive_cutoff_limit: pref_.checker_match_exhaustive_cutoff_limit v_current_commit_hash: version.githash(pref_.building_v) } + checker.comptime = &comptime.ComptimeInfo{ + resolver: checker + table: table + } + return checker } fn (mut c Checker) reset_checker_state_at_start_of_new_file() { @@ -1448,8 +1445,8 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { } } // evaluates comptime field. (from T.fields) - if c.check_comptime_is_field_selector(node) { - if c.check_comptime_is_field_selector_bool(node) { + if c.comptime.check_comptime_is_field_selector(node) { + if c.comptime.check_comptime_is_field_selector_bool(node) { node.expr_type = ast.bool_type return node.expr_type } @@ -1472,9 +1469,10 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { c.error('`${node.expr}` does not return a value', node.pos) node.expr_type = ast.void_type return ast.void_type - } else if c.inside_comptime_for_field && typ == c.enum_data_type && node.field_name == 'value' { + } else if c.comptime.inside_comptime_for && typ == c.enum_data_type + && node.field_name == 'value' { // for comp-time enum.values - node.expr_type = c.comptime_fields_type['${c.comptime_for_field_var}.typ'] + node.expr_type = c.comptime.type_map['${c.comptime.comptime_for_enum_var}.typ'] node.typ = typ return node.expr_type } @@ -2169,7 +2167,7 @@ fn (mut c Checker) branch_stmt(node ast.BranchStmt) { c.error('`${node.kind.str()}` is not allowed in defer statements', node.pos) } if c.in_for_count == 0 { - if c.inside_comptime_for_field { + if c.comptime.inside_comptime_for { c.error('${node.kind.str()} is not allowed within a compile-time loop', node.pos) } else { c.error('${node.kind.str()} statement not within a loop', node.pos) @@ -2712,11 +2710,11 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { c.expected_type = ast.string_type node.expr_type = c.expr(mut node.expr) - if c.inside_comptime_for_field && node.expr is ast.Ident { - if c.table.is_comptime_var(node.expr) { - node.expr_type = c.get_comptime_var_type(node.expr as ast.Ident) - } else if (node.expr as ast.Ident).name in c.comptime_fields_type { - node.expr_type = c.comptime_fields_type[(node.expr as ast.Ident).name] + if c.comptime.inside_comptime_for && node.expr is ast.Ident { + if c.comptime.is_comptime_var(node.expr) { + node.expr_type = c.comptime.get_comptime_var_type(node.expr as ast.Ident) + } else if (node.expr as ast.Ident).name in c.comptime.type_map { + node.expr_type = c.comptime.type_map[(node.expr as ast.Ident).name] } } c.check_expr_opt_call(node.expr, node.expr_type) @@ -2986,7 +2984,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { node.expr_type = c.expr(mut node.expr) // type to be casted if mut node.expr is ast.ComptimeSelector { - node.expr_type = c.get_comptime_selector_type(node.expr, node.expr_type) + node.expr_type = c.comptime.get_comptime_selector_type(node.expr, node.expr_type) } mut from_type := c.unwrap_generic(node.expr_type) @@ -3476,8 +3474,8 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type { // second use if node.kind in [.constant, .global, .variable] { info := node.info as ast.IdentVar - typ := if c.table.is_comptime_var(node) { - ctype := c.get_comptime_var_type(node) + typ := if c.comptime.is_comptime_var(node) { + ctype := c.comptime.get_comptime_var_type(node) if ctype != ast.void_type { ctype } else { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 63701813548f08..b489802163a8f7 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -8,64 +8,7 @@ import v.pref import v.token import v.util import v.pkgconfig - -@[inline] -fn (mut c Checker) get_ct_type_var(node ast.Expr) ast.ComptimeVarKind { - return if node is ast.Ident && node.obj is ast.Var { - (node.obj as ast.Var).ct_type_var - } else { - .no_comptime - } -} - -@[inline] -fn (mut c Checker) get_comptime_var_type(node ast.Expr) ast.Type { - if node is ast.Ident && node.obj is ast.Var { - return match (node.obj as ast.Var).ct_type_var { - .generic_param { - // generic parameter from current function - node.obj.typ - } - .key_var, .value_var { - // key and value variables from normal for stmt - c.comptime_fields_type[node.name] or { ast.void_type } - } - .field_var { - // field var from $for loop - c.comptime_fields_default_type - } - else { - ast.void_type - } - } - } else if node is ast.ComptimeSelector { - // val.$(field.name) - return c.get_comptime_selector_type(node, ast.void_type) - } else if node is ast.SelectorExpr && c.is_comptime_selector_type(node) { - if node.expr is ast.Ident { - match node.expr.name { - c.comptime_for_variant_var { - return c.comptime_fields_type['${c.comptime_for_variant_var}.typ'] - } - else { - // field_var.typ from $for field - return c.comptime_fields_default_type - } - } - } - return c.comptime_fields_default_type - } else if node is ast.ComptimeCall { - method_name := c.comptime_for_method - left_sym := c.table.sym(c.unwrap_generic(node.left_type)) - f := left_sym.find_method(method_name) or { - c.error('could not find method `${method_name}` on compile-time resolution', - node.method_pos) - return ast.void_type - } - return f.return_type - } - return ast.void_type -} +import v.comptime fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { if node.left !is ast.EmptyExpr { @@ -174,7 +117,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { node.args[i].typ = c.expr(mut arg.expr) } c.stmts_ending_with_expression(mut node.or_block.stmts) - return c.get_comptime_var_type(node) + return c.comptime.get_comptime_var_type(node) } if node.method_name == 'res' { if !c.inside_defer { @@ -250,17 +193,17 @@ fn (mut c Checker) comptime_selector(mut node ast.ComptimeSelector) ast.Type { } if mut node.field_expr is ast.SelectorExpr { left_pos := node.field_expr.expr.pos() - if c.comptime_fields_type.len == 0 { + if c.comptime.type_map.len == 0 { c.error('compile time field access can only be used when iterating over `T.fields`', left_pos) } - expr_type = c.get_comptime_selector_type(node, ast.void_type) + expr_type = c.comptime.get_comptime_selector_type(node, ast.void_type) if expr_type != ast.void_type { return expr_type } expr_name := node.field_expr.expr.str() - if expr_name in c.comptime_fields_type { - return c.comptime_fields_type[expr_name] + if expr_name in c.comptime.type_map { + return c.comptime.type_map[expr_name] } c.error('unknown `\$for` variable `${expr_name}`', left_pos) } else { @@ -292,17 +235,17 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { return } } - c.push_existing_comptime_values() - c.inside_comptime_for_field = true for field in fields { + c.push_new_comptime_info() + c.comptime.inside_comptime_for = true if c.field_data_type == 0 { c.field_data_type = ast.Type(c.table.find_type_idx('FieldData')) } - c.comptime_for_field_value = field - c.comptime_for_field_var = node.val_var - c.comptime_fields_type[node.val_var] = c.field_data_type - c.comptime_fields_type['${node.val_var}.typ'] = node.typ - c.comptime_fields_default_type = field.typ + c.comptime.comptime_for_field_value = field + c.comptime.comptime_for_field_var = node.val_var + c.comptime.type_map[node.val_var] = c.field_data_type + c.comptime.type_map['${node.val_var}.typ'] = node.typ + c.comptime.comptime_for_field_type = field.typ c.stmts(mut node.stmts) unwrapped_expr_type := c.unwrap_generic(field.typ) @@ -316,8 +259,8 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { info.size_expr, true) } } + c.pop_comptime_info() } - c.pop_existing_comptime_values() } else if c.table.generic_type_names(node.typ).len == 0 && sym.kind != .placeholder { c.error('iterating over .fields is supported only for structs and interfaces, and ${sym.name} is neither', node.typ_pos) @@ -325,20 +268,16 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { } } else if node.kind == .values { if sym.kind == .enum_ { - c.push_existing_comptime_values() - sym_info := sym.info as ast.Enum - c.inside_comptime_for_field = true + c.push_new_comptime_info() + c.comptime.inside_comptime_for = true if c.enum_data_type == 0 { c.enum_data_type = ast.Type(c.table.find_type_idx('EnumData')) } - for field in sym_info.vals { - c.comptime_enum_field_value = field - c.comptime_for_field_var = node.val_var - c.comptime_fields_type[node.val_var] = c.enum_data_type - c.comptime_fields_type['${node.val_var}.typ'] = node.typ - c.stmts(mut node.stmts) - } - c.pop_existing_comptime_values() + c.comptime.comptime_for_enum_var = node.val_var + c.comptime.type_map[node.val_var] = c.enum_data_type + c.comptime.type_map['${node.val_var}.typ'] = node.typ + c.stmts(mut node.stmts) + c.pop_comptime_info() } else { c.error('iterating over .values is supported only for enums, and ${sym.name} is not an enum', node.typ_pos) @@ -349,28 +288,29 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { methods_with_attrs := sym.methods.filter(it.attrs.len > 0) // methods with attrs second methods << methods_with_attrs - c.push_existing_comptime_values() for method in methods { - c.comptime_for_method = method.name - c.comptime_for_method_var = node.val_var - c.comptime_for_method_ret_type = method.return_type - c.comptime_fields_type['${node.val_var}.return_type'] = method.return_type + c.push_new_comptime_info() + c.comptime.inside_comptime_for = true + c.comptime.comptime_for_method = method.name + c.comptime.comptime_for_method_var = node.val_var + c.comptime.comptime_for_method_ret_type = method.return_type + c.comptime.type_map['${node.val_var}.return_type'] = method.return_type c.stmts(mut node.stmts) + c.pop_comptime_info() } - c.pop_existing_comptime_values() } else if node.kind == .variants { - c.push_existing_comptime_values() - c.inside_comptime_for_field = true if c.variant_data_type == 0 { c.variant_data_type = ast.Type(c.table.find_type_idx('VariantData')) } for variant in (sym.info as ast.SumType).variants { - c.comptime_for_variant_var = node.val_var - c.comptime_fields_type[node.val_var] = c.variant_data_type - c.comptime_fields_type['${node.val_var}.typ'] = variant + c.push_new_comptime_info() + c.comptime.inside_comptime_for = true + c.comptime.comptime_for_variant_var = node.val_var + c.comptime.type_map[node.val_var] = c.variant_data_type + c.comptime.type_map['${node.val_var}.typ'] = variant c.stmts(mut node.stmts) + c.pop_comptime_info() } - c.pop_existing_comptime_values() } else { c.stmts(mut node.stmts) } @@ -786,7 +726,7 @@ fn (mut c Checker) comptime_if_branch(mut cond ast.Expr, pos token.Pos) Comptime } else if cond.left is ast.TypeNode && mut cond.right is ast.ComptimeType { left := cond.left as ast.TypeNode checked_type := c.unwrap_generic(left.typ) - return if c.table.is_comptime_type(checked_type, cond.right) { + return if c.comptime.is_comptime_type(checked_type, cond.right) { .eval } else { .skip @@ -794,10 +734,11 @@ fn (mut c Checker) comptime_if_branch(mut cond ast.Expr, pos token.Pos) Comptime } else if cond.left in [ast.Ident, ast.SelectorExpr, ast.TypeNode] { // `$if method.@type is string` c.expr(mut cond.left) - if cond.left is ast.SelectorExpr && c.is_comptime_selector_type(cond.left) + if cond.left is ast.SelectorExpr + && c.comptime.is_comptime_selector_type(cond.left) && mut cond.right is ast.ComptimeType { - checked_type := c.get_comptime_var_type(cond.left) - return if c.table.is_comptime_type(checked_type, cond.right) { + checked_type := c.comptime.get_comptime_var_type(cond.left) + return if c.comptime.is_comptime_type(checked_type, cond.right) { .eval } else { .skip @@ -816,10 +757,10 @@ fn (mut c Checker) comptime_if_branch(mut cond ast.Expr, pos token.Pos) Comptime // $if method.args.len == 1 return .unknown } else if cond.left is ast.SelectorExpr - && c.check_comptime_is_field_selector_bool(cond.left) { + && c.comptime.check_comptime_is_field_selector_bool(cond.left) { // field.is_public (from T.fields) } else if cond.right is ast.SelectorExpr - && c.check_comptime_is_field_selector_bool(cond.right) { + && c.comptime.check_comptime_is_field_selector_bool(cond.right) { // field.is_public (from T.fields) } else if cond.left is ast.Ident { // $if version == 2 @@ -873,7 +814,7 @@ fn (mut c Checker) comptime_if_branch(mut cond ast.Expr, pos token.Pos) Comptime } .gt, .lt, .ge, .le { if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral - && c.is_comptime_selector_field_name(cond.left, 'indirections') { + && c.comptime.is_comptime_selector_field_name(cond.left, 'indirections') { return .unknown } c.error('invalid `\$if` condition', cond.pos) @@ -1000,12 +941,12 @@ fn (mut c Checker) comptime_if_branch(mut cond ast.Expr, pos token.Pos) Comptime return .eval } ast.SelectorExpr { - if c.check_comptime_is_field_selector(cond) { - if c.check_comptime_is_field_selector_bool(cond) { - ret_bool := c.get_comptime_selector_bool_field(cond.field_name) + if c.comptime.check_comptime_is_field_selector(cond) { + if c.comptime.check_comptime_is_field_selector_bool(cond) { + ret_bool := c.comptime.get_comptime_selector_bool_field(cond.field_name) return if ret_bool { .eval } else { .skip } } - c.error('unknown field `${cond.field_name}` from ${c.comptime_for_field_var}', + c.error('unknown field `${cond.field_name}` from ${c.comptime.comptime_for_field_var}', cond.pos) } return .unknown @@ -1017,112 +958,37 @@ fn (mut c Checker) comptime_if_branch(mut cond ast.Expr, pos token.Pos) Comptime return .unknown } -// get_comptime_selector_type retrieves the var.$(field.name) type when field_name is 'name' otherwise default_type is returned -@[inline] -fn (mut c Checker) get_comptime_selector_type(node ast.ComptimeSelector, default_type ast.Type) ast.Type { - if node.field_expr is ast.SelectorExpr && c.check_comptime_is_field_selector(node.field_expr) - && node.field_expr.field_name == 'name' { - return c.unwrap_generic(c.comptime_fields_default_type) - } - return default_type -} - -// is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable accessing specific field name provided by `field_name` -@[inline] -fn (mut c Checker) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool { - return c.inside_comptime_for_field && node.expr is ast.Ident - && node.expr.name == c.comptime_for_field_var && node.field_name == field_name -} - -// is_comptime_selector_type checks if the SelectorExpr is related to $for variable accessing .typ field -@[inline] -fn (mut c Checker) is_comptime_selector_type(node ast.SelectorExpr) bool { - if c.inside_comptime_for_field && node.expr is ast.Ident { - return node.expr.name in [c.comptime_for_variant_var, c.comptime_for_field_var] - && node.field_name == 'typ' - } - return false -} - -// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable -@[inline] -fn (mut c Checker) check_comptime_is_field_selector(node ast.SelectorExpr) bool { - if c.inside_comptime_for_field && node.expr is ast.Ident { - return node.expr.name == c.comptime_for_field_var - } - return false -} - -// check_comptime_is_field_selector_bool checks if the SelectorExpr is related to field.is_* boolean fields -@[inline] -fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr) bool { - if c.check_comptime_is_field_selector(node) { - return node.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_option', - 'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias', 'is_enum'] - } - return false -} - -// get_comptime_selector_bool_field evaluates the bool value for field.is_* fields -fn (mut c Checker) get_comptime_selector_bool_field(field_name string) bool { - field := c.comptime_for_field_value - field_typ := c.comptime_fields_default_type - field_sym := c.table.sym(c.unwrap_generic(c.comptime_fields_default_type)) - - match field_name { - 'is_pub' { return field.is_pub } - 'is_mut' { return field.is_mut } - 'is_shared' { return field_typ.has_flag(.shared_f) } - 'is_atomic' { return field_typ.has_flag(.atomic_f) } - 'is_option' { return field.typ.has_flag(.option) } - 'is_array' { return field_sym.kind in [.array, .array_fixed] } - 'is_map' { return field_sym.kind == .map } - 'is_chan' { return field_sym.kind == .chan } - 'is_struct' { return field_sym.kind == .struct_ } - 'is_alias' { return field_sym.kind == .alias } - 'is_enum' { return field_sym.kind == .enum_ } - else { return false } - } -} - -struct CurrentComptimeValues { - inside_comptime_for_field bool - comptime_for_field_var string - comptime_for_variant_var string - comptime_fields_default_type ast.Type - comptime_fields_type map[string]ast.Type - comptime_for_field_value ast.StructField - comptime_enum_field_value string - comptime_for_method string - comptime_for_method_var string - comptime_for_method_ret_type ast.Type -} - -fn (mut c Checker) push_existing_comptime_values() { - c.comptime_values_stack << CurrentComptimeValues{ - inside_comptime_for_field: c.inside_comptime_for_field - comptime_for_field_var: c.comptime_for_field_var - comptime_for_variant_var: c.comptime_for_variant_var - comptime_fields_default_type: c.comptime_fields_default_type - comptime_fields_type: c.comptime_fields_type.clone() - comptime_for_field_value: c.comptime_for_field_value - comptime_enum_field_value: c.comptime_enum_field_value - comptime_for_method: c.comptime_for_method - comptime_for_method_var: c.comptime_for_method_var - comptime_for_method_ret_type: c.comptime_for_method_ret_type +// push_new_comptime_info saves the current comptime information +fn (mut c Checker) push_new_comptime_info() { + c.comptime_info_stack << comptime.ComptimeInfo{ + resolver: c.comptime.resolver + table: c.comptime.table + type_map: c.comptime.type_map.clone() + inside_comptime_for: c.comptime.inside_comptime_for + comptime_for_variant_var: c.comptime.comptime_for_variant_var + comptime_for_field_var: c.comptime.comptime_for_field_var + comptime_for_field_type: c.comptime.comptime_for_field_type + comptime_for_field_value: c.comptime.comptime_for_field_value + comptime_for_enum_var: c.comptime.comptime_for_enum_var + comptime_for_method_var: c.comptime.comptime_for_method_var + comptime_for_method: c.comptime.comptime_for_method + comptime_for_method_ret_type: c.comptime.comptime_for_method_ret_type } } -fn (mut c Checker) pop_existing_comptime_values() { - old := c.comptime_values_stack.pop() - c.inside_comptime_for_field = old.inside_comptime_for_field - c.comptime_for_field_var = old.comptime_for_field_var - c.comptime_for_variant_var = old.comptime_for_variant_var - c.comptime_fields_default_type = old.comptime_fields_default_type - c.comptime_fields_type = old.comptime_fields_type.clone() - c.comptime_for_field_value = old.comptime_for_field_value - c.comptime_enum_field_value = old.comptime_enum_field_value - c.comptime_for_method = old.comptime_for_method - c.comptime_for_method_var = old.comptime_for_method_var - c.comptime_for_method_ret_type = old.comptime_for_method_ret_type +// pop_comptime_info pops the current comptime information frame +fn (mut c Checker) pop_comptime_info() { + old := c.comptime_info_stack.pop() + c.comptime.resolver = old.resolver + c.comptime.table = old.table + c.comptime.type_map = old.type_map.clone() + c.comptime.inside_comptime_for = old.inside_comptime_for + c.comptime.comptime_for_variant_var = old.comptime_for_variant_var + c.comptime.comptime_for_field_var = old.comptime_for_field_var + c.comptime.comptime_for_field_type = old.comptime_for_field_type + c.comptime.comptime_for_field_value = old.comptime_for_field_value + c.comptime.comptime_for_enum_var = old.comptime_for_enum_var + c.comptime.comptime_for_method_var = old.comptime_for_method_var + c.comptime.comptime_for_method = old.comptime_for_method + c.comptime.comptime_for_method_ret_type = old.comptime_for_method_ret_type } diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 8a8052fa80daae..c8d1fae5b0e0f1 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1199,7 +1199,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. arg_typ = c.expr(mut call_arg.expr) } node.args[i].typ = arg_typ - if c.inside_comptime_for_field { + if c.comptime.comptime_for_field_var != '' { if mut call_arg.expr is ast.Ident { if mut call_arg.expr.obj is ast.Var { node.args[i].typ = call_arg.expr.obj.typ @@ -1440,7 +1440,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. continue } c.check_expected_call_arg(utyp, unwrap_typ, node.language, call_arg) or { - if c.comptime_fields_type.len > 0 { + if c.comptime.type_map.len > 0 { continue } c.error('${err.msg()} in argument ${i + 1} to `${fn_name}`', call_arg.pos) @@ -1505,7 +1505,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. fn (mut c Checker) resolve_comptime_args(func ast.Fn, node_ ast.CallExpr, concrete_types []ast.Type) map[int]ast.Type { mut comptime_args := map[int]ast.Type{} has_dynamic_vars := (c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0) - || c.inside_comptime_for_field + || c.comptime.comptime_for_field_var != '' if has_dynamic_vars { offset := if func.is_method { 1 } else { 0 } mut k := -1 @@ -1523,7 +1523,7 @@ fn (mut c Checker) resolve_comptime_args(func ast.Fn, node_ ast.CallExpr, concre if call_arg.expr is ast.Ident { if call_arg.expr.obj is ast.Var { if call_arg.expr.obj.ct_type_var !in [.generic_param, .no_comptime] { - mut ctyp := c.get_comptime_var_type(call_arg.expr) + mut ctyp := c.comptime.get_comptime_var_type(call_arg.expr) if ctyp != ast.void_type { arg_sym := c.table.sym(ctyp) if arg_sym.info is ast.Array && param_typ.has_flag(.generic) @@ -1533,7 +1533,7 @@ fn (mut c Checker) resolve_comptime_args(func ast.Fn, node_ ast.CallExpr, concre comptime_args[k] = ctyp } } else if call_arg.expr.obj.ct_type_var == .generic_param { - mut ctyp := c.get_comptime_var_type(call_arg.expr) + mut ctyp := c.comptime.get_comptime_var_type(call_arg.expr) if ctyp != ast.void_type { arg_sym := c.table.final_sym(call_arg.typ) param_typ_sym := c.table.sym(param_typ) @@ -1592,14 +1592,14 @@ fn (mut c Checker) resolve_comptime_args(func ast.Fn, node_ ast.CallExpr, concre } } else if call_arg.expr is ast.PrefixExpr { if call_arg.expr.right is ast.ComptimeSelector { - comptime_args[k] = c.get_comptime_var_type(call_arg.expr.right) + comptime_args[k] = c.comptime.get_comptime_var_type(call_arg.expr.right) comptime_args[k] = comptime_args[k].deref() if comptime_args[k].nr_muls() > 0 && param_typ.nr_muls() > 0 { comptime_args[k] = comptime_args[k].set_nr_muls(0) } } } else if call_arg.expr is ast.ComptimeSelector { - ct_value := c.get_comptime_var_type(call_arg.expr) + ct_value := c.comptime.get_comptime_var_type(call_arg.expr) param_typ_sym := c.table.sym(param_typ) if ct_value != ast.void_type { cparam_type_sym := c.table.sym(c.unwrap_generic(ct_value)) @@ -1610,7 +1610,7 @@ fn (mut c Checker) resolve_comptime_args(func ast.Fn, node_ ast.CallExpr, concre } } } else if call_arg.expr is ast.ComptimeCall { - comptime_args[k] = c.get_comptime_var_type(call_arg.expr) + comptime_args[k] = c.comptime.get_comptime_var_type(call_arg.expr) } } } diff --git a/vlib/v/checker/for.v b/vlib/v/checker/for.v index 7ca1892ee088cd..11eb72b2a3b400 100644 --- a/vlib/v/checker/for.v +++ b/vlib/v/checker/for.v @@ -73,9 +73,9 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { node.scope.update_var_type(node.val_var, node.val_type) } else { mut is_comptime := false - if (node.cond is ast.Ident && c.table.is_comptime_var(node.cond)) + if (node.cond is ast.Ident && c.comptime.is_comptime_var(node.cond)) || node.cond is ast.ComptimeSelector { - ctyp := c.get_comptime_var_type(node.cond) + ctyp := c.comptime.get_comptime_var_type(node.cond) if ctyp != ast.void_type { is_comptime = true typ = ctyp @@ -89,7 +89,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { node.val_is_ref = node.cond.op == .amp } ast.ComptimeSelector { - comptime_typ := c.get_comptime_selector_type(node.cond, ast.void_type) + comptime_typ := c.comptime.get_comptime_selector_type(node.cond, ast.void_type) if comptime_typ != ast.void_type { sym = c.table.final_sym(comptime_typ) typ = comptime_typ @@ -136,11 +136,11 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { node.scope.update_var_type(node.val_var, val_type) if is_comptime { - c.comptime_fields_type[node.val_var] = val_type + c.comptime.type_map[node.val_var] = val_type node.scope.update_ct_var_kind(node.val_var, .value_var) defer { - c.comptime_fields_type.delete(node.val_var) + c.comptime.type_map.delete(node.val_var) } } } else if sym.kind == .any { @@ -159,11 +159,11 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { node.scope.update_var_type(node.key_var, key_type) if is_comptime { - c.comptime_fields_type[node.key_var] = key_type + c.comptime.type_map[node.key_var] = key_type node.scope.update_ct_var_kind(node.key_var, .key_var) defer { - c.comptime_fields_type.delete(node.key_var) + c.comptime.type_map.delete(node.key_var) } } } @@ -172,11 +172,11 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { node.scope.update_var_type(node.val_var, value_type) if is_comptime { - c.comptime_fields_type[node.val_var] = value_type + c.comptime.type_map[node.val_var] = value_type node.scope.update_ct_var_kind(node.val_var, .value_var) defer { - c.comptime_fields_type.delete(node.val_var) + c.comptime.type_map.delete(node.val_var) } } } else { @@ -194,11 +194,11 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { node.scope.update_var_type(node.key_var, key_type) if is_comptime { - c.comptime_fields_type[node.key_var] = key_type + c.comptime.type_map[node.key_var] = key_type node.scope.update_ct_var_kind(node.key_var, .key_var) defer { - c.comptime_fields_type.delete(node.key_var) + c.comptime.type_map.delete(node.key_var) } } } @@ -254,11 +254,11 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { node.val_type = value_type node.scope.update_var_type(node.val_var, value_type) if is_comptime { - c.comptime_fields_type[node.val_var] = value_type + c.comptime.type_map[node.val_var] = value_type node.scope.update_ct_var_kind(node.val_var, .value_var) defer { - c.comptime_fields_type.delete(node.val_var) + c.comptime.type_map.delete(node.val_var) } } } diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index d3330ce5e3300d..9a0dbbbccebdd5 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -111,7 +111,9 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { if left is ast.TypeNode { is_comptime_type_is_expr = true checked_type = c.unwrap_generic(left.typ) - skip_state = if c.table.is_comptime_type(checked_type, right as ast.ComptimeType) { + skip_state = if c.comptime.is_comptime_type(checked_type, + right as ast.ComptimeType) + { .eval } else { .skip @@ -121,7 +123,9 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { if var := left.scope.find_var(left.name) { checked_type = c.unwrap_generic(var.typ) } - skip_state = if c.table.is_comptime_type(checked_type, right as ast.ComptimeType) { + skip_state = if c.comptime.is_comptime_type(checked_type, + right as ast.ComptimeType) + { .eval } else { .skip @@ -139,30 +143,33 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { if left is ast.SelectorExpr { comptime_field_name = left.expr.str() - c.comptime_fields_type[comptime_field_name] = got_type + c.comptime.type_map[comptime_field_name] = got_type is_comptime_type_is_expr = true - if comptime_field_name == c.comptime_for_field_var { - left_type := c.unwrap_generic(c.comptime_fields_default_type) + if comptime_field_name == c.comptime.comptime_for_field_var { + left_type := c.unwrap_generic(c.comptime.comptime_for_field_type) if left.field_name == 'typ' { skip_state = c.check_compatible_types(left_type, right as ast.TypeNode) } else if left.field_name == 'unaliased_typ' { skip_state = c.check_compatible_types(c.table.unaliased_type(left_type), right as ast.TypeNode) } - } else if c.check_comptime_is_field_selector_bool(left) { - skip_state = if c.get_comptime_selector_bool_field(left.field_name) { + } else if c.comptime.check_comptime_is_field_selector_bool(left) { + skip_state = if c.comptime.get_comptime_selector_bool_field(left.field_name) { .eval } else { .skip } - } else if comptime_field_name == c.comptime_for_method_var { + } else if comptime_field_name == c.comptime.comptime_for_method_var { if left.field_name == 'return_type' { - skip_state = c.check_compatible_types(c.unwrap_generic(c.comptime_for_method_ret_type), + skip_state = c.check_compatible_types(c.unwrap_generic(c.comptime.comptime_for_method_ret_type), right as ast.TypeNode) } - } else if comptime_field_name == c.comptime_for_variant_var { + } else if comptime_field_name in [ + c.comptime.comptime_for_variant_var, + c.comptime.comptime_for_enum_var, + ] { if left.field_name == 'typ' { - skip_state = c.check_compatible_types(c.comptime_fields_type['${c.comptime_for_variant_var}.typ'], + skip_state = c.check_compatible_types(c.comptime.type_map['${comptime_field_name}.typ'], right as ast.TypeNode) } } @@ -188,46 +195,46 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { if left is ast.SelectorExpr && right is ast.IntegerLiteral { comptime_field_name = left.expr.str() is_comptime_type_is_expr = true - if comptime_field_name == c.comptime_for_field_var { + if comptime_field_name == c.comptime.comptime_for_field_var { if left.field_name == 'indirections' { skip_state = match branch.cond.op { .gt { - if c.comptime_fields_default_type.nr_muls() > right.val.i64() { + if c.comptime.comptime_for_field_type.nr_muls() > right.val.i64() { ComptimeBranchSkipState.eval } else { ComptimeBranchSkipState.skip } } .lt { - if c.comptime_fields_default_type.nr_muls() < right.val.i64() { + if c.comptime.comptime_for_field_type.nr_muls() < right.val.i64() { ComptimeBranchSkipState.eval } else { ComptimeBranchSkipState.skip } } .ge { - if c.comptime_fields_default_type.nr_muls() >= right.val.i64() { + if c.comptime.comptime_for_field_type.nr_muls() >= right.val.i64() { ComptimeBranchSkipState.eval } else { ComptimeBranchSkipState.skip } } .le { - if c.comptime_fields_default_type.nr_muls() <= right.val.i64() { + if c.comptime.comptime_for_field_type.nr_muls() <= right.val.i64() { ComptimeBranchSkipState.eval } else { ComptimeBranchSkipState.skip } } .ne { - if c.comptime_fields_default_type.nr_muls() != right.val.i64() { + if c.comptime.comptime_for_field_type.nr_muls() != right.val.i64() { ComptimeBranchSkipState.eval } else { ComptimeBranchSkipState.skip } } .eq { - if c.comptime_fields_default_type.nr_muls() == right.val.i64() { + if c.comptime.comptime_for_field_type.nr_muls() == right.val.i64() { ComptimeBranchSkipState.eval } else { ComptimeBranchSkipState.skip @@ -242,19 +249,19 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } else if branch.cond.op in [.eq, .ne] && left is ast.SelectorExpr && right is ast.StringLiteral { match left.expr.str() { - c.comptime_for_field_var { + c.comptime.comptime_for_field_var { if left.field_name == 'name' { is_comptime_type_is_expr = true match branch.cond.op { .eq { - skip_state = if c.comptime_for_field_value.name == right.val.str() { + skip_state = if c.comptime.comptime_for_field_value.name == right.val.str() { ComptimeBranchSkipState.eval } else { ComptimeBranchSkipState.skip } } .ne { - skip_state = if c.comptime_for_field_value.name == right.val.str() { + skip_state = if c.comptime.comptime_for_field_value.name == right.val.str() { ComptimeBranchSkipState.skip } else { ComptimeBranchSkipState.eval @@ -264,19 +271,19 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } } } - c.comptime_for_method_var { + c.comptime.comptime_for_method_var { if left.field_name == 'name' { is_comptime_type_is_expr = true match branch.cond.op { .eq { - skip_state = if c.comptime_for_method == right.val.str() { + skip_state = if c.comptime.comptime_for_method == right.val.str() { ComptimeBranchSkipState.eval } else { ComptimeBranchSkipState.skip } } .ne { - skip_state = if c.comptime_for_method == right.val.str() { + skip_state = if c.comptime.comptime_for_method == right.val.str() { ComptimeBranchSkipState.skip } else { ComptimeBranchSkipState.eval @@ -336,10 +343,10 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { node.branches[i].stmts = [] } if comptime_field_name.len > 0 { - if comptime_field_name == c.comptime_for_method_var { - c.comptime_fields_type[comptime_field_name] = c.comptime_for_method_ret_type + if comptime_field_name == c.comptime.comptime_for_method_var { + c.comptime.type_map[comptime_field_name] = c.comptime.comptime_for_method_ret_type } else { - c.comptime_fields_type[comptime_field_name] = c.comptime_fields_default_type + c.comptime.type_map[comptime_field_name] = c.comptime.comptime_for_field_type } } c.skip_flags = cur_skip_flags diff --git a/vlib/v/checker/postfix.v b/vlib/v/checker/postfix.v index 66cb8c28c103f1..c59372229c0087 100644 --- a/vlib/v/checker/postfix.v +++ b/vlib/v/checker/postfix.v @@ -23,9 +23,9 @@ fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type { c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) } if !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) { - if c.inside_comptime_for_field { - if c.table.is_comptime_var(node.expr) || node.expr is ast.ComptimeSelector { - node.typ = c.unwrap_generic(c.get_comptime_var_type(node.expr)) + if c.comptime.comptime_for_field_var != '' { + if c.comptime.is_comptime_var(node.expr) || node.expr is ast.ComptimeSelector { + node.typ = c.unwrap_generic(c.comptime.get_comptime_var_type(node.expr)) if node.op == .question { node.typ = node.typ.clear_flag(.option) } diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index c4142d3bbecffb..452a0cb10c00a8 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -45,8 +45,8 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type { c.inside_interface_deref = true for i, mut expr in node.exprs { mut ftyp := c.expr(mut expr) - if c.table.is_comptime_var(expr) { - ctyp := c.get_comptime_var_type(expr) + if c.comptime.is_comptime_var(expr) { + ctyp := c.comptime.get_comptime_var_type(expr) if ctyp != ast.void_type { ftyp = ctyp } @@ -78,8 +78,8 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type { c.error('no known default format for type `${c.table.get_type_name(ftyp)}`', node.fmt_poss[i]) } - } else if c.table.is_comptime_var(expr) - && c.get_comptime_var_type(expr) != ast.void_type { + } else if c.comptime.is_comptime_var(expr) + && c.comptime.get_comptime_var_type(expr) != ast.void_type { // still `_` placeholder for comptime variable without specifier node.need_fmts[i] = false } else { diff --git a/vlib/v/comptime/comptimeinfo.v b/vlib/v/comptime/comptimeinfo.v new file mode 100644 index 00000000000000..39c7d37eca464c --- /dev/null +++ b/vlib/v/comptime/comptimeinfo.v @@ -0,0 +1,286 @@ +// Copyright (c) 2019-2023 V devs. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. +module comptime + +import v.ast +import v.token +import v.util + +pub interface IResolverType { +mut: + file &ast.File + unwrap_generic(t ast.Type) ast.Type +} + +@[noreturn] +fn (mut ct ComptimeInfo) error(s string, pos token.Pos) { + util.show_compiler_message('cgen error:', pos: pos, file_path: ct.resolver.file.path, message: s) + exit(1) +} + +@[inline] +pub fn (mut ct ComptimeInfo) get_comptime_selector_key_type(val ast.ComptimeSelector) string { + if val.field_expr is ast.SelectorExpr { + if val.field_expr.expr is ast.Ident { + return '${val.field_expr.expr.name}.typ' + } + } + return '' +} + +// is_comptime_var checks if the node is related to a comptime variable +@[inline] +pub fn (mut ct ComptimeInfo) is_comptime_var(node ast.Expr) bool { + return ct.get_ct_type_var(node) != .no_comptime +} + +// get_ct_type_var gets the comptime type of the variable (.generic_param, .key_var, etc) +@[inline] +pub fn (mut ct ComptimeInfo) get_ct_type_var(node ast.Expr) ast.ComptimeVarKind { + return if node is ast.Ident && node.obj is ast.Var { + (node.obj as ast.Var).ct_type_var + } else { + .no_comptime + } +} + +// get_comptime_var_type retrieves the actual type from a comptime related ast node +@[inline] +pub fn (mut ct ComptimeInfo) get_comptime_var_type(node ast.Expr) ast.Type { + if node is ast.Ident && node.obj is ast.Var { + return match (node.obj as ast.Var).ct_type_var { + .generic_param { + // generic parameter from current function + node.obj.typ + } + .key_var, .value_var { + // key and value variables from normal for stmt + ct.type_map[node.name] or { ast.void_type } + } + .field_var { + // field var from $for loop + ct.comptime_for_field_type + } + else { + ast.void_type + } + } + } else if node is ast.ComptimeSelector { + // val.$(field.name) + return ct.get_comptime_selector_type(node, ast.void_type) + } else if node is ast.SelectorExpr && ct.is_comptime_selector_type(node) { + if node.expr is ast.Ident { + match node.expr.name { + ct.comptime_for_variant_var { + return ct.type_map['${ct.comptime_for_variant_var}.typ'] + } + ct.comptime_for_enum_var { + return ct.type_map['${ct.comptime_for_enum_var}.typ'] + } + else { + // field_var.typ from $for field + return ct.comptime_for_field_type + } + } + } + } else if node is ast.ComptimeCall { + method_name := ct.comptime_for_method + left_sym := ct.table.sym(ct.resolver.unwrap_generic(node.left_type)) + f := left_sym.find_method(method_name) or { + ct.error('could not find method `${method_name}` on compile-time resolution', + node.method_pos) + return ast.void_type + } + return f.return_type + } + return ast.void_type +} + +pub fn (mut ct ComptimeInfo) get_comptime_selector_var_type(node ast.ComptimeSelector) (ast.StructField, string) { + field_name := ct.comptime_for_field_value.name + left_sym := ct.table.sym(ct.resolver.unwrap_generic(node.left_type)) + field := ct.table.find_field_with_embeds(left_sym, field_name) or { + ct.error('`${node.left}` has no field named `${field_name}`', node.left.pos()) + } + return field, field_name +} + +// get_comptime_selector_type retrieves the var.$(field.name) type when field_name is 'name' otherwise default_type is returned +@[inline] +pub fn (mut ct ComptimeInfo) get_comptime_selector_type(node ast.ComptimeSelector, default_type ast.Type) ast.Type { + if node.field_expr is ast.SelectorExpr && ct.check_comptime_is_field_selector(node.field_expr) + && node.field_expr.field_name == 'name' { + return ct.resolver.unwrap_generic(ct.comptime_for_field_type) + } + return default_type +} + +// is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable accessing specific field name provided by `field_name` +@[inline] +pub fn (mut ct ComptimeInfo) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool { + return ct.comptime_for_field_var != '' && node.expr is ast.Ident + && node.expr.name == ct.comptime_for_field_var && node.field_name == field_name +} + +// is_comptime_selector_type checks if the SelectorExpr is related to $for variable accessing .typ field +@[inline] +pub fn (mut ct ComptimeInfo) is_comptime_selector_type(node ast.SelectorExpr) bool { + if ct.inside_comptime_for && node.expr is ast.Ident { + return + node.expr.name in [ct.comptime_for_enum_var, ct.comptime_for_variant_var, ct.comptime_for_field_var] + && node.field_name == 'typ' + } + return false +} + +// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable +@[inline] +pub fn (mut ct ComptimeInfo) check_comptime_is_field_selector(node ast.SelectorExpr) bool { + if ct.comptime_for_field_var != '' && node.expr is ast.Ident { + return node.expr.name == ct.comptime_for_field_var + } + return false +} + +// check_comptime_is_field_selector_bool checks if the SelectorExpr is related to field.is_* boolean fields +@[inline] +pub fn (mut ct ComptimeInfo) check_comptime_is_field_selector_bool(node ast.SelectorExpr) bool { + if ct.check_comptime_is_field_selector(node) { + return node.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_option', + 'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias', 'is_enum'] + } + return false +} + +// get_comptime_selector_bool_field evaluates the bool value for field.is_* fields +pub fn (mut ct ComptimeInfo) get_comptime_selector_bool_field(field_name string) bool { + field := ct.comptime_for_field_value + field_typ := ct.comptime_for_field_type + field_sym := ct.table.sym(ct.resolver.unwrap_generic(ct.comptime_for_field_type)) + + match field_name { + 'is_pub' { return field.is_pub } + 'is_mut' { return field.is_mut } + 'is_shared' { return field_typ.has_flag(.shared_f) } + 'is_atomic' { return field_typ.has_flag(.atomic_f) } + 'is_option' { return field.typ.has_flag(.option) } + 'is_array' { return field_sym.kind in [.array, .array_fixed] } + 'is_map' { return field_sym.kind == .map } + 'is_chan' { return field_sym.kind == .chan } + 'is_struct' { return field_sym.kind == .struct_ } + 'is_alias' { return field_sym.kind == .alias } + 'is_enum' { return field_sym.kind == .enum_ } + else { return false } + } +} + +pub fn (mut ct ComptimeInfo) is_comptime_type(x ast.Type, y ast.ComptimeType) bool { + x_kind := ct.table.type_kind(x) + match y.kind { + .unknown { + return false + } + .map_ { + return x_kind == .map + } + .int { + return x_kind in [.i8, .i16, .int, .i64, .u8, .u16, .u32, .u64, .usize, .isize, + .int_literal] + } + .float { + return x_kind in [.f32, .f64, .float_literal] + } + .struct_ { + return x_kind == .struct_ + } + .iface { + return x_kind == .interface_ + } + .array { + return x_kind in [.array, .array_fixed] + } + .array_dynamic { + return x_kind == .array + } + .array_fixed { + return x_kind == .array_fixed + } + .sum_type { + return x_kind == .sum_type + } + .enum_ { + return x_kind == .enum_ + } + .alias { + return x_kind == .alias + } + .function { + return x_kind == .function + } + .option { + return x.has_flag(.option) + } + } +} + +// comptime_get_kind_var identifies the comptime variable kind (i.e. if it is about .values, .fields, .methods etc) +fn (mut ct ComptimeInfo) comptime_get_kind_var(var ast.Ident) ?ast.ComptimeForKind { + if ct.inside_comptime_for { + return none + } + + match var.name { + ct.comptime_for_variant_var { + return .variants + } + ct.comptime_for_field_var { + return .fields + } + ct.comptime_for_enum_var { + return .values + } + ct.comptime_for_method_var { + return .methods + } + ct.comptime_for_attr_var { + return .attributes + } + else { + return none + } + } +} + +pub struct DummyResolver { +mut: + file &ast.File = unsafe { nil } +} + +fn (d DummyResolver) unwrap_generic(t ast.Type) ast.Type { + return t +} + +pub struct ComptimeInfo { +pub mut: + // variable type resolver + resolver IResolverType = DummyResolver{} + // symbol table resolver + table &ast.Table = unsafe { nil } + // $for + inside_comptime_for bool + type_map map[string]ast.Type + // .variants + comptime_for_variant_var string + // .fields + comptime_for_field_var string + comptime_for_field_type ast.Type + comptime_for_field_value ast.StructField + // .values + comptime_for_enum_var string + // .attributes + comptime_for_attr_var string + // .methods + comptime_for_method_var string + comptime_for_method string + comptime_for_method_ret_type ast.Type +} diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index 1fb2e598f9a4fc..7574a88d41201b 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -544,8 +544,8 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) { ast.CastExpr { // value.map(Type(it)) when `value` is a comptime var if expr.expr is ast.Ident && node.left is ast.Ident - && g.table.is_comptime_var(node.left) { - ctyp := g.get_comptime_var_type(node.left) + && g.comptime.is_comptime_var(node.left) { + ctyp := g.comptime.get_comptime_var_type(node.left) if ctyp != ast.void_type { expr.expr_type = g.table.value_type(ctyp) } diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 2106bbb4d0c33d..1ebf10db776011 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -106,7 +106,7 @@ fn (mut g Gen) expr_with_opt(expr ast.Expr, expr_typ ast.Type, ret_typ ast.Type) } g.expr(expr) if expr is ast.ComptimeSelector { - return '${expr.left.str()}.${g.comptime_for_field_value.name}' + return '${expr.left.str()}.${g.comptime.comptime_for_field_value.name}' } else { return expr.str() } @@ -236,7 +236,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } if mut left.obj is ast.Var { if val is ast.Ident && g.table.is_comptime_var(val) { - ctyp := g.unwrap_generic(g.get_comptime_var_type(val)) + ctyp := g.unwrap_generic(g.comptime.get_comptime_var_type(val)) if ctyp != ast.void_type { var_type = ctyp val_type = var_type @@ -248,20 +248,20 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { g.assign_ct_type = var_type } } else if val is ast.ComptimeSelector { - key_str := g.get_comptime_selector_key_type(val) + key_str := g.comptime.get_comptime_selector_key_type(val) if key_str != '' { if is_decl { - var_type = g.comptime_var_type_map[key_str] or { var_type } + var_type = g.comptime.type_map[key_str] or { var_type } val_type = var_type left.obj.typ = var_type } else { - val_type = g.comptime_var_type_map[key_str] or { var_type } + val_type = g.comptime.type_map[key_str] or { var_type } } g.assign_ct_type = var_type } } else if val is ast.ComptimeCall { key_str := '${val.method_name}.return_type' - var_type = g.comptime_var_type_map[key_str] or { var_type } + var_type = g.comptime.type_map[key_str] or { var_type } left.obj.typ = var_type g.assign_ct_type = var_type } else if is_decl && val is ast.Ident && val.info is ast.IdentVar { @@ -272,9 +272,9 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { left.obj.typ = var_type } } else if val is ast.DumpExpr && val.expr is ast.ComptimeSelector { - key_str := g.get_comptime_selector_key_type(val.expr as ast.ComptimeSelector) + key_str := g.comptime.get_comptime_selector_key_type(val.expr as ast.ComptimeSelector) if key_str != '' { - var_type = g.comptime_var_type_map[key_str] or { var_type } + var_type = g.comptime.type_map[key_str] or { var_type } val_type = var_type left.obj.typ = var_type } @@ -293,21 +293,21 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { is_auto_heap = left.obj.is_auto_heap } } else if mut left is ast.ComptimeSelector { - key_str := g.get_comptime_selector_key_type(left) + key_str := g.comptime.get_comptime_selector_key_type(left) if key_str != '' { - var_type = g.comptime_var_type_map[key_str] or { var_type } + var_type = g.comptime.type_map[key_str] or { var_type } } if val is ast.ComptimeSelector { - key_str_right := g.get_comptime_selector_key_type(val) + key_str_right := g.comptime.get_comptime_selector_key_type(val) if key_str_right != '' { - val_type = g.comptime_var_type_map[key_str_right] or { var_type } + val_type = g.comptime.type_map[key_str_right] or { var_type } } } g.assign_ct_type = var_type } else if mut left is ast.IndexExpr && val is ast.ComptimeSelector { - key_str := g.get_comptime_selector_key_type(val) + key_str := g.comptime.get_comptime_selector_key_type(val) if key_str != '' { - val_type = g.comptime_var_type_map[key_str] or { var_type } + val_type = g.comptime.type_map[key_str] or { var_type } } g.assign_ct_type = val_type } @@ -322,7 +322,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { ast.CallExpr { is_call = true if val.comptime_ret_val { - return_type = g.comptime_for_field_type + return_type = g.comptime.comptime_for_field_type styp = g.typ(return_type) } else { return_type = val.return_type @@ -656,7 +656,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } } if !cloned { - if !g.inside_comptime_for_field + if g.comptime.comptime_for_field_var == '' && ((var_type.has_flag(.option) && !val_type.has_flag(.option)) || (var_type.has_flag(.result) && !val_type.has_flag(.result))) { old_inside_opt_or_res := g.inside_opt_or_res diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 6be8b293ec106a..158abe5628e1d2 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -12,6 +12,7 @@ import v.token import v.util import v.util.version import v.depgraph +import v.comptime import sync.pool // Note: some of the words in c_reserved, are not reserved in C, but are @@ -139,62 +140,62 @@ mut: inside_curry_call bool // inside foo()()!, foo()()?, foo()() expected_fixed_arr bool inside_for_c_stmt bool - inside_comptime_for_field bool - inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls) - inside_cast bool - inside_const bool - inside_array_item bool - inside_const_opt_or_res bool - inside_lambda bool - inside_cinit bool - inside_interface_deref bool - last_tmp_call_var []string - loop_depth int - ternary_names map[string]string - ternary_level_names map[string][]string - arraymap_set_pos int // map or array set value position - stmt_path_pos []int // positions of each statement start, for inserting C statements before the current statement - skip_stmt_pos bool // for handling if expressions + autofree (since both prepend C statements) - left_is_opt bool // left hand side on assignment is an option - right_is_opt bool // right hand side on assignment is an option - assign_ct_type ast.Type // left hand side resolved comptime type - indent int - empty_line bool - assign_op token.Kind // *=, =, etc (for array_set) - defer_stmts []ast.DeferStmt - defer_ifdef string - defer_profile_code string - defer_vars []string - str_types []StrType // types that need automatic str() generation - generated_str_fns []StrType // types that already have a str() function - str_fn_names []string // remove duplicate function names - threaded_fns shared []string // for generating unique wrapper types and fns for `go xxx()` - waiter_fns shared []string // functions that wait for `go xxx()` to finish - needed_equality_fns []ast.Type - generated_eq_fns []ast.Type - array_sort_fn shared []string - array_contains_types []ast.Type - array_index_types []ast.Type - auto_fn_definitions []string // auto generated functions definition list - sumtype_casting_fns []SumtypeCastingFn - anon_fn_definitions []string // anon generated functions definition list - sumtype_definitions map[int]bool // `_TypeA_to_sumtype_TypeB()` fns that have been generated - json_types []ast.Type // to avoid json gen duplicates - pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name - hotcode_fn_names []string - hotcode_fpaths []string - embedded_files []ast.EmbeddedFile - sql_i int - sql_stmt_name string - sql_bind_name string - sql_idents []string - sql_idents_types []ast.Type - sql_left_type ast.Type - sql_table_name string - sql_fkey string - sql_parent_id string - sql_side SqlExprSide // left or right, to distinguish idents in `name == name` - strs_to_free0 []string // strings.Builder + // inside_comptime_for_field bool + inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls) + inside_cast bool + inside_const bool + inside_array_item bool + inside_const_opt_or_res bool + inside_lambda bool + inside_cinit bool + inside_interface_deref bool + last_tmp_call_var []string + loop_depth int + ternary_names map[string]string + ternary_level_names map[string][]string + arraymap_set_pos int // map or array set value position + stmt_path_pos []int // positions of each statement start, for inserting C statements before the current statement + skip_stmt_pos bool // for handling if expressions + autofree (since both prepend C statements) + left_is_opt bool // left hand side on assignment is an option + right_is_opt bool // right hand side on assignment is an option + assign_ct_type ast.Type // left hand side resolved comptime type + indent int + empty_line bool + assign_op token.Kind // *=, =, etc (for array_set) + defer_stmts []ast.DeferStmt + defer_ifdef string + defer_profile_code string + defer_vars []string + str_types []StrType // types that need automatic str() generation + generated_str_fns []StrType // types that already have a str() function + str_fn_names []string // remove duplicate function names + threaded_fns shared []string // for generating unique wrapper types and fns for `go xxx()` + waiter_fns shared []string // functions that wait for `go xxx()` to finish + needed_equality_fns []ast.Type + generated_eq_fns []ast.Type + array_sort_fn shared []string + array_contains_types []ast.Type + array_index_types []ast.Type + auto_fn_definitions []string // auto generated functions definition list + sumtype_casting_fns []SumtypeCastingFn + anon_fn_definitions []string // anon generated functions definition list + sumtype_definitions map[int]bool // `_TypeA_to_sumtype_TypeB()` fns that have been generated + json_types []ast.Type // to avoid json gen duplicates + pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name + hotcode_fn_names []string + hotcode_fpaths []string + embedded_files []ast.EmbeddedFile + sql_i int + sql_stmt_name string + sql_bind_name string + sql_idents []string + sql_idents_types []ast.Type + sql_left_type ast.Type + sql_table_name string + sql_fkey string + sql_parent_id string + sql_side SqlExprSide // left or right, to distinguish idents in `name == name` + strs_to_free0 []string // strings.Builder // strs_to_free []string // strings.Builder // tmp_arg_vars_to_free []string // autofree_pregen map[string]string @@ -202,14 +203,8 @@ mut: // autofree_tmp_vars []string // to avoid redefining the same tmp vars in a single function // nr_vars_to_free int // doing_autofree_tmp bool - comptime_for_method string // $for method in T.methods {} - comptime_for_method_var string // $for method in T.methods {}; the variable name - comptime_for_field_var string // $for field in T.fields {}; the variable name - comptime_for_field_value ast.StructField // value of the field variable - comptime_for_field_type ast.Type // type of the field variable inferred from `$if field.typ is T {}` - comptime_enum_field_value string // value of enum name - comptime_var_type_map map[string]ast.Type - comptime_values_stack []CurrentComptimeValues // stores the values from the above on each $for loop, to make nesting them easier + comptime_info_stack []comptime.ComptimeInfo // stores the values from the above on each $for loop, to make nesting them easier + comptime comptime.ComptimeInfo prevent_sum_type_unwrapping_once bool // needed for assign new values to sum type // used in match multi branch // TypeOne, TypeTwo {} @@ -326,6 +321,11 @@ pub fn gen(files []&ast.File, table &ast.Table, pref_ &pref.Preferences) (string reflection_strings: &reflection_strings } + global_g.comptime = &comptime.ComptimeInfo{ + resolver: &global_g + table: table + } + /* global_g.out_parallel = []strings.Builder{len: nr_cpus} for i in 0 .. nr_cpus { @@ -688,6 +688,10 @@ fn cgen_process_one_file_cb(mut p pool.PoolProcessor, idx int, wid int) &Gen { has_reflection: 'v.reflection' in global_g.table.modules reflection_strings: global_g.reflection_strings } + g.comptime = &comptime.ComptimeInfo{ + resolver: g + table: global_g.table + } g.gen_file() return g } @@ -3416,8 +3420,8 @@ fn (mut g Gen) expr(node_ ast.Expr) { mut expr_str := '' if mut node.expr is ast.ComptimeSelector && node.expr.left is ast.Ident { // val.$(field.name)? - expr_str = '${node.expr.left.str()}.${g.comptime_for_field_value.name}' - } else if mut node.expr is ast.Ident && g.table.is_comptime_var(node.expr) { + expr_str = '${node.expr.left.str()}.${g.comptime.comptime_for_field_value.name}' + } else if mut node.expr is ast.Ident && g.comptime.is_comptime_var(node.expr) { // val? expr_str = node.expr.name } @@ -4398,7 +4402,7 @@ fn (mut g Gen) ident(node ast.Ident) { if node.info is ast.IdentVar { if node.obj is ast.Var { if !g.is_assign_lhs && node.obj.ct_type_var !in [.generic_param, .no_comptime] { - comptime_type := g.get_comptime_var_type(node) + comptime_type := g.comptime.get_comptime_var_type(node) if comptime_type.has_flag(.option) { if (g.inside_opt_or_res || g.left_is_opt) && node.or_expr.kind == .absent { if !g.is_assign_lhs && is_auto_heap { @@ -4589,7 +4593,7 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) { sym := g.table.sym(node_typ) if (node.expr is ast.Ident && g.table.is_comptime_var(node.expr)) || node.expr is ast.ComptimeSelector { - expr_type = g.unwrap_generic(g.get_comptime_var_type(node.expr)) + expr_type = g.unwrap_generic(g.comptime.get_comptime_var_type(node.expr)) } if sym.kind in [.sum_type, .interface_] { if node.typ.has_flag(.option) && node.expr is ast.None { @@ -6616,7 +6620,7 @@ fn (g Gen) get_all_test_function_names() []string { @[inline] fn (mut g Gen) get_type(typ ast.Type) ast.Type { - return if typ == g.field_data_type { g.comptime_for_field_value.typ } else { typ } + return if typ == g.field_data_type { g.comptime.comptime_for_field_value.typ } else { typ } } fn (mut g Gen) size_of(node ast.SizeOf) { diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 0b34bc86b9d436..ae530e160d710f 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -7,45 +7,7 @@ import os import v.ast import v.util import v.pref - -fn (mut g Gen) get_comptime_selector_key_type(val ast.ComptimeSelector) string { - if val.field_expr is ast.SelectorExpr { - if val.field_expr.expr is ast.Ident { - return '${val.field_expr.expr.name}.typ' - } - } - return '' -} - -fn (mut g Gen) get_comptime_selector_var_type(node ast.ComptimeSelector) (ast.StructField, string) { - field_name := g.comptime_for_field_value.name - left_sym := g.table.sym(g.unwrap_generic(node.left_type)) - field := g.table.find_field_with_embeds(left_sym, field_name) or { - g.error('`${node.left}` has no field named `${field_name}`', node.left.pos()) - } - return field, field_name -} - -fn (mut g Gen) get_comptime_selector_bool_field(field_name string) bool { - field := g.comptime_for_field_value - field_typ := g.comptime_for_field_type - field_sym := g.table.sym(g.unwrap_generic(g.comptime_for_field_type)) - - match field_name { - 'is_pub' { return field.is_pub } - 'is_mut' { return field.is_mut } - 'is_shared' { return field_typ.has_flag(.shared_f) } - 'is_atomic' { return field_typ.has_flag(.atomic_f) } - 'is_option' { return field.typ.has_flag(.option) } - 'is_array' { return field_sym.kind in [.array, .array_fixed] } - 'is_map' { return field_sym.kind == .map } - 'is_chan' { return field_sym.kind == .chan } - 'is_struct' { return field_sym.kind == .struct_ } - 'is_alias' { return field_sym.kind == .alias } - 'is_enum' { return field_sym.kind == .enum_ } - else { return false } - } -} +import v.comptime fn (mut g Gen) comptime_selector(node ast.ComptimeSelector) { g.expr(node.left) @@ -57,9 +19,9 @@ fn (mut g Gen) comptime_selector(node ast.ComptimeSelector) { // check for field.name if node.field_expr is ast.SelectorExpr { if node.field_expr.expr is ast.Ident { - if node.field_expr.expr.name == g.comptime_for_field_var + if node.field_expr.expr.name == g.comptime.comptime_for_field_var && node.field_expr.field_name == 'name' { - _, field_name := g.get_comptime_selector_var_type(node) + _, field_name := g.comptime.get_comptime_selector_var_type(node) g.write(c_name(field_name)) return } @@ -130,7 +92,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { g.trace_autofree('// \$method call. sym="${sym.name}"') if node.method_name == 'method' { // `app.$method()` - m := sym.find_method(g.comptime_for_method) or { return } + m := sym.find_method(g.comptime.comptime_for_method) or { return } /* vals := m.attrs[0].split('/') args := vals.filter(it.starts_with(':')).map(it[1..]) @@ -175,7 +137,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { g.write('(*(${g.base_type(m.return_type)}*)') } // TODO: check argument types - g.write('${util.no_dots(sym.name)}_${g.comptime_for_method}(') + g.write('${util.no_dots(sym.name)}_${g.comptime.comptime_for_method}(') // try to see if we need to pass a pointer if mut node.left is ast.Ident { @@ -447,8 +409,8 @@ fn (mut g Gen) get_expr_type(cond ast.Expr) ast.Type { return g.unwrap_generic(cond.name_type) } else { name := '${cond.expr}.${cond.field_name}' - if name in g.comptime_var_type_map { - return g.comptime_var_type_map[name] + if name in g.comptime.type_map { + return g.comptime.type_map[name] } else { return g.unwrap_generic(cond.typ) } @@ -556,16 +518,16 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { } .eq, .ne { // TODO Implement `$if method.args.len == 1` - if cond.left is ast.SelectorExpr - && (g.comptime_for_field_var.len > 0 || g.comptime_for_method.len > 0) { + if cond.left is ast.SelectorExpr && (g.comptime.comptime_for_field_var.len > 0 + || g.comptime.comptime_for_method.len > 0) { if cond.right is ast.StringLiteral { if cond.left.expr is ast.Ident && cond.left.field_name == 'name' { - if g.comptime_for_method_var.len > 0 - && cond.left.expr.name == g.comptime_for_method_var { + if g.comptime.comptime_for_method_var.len > 0 + && cond.left.expr.name == g.comptime.comptime_for_method_var { is_true := if cond.op == .eq { - g.comptime_for_method == cond.right.val + g.comptime.comptime_for_method == cond.right.val } else { - g.comptime_for_method != cond.right.val + g.comptime.comptime_for_method != cond.right.val } if is_true { g.write('1') @@ -573,12 +535,12 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { g.write('0') } return is_true, true - } else if g.comptime_for_field_var.len > 0 - && cond.left.expr.name == g.comptime_for_field_var { + } else if g.comptime.comptime_for_field_var.len > 0 + && cond.left.expr.name == g.comptime.comptime_for_field_var { is_true := if cond.op == .eq { - g.comptime_for_field_value.name == cond.right.val + g.comptime.comptime_for_field_value.name == cond.right.val } else { - g.comptime_for_field_value.name != cond.right.val + g.comptime.comptime_for_field_value.name != cond.right.val } if is_true { g.write('1') @@ -589,10 +551,10 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { } } } else if cond.right is ast.IntegerLiteral { - if g.is_comptime_selector_field_name(cond.left, 'indirections') { + if g.comptime.is_comptime_selector_field_name(cond.left, 'indirections') { is_true := match cond.op { - .eq { g.comptime_for_field_type.nr_muls() == cond.right.val.i64() } - .ne { g.comptime_for_field_type.nr_muls() != cond.right.val.i64() } + .eq { g.comptime.comptime_for_field_type.nr_muls() == cond.right.val.i64() } + .ne { g.comptime.comptime_for_field_type.nr_muls() != cond.right.val.i64() } else { false } } if is_true { @@ -652,12 +614,12 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { } .gt, .lt, .ge, .le { if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral - && g.is_comptime_selector_field_name(cond.left, 'indirections') { + && g.comptime.is_comptime_selector_field_name(cond.left, 'indirections') { is_true := match cond.op { - .gt { g.comptime_for_field_type.nr_muls() > cond.right.val.i64() } - .lt { g.comptime_for_field_type.nr_muls() < cond.right.val.i64() } - .ge { g.comptime_for_field_type.nr_muls() >= cond.right.val.i64() } - .le { g.comptime_for_field_type.nr_muls() <= cond.right.val.i64() } + .gt { g.comptime.comptime_for_field_type.nr_muls() > cond.right.val.i64() } + .lt { g.comptime.comptime_for_field_type.nr_muls() < cond.right.val.i64() } + .ge { g.comptime.comptime_for_field_type.nr_muls() >= cond.right.val.i64() } + .le { g.comptime.comptime_for_field_type.nr_muls() <= cond.right.val.i64() } else { false } } if is_true { @@ -685,10 +647,10 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { return true, false } ast.SelectorExpr { - if g.inside_comptime_for_field && cond.expr is ast.Ident - && cond.expr.name == g.comptime_for_field_var + if g.comptime.comptime_for_field_var != '' && cond.expr is ast.Ident + && cond.expr.name == g.comptime.comptime_for_field_var && cond.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_option', 'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias', 'is_enum'] { - ret_bool := g.get_comptime_selector_bool_field(cond.field_name) + ret_bool := g.comptime.get_comptime_selector_bool_field(cond.field_name) g.write(ret_bool.str()) return ret_bool, true } else { @@ -704,92 +666,44 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { } } -// - -struct CurrentComptimeValues { - inside_comptime_for_field bool - comptime_for_method string - comptime_for_method_var string - comptime_for_field_var string - comptime_for_field_value ast.StructField - comptime_for_field_type ast.Type - comptime_var_type_map map[string]ast.Type -} - -fn (mut g Gen) push_existing_comptime_values() { - g.comptime_values_stack << CurrentComptimeValues{ - inside_comptime_for_field: g.inside_comptime_for_field - comptime_for_method: g.comptime_for_method - comptime_for_method_var: g.comptime_for_method_var - comptime_for_field_var: g.comptime_for_field_var - comptime_for_field_value: g.comptime_for_field_value - comptime_for_field_type: g.comptime_for_field_type - comptime_var_type_map: g.comptime_var_type_map.clone() +// push_new_comptime_info saves the current comptime information +fn (mut g Gen) push_new_comptime_info() { + g.comptime_info_stack << comptime.ComptimeInfo{ + resolver: g.comptime.resolver + table: g.comptime.table + type_map: g.comptime.type_map.clone() + inside_comptime_for: g.comptime.inside_comptime_for + comptime_for_variant_var: g.comptime.comptime_for_variant_var + comptime_for_field_var: g.comptime.comptime_for_field_var + comptime_for_field_type: g.comptime.comptime_for_field_type + comptime_for_field_value: g.comptime.comptime_for_field_value + comptime_for_enum_var: g.comptime.comptime_for_enum_var + comptime_for_method_var: g.comptime.comptime_for_method_var + comptime_for_method: g.comptime.comptime_for_method + comptime_for_method_ret_type: g.comptime.comptime_for_method_ret_type } } -fn (mut g Gen) pop_existing_comptime_values() { - old := g.comptime_values_stack.pop() - g.inside_comptime_for_field = old.inside_comptime_for_field - g.comptime_for_method = old.comptime_for_method - g.comptime_for_method_var = old.comptime_for_method_var - g.comptime_for_field_var = old.comptime_for_field_var - g.comptime_for_field_value = old.comptime_for_field_value - g.comptime_for_field_type = old.comptime_for_field_type - g.comptime_var_type_map = old.comptime_var_type_map.clone() -} - -// is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable accessing specific field name provided by `field_name` -@[inline] -fn (mut g Gen) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool { - return g.inside_comptime_for_field && node.expr is ast.Ident - && node.expr.name == g.comptime_for_field_var && node.field_name == field_name -} - -// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable accessing .typ field -@[inline] -fn (mut g Gen) is_comptime_selector_type(node ast.SelectorExpr) bool { - if g.inside_comptime_for_field && node.expr is ast.Ident { - return node.expr.name == g.comptime_for_field_var && node.field_name == 'typ' - } - return false -} - -fn (mut g Gen) get_comptime_var_type(node ast.Expr) ast.Type { - if node is ast.Ident && node.obj is ast.Var { - return match (node.obj as ast.Var).ct_type_var { - .generic_param { - // generic parameter from current function - node.obj.typ - } - .key_var, .value_var { - // key and value variables from normal for stmt - g.comptime_var_type_map[node.name] or { ast.void_type } - } - .field_var { - // field var from $for loop - g.comptime_for_field_type - } - else { - ast.void_type - } - } - } else if node is ast.ComptimeSelector { - // val.$(field.name) - key_str := g.get_comptime_selector_key_type(node) - if key_str != '' { - return g.comptime_var_type_map[key_str] or { ast.void_type } - } - } else if node is ast.SelectorExpr && g.is_comptime_selector_type(node) { - // field_var.typ from $for field - return g.comptime_for_field_type - } - return ast.void_type +// pop_comptime_info pops the current comptime information frame +fn (mut g Gen) pop_comptime_info() { + old := g.comptime_info_stack.pop() + g.comptime.resolver = old.resolver + g.comptime.table = old.table + g.comptime.type_map = old.type_map.clone() + g.comptime.inside_comptime_for = old.inside_comptime_for + g.comptime.comptime_for_variant_var = old.comptime_for_variant_var + g.comptime.comptime_for_field_var = old.comptime_for_field_var + g.comptime.comptime_for_field_type = old.comptime_for_field_type + g.comptime.comptime_for_field_value = old.comptime_for_field_value + g.comptime.comptime_for_enum_var = old.comptime_for_enum_var + g.comptime.comptime_for_method_var = old.comptime_for_method_var + g.comptime.comptime_for_method = old.comptime_for_method + g.comptime.comptime_for_method_ret_type = old.comptime_for_method_ret_type } fn (mut g Gen) resolve_comptime_type(node ast.Expr, default_type ast.Type) ast.Type { - if (node is ast.Ident && g.table.is_comptime_var(node)) || node is ast.ComptimeSelector { - return g.get_comptime_var_type(node) + if (node is ast.Ident && g.comptime.is_comptime_var(node)) || node is ast.ComptimeSelector { + return g.comptime.get_comptime_var_type(node) } else if node is ast.SelectorExpr && node.expr_type != 0 { sym := g.table.sym(g.unwrap_generic(node.expr_type)) if f := g.table.find_field_with_embeds(sym, node.field_name) { @@ -814,7 +728,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { } typ_vweb_result := g.table.find_type_idx('vweb.Result') for method in methods { - g.push_existing_comptime_values() + g.push_new_comptime_info() // filter vweb route methods (non-generic method) if method.receiver_type != 0 && method.return_type == typ_vweb_result { rec_sym := g.table.sym(method.receiver_type) @@ -822,14 +736,14 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { if _ := g.table.find_field_with_embeds(rec_sym, 'Context') { if method.generic_names.len > 0 || (method.params.len > 1 && method.attrs.len == 0) { - g.pop_existing_comptime_values() + g.pop_comptime_info() continue } } } } - g.comptime_for_method = method.name - g.comptime_for_method_var = node.val_var + g.comptime.comptime_for_method = method.name + g.comptime.comptime_for_method_var = node.val_var g.writeln('/* method ${i} */ {') g.writeln('\t${node.val_var}.name = _SLIT("${method.name}");') if method.attrs.len == 0 { @@ -853,7 +767,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { if j < len - 1 { g.write(', ') } - g.comptime_var_type_map['${node.val_var}.args[${j}].typ'] = typ + g.comptime.type_map['${node.val_var}.args[${j}].typ'] = typ } g.writeln('}));\n') } @@ -879,12 +793,12 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.writeln('\t${node.val_var}.typ = ${styp};') g.writeln('\t${node.val_var}.return_type = ${ret_typ.idx()};') - g.comptime_var_type_map['${node.val_var}.return_type'] = ret_typ - g.comptime_var_type_map['${node.val_var}.typ'] = styp + g.comptime.type_map['${node.val_var}.return_type'] = ret_typ + g.comptime.type_map['${node.val_var}.typ'] = styp g.stmts(node.stmts) i++ g.writeln('}') - g.pop_existing_comptime_values() + g.pop_comptime_info() } } else if node.kind == .fields { if sym.kind in [.struct_, .interface_] { @@ -904,12 +818,12 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { if fields.len > 0 { g.writeln('\tFieldData ${node.val_var} = {0};') } + g.push_new_comptime_info() for field in fields { - g.push_existing_comptime_values() - g.inside_comptime_for_field = true - g.comptime_for_field_var = node.val_var - g.comptime_for_field_value = field - g.comptime_for_field_type = field.typ + g.comptime.inside_comptime_for = true + g.comptime.comptime_for_field_var = node.val_var + g.comptime.comptime_for_field_value = field + g.comptime.comptime_for_field_type = field.typ g.writeln('/* field ${i} */ {') g.writeln('\t${node.val_var}.name = _SLIT("${field.name}");') if field.attrs.len == 0 { @@ -942,13 +856,13 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.writeln('\t${node.val_var}.indirections = ${field.typ.nr_muls()};') - g.comptime_var_type_map['${node.val_var}.typ'] = styp - g.comptime_var_type_map['${node.val_var}.unaliased_typ'] = unaliased_styp + g.comptime.type_map['${node.val_var}.typ'] = field.typ + g.comptime.type_map['${node.val_var}.unaliased_typ'] = unaliased_styp g.stmts(node.stmts) i++ g.writeln('}') - g.pop_existing_comptime_values() } + g.pop_comptime_info() } } else if node.kind == .values { if sym.kind == .enum_ { @@ -957,16 +871,13 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.writeln('\tEnumData ${node.val_var} = {0};') } for val in sym.info.vals { - g.comptime_enum_field_value = val - g.comptime_for_field_type = node.typ - g.writeln('/* enum vals ${i} */ {') g.writeln('\t${node.val_var}.name = _SLIT("${val}");') g.write('\t${node.val_var}.value = ') if g.pref.translated && node.typ.is_number() { - g.writeln('_const_main__${g.comptime_enum_field_value};') + g.writeln('_const_main__${val};') } else { - g.writeln('${g.typ(g.comptime_for_field_type)}__${g.comptime_enum_field_value};') + g.writeln('${g.typ(node.typ)}__${val};') } enum_attrs := sym.info.attrs[val] if enum_attrs.len == 0 { @@ -1004,11 +915,11 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { if sym.info.variants.len > 0 { g.writeln('\tVariantData ${node.val_var} = {0};') } - g.inside_comptime_for_field = true - g.push_existing_comptime_values() + g.comptime.inside_comptime_for = true + g.push_new_comptime_info() for variant in sym.info.variants { - g.comptime_for_field_var = node.val_var - g.comptime_var_type_map['${node.val_var}.typ'] = variant + g.comptime.comptime_for_field_var = node.val_var + g.comptime.type_map['${node.val_var}.typ'] = variant g.writeln('/* variant ${i} */ {') g.writeln('\t${node.val_var}.typ = ${variant.idx()};') @@ -1016,7 +927,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.writeln('}') i++ } - g.pop_existing_comptime_values() + g.pop_comptime_info() } } g.indent-- diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index cdbad1293baa10..9f01ca2e1d1cbd 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -29,17 +29,17 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) { if node.expr is ast.ComptimeSelector { if node.expr.field_expr is ast.SelectorExpr { if node.expr.field_expr.expr is ast.Ident { - if node.expr.field_expr.expr.name == g.comptime_for_field_var + if node.expr.field_expr.expr.name == g.comptime.comptime_for_field_var && node.expr.field_expr.field_name == 'name' { - field, _ := g.get_comptime_selector_var_type(node.expr) + field, _ := g.comptime.get_comptime_selector_var_type(node.expr) 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.table.is_comptime_var(node.expr) { - expr_type = g.get_comptime_var_type(node.expr) + } else if node.expr is ast.Ident && g.comptime.inside_comptime_for + && g.comptime.is_comptime_var(node.expr) { + expr_type = g.comptime.get_comptime_var_type(node.expr) name = g.typ(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*', '') } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 1372aa00718979..a75e8b66c7b3db 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -957,9 +957,9 @@ fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool { } left_node := node.left if left_node is ast.ComptimeSelector { - key_str := g.get_comptime_selector_key_type(left_node) + key_str := g.comptime.get_comptime_selector_key_type(left_node) if key_str != '' { - rec_type = g.comptime_var_type_map[key_str] or { rec_type } + rec_type = g.comptime.type_map[key_str] or { rec_type } g.gen_expr_to_string(left_node, rec_type) return true } @@ -973,7 +973,7 @@ fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool { } else if left_node is ast.ComptimeCall { if left_node.method_name == 'method' { sym := g.table.sym(g.unwrap_generic(left_node.left_type)) - if m := sym.find_method(g.comptime_for_method) { + if m := sym.find_method(g.comptime.comptime_for_method) { rec_type = m.return_type g.gen_expr_to_string(left_node, rec_type) return true @@ -982,10 +982,10 @@ fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool { } else if left_node is ast.Ident { if left_node.obj is ast.Var { if left_node.obj.ct_type_var != .no_comptime { - rec_type = g.get_comptime_var_type(left_node) + rec_type = g.comptime.get_comptime_var_type(left_node) g.gen_expr_to_string(left_node, rec_type) return true - } else if g.comptime_var_type_map.len > 0 { + } else if g.comptime.type_map.len > 0 { rec_type = left_node.obj.typ g.gen_expr_to_string(left_node, rec_type) return true @@ -1053,7 +1053,7 @@ fn (g Gen) get_generic_array_element_type(array ast.Array) ast.Type { fn (mut g Gen) resolve_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concrete_types []ast.Type) map[int]ast.Type { mut comptime_args := map[int]ast.Type{} has_dynamic_vars := (g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0) - || g.inside_comptime_for_field + || g.comptime.comptime_for_field_var != '' if has_dynamic_vars { offset := if func.is_method { 1 } else { 0 } mut k := -1 @@ -1072,7 +1072,7 @@ fn (mut g Gen) resolve_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concre if mut call_arg.expr.obj is ast.Var { node_.args[i].typ = call_arg.expr.obj.typ if call_arg.expr.obj.ct_type_var !in [.generic_param, .no_comptime] { - mut ctyp := g.get_comptime_var_type(call_arg.expr) + mut ctyp := g.comptime.get_comptime_var_type(call_arg.expr) if ctyp != ast.void_type { arg_sym := g.table.sym(ctyp) param_sym := g.table.final_sym(param_typ) @@ -1094,7 +1094,7 @@ fn (mut g Gen) resolve_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concre comptime_args[k] = ctyp } } else if call_arg.expr.obj.ct_type_var == .generic_param { - mut ctyp := g.get_comptime_var_type(call_arg.expr) + mut ctyp := g.comptime.get_comptime_var_type(call_arg.expr) if ctyp != ast.void_type { arg_sym := g.table.final_sym(call_arg.typ) param_typ_sym := g.table.sym(param_typ) @@ -1152,14 +1152,14 @@ fn (mut g Gen) resolve_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concre } } else if mut call_arg.expr is ast.PrefixExpr { if call_arg.expr.right is ast.ComptimeSelector { - comptime_args[k] = g.comptime_for_field_type + comptime_args[k] = g.comptime.comptime_for_field_type comptime_args[k] = comptime_args[k].deref() if param_typ.nr_muls() > 0 && comptime_args[k].nr_muls() > 0 { comptime_args[k] = comptime_args[k].set_nr_muls(0) } } } else if mut call_arg.expr is ast.ComptimeSelector { - comptime_args[k] = g.comptime_for_field_type + comptime_args[k] = g.comptime.comptime_for_field_type arg_sym := g.table.final_sym(call_arg.typ) param_typ_sym := g.table.sym(param_typ) if arg_sym.kind == .array && param_typ.has_flag(.generic) @@ -1173,7 +1173,7 @@ fn (mut g Gen) resolve_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concre if call_arg.expr.method_name == 'method' { sym := g.table.sym(g.unwrap_generic(call_arg.expr.left_type)) // `app.$method()` - if m := sym.find_method(g.comptime_for_method) { + if m := sym.find_method(g.comptime.comptime_for_method) { comptime_args[k] = m.return_type } } @@ -1743,15 +1743,15 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { // Handle `print(x)` mut print_auto_str := false if is_print && (node.args[0].typ != ast.string_type - || g.comptime_for_method.len > 0 + || g.comptime.comptime_for_method.len > 0 || g.table.is_comptime_var(node.args[0].expr)) { g.inside_interface_deref = true defer { g.inside_interface_deref = false } mut typ := node.args[0].typ - if g.table.is_comptime_var(node.args[0].expr) { - ctyp := g.get_comptime_var_type(node.args[0].expr) + if g.comptime.is_comptime_var(node.args[0].expr) { + ctyp := g.comptime.get_comptime_var_type(node.args[0].expr) if ctyp != ast.void_type { typ = ctyp } @@ -1759,7 +1759,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { if typ == 0 { g.checker_bug('print arg.typ is 0', node.pos) } - if typ != ast.string_type || g.comptime_for_method.len > 0 { + if typ != ast.string_type || g.comptime.comptime_for_method.len > 0 { expr := node.args[0].expr typ_sym := g.table.sym(typ) if typ_sym.kind == .interface_ && (typ_sym.info as ast.Interface).defines_method('str') { @@ -1783,14 +1783,14 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { } else { g.write('${c_fn_name(print_method)}(') if expr is ast.ComptimeSelector { - key_str := g.get_comptime_selector_key_type(expr) + key_str := g.comptime.get_comptime_selector_key_type(expr) if key_str != '' { - typ = g.comptime_var_type_map[key_str] or { typ } + typ = g.comptime.type_map[key_str] or { typ } } } else if expr is ast.ComptimeCall { if expr.method_name == 'method' { sym := g.table.sym(g.unwrap_generic(expr.left_type)) - if m := sym.find_method(g.comptime_for_method) { + if m := sym.find_method(g.comptime.comptime_for_method) { typ = m.return_type } } diff --git a/vlib/v/gen/c/for.v b/vlib/v/gen/c/for.v index 1bb1a401739cb5..0c1dbbd2cac451 100644 --- a/vlib/v/gen/c/for.v +++ b/vlib/v/gen/c/for.v @@ -144,7 +144,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { if (node.cond is ast.Ident && g.table.is_comptime_var(node.cond)) || node.cond is ast.ComptimeSelector { mut unwrapped_typ := g.unwrap_generic(node.cond_type) - ctyp := g.get_comptime_var_type(node.cond) + ctyp := g.comptime.get_comptime_var_type(node.cond) if ctyp != ast.void_type { unwrapped_typ = g.unwrap_generic(ctyp) is_comptime = true @@ -158,11 +158,11 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { node.kind = unwrapped_sym.kind if is_comptime { - g.comptime_var_type_map[node.val_var] = node.val_type + g.comptime.type_map[node.val_var] = node.val_type node.scope.update_ct_var_kind(node.val_var, .value_var) defer { - g.comptime_var_type_map.delete(node.val_var) + g.comptime.type_map.delete(node.val_var) } } @@ -175,11 +175,11 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { node.scope.update_var_type(node.key_var, key_type) if is_comptime { - g.comptime_var_type_map[node.key_var] = node.key_type + g.comptime.type_map[node.key_var] = node.key_type node.scope.update_ct_var_kind(node.key_var, .key_var) defer { - g.comptime_var_type_map.delete(node.key_var) + g.comptime.type_map.delete(node.key_var) } } } @@ -223,7 +223,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { if is_comptime && g.table.is_comptime_var(node.cond) { mut unwrapped_typ := g.unwrap_generic(node.cond_type) - ctyp := g.unwrap_generic(g.get_comptime_var_type(node.cond)) + ctyp := g.unwrap_generic(g.comptime.get_comptime_var_type(node.cond)) if ctyp != ast.void_type { unwrapped_typ = ctyp } diff --git a/vlib/v/gen/c/infix.v b/vlib/v/gen/c/infix.v index efbde5809dd1b5..ab529fb9949f3b 100644 --- a/vlib/v/gen/c/infix.v +++ b/vlib/v/gen/c/infix.v @@ -97,12 +97,12 @@ fn (mut g Gen) infix_expr_arrow_op(node ast.InfixExpr) { // infix_expr_eq_op generates code for `==` and `!=` fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) { left_type := if node.left is ast.ComptimeSelector { - g.get_comptime_var_type(node.left) + g.comptime.get_comptime_var_type(node.left) } else { node.left_type } right_type := if node.right is ast.ComptimeSelector { - g.get_comptime_var_type(node.right) + g.comptime.get_comptime_var_type(node.right) } else { node.right_type } diff --git a/vlib/v/gen/c/str_intp.v b/vlib/v/gen/c/str_intp.v index a45bb531439903..b3253e3de51971 100644 --- a/vlib/v/gen/c/str_intp.v +++ b/vlib/v/gen/c/str_intp.v @@ -166,7 +166,7 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int, fmts []u8) { fmt := fmts[i] typ := g.unwrap_generic(node.expr_types[i]) typ_sym := g.table.sym(typ) - if typ == ast.string_type && g.comptime_for_method.len == 0 { + if typ == ast.string_type && g.comptime.comptime_for_method.len == 0 { if g.inside_vweb_tmpl { g.write('vweb__filter(') if expr.is_auto_deref_var() && fmt != `p` { @@ -193,7 +193,7 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int, fmts []u8) { mut exp_typ := typ if expr is ast.Ident { if expr.obj is ast.Var { - if g.comptime_var_type_map.len > 0 || g.comptime_for_method.len > 0 { + if g.comptime.type_map.len > 0 || g.comptime.comptime_for_method.len > 0 { exp_typ = expr.obj.typ } else if expr.obj.smartcasts.len > 0 { exp_typ = g.unwrap_generic(expr.obj.smartcasts.last()) @@ -246,8 +246,8 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { mut node_ := unsafe { node } mut fmts := node_.fmts.clone() for i, mut expr in node_.exprs { - if g.table.is_comptime_var(expr) { - ctyp := g.get_comptime_var_type(expr) + if g.comptime.is_comptime_var(expr) { + ctyp := g.comptime.get_comptime_var_type(expr) if ctyp != ast.void_type { node_.expr_types[i] = ctyp if node_.fmts[i] == `_` { diff --git a/vlib/v/tests/comptime_variant_test.v b/vlib/v/tests/comptime_variant_test.v new file mode 100644 index 00000000000000..f87e3ae2b2fa1e --- /dev/null +++ b/vlib/v/tests/comptime_variant_test.v @@ -0,0 +1,22 @@ +type TestSum = int | string + +fn gen[T](val T) { + $if val is $sumtype { + $for f in T.variants { + dump(f) + dump(f.typ) + $if f.typ is $int { + dump('is int') + assert f.typ == typeof[int]().idx + } $else $if f.typ is string { + dump('is string') + assert f.typ == typeof[string]().idx + } + } + } +} + +fn test_main() { + a := TestSum(123) + gen(a) +}