From 300506bee90de7ec3cc92064087122295e76a189 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 28 Dec 2024 10:35:26 -0300 Subject: [PATCH] refactor --- vlib/v/checker/assign.v | 11 +- vlib/v/checker/check_types.v | 6 +- vlib/v/checker/checker.v | 28 +- vlib/v/checker/comptime.v | 50 ++- vlib/v/checker/fn.v | 46 +-- vlib/v/checker/for.v | 25 +- vlib/v/checker/if.v | 22 +- vlib/v/checker/infix.v | 2 +- vlib/v/checker/postfix.v | 2 +- vlib/v/checker/return.v | 2 +- vlib/v/checker/str.v | 4 +- vlib/v/comptime/comptimeinfo.v | 467 ----------------------- vlib/v/gen/c/array.v | 2 +- vlib/v/gen/c/assert.v | 4 +- vlib/v/gen/c/assign.v | 22 +- vlib/v/gen/c/cgen.v | 37 +- vlib/v/gen/c/comptime.v | 52 ++- vlib/v/gen/c/dumpexpr.v | 4 +- vlib/v/gen/c/fn.v | 26 +- vlib/v/gen/c/for.v | 12 +- vlib/v/gen/c/infix.v | 14 +- vlib/v/gen/c/str_intp.v | 4 +- vlib/v/type_resolver/comptime_resolver.v | 270 +++++++++++++ vlib/v/type_resolver/generic_resolver.v | 36 ++ vlib/v/type_resolver/type_resolver.v | 221 +++++++++++ 25 files changed, 694 insertions(+), 675 deletions(-) delete mode 100644 vlib/v/comptime/comptimeinfo.v create mode 100644 vlib/v/type_resolver/comptime_resolver.v create mode 100644 vlib/v/type_resolver/generic_resolver.v create mode 100644 vlib/v/type_resolver/type_resolver.v diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 4886dfdb7cc7a6..3c4854e2a67d92 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -393,7 +393,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { && right.or_expr.kind == .absent { right_obj_var := right.obj as ast.Var if right_obj_var.ct_type_var != .no_comptime { - ctyp := c.comptime.get_type(right) + ctyp := c.type_resolver.get_type(right) if ctyp != ast.void_type { left.obj.ct_type_var = right_obj_var.ct_type_var left.obj.typ = ctyp @@ -407,7 +407,8 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { if left.obj.ct_type_var in [.generic_var, .no_comptime] && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len != 0 - && !right.comptime_ret_val && c.is_generic_expr(right) { + && !right.comptime_ret_val + && c.type_resolver.is_generic_expr(right) { // mark variable as generic var because its type changes according to fn return generic resolution type left.obj.ct_type_var = .generic_var if right.return_type_generic.has_flag(.generic) { @@ -419,7 +420,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { } else { fn_ret_type.clear_option_and_result() } - c.comptime.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type + c.type_resolver.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type } } else if right.is_static_method && right.left_type.has_flag(.generic) { @@ -429,7 +430,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { } else { fn_ret_type.clear_option_and_result() } - c.comptime.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type + c.type_resolver.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type } } } @@ -505,7 +506,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { if (left.is_map || left.is_farray) && left.is_setter { left.recursive_mapset_is_setter(true) } - right_type = c.comptime.get_type_or_default(right, right_type) + right_type = c.type_resolver.get_type_or_default(right, right_type) } if mut left is ast.InfixExpr { c.error('cannot use infix expression on the left side of `${node.op}`', diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index ca456270ea3b5e..41a16df5a4890b 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -1022,7 +1022,8 @@ fn (mut c Checker) infer_fn_generic_types(func &ast.Fn, mut node ast.CallExpr) { typ = ast.new_type(idx).derive(arg.typ) } else if c.comptime.comptime_for_field_var != '' && sym.kind in [.struct, .any] && arg.expr is ast.ComptimeSelector { - comptime_typ := c.comptime.get_comptime_selector_type(arg.expr, ast.void_type) + comptime_typ := c.type_resolver.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) @@ -1121,7 +1122,8 @@ fn (mut c Checker) infer_fn_generic_types(func &ast.Fn, mut node ast.CallExpr) { } // resolve lambda with generic return type if arg.expr is ast.LambdaExpr && typ.has_flag(.generic) { - typ = c.comptime.unwrap_generic_expr(arg.expr.expr, typ) + typ = c.type_resolver.unwrap_generic_expr(arg.expr.expr, + typ) if typ.has_flag(.generic) { lambda_ret_gt_name := c.table.type_to_str(typ) idx := func.generic_names.index(lambda_ret_gt_name) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 327e2442ef4082..4c05126c2e1252 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -13,7 +13,7 @@ import v.util.version import v.errors import v.pkgconfig import v.transformer -import v.comptime +import v.type_resolver // prevent stack overflows by restricting too deep recursion: const expr_level_cutoff_limit = 40 @@ -116,9 +116,9 @@ mut: loop_labels []string // filled, when inside labelled for loops: `a_label: for x in 0..10 {` vweb_gen_types []ast.Type // vweb route checks timers &util.Timers = util.get_timers() - 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 } + type_resolver type_resolver.TypeResolver + comptime &type_resolver.ResolverInfo = unsafe { nil } + fn_scope &ast.Scope = unsafe { nil } main_fn_decl_node ast.FnDecl match_exhaustive_cutoff_limit int = 10 is_last_stmt bool @@ -164,10 +164,8 @@ pub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker { v_current_commit_hash: if pref_.building_v { version.githash(pref_.vroot) or { @VCURRENTHASH} } else { @VCURRENTHASH } } - checker.comptime = &comptime.ComptimeInfo{ - resolver: checker - table: table - } + checker.type_resolver = type_resolver.TypeResolver.new(table, checker) + checker.comptime = &checker.type_resolver.info return checker } @@ -1674,7 +1672,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { } 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.type_map['${c.comptime.comptime_for_enum_var}.typ'] + node.expr_type = c.type_resolver.type_map['${c.comptime.comptime_for_enum_var}.typ'] node.typ = typ return node.expr_type } @@ -3056,9 +3054,9 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { } if c.comptime.inside_comptime_for && mut node.expr is ast.Ident { if node.expr.ct_expr { - node.expr_type = c.comptime.get_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] + node.expr_type = c.type_resolver.get_type(node.expr as ast.Ident) + } else if (node.expr as ast.Ident).name in c.type_resolver.type_map { + node.expr_type = c.type_resolver.type_map[(node.expr as ast.Ident).name] } } c.check_expr_option_or_result_call(node.expr, node.expr_type) @@ -3348,9 +3346,9 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { c.inside_integer_literal_cast = old_inside_integer_literal_cast if mut node.expr is ast.ComptimeSelector { - node.expr_type = c.comptime.get_comptime_selector_type(node.expr, node.expr_type) + node.expr_type = c.type_resolver.get_comptime_selector_type(node.expr, node.expr_type) } else if node.expr is ast.Ident && c.comptime.is_comptime_variant_var(node.expr) { - node.expr_type = c.comptime.type_map['${c.comptime.comptime_for_variant_var}.typ'] + node.expr_type = c.type_resolver.type_map['${c.comptime.comptime_for_variant_var}.typ'] } mut from_type := c.unwrap_generic(node.expr_type) from_sym := c.table.sym(from_type) @@ -3960,7 +3958,7 @@ 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 := c.comptime.get_type_or_default(node, info.typ) + typ := c.type_resolver.get_type_or_default(node, info.typ) // Got a var with type T, return current generic type if node.or_expr.kind != .absent { if !typ.has_flag(.option) { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 894e4f10c6c146..93bcfd90eb42c4 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -8,7 +8,7 @@ import v.pref import v.token import v.util import v.pkgconfig -import v.comptime +import v.type_resolver fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { if node.left !is ast.EmptyExpr { @@ -160,7 +160,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { } } c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type) - return c.comptime.get_type(node) + return c.type_resolver.get_type(node) } if node.method_name == 'res' { if !c.inside_defer { @@ -240,17 +240,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.type_map.len == 0 { + if c.type_resolver.type_map.len == 0 { c.error('compile time field access can only be used when iterating over `T.fields`', left_pos) } - expr_type = c.comptime.get_comptime_selector_type(node, ast.void_type) + expr_type = c.type_resolver.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.type_map { - return c.comptime.type_map[expr_name] + if expr_name in c.type_resolver.type_map { + return c.type_resolver.type_map[expr_name] } c.error('unknown `\$for` variable `${expr_name}`', left_pos) } else { @@ -300,8 +300,8 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { } 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.type_resolver.type_map[node.val_var] = c.field_data_type + c.type_resolver.type_map['${node.val_var}.typ'] = node.typ c.comptime.comptime_for_field_type = field.typ c.stmts(mut node.stmts) @@ -345,8 +345,8 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { c.enum_data_type = c.table.find_type('EnumData') } 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.type_resolver.type_map[node.val_var] = c.enum_data_type + c.type_resolver.type_map['${node.val_var}.typ'] = node.typ c.stmts(mut node.stmts) c.pop_comptime_info() c.table.used_features.comptime_for = true @@ -363,7 +363,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { c.comptime.comptime_for_method = unsafe { &method } 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.type_resolver.type_map['${node.val_var}.return_type'] = method.return_type c.stmts(mut node.stmts) c.pop_comptime_info() } @@ -398,8 +398,8 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { 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.type_resolver.type_map[node.val_var] = c.variant_data_type + c.type_resolver.type_map['${node.val_var}.typ'] = variant c.stmts(mut node.stmts) c.pop_comptime_info() } @@ -833,7 +833,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr } 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.comptime.is_comptime_type(checked_type, cond.right) { + return if c.type_resolver.is_comptime_type(checked_type, cond.right) { .eval } else { .skip @@ -844,8 +844,10 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr if mut cond.left is ast.SelectorExpr && cond.right is ast.ComptimeType { comptime_type := cond.right as ast.ComptimeType if c.comptime.is_comptime_selector_type(cond.left) { - checked_type := c.comptime.get_type(cond.left) - return if c.comptime.is_comptime_type(checked_type, comptime_type) { + checked_type := c.type_resolver.get_type(cond.left) + return if c.type_resolver.is_comptime_type(checked_type, + comptime_type) + { .eval } else { .skip @@ -854,7 +856,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr && cond.left.name_type != 0 { // T.unaliased_typ checked_type := c.unwrap_generic(cond.left.name_type) - return if c.comptime.is_comptime_type(c.table.unaliased_type(checked_type), + return if c.type_resolver.is_comptime_type(c.table.unaliased_type(checked_type), comptime_type) { .eval @@ -1085,7 +1087,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr ast.SelectorExpr { 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) + ret_bool := c.type_resolver.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.comptime_for_field_var}', @@ -1102,10 +1104,8 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr // 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() + c.type_resolver.info_stack << type_resolver.ResolverInfo{ + saved_type_map: c.type_resolver.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 @@ -1120,10 +1120,8 @@ fn (mut c Checker) push_new_comptime_info() { // 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() + old := c.type_resolver.info_stack.pop() + c.type_resolver.type_map = old.saved_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 diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 2814c7bac8f5b6..dd416f869e34a4 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1805,7 +1805,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.type_map.len > 0 { + if c.type_resolver.type_map.len > 0 { continue } if mut call_arg.expr is ast.LambdaExpr { @@ -1885,38 +1885,6 @@ fn (mut c Checker) register_trace_call(node &ast.CallExpr, func &ast.Fn) { } } -// is_generic_expr checks if the expr relies on fn generic argument -fn (mut c Checker) is_generic_expr(node ast.Expr) bool { - return match node { - ast.Ident { - // variable declared as generic type - c.comptime.is_generic_param_var(node) - } - ast.IndexExpr { - // generic_var[N] - c.comptime.is_generic_param_var(node.left) - } - ast.CallExpr { - // fn which has any generic dependent expr - if node.args.any(c.comptime.is_generic_param_var(it.expr)) { - return true - } - if node.is_static_method && node.left_type.has_flag(.generic) { - return true - } - // fn[T]() or generic_var.fn[T]() - node.concrete_types.any(it.has_flag(.generic)) - } - ast.SelectorExpr { - // generic_var.property - c.comptime.is_generic_param_var(node.expr) - } - else { - false - } - } -} - 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) @@ -1938,7 +1906,7 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr 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_var, .generic_param, .no_comptime] { - mut ctyp := c.comptime.get_type(call_arg.expr) + mut ctyp := c.type_resolver.get_type(call_arg.expr) if ctyp != ast.void_type { arg_sym := c.table.sym(ctyp) param_sym := c.table.final_sym(param_typ) @@ -1961,7 +1929,7 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr comptime_args[k] = ctyp } } else if call_arg.expr.obj.ct_type_var == .generic_param { - mut ctyp := c.comptime.get_type(call_arg.expr) + mut ctyp := c.type_resolver.get_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) @@ -2024,7 +1992,7 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr } } } else if call_arg.expr.obj.ct_type_var == .generic_var { - mut ctyp := c.comptime.get_type(call_arg.expr) + mut ctyp := c.type_resolver.get_type(call_arg.expr) if node_.args[i].expr.is_auto_deref_var() { ctyp = ctyp.deref() } @@ -2036,14 +2004,14 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr } } else if call_arg.expr is ast.PrefixExpr { if call_arg.expr.right is ast.ComptimeSelector { - comptime_args[k] = c.comptime.get_type(call_arg.expr.right) + comptime_args[k] = c.type_resolver.get_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.comptime.get_type(call_arg.expr) + ct_value := c.type_resolver.get_type(call_arg.expr) param_typ_sym := c.table.sym(param_typ) if ct_value != ast.void_type { arg_sym := c.table.final_sym(call_arg.typ) @@ -2068,7 +2036,7 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr } } } else if call_arg.expr is ast.ComptimeCall { - comptime_args[k] = c.comptime.get_type(call_arg.expr) + comptime_args[k] = c.type_resolver.get_type(call_arg.expr) } } } diff --git a/vlib/v/checker/for.v b/vlib/v/checker/for.v index 1c081bba3ca428..e98f3d84a5a0c1 100644 --- a/vlib/v/checker/for.v +++ b/vlib/v/checker/for.v @@ -95,7 +95,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { } mut is_comptime := false if (node.cond is ast.Ident && node.cond.ct_expr) || node.cond is ast.ComptimeSelector { - ctyp := c.comptime.get_type(node.cond) + ctyp := c.type_resolver.get_type(node.cond) if ctyp != ast.void_type { is_comptime = true typ = ctyp @@ -109,7 +109,8 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { node.val_is_ref = node.cond.op == .amp } ast.ComptimeSelector { - comptime_typ := c.comptime.get_comptime_selector_type(node.cond, ast.void_type) + comptime_typ := c.type_resolver.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 @@ -158,11 +159,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.type_map[node.val_var] = val_type + c.type_resolver.type_map[node.val_var] = val_type node.scope.update_ct_var_kind(node.val_var, .value_var) defer { - c.comptime.type_map.delete(node.val_var) + c.type_resolver.type_map.delete(node.val_var) } } } else if sym.kind == .any { @@ -181,11 +182,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.type_map[node.key_var] = key_type + c.type_resolver.type_map[node.key_var] = key_type node.scope.update_ct_var_kind(node.key_var, .key_var) defer { - c.comptime.type_map.delete(node.key_var) + c.type_resolver.type_map.delete(node.key_var) } } } @@ -194,11 +195,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.type_map[node.val_var] = value_type + c.type_resolver.type_map[node.val_var] = value_type node.scope.update_ct_var_kind(node.val_var, .value_var) defer { - c.comptime.type_map.delete(node.val_var) + c.type_resolver.type_map.delete(node.val_var) } } } else { @@ -219,11 +220,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.type_map[node.key_var] = key_type + c.type_resolver.type_map[node.key_var] = key_type node.scope.update_ct_var_kind(node.key_var, .key_var) defer { - c.comptime.type_map.delete(node.key_var) + c.type_resolver.type_map.delete(node.key_var) } } } @@ -278,11 +279,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.type_map[node.val_var] = value_type + c.type_resolver.type_map[node.val_var] = value_type node.scope.update_ct_var_kind(node.val_var, .value_var) defer { - c.comptime.type_map.delete(node.val_var) + c.type_resolver.type_map.delete(node.val_var) } } } diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index b20d72fe8de90f..2387cfc37ca1cf 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -129,7 +129,7 @@ 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.comptime.is_comptime_type(checked_type, + skip_state = if c.type_resolver.is_comptime_type(checked_type, right as ast.ComptimeType) { .eval @@ -144,7 +144,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { checked_type = c.unwrap_generic(var.smartcasts.last()) } } - skip_state = if c.comptime.is_comptime_type(checked_type, + skip_state = if c.type_resolver.is_comptime_type(checked_type, right as ast.ComptimeType) { .eval @@ -173,7 +173,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { right as ast.TypeNode) } } else if c.comptime.check_comptime_is_field_selector_bool(left) { - skip_state = if c.comptime.get_comptime_selector_bool_field(left.field_name) { + skip_state = if c.type_resolver.get_comptime_selector_bool_field(left.field_name) { .eval } else { .skip @@ -188,7 +188,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { c.comptime.comptime_for_enum_var, ] { if left.field_name == 'typ' { - skip_state = c.check_compatible_types(c.comptime.type_map['${comptime_field_name}.typ'], + skip_state = c.check_compatible_types(c.type_resolver.type_map['${comptime_field_name}.typ'], right as ast.TypeNode) } } @@ -387,9 +387,9 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } if comptime_field_name.len > 0 { if comptime_field_name == c.comptime.comptime_for_method_var { - c.comptime.type_map[comptime_field_name] = c.comptime.comptime_for_method_ret_type + c.type_resolver.type_map[comptime_field_name] = c.comptime.comptime_for_method_ret_type } else if comptime_field_name == c.comptime.comptime_for_field_var { - c.comptime.type_map[comptime_field_name] = c.comptime.comptime_for_field_type + c.type_resolver.type_map[comptime_field_name] = c.comptime.comptime_for_field_type } } c.skip_flags = cur_skip_flags @@ -513,7 +513,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(stmt.typ)}`', node.pos) } else { - if node.is_expr == false && c.comptime.is_generic_param_var(stmt.expr) { + if node.is_expr == false && c.type_resolver.is_generic_param_var(stmt.expr) { // generic variable no yet type bounded node.is_expr = true } @@ -583,7 +583,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, co } else if node.left in [ast.Ident, ast.SelectorExpr] && node.op == .ne && node.right is ast.None { if node.left is ast.Ident && c.comptime.get_ct_type_var(node.left) == .smartcast { - node.left_type = c.comptime.get_type(node.left) + node.left_type = c.type_resolver.get_type(node.left) c.smartcast(mut node.left, node.left_type, node.left_type.clear_flag(.option), mut scope, true, true) } else { @@ -592,7 +592,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, co } } else if node.op == .key_is { if node.left is ast.Ident && node.left.ct_expr { - node.left_type = c.comptime.get_type(node.left) + node.left_type = c.type_resolver.get_type(node.left) } else { node.left_type = c.expr(mut node.left) } @@ -608,7 +608,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, co ast.Ident { if right_expr.name == c.comptime.comptime_for_variant_var { is_comptime = true - c.comptime.type_map['${c.comptime.comptime_for_variant_var}.typ'] + c.type_resolver.type_map['${c.comptime.comptime_for_variant_var}.typ'] } else { c.error('invalid type `${right_expr}`', right_expr.pos) ast.no_type @@ -676,7 +676,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, co if first_cond.left is ast.Ident && first_cond.op == .eq && first_cond.right is ast.None { if first_cond.left is ast.Ident && c.comptime.get_ct_type_var(first_cond.left) == .smartcast { - first_cond.left_type = c.comptime.get_type(first_cond.left) + first_cond.left_type = c.type_resolver.get_type(first_cond.left) c.smartcast(mut first_cond.left, first_cond.left_type, first_cond.left_type.clear_flag(.option), mut scope, true, true) } else { diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index 21825362df54f2..89d89ba622fa2a 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -763,7 +763,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } ast.Ident { if right_expr.name == c.comptime.comptime_for_variant_var { - c.comptime.type_map['${c.comptime.comptime_for_variant_var}.typ'] + c.type_resolver.type_map['${c.comptime.comptime_for_variant_var}.typ'] } else { c.error('invalid type `${right_expr}`', right_expr.pos) ast.no_type diff --git a/vlib/v/checker/postfix.v b/vlib/v/checker/postfix.v index 30223759fc47fe..352b052f15291c 100644 --- a/vlib/v/checker/postfix.v +++ b/vlib/v/checker/postfix.v @@ -26,7 +26,7 @@ fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type { if !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) { if c.comptime.comptime_for_field_var != '' { if c.comptime.is_comptime(node.expr) || node.expr is ast.ComptimeSelector { - node.typ = c.unwrap_generic(c.comptime.get_type(node.expr)) + node.typ = c.unwrap_generic(c.type_resolver.get_type(node.expr)) if node.op == .question { node.typ = node.typ.clear_flag(.option) } diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index d751df961a26bf..09fc9b05ab4139 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -108,7 +108,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) { typ = c.unwrap_generic(expr.obj.smartcasts.last()) } if expr.obj.ct_type_var != .no_comptime { - typ = c.comptime.get_type_or_default(expr, typ) + typ = c.type_resolver.get_type_or_default(expr, typ) } if mut expr.obj.expr is ast.IfGuardExpr { if var := expr.scope.find_var(expr.name) { diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index f5680eabe5d0d3..75f8ae987426c0 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -45,7 +45,7 @@ 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) - ftyp = c.comptime.get_type_or_default(expr, c.check_expr_option_or_result_call(expr, + ftyp = c.type_resolver.get_type_or_default(expr, c.check_expr_option_or_result_call(expr, ftyp)) if ftyp == ast.void_type { c.error('expression does not return a value', expr.pos()) @@ -86,7 +86,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type { node.fmt_poss[i]) } } else if c.comptime.is_comptime(expr) - && c.comptime.get_type_or_default(expr, ast.void_type) != ast.void_type { + && c.type_resolver.get_type_or_default(expr, ast.void_type) != 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 deleted file mode 100644 index 156ab624c3ef47..00000000000000 --- a/vlib/v/comptime/comptimeinfo.v +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright (c) 2019-2024 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_expr checks if the node is related to a comptime expr -@[inline] -pub fn (mut ct ComptimeInfo) is_comptime_expr(node ast.Expr) bool { - return (node is ast.Ident && node.ct_expr) - || (node is ast.IndexExpr && ct.is_comptime_expr(node.left)) - || node is ast.ComptimeSelector -} - -// has_comptime_expr checks if the expr contains some comptime expr -@[inline] -pub fn (mut ct ComptimeInfo) has_comptime_expr(node ast.Expr) bool { - return (node is ast.Ident && node.ct_expr) - || (node is ast.IndexExpr && ct.has_comptime_expr(node.left)) - || node is ast.ComptimeSelector - || (node is ast.SelectorExpr && ct.has_comptime_expr(node.expr)) - || (node is ast.InfixExpr && (ct.has_comptime_expr(node.left) - || ct.has_comptime_expr(node.right))) -} - -// is_comptime checks if the node is related to a comptime marked variable -@[inline] -pub fn (mut ct ComptimeInfo) is_comptime(node ast.Expr) bool { - return match node { - ast.Ident { - node.ct_expr - } - ast.IndexExpr { - if node.left is ast.Ident { - node.left.ct_expr - } else { - false - } - } - ast.SelectorExpr { - return node.expr is ast.Ident && node.expr.ct_expr - } - ast.InfixExpr { - return ct.is_comptime(node.left) || ct.is_comptime(node.right) - } - ast.ParExpr { - return ct.is_comptime(node.expr) - } - else { - false - } - } -} - -// is_comptime_variant_var checks if the node is related to a comptime variant variable -@[inline] -pub fn (mut ct ComptimeInfo) is_comptime_variant_var(node ast.Ident) bool { - return node.name == ct.comptime_for_variant_var -} - -// 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 { - if node is ast.Ident { - if node.obj is ast.Var { - return node.obj.ct_type_var - } - } else if node is ast.IndexExpr { - return ct.get_ct_type_var(node.left) - } - return .no_comptime -} - -@[inline] -pub fn (mut ct ComptimeInfo) is_generic_param_var(node ast.Expr) bool { - return node is ast.Ident && node.info is ast.IdentVar && node.obj is ast.Var - && (node.obj as ast.Var).ct_type_var == .generic_param -} - -// get_expr_type_or_default computes the ast node type regarding its or_expr if its comptime var otherwise default_typ is returned -pub fn (mut ct ComptimeInfo) get_expr_type_or_default(node ast.Expr, default_typ ast.Type) ast.Type { - if !ct.is_comptime_expr(node) { - return default_typ - } - ctyp := ct.get_type(node) - match node { - ast.Ident { - // returns the unwrapped type of the var - if ctyp.has_flag(.option) && node.or_expr.kind != .absent { - return ctyp.clear_flag(.option) - } - } - else {} - } - return if ctyp != ast.void_type { ctyp } else { default_typ } -} - -// get_type_or_default retries the comptime value if the AST node is related to comptime otherwise default_typ is returned -@[inline] -pub fn (mut ct ComptimeInfo) get_type_or_default(node ast.Expr, default_typ ast.Type) ast.Type { - match node { - ast.Ident { - if node.ct_expr { - ctyp := ct.get_type(node) - return if ctyp != ast.void_type { ctyp } else { default_typ } - } - } - ast.SelectorExpr { - if node.expr is ast.Ident && node.expr.ct_expr { - struct_typ := ct.resolver.unwrap_generic(ct.get_type(node.expr)) - struct_sym := ct.table.final_sym(struct_typ) - // Struct[T] can have field with generic type - if struct_sym.info is ast.Struct && struct_sym.info.generic_types.len > 0 { - if field := ct.table.find_field(struct_sym, node.field_name) { - return field.typ - } - } - } - } - ast.ParExpr { - return ct.get_type_or_default(node.expr, default_typ) - } - ast.InfixExpr { - if node.op in [.plus, .minus, .mul, .div, .mod] { - return ct.get_type_or_default(node.left, default_typ) - } - } - else { - return default_typ - } - } - return default_typ -} - -// get_type retrieves the actual type from a comptime related ast node -@[inline] -pub fn (mut ct ComptimeInfo) get_type(node ast.Expr) ast.Type { - if node is ast.Ident { - if node.obj is ast.Var { - return match node.obj.ct_type_var { - .generic_param { - // generic parameter from current function - node.obj.typ - } - .generic_var { - // generic var used on fn call assignment - if node.obj.smartcasts.len > 0 { - node.obj.smartcasts.last() - } else { - ct.type_map['g.${node.name}.${node.obj.pos.pos}'] or { node.obj.typ } - } - } - .smartcast { - ctyp := ct.type_map['${ct.comptime_for_variant_var}.typ'] or { node.obj.typ } - return if (node.obj as ast.Var).is_unwrapped { - ctyp.clear_flag(.option) - } else { - ctyp - } - } - .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) { - return ct.get_type_from_comptime_var(node.expr as ast.Ident) - } else if node is ast.ComptimeCall { - method_name := ct.comptime_for_method.name - 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 - } else if node is ast.IndexExpr && ct.is_comptime(node.left) { - nltype := ct.get_type(node.left) - nltype_unwrapped := ct.resolver.unwrap_generic(nltype) - return ct.table.value_type(nltype_unwrapped) - } - return ast.void_type -} - -// get_type_from_comptime_var retrives the comptime type related to $for variable -@[inline] -pub fn (mut ct ComptimeInfo) get_type_from_comptime_var(var ast.Ident) ast.Type { - return match var.name { - ct.comptime_for_variant_var { - ct.type_map['${ct.comptime_for_variant_var}.typ'] - } - ct.comptime_for_method_param_var { - ct.type_map['${ct.comptime_for_method_param_var}.typ'] - } - else { - // field_var.typ from $for field - ct.comptime_for_field_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, ct.comptime_for_method_param_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 - } - .string { - return x_kind == .string - } - .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, .args 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 - } - ct.comptime_for_method_param_var { - return .params - } - else { - return none - } - } -} - -pub fn (mut ct ComptimeInfo) unwrap_generic_expr(expr ast.Expr, default_typ ast.Type) ast.Type { - match expr { - ast.StringLiteral, ast.StringInterLiteral { - return ast.string_type - } - ast.ParExpr { - return ct.unwrap_generic_expr(expr.expr, default_typ) - } - ast.CastExpr { - return expr.typ - } - ast.InfixExpr { - if ct.is_comptime(expr.left) { - return ct.resolver.unwrap_generic(ct.get_type(expr.left)) - } - if ct.is_comptime(expr.right) { - return ct.resolver.unwrap_generic(ct.get_type(expr.right)) - } - return default_typ - } - ast.Ident { - return if expr.ct_expr { - ct.resolver.unwrap_generic(ct.get_type(expr)) - } else { - default_typ - } - } - else { - return default_typ - } - } -} - -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 } - // loop id for loop distinction - comptime_loop_id int - // $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 &ast.Fn = unsafe { nil } - comptime_for_method_ret_type ast.Type - // .args - comptime_for_method_param_var string -} diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index 3bb1c362903aed..ec672967a7f80c 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -574,7 +574,7 @@ 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 && node.left.ct_expr { - ctyp := g.comptime.get_type(node.left) + ctyp := g.type_resolver.get_type(node.left) if ctyp != ast.void_type { expr.expr_type = g.table.value_type(ctyp) } diff --git a/vlib/v/gen/c/assert.v b/vlib/v/gen/c/assert.v index c4ad30b892b2a7..63f48feca2c24d 100644 --- a/vlib/v/gen/c/assert.v +++ b/vlib/v/gen/c/assert.v @@ -152,12 +152,12 @@ fn (mut g Gen) gen_assert_metainfo(node ast.AssertStmt, kind AssertMetainfoKind) g.writeln('\t${metaname}.llabel = ${expr_left_str};') g.writeln('\t${metaname}.rlabel = ${expr_right_str};') left_type := if g.comptime.is_comptime_expr(node.expr.left) { - g.comptime.get_type(node.expr.left) + g.type_resolver.get_type(node.expr.left) } else { node.expr.left_type } right_type := if g.comptime.is_comptime_expr(node.expr.right) { - g.comptime.get_type(node.expr.right) + g.type_resolver.get_type(node.expr.right) } else { node.expr.right_type } diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 1204a4ae7bfa10..15cc6511e1dcc1 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -293,7 +293,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } if mut left.obj is ast.Var { if val is ast.Ident && val.ct_expr { - ctyp := g.unwrap_generic(g.comptime.get_type(val)) + ctyp := g.unwrap_generic(g.type_resolver.get_type(val)) if ctyp != ast.void_type { var_type = ctyp val_type = var_type @@ -308,17 +308,17 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { key_str := g.comptime.get_comptime_selector_key_type(val) if key_str != '' { if is_decl { - var_type = g.comptime.type_map[key_str] or { var_type } + var_type = g.type_resolver.type_map[key_str] or { var_type } val_type = var_type left.obj.typ = var_type } else { - val_type = g.comptime.type_map[key_str] or { var_type } + val_type = g.type_resolver.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.type_map[key_str] or { var_type } + var_type = g.type_resolver.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 { @@ -331,13 +331,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } else if val is ast.DumpExpr && val.expr is ast.ComptimeSelector { key_str := g.comptime.get_comptime_selector_key_type(val.expr as ast.ComptimeSelector) if key_str != '' { - var_type = g.comptime.type_map[key_str] or { var_type } + var_type = g.type_resolver.type_map[key_str] or { var_type } val_type = var_type left.obj.typ = var_type } g.assign_ct_type = var_type } else if val is ast.IndexExpr { - if val.left is ast.Ident && g.comptime.is_generic_param_var(val.left) { + if val.left is ast.Ident && g.type_resolver.is_generic_param_var(val.left) { ctyp := g.unwrap_generic(g.get_gn_var_type(val.left)) if ctyp != ast.void_type { var_type = ctyp @@ -353,7 +353,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { var_type = fn_ret_type val_type = var_type left.obj.typ = var_type - g.comptime.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type + g.type_resolver.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type // eprintln('>> ${func.name} > resolve ${left.name}.${left.obj.pos.pos}.generic to ${g.table.type_to_str(var_type)}') } } else if val.is_static_method && val.left_type.has_flag(.generic) { @@ -361,7 +361,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { var_type = fn_ret_type val_type = var_type left.obj.typ = var_type - g.comptime.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type + g.type_resolver.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type g.assign_ct_type = var_type } } @@ -370,13 +370,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } else if mut left is ast.ComptimeSelector { key_str := g.comptime.get_comptime_selector_key_type(left) if key_str != '' { - var_type = g.comptime.type_map[key_str] or { var_type } + var_type = g.type_resolver.type_map[key_str] or { var_type } } g.assign_ct_type = var_type if val is ast.ComptimeSelector { key_str_right := g.comptime.get_comptime_selector_key_type(val) if key_str_right != '' { - val_type = g.comptime.type_map[key_str_right] or { var_type } + val_type = g.type_resolver.type_map[key_str_right] or { var_type } } } else if val is ast.CallExpr { g.assign_ct_type = g.comptime.comptime_for_field_type @@ -384,7 +384,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } else if mut left is ast.IndexExpr && val is ast.ComptimeSelector { key_str := g.comptime.get_comptime_selector_key_type(val) if key_str != '' { - val_type = g.comptime.type_map[key_str] or { var_type } + val_type = g.type_resolver.type_map[key_str] or { var_type } } g.assign_ct_type = val_type } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index a702a28a40d009..43bd9d63e79a74 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -13,7 +13,7 @@ import v.token import v.util import v.util.version import v.depgraph -import v.comptime +import v.type_resolver import sync.pool // Note: some of the words in c_reserved, are not reserved in C, but are @@ -224,8 +224,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_info_stack []comptime.ComptimeInfo // stores the values from the above on each $for loop, to make nesting them easier - comptime comptime.ComptimeInfo + type_resolver type_resolver.TypeResolver + comptime &type_resolver.ResolverInfo = unsafe { nil } prevent_sum_type_unwrapping_once bool // needed for assign new values to sum type // used in match multi branch // TypeOne, TypeTwo {} @@ -355,11 +355,8 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO reflection_strings: &reflection_strings } - global_g.comptime = &comptime.ComptimeInfo{ - resolver: &global_g - table: table - } - + global_g.type_resolver = type_resolver.TypeResolver.new(table, global_g) + global_g.comptime = &global_g.type_resolver.info /* global_g.out_parallel = []strings.Builder{len: nr_cpus} for i in 0 .. nr_cpus { @@ -824,10 +821,8 @@ fn cgen_process_one_file_cb(mut p pool.PoolProcessor, idx int, wid int) &Gen { has_debugger: 'v.debug' in global_g.table.modules reflection_strings: global_g.reflection_strings } - g.comptime = &comptime.ComptimeInfo{ - resolver: g - table: global_g.table - } + g.type_resolver = type_resolver.TypeResolver.new(global_g.table, g) + g.comptime = &g.type_resolver.info g.gen_file() return g } @@ -2723,7 +2718,7 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp_is_ptr if got_styp == 'none' && !g.cur_fn.return_type.has_flag(.option) { g.write('(none){EMPTY_STRUCT_INITIALIZATION}') } else if is_comptime_variant { - g.write(g.type_default(g.comptime.type_map['${g.comptime.comptime_for_variant_var}.typ'])) + g.write(g.type_default(g.type_resolver.type_map['${g.comptime.comptime_for_variant_var}.typ'])) } else { g.expr(expr) } @@ -4299,7 +4294,7 @@ fn (mut g Gen) debugger_stmt(node ast.DebuggerStmt) { if obj is ast.Var && g.check_var_scope(obj, node.pos.pos) { keys.write_string('_SLIT("${obj.name}")') var_typ := if obj.ct_type_var != .no_comptime { - g.comptime.get_type(ast.Ident{ obj: obj }) + g.type_resolver.get_type(ast.Ident{ obj: obj }) } else if obj.smartcasts.len > 0 { obj.smartcasts.last() } else { @@ -4342,7 +4337,7 @@ fn (mut g Gen) debugger_stmt(node ast.DebuggerStmt) { dot := if obj.orig_type.is_ptr() || obj.is_auto_heap { '->' } else { '.' } if obj.ct_type_var == .smartcast { - cur_variant_sym := g.table.sym(g.unwrap_generic(g.comptime.type_map['${g.comptime.comptime_for_variant_var}.typ'])) + cur_variant_sym := g.table.sym(g.unwrap_generic(g.type_resolver.type_map['${g.comptime.comptime_for_variant_var}.typ'])) param_var.write_string('${obj.name}${dot}_${cur_variant_sym.cname}') } else if cast_sym.info is ast.Aggregate { sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx]) @@ -4896,7 +4891,7 @@ fn (mut g Gen) ident(node ast.Ident) { if node.obj is ast.Var { if !g.is_assign_lhs && node.obj.ct_type_var !in [.smartcast, .generic_param, .no_comptime] { - comptime_type := g.comptime.get_type(node) + comptime_type := g.type_resolver.get_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 { @@ -4968,7 +4963,7 @@ fn (mut g Gen) ident(node ast.Ident) { if has_smartcast { obj_sym := g.table.sym(g.unwrap_generic(node.obj.typ)) if node.obj.ct_type_var == .smartcast { - ctyp := g.unwrap_generic(g.comptime.get_type(node)) + ctyp := g.unwrap_generic(g.type_resolver.get_type(node)) cur_variant_sym := g.table.sym(ctyp) variant_name := g.get_sumtype_variant_name(ctyp, cur_variant_sym) g.write('._${variant_name}') @@ -5004,7 +4999,7 @@ fn (mut g Gen) ident(node ast.Ident) { is_option_unwrap := is_option && typ == node.obj.typ.clear_flag(.option) g.write('(') if i == 0 && node.obj.is_unwrapped && node.obj.ct_type_var == .smartcast { - ctyp := g.unwrap_generic(g.comptime.get_type(node)) + ctyp := g.unwrap_generic(g.type_resolver.get_type(node)) g.write('*(${g.base_type(ctyp)}*)(') } if obj_sym.kind == .sum_type && !is_auto_heap { @@ -5060,7 +5055,7 @@ fn (mut g Gen) ident(node ast.Ident) { } } if node.obj.ct_type_var == .smartcast { - mut ctyp := g.unwrap_generic(g.comptime.get_type(node)) + mut ctyp := g.unwrap_generic(g.type_resolver.get_type(node)) cur_variant_sym := g.table.sym(ctyp) if node.obj.is_unwrapped { ctyp = ctyp.set_flag(.option) @@ -5139,14 +5134,14 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) { mut expr_type := node.expr_type sym := g.table.sym(node_typ) if g.comptime.is_comptime_expr(node.expr) { - expr_type = g.unwrap_generic(g.comptime.get_type(node.expr)) + expr_type = g.unwrap_generic(g.type_resolver.get_type(node.expr)) } node_typ_is_option := node.typ.has_flag(.option) if sym.kind in [.sum_type, .interface] { if node_typ_is_option && node.expr is ast.None { g.gen_option_error(node.typ, node.expr) } else if node.expr is ast.Ident && g.comptime.is_comptime_variant_var(node.expr) { - g.expr_with_cast(node.expr, g.comptime.type_map['${g.comptime.comptime_for_variant_var}.typ'], + g.expr_with_cast(node.expr, g.type_resolver.type_map['${g.comptime.comptime_for_variant_var}.typ'], node_typ) } else if node_typ_is_option { g.expr_with_opt(node.expr, expr_type, node.typ) diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index fae9b9a7f72e75..12b84dee799154 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -7,7 +7,7 @@ import os import v.ast import v.util import v.pref -import v.comptime +import v.type_resolver fn (mut g Gen) comptime_selector(node ast.ComptimeSelector) { is_interface_field := g.table.sym(node.left_type).kind == .interface @@ -25,7 +25,7 @@ fn (mut g Gen) comptime_selector(node ast.ComptimeSelector) { if node.field_expr.expr is ast.Ident { if node.field_expr.expr.name == g.comptime.comptime_for_field_var && node.field_expr.field_name == 'name' { - _, field_name := g.comptime.get_comptime_selector_var_type(node) + _, field_name := g.type_resolver.get_comptime_selector_var_type(node) g.write(c_name(field_name)) if is_interface_field { g.write(')') @@ -463,7 +463,7 @@ fn (mut g Gen) comptime_if(node ast.IfExpr) { fn (mut g Gen) get_expr_type(cond ast.Expr) ast.Type { match cond { ast.Ident { - return g.unwrap_generic(g.comptime.get_type_or_default(cond, cond.obj.typ)) + return g.unwrap_generic(g.type_resolver.get_type_or_default(cond, cond.obj.typ)) } ast.TypeNode { return g.unwrap_generic(cond.typ) @@ -477,8 +477,8 @@ fn (mut g Gen) get_expr_type(cond ast.Expr) ast.Type { return ast.int_type } else { name := '${cond.expr}.${cond.field_name}' - if name in g.comptime.type_map { - return g.comptime.type_map[name] + if name in g.type_resolver.type_map { + return g.type_resolver.type_map[name] } else { return g.unwrap_generic(cond.typ) } @@ -540,7 +540,7 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { && cond.right in [ast.ComptimeType, ast.TypeNode] { exp_type := g.get_expr_type(cond.left) if cond.right is ast.ComptimeType { - is_true := g.comptime.is_comptime_type(exp_type, cond.right) + is_true := g.type_resolver.is_comptime_type(exp_type, cond.right) if cond.op == .key_is { if is_true { g.write('1') @@ -672,7 +672,7 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { for expr in cond.right.exprs { if expr is ast.ComptimeType { - if g.comptime.is_comptime_type(checked_type, expr as ast.ComptimeType) { + if g.type_resolver.is_comptime_type(checked_type, expr as ast.ComptimeType) { if cond.op == .key_in { g.write('1') } else { @@ -754,7 +754,7 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { 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.comptime.get_comptime_selector_bool_field(cond.field_name) + ret_bool := g.type_resolver.get_comptime_selector_bool_field(cond.field_name) g.write(ret_bool.str()) return ret_bool, true } else { @@ -772,10 +772,8 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { // 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() + g.type_resolver.info_stack << type_resolver.ResolverInfo{ + saved_type_map: g.type_resolver.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 @@ -791,10 +789,8 @@ fn (mut g Gen) push_new_comptime_info() { // 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() + old := g.type_resolver.info_stack.pop() + g.type_resolver.type_map = old.saved_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 @@ -808,10 +804,10 @@ fn (mut g Gen) pop_comptime_info() { fn (mut g Gen) resolve_comptime_type(node ast.Expr, default_type ast.Type) ast.Type { if g.comptime.is_comptime_expr(node) { - return g.comptime.get_type(node) + return g.type_resolver.get_type(node) } else if node is ast.SelectorExpr && node.expr_type != 0 { if node.expr is ast.Ident && g.comptime.is_comptime_selector_type(node) { - return g.comptime.get_type_from_comptime_var(node.expr) + return g.type_resolver.get_type_from_comptime_var(node.expr) } sym := g.table.sym(g.unwrap_generic(node.expr_type)) if f := g.table.find_field_with_embeds(sym, node.field_name) { @@ -877,7 +873,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { if j < len - 1 { g.write(', ') } - g.comptime.type_map['${node.val_var}.args[${j}].typ'] = typ + g.type_resolver.type_map['${node.val_var}.args[${j}].typ'] = typ } g.writeln('}));\n') } @@ -903,8 +899,8 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.writeln('\t${node.val_var}.typ = ${int(styp)};') g.writeln('\t${node.val_var}.return_type = ${int(ret_typ.idx())};') - g.comptime.type_map['${node.val_var}.return_type'] = ret_typ - g.comptime.type_map['${node.val_var}.typ'] = styp + g.type_resolver.type_map['${node.val_var}.return_type'] = ret_typ + g.type_resolver.type_map['${node.val_var}.typ'] = styp g.stmts(node.stmts) i++ g.writeln('}') @@ -966,8 +962,8 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.writeln('\t${node.val_var}.indirections = ${field.typ.nr_muls()};') - g.comptime.type_map['${node.val_var}.typ'] = field.typ - g.comptime.type_map['${node.val_var}.unaliased_typ'] = unaliased_styp + g.type_resolver.type_map['${node.val_var}.typ'] = field.typ + g.type_resolver.type_map['${node.val_var}.unaliased_typ'] = unaliased_styp g.stmts(node.stmts) i++ g.writeln('}') @@ -983,7 +979,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.push_new_comptime_info() for val in sym.info.vals { g.comptime.comptime_for_enum_var = node.val_var - g.comptime.type_map['${node.val_var}.typ'] = node.typ + g.type_resolver.type_map['${node.val_var}.typ'] = node.typ g.writeln('/* enum vals ${i} */ {') g.writeln('\t${node.val_var}.name = _SLIT("${val}");') @@ -1034,7 +1030,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.push_new_comptime_info() for variant in sym.info.variants { g.comptime.comptime_for_variant_var = node.val_var - g.comptime.type_map['${node.val_var}.typ'] = variant + g.type_resolver.type_map['${node.val_var}.typ'] = variant g.writeln('/* variant ${i} */ {') g.writeln('\t${node.val_var}.typ = ${int(variant)};') @@ -1054,7 +1050,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.comptime.inside_comptime_for = true g.comptime.comptime_for_method_param_var = node.val_var for param in method.params[1..] { - g.comptime.type_map['${node.val_var}.typ'] = param.typ + g.type_resolver.type_map['${node.val_var}.typ'] = param.typ g.writeln('/* method param ${i} */ {') g.writeln('\t${node.val_var}.typ = ${int(param.typ)};') @@ -1077,7 +1073,7 @@ fn (mut g Gen) comptime_selector_type(node ast.SelectorExpr) ast.Type { prevent_sum_type_unwrapping_once := g.prevent_sum_type_unwrapping_once g.prevent_sum_type_unwrapping_once = false - mut typ := g.comptime.get_type(node.expr) + mut typ := g.type_resolver.get_type(node.expr) if node.expr.is_auto_deref_var() { if node.expr is ast.Ident { if node.expr.obj is ast.Var { @@ -1087,7 +1083,7 @@ fn (mut g Gen) comptime_selector_type(node ast.SelectorExpr) ast.Type { } if g.comptime.inside_comptime_for && typ == g.enum_data_type && node.field_name == 'value' { // for comp-time enum.values - return g.comptime.type_map['${g.comptime.comptime_for_enum_var}.typ'] + return g.type_resolver.type_map['${g.comptime.comptime_for_enum_var}.typ'] } field_name := node.field_name sym := g.table.sym(typ) diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index 216ed85dba43df..5546efa7bc4e50 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -38,14 +38,14 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) { if node.expr.field_expr.expr is ast.Ident { if node.expr.field_expr.expr.name == g.comptime.comptime_for_field_var && node.expr.field_expr.field_name == 'name' { - field, _ := g.comptime.get_comptime_selector_var_type(node.expr) + field, _ := g.type_resolver.get_comptime_selector_var_type(node.expr) name = g.styp(g.unwrap_generic(field.typ.clear_flags(.shared_f, .result))) expr_type = field.typ } } } } else if node.expr is ast.Ident && node.expr.ct_expr { - expr_type = g.comptime.get_type(node.expr) + expr_type = g.type_resolver.get_type(node.expr) name = g.styp(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*', '') } else if node.expr is ast.SelectorExpr && node.expr.expr is ast.Ident diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index b1dd98680c3499..f69407a0b4274d 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1304,7 +1304,7 @@ fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool { if left_node is ast.ComptimeSelector { key_str := g.comptime.get_comptime_selector_key_type(left_node) if key_str != '' { - rec_type = g.comptime.type_map[key_str] or { rec_type } + rec_type = g.type_resolver.type_map[key_str] or { rec_type } g.gen_expr_to_string(left_node, rec_type) return true } @@ -1327,7 +1327,7 @@ 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.comptime.get_type(left_node) + rec_type = g.type_resolver.get_type(left_node) g.gen_expr_to_string(left_node, rec_type) return true } else if left_node.obj.smartcasts.len > 0 { @@ -1506,7 +1506,7 @@ fn (mut g Gen) resolve_comptime_args(func &ast.Fn, mut node_ ast.CallExpr, concr 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_var, .generic_param, .no_comptime] { - mut ctyp := g.comptime.get_type(call_arg.expr) + mut ctyp := g.type_resolver.get_type(call_arg.expr) if ctyp != ast.void_type { arg_sym := g.table.sym(ctyp) param_sym := g.table.final_sym(param_typ) @@ -1540,7 +1540,7 @@ fn (mut g Gen) resolve_comptime_args(func &ast.Fn, mut node_ ast.CallExpr, concr comptime_args[k] = ctyp } } else if call_arg.expr.obj.ct_type_var == .generic_param { - mut ctyp := g.comptime.get_type(call_arg.expr) + mut ctyp := g.type_resolver.get_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) @@ -1611,7 +1611,7 @@ fn (mut g Gen) resolve_comptime_args(func &ast.Fn, mut node_ ast.CallExpr, concr } } else if mut call_arg.expr.right is ast.Ident { if g.comptime.get_ct_type_var(call_arg.expr.right) != .generic_var { - mut ctyp := g.comptime.get_type(call_arg.expr.right) + mut ctyp := g.type_resolver.get_type(call_arg.expr.right) if ctyp != ast.void_type { comptime_args[k] = ctyp if param_typ.nr_muls() > 0 && comptime_args[k].nr_muls() > 0 { @@ -1687,7 +1687,7 @@ fn (mut g Gen) unwrap_receiver_type(node ast.CallExpr) (ast.Type, &ast.TypeSymbo mut unwrapped_rec_type := node.receiver_type if g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0 { // in generic fn unwrapped_rec_type = g.unwrap_generic(node.receiver_type) - unwrapped_rec_type = g.comptime.unwrap_generic_expr(node.left, unwrapped_rec_type) + unwrapped_rec_type = g.type_resolver.unwrap_generic_expr(node.left, unwrapped_rec_type) } else { // in non-generic fn sym := g.table.sym(node.receiver_type) match sym.info { @@ -1708,7 +1708,7 @@ fn (mut g Gen) unwrap_receiver_type(node ast.CallExpr) (ast.Type, &ast.TypeSymbo if node.left.obj is ast.Var { if node.left.obj.smartcasts.len > 0 { if node.left.obj.ct_type_var == .smartcast { - unwrapped_rec_type = g.unwrap_generic(g.comptime.get_type(node.left)) + unwrapped_rec_type = g.unwrap_generic(g.type_resolver.get_type(node.left)) } else { unwrapped_rec_type = g.unwrap_generic(node.left.obj.smartcasts.last()) cast_sym := g.table.sym(unwrapped_rec_type) @@ -2246,7 +2246,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { defer { g.inside_interface_deref = false } - mut typ := g.comptime.get_type_or_default(node.args[0].expr, node.args[0].typ) + mut typ := g.type_resolver.get_type_or_default(node.args[0].expr, node.args[0].typ) if typ == 0 { g.checker_bug('print arg.typ is 0', node.pos) } @@ -2276,7 +2276,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { if expr is ast.ComptimeSelector { key_str := g.comptime.get_comptime_selector_key_type(expr) if key_str != '' { - typ = g.comptime.type_map[key_str] or { typ } + typ = g.type_resolver.type_map[key_str] or { typ } } } else if expr is ast.ComptimeCall { if expr.method_name == 'method' { @@ -2294,7 +2294,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { if cast_sym.info is ast.Aggregate { typ = cast_sym.info.types[g.aggregate_type_idx] } else if expr.obj.ct_type_var == .smartcast { - typ = g.unwrap_generic(g.comptime.get_type(expr)) + typ = g.unwrap_generic(g.type_resolver.get_type(expr)) } } // handling println( var or { ... }) @@ -2640,7 +2640,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) { if i < node.expected_arg_types.len && node.expected_arg_types[i].has_flag(.generic) && arg.expr.obj.ct_type_var !in [.generic_param, .no_comptime] { exp_option := node.expected_arg_types[i].has_flag(.option) - expected_types[i] = g.unwrap_generic(g.comptime.get_type(arg.expr)) + expected_types[i] = g.unwrap_generic(g.type_resolver.get_type(arg.expr)) if !exp_option { expected_types[i] = expected_types[i].clear_flag(.option) } @@ -2674,7 +2674,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) { } else if arg.expr is ast.ComptimeSelector && i < node.expected_arg_types.len && node.expected_arg_types[i].has_flag(.generic) { exp_option := node.expected_arg_types[i].has_flag(.option) - expected_types[i] = g.unwrap_generic(g.comptime.get_type(arg.expr)) + expected_types[i] = g.unwrap_generic(g.type_resolver.get_type(arg.expr)) if !exp_option { expected_types[i] = expected_types[i].clear_flag(.option) } @@ -2841,7 +2841,7 @@ fn (mut g Gen) keep_alive_call_postgen(node ast.CallExpr, tmp_cnt_save int) { @[inline] fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang ast.Language, is_smartcast bool) { arg_typ := if arg.expr is ast.ComptimeSelector { - g.unwrap_generic(g.comptime.get_type(arg.expr)) + g.unwrap_generic(g.type_resolver.get_type(arg.expr)) } else { g.unwrap_generic(arg.typ) } diff --git a/vlib/v/gen/c/for.v b/vlib/v/gen/c/for.v index 545451367e868c..e1be2ab6ae0797 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 && node.cond.ct_expr) || node.cond is ast.ComptimeSelector { mut unwrapped_typ := g.unwrap_generic(node.cond_type) - ctyp := g.comptime.get_type(node.cond) + ctyp := g.type_resolver.get_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.type_map[node.val_var] = node.val_type + g.type_resolver.type_map[node.val_var] = node.val_type node.scope.update_ct_var_kind(node.val_var, .value_var) defer { - g.comptime.type_map.delete(node.val_var) + g.type_resolver.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.type_map[node.key_var] = node.key_type + g.type_resolver.type_map[node.key_var] = node.key_type node.scope.update_ct_var_kind(node.key_var, .key_var) defer { - g.comptime.type_map.delete(node.key_var) + g.type_resolver.type_map.delete(node.key_var) } } } @@ -223,7 +223,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { if is_comptime && g.comptime.is_comptime(node.cond) { mut unwrapped_typ := g.unwrap_generic(node.cond_type) - ctyp := g.unwrap_generic(g.comptime.get_type(node.cond)) + ctyp := g.unwrap_generic(g.type_resolver.get_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 9f1888f1e54fda..96fadb5e254ced 100644 --- a/vlib/v/gen/c/infix.v +++ b/vlib/v/gen/c/infix.v @@ -96,8 +96,8 @@ 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 := g.comptime.get_expr_type_or_default(node.left, node.left_type) - right_type := g.comptime.get_expr_type_or_default(node.right, node.right_type) + left_type := g.type_resolver.get_expr_type_or_default(node.left, node.left_type) + right_type := g.type_resolver.get_expr_type_or_default(node.right, node.right_type) left := g.unwrap(left_type) right := g.unwrap(right_type) mut has_defined_eq_operator := false @@ -834,7 +834,7 @@ fn (mut g Gen) infix_expr_in_optimization(left ast.Expr, left_type ast.Type, rig // infix_expr_is_op generates code for `is` and `!is` fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) { - mut left_sym := g.table.sym(g.unwrap_generic(g.comptime.get_type_or_default(node.left, + mut left_sym := g.table.sym(g.unwrap_generic(g.type_resolver.get_type_or_default(node.left, node.left_type))) is_aggregate := left_sym.kind == .aggregate if is_aggregate { @@ -886,7 +886,7 @@ fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) { if node.right is ast.None { g.write('${ast.none_type.idx()}') } else if node.right is ast.Ident && node.right.name == g.comptime.comptime_for_variant_var { - variant_idx := g.comptime.type_map['${g.comptime.comptime_for_variant_var}.typ'] or { + variant_idx := g.type_resolver.type_map['${g.comptime.comptime_for_variant_var}.typ'] or { ast.void_type } g.write('${int(variant_idx)}') @@ -925,8 +925,8 @@ fn (mut g Gen) gen_interface_is_op(node ast.InfixExpr) { // infix_expr_arithmetic_op generates code for `+`, `-`, `*`, `/`, and `%` // It handles operator overloading when necessary fn (mut g Gen) infix_expr_arithmetic_op(node ast.InfixExpr) { - left := g.unwrap(g.comptime.get_type_or_default(node.left, node.left_type)) - right := g.unwrap(g.comptime.get_type_or_default(node.right, node.right_type)) + left := g.unwrap(g.type_resolver.get_type_or_default(node.left, node.left_type)) + right := g.unwrap(g.type_resolver.get_type_or_default(node.right, node.right_type)) if left.sym.info is ast.Struct && left.sym.info.generic_types.len > 0 { mut method_name := left.sym.cname + '_' + util.replace_op(node.op.str()) method_name = g.generic_fn_name(left.sym.info.concrete_types, method_name) @@ -1189,7 +1189,7 @@ fn (mut g Gen) gen_plain_infix_expr(node ast.InfixExpr) { || g.file.is_translated) if needs_cast { typ_str := if g.comptime.is_comptime(node.left) { - g.styp(g.comptime.get_type_or_default(node.left, node.promoted_type)) + g.styp(g.type_resolver.get_type_or_default(node.left, node.promoted_type)) } else { g.styp(node.promoted_type) } diff --git a/vlib/v/gen/c/str_intp.v b/vlib/v/gen/c/str_intp.v index 52d9149ac493cd..d21e04c2c787a2 100644 --- a/vlib/v/gen/c/str_intp.v +++ b/vlib/v/gen/c/str_intp.v @@ -187,7 +187,7 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int, fmts []u8) { mut exp_typ := typ if expr is ast.Ident { if g.comptime.get_ct_type_var(expr) == .smartcast { - exp_typ = g.comptime.get_type(expr) + exp_typ = g.type_resolver.get_type(expr) } else if expr.obj is ast.Var { if expr.obj.smartcasts.len > 0 { exp_typ = g.unwrap_generic(expr.obj.smartcasts.last()) @@ -241,7 +241,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { mut fmts := node_.fmts.clone() for i, mut expr in node_.exprs { if g.comptime.is_comptime(expr) { - ctyp := g.comptime.get_type_or_default(expr, node_.expr_types[i]) + ctyp := g.type_resolver.get_type_or_default(expr, node_.expr_types[i]) if ctyp != ast.void_type { node_.expr_types[i] = ctyp if node_.fmts[i] == `_` { diff --git a/vlib/v/type_resolver/comptime_resolver.v b/vlib/v/type_resolver/comptime_resolver.v new file mode 100644 index 00000000000000..2e6514c5fedf57 --- /dev/null +++ b/vlib/v/type_resolver/comptime_resolver.v @@ -0,0 +1,270 @@ +// Copyright (c) 2019-2024 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 type_resolver + +import v.ast + +@[inline] +pub fn (_ &ResolverInfo) 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_expr checks if the node is related to a comptime expr +@[inline] +pub fn (ct &ResolverInfo) is_comptime_expr(node ast.Expr) bool { + return (node is ast.Ident && node.ct_expr) + || (node is ast.IndexExpr && ct.is_comptime_expr(node.left)) + || node is ast.ComptimeSelector +} + +// has_comptime_expr checks if the expr contains some comptime expr +@[inline] +pub fn (mut ct ResolverInfo) has_comptime_expr(node ast.Expr) bool { + return (node is ast.Ident && node.ct_expr) + || (node is ast.IndexExpr && ct.has_comptime_expr(node.left)) + || node is ast.ComptimeSelector + || (node is ast.SelectorExpr && ct.has_comptime_expr(node.expr)) + || (node is ast.InfixExpr && (ct.has_comptime_expr(node.left) + || ct.has_comptime_expr(node.right))) +} + +// is_comptime checks if the node is related to a comptime marked variable +@[inline] +pub fn (mut ct ResolverInfo) is_comptime(node ast.Expr) bool { + return match node { + ast.Ident { + node.ct_expr + } + ast.IndexExpr { + if node.left is ast.Ident { + node.left.ct_expr + } else { + false + } + } + ast.SelectorExpr { + return node.expr is ast.Ident && node.expr.ct_expr + } + ast.InfixExpr { + return ct.is_comptime(node.left) || ct.is_comptime(node.right) + } + ast.ParExpr { + return ct.is_comptime(node.expr) + } + else { + false + } + } +} + +// is_comptime_variant_var checks if the node is related to a comptime variant variable +@[inline] +pub fn (mut ct ResolverInfo) is_comptime_variant_var(node ast.Ident) bool { + return node.name == ct.comptime_for_variant_var +} + +// get_ct_type_var gets the comptime type of the variable (.generic_param, .key_var, etc) +@[inline] +pub fn (mut ct ResolverInfo) get_ct_type_var(node ast.Expr) ast.ComptimeVarKind { + if node is ast.Ident { + if node.obj is ast.Var { + return node.obj.ct_type_var + } + } else if node is ast.IndexExpr { + return ct.get_ct_type_var(node.left) + } + return .no_comptime +} + +// get_expr_type_or_default computes the ast node type regarding its or_expr if its comptime var otherwise default_typ is returned +pub fn (mut ct TypeResolver) get_expr_type_or_default(node ast.Expr, default_typ ast.Type) ast.Type { + if !ct.info.is_comptime_expr(node) { + return default_typ + } + ctyp := ct.get_type(node) + match node { + ast.Ident { + // returns the unwrapped type of the var + if ctyp.has_flag(.option) && node.or_expr.kind != .absent { + return ctyp.clear_flag(.option) + } + } + else {} + } + return if ctyp != ast.void_type { ctyp } else { default_typ } +} + +// get_type_from_comptime_var retrives the comptime type related to $for variable +@[inline] +pub fn (mut ct TypeResolver) get_type_from_comptime_var(var ast.Ident) ast.Type { + return match var.name { + ct.info.comptime_for_variant_var { + ct.type_map['${ct.info.comptime_for_variant_var}.typ'] + } + ct.info.comptime_for_method_param_var { + ct.type_map['${ct.info.comptime_for_method_param_var}.typ'] + } + else { + // field_var.typ from $for field + ct.info.comptime_for_field_type + } + } +} + +// 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 TypeResolver) get_comptime_selector_type(node ast.ComptimeSelector, default_type ast.Type) ast.Type { + if node.field_expr is ast.SelectorExpr + && ct.info.check_comptime_is_field_selector(node.field_expr) + && node.field_expr.field_name == 'name' { + return ct.resolver.unwrap_generic(ct.info.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 ResolverInfo) 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 ResolverInfo) 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, ct.comptime_for_method_param_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 ResolverInfo) 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 ResolverInfo) 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 TypeResolver) get_comptime_selector_bool_field(field_name string) bool { + field := ct.info.comptime_for_field_value + field_typ := ct.info.comptime_for_field_type + field_sym := ct.table.sym(ct.resolver.unwrap_generic(ct.info.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 TypeResolver) 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 + } + .string { + return x_kind == .string + } + .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, .args etc) +fn (mut ct ResolverInfo) 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 + } + ct.comptime_for_method_param_var { + return .params + } + else { + return none + } + } +} diff --git a/vlib/v/type_resolver/generic_resolver.v b/vlib/v/type_resolver/generic_resolver.v new file mode 100644 index 00000000000000..9240428115a7ec --- /dev/null +++ b/vlib/v/type_resolver/generic_resolver.v @@ -0,0 +1,36 @@ +module type_resolver + +import v.ast + +pub fn (mut ct TypeResolver) unwrap_generic_expr(expr ast.Expr, default_typ ast.Type) ast.Type { + match expr { + ast.StringLiteral, ast.StringInterLiteral { + return ast.string_type + } + ast.ParExpr { + return ct.unwrap_generic_expr(expr.expr, default_typ) + } + ast.CastExpr { + return expr.typ + } + ast.InfixExpr { + if ct.info.is_comptime(expr.left) { + return ct.resolver.unwrap_generic(ct.get_type(expr.left)) + } + if ct.info.is_comptime(expr.right) { + return ct.resolver.unwrap_generic(ct.get_type(expr.right)) + } + return default_typ + } + ast.Ident { + return if expr.ct_expr { + ct.resolver.unwrap_generic(ct.get_type(expr)) + } else { + default_typ + } + } + else { + return default_typ + } + } +} diff --git a/vlib/v/type_resolver/type_resolver.v b/vlib/v/type_resolver/type_resolver.v new file mode 100644 index 00000000000000..9b77248b6e1879 --- /dev/null +++ b/vlib/v/type_resolver/type_resolver.v @@ -0,0 +1,221 @@ +module type_resolver + +import ast +import v.token +import v.util + +pub struct ResolverInfo { +pub mut: + saved_type_map map[string]ast.Type + + // loop id for loop distinction + comptime_loop_id int + // $for + inside_comptime_for bool + // .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 &ast.Fn = unsafe { nil } + comptime_for_method_ret_type ast.Type + // .args + comptime_for_method_param_var string +} + +pub interface IResolverType { +mut: + file &ast.File + unwrap_generic(t ast.Type) ast.Type + // resolve_return_type(node ast.CallExpr) ast.Type +} + +pub struct DummyResolver { +mut: + file &ast.File = unsafe { nil } +} + +fn (d DummyResolver) unwrap_generic(t ast.Type) ast.Type { + return t +} + +fn (d DummyResolver) resolve_return_type(node ast.CallExpr) ast.Type { + return ast.void_type +} + +@[heap] +pub struct TypeResolver { +pub mut: + resolver IResolverType = DummyResolver{} + table &ast.Table = unsafe { nil } + info ResolverInfo // infoent info + info_stack []ResolverInfo // stores the values from the above on each $for loop, to make nesting them easier + type_map map[string]ast.Type +} + +pub fn TypeResolver.new(table &ast.Table, resolver &IResolverType) &TypeResolver { + return &TypeResolver{ + table: table + resolver: resolver + } +} + +@[noreturn] +fn (mut ct TypeResolver) error(s string, pos token.Pos) { + util.show_compiler_message('cgen error:', pos: pos, file_path: ct.resolver.file.path, message: s) + exit(1) +} + +pub fn (mut ct TypeResolver) get_comptime_selector_var_type(node ast.ComptimeSelector) (ast.StructField, string) { + field_name := ct.info.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_type_or_default retries the comptime value if the AST node is related to comptime otherwise default_typ is returned +@[inline] +pub fn (mut ct TypeResolver) get_type_or_default(node ast.Expr, default_typ ast.Type) ast.Type { + match node { + ast.Ident { + if node.ct_expr { + ctyp := ct.get_type(node) + return if ctyp != ast.void_type { ctyp } else { default_typ } + } + } + ast.SelectorExpr { + if node.expr is ast.Ident && node.expr.ct_expr { + struct_typ := ct.resolver.unwrap_generic(ct.get_type(node.expr)) + struct_sym := ct.table.final_sym(struct_typ) + // Struct[T] can have field with generic type + if struct_sym.info is ast.Struct && struct_sym.info.generic_types.len > 0 { + if field := ct.table.find_field(struct_sym, node.field_name) { + return field.typ + } + } + } + } + ast.ParExpr { + return ct.get_type_or_default(node.expr, default_typ) + } + ast.InfixExpr { + if node.op in [.plus, .minus, .mul, .div, .mod] { + return ct.get_type_or_default(node.left, default_typ) + } + } + else { + return default_typ + } + } + return default_typ +} + +// get_type retrieves the actual type from a comptime related ast node +@[inline] +pub fn (mut ct TypeResolver) get_type(node ast.Expr) ast.Type { + if node is ast.Ident { + if node.obj is ast.Var { + return match node.obj.ct_type_var { + .generic_param { + // generic parameter from infoent function + node.obj.typ + } + .generic_var { + // generic var used on fn call assignment + if node.obj.smartcasts.len > 0 { + node.obj.smartcasts.last() + } else { + ct.type_map['g.${node.name}.${node.obj.pos.pos}'] or { node.obj.typ } + } + } + .smartcast { + ctyp := ct.type_map['${ct.info.comptime_for_variant_var}.typ'] or { + node.obj.typ + } + return if (node.obj as ast.Var).is_unwrapped { + ctyp.clear_flag(.option) + } else { + ctyp + } + } + .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.info.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.info.is_comptime_selector_type(node) { + return ct.get_type_from_comptime_var(node.expr as ast.Ident) + } else if node is ast.ComptimeCall { + method_name := ct.info.comptime_for_method.name + 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 + } else if node is ast.IndexExpr && ct.info.is_comptime(node.left) { + nltype := ct.get_type(node.left) + nltype_unwrapped := ct.resolver.unwrap_generic(nltype) + return ct.table.value_type(nltype_unwrapped) + } + return ast.void_type +} + +@[inline] +pub fn (mut g TypeResolver) is_generic_param_var(node ast.Expr) bool { + return node is ast.Ident && node.info is ast.IdentVar && node.obj is ast.Var + && (node.obj as ast.Var).ct_type_var == .generic_param +} + +// is_generic_expr checks if the expr relies on fn generic argument +pub fn (mut g TypeResolver) is_generic_expr(node ast.Expr) bool { + return match node { + ast.Ident { + // variable declared as generic type + g.is_generic_param_var(node) + } + ast.IndexExpr { + // generic_var[N] + g.is_generic_param_var(node.left) + } + ast.CallExpr { + // fn which has any generic dependent expr + if node.args.any(g.is_generic_param_var(it.expr)) { + return true + } + if node.is_static_method && node.left_type.has_flag(.generic) { + return true + } + // fn[T]() or generic_var.fn[T]() + node.concrete_types.any(it.has_flag(.generic)) + } + ast.SelectorExpr { + // generic_var.property + g.is_generic_param_var(node.expr) + } + else { + false + } + } +}