mirror of
https://github.com/vlang/v.git
synced 2025-09-24 04:48:28 -04:00
This commit is contained in:
parent
9ba294bc73
commit
6ab25623e3
@ -861,6 +861,7 @@ pub mut:
|
|||||||
pos token.Pos
|
pos token.Pos
|
||||||
should_be_ptr bool // fn expects a ptr for this arg
|
should_be_ptr bool // fn expects a ptr for this arg
|
||||||
// tmp_name string // for autofree
|
// tmp_name string // for autofree
|
||||||
|
ct_expr bool // true, when the expression is a comptime/generic expression
|
||||||
}
|
}
|
||||||
|
|
||||||
// function return statement
|
// function return statement
|
||||||
|
@ -412,51 +412,9 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if right is ast.ComptimeSelector {
|
// flag the variable as comptime/generic related on its declaration
|
||||||
if is_decl {
|
if is_decl {
|
||||||
left.obj.ct_type_var = .field_var
|
c.change_flags_if_comptime_expr(mut left, right)
|
||||||
left.obj.typ = c.comptime.comptime_for_field_type
|
|
||||||
}
|
|
||||||
} else if mut right is ast.InfixExpr {
|
|
||||||
right_ct_var := c.comptime.get_ct_type_var(right.left)
|
|
||||||
if right_ct_var != .no_comptime {
|
|
||||||
left.obj.ct_type_var = right_ct_var
|
|
||||||
}
|
|
||||||
} else if mut right is ast.IndexExpr
|
|
||||||
&& c.comptime.is_comptime(right) {
|
|
||||||
right_ct_var := c.comptime.get_ct_type_var(right.left)
|
|
||||||
if right_ct_var != .no_comptime {
|
|
||||||
left.obj.ct_type_var = right_ct_var
|
|
||||||
}
|
|
||||||
} else if mut right is ast.Ident && right.obj is ast.Var
|
|
||||||
&& right.or_expr.kind == .absent {
|
|
||||||
right_obj_var := right.obj as ast.Var
|
|
||||||
if right_obj_var.ct_type_var != .no_comptime {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if right is ast.DumpExpr
|
|
||||||
&& right.expr is ast.ComptimeSelector {
|
|
||||||
left.obj.ct_type_var = .field_var
|
|
||||||
left.obj.typ = c.comptime.comptime_for_field_type
|
|
||||||
} else if mut right is ast.CallExpr {
|
|
||||||
if right.left_type != 0
|
|
||||||
&& c.table.type_kind(right.left_type) == .array
|
|
||||||
&& right.name == 'map' && right.args.len > 0
|
|
||||||
&& right.args[0].expr is ast.AsCast
|
|
||||||
&& right.args[0].expr.typ.has_flag(.generic) {
|
|
||||||
left.obj.ct_type_var = .generic_var
|
|
||||||
} else 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.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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.GlobalField {
|
ast.GlobalField {
|
||||||
@ -962,3 +920,46 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
|
|||||||
c.error('assign statement left type number mismatch', node.pos)
|
c.error('assign statement left type number mismatch', node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// change_flags_if_comptime_expr changes the flags of the left variable if the right expression is comptime/generic expr
|
||||||
|
fn (mut c Checker) change_flags_if_comptime_expr(mut left ast.Ident, right ast.Expr) {
|
||||||
|
if mut left.obj is ast.Var {
|
||||||
|
if right is ast.ComptimeSelector {
|
||||||
|
left.obj.ct_type_var = .field_var
|
||||||
|
left.obj.typ = c.comptime.comptime_for_field_type
|
||||||
|
} else if right is ast.InfixExpr {
|
||||||
|
right_ct_var := c.comptime.get_ct_type_var(right.left)
|
||||||
|
if right_ct_var != .no_comptime {
|
||||||
|
left.obj.ct_type_var = right_ct_var
|
||||||
|
}
|
||||||
|
} else if right is ast.IndexExpr && c.comptime.is_comptime(right) {
|
||||||
|
right_ct_var := c.comptime.get_ct_type_var(right.left)
|
||||||
|
if right_ct_var != .no_comptime {
|
||||||
|
left.obj.ct_type_var = right_ct_var
|
||||||
|
}
|
||||||
|
} else if right is ast.Ident && right.obj is ast.Var && right.or_expr.kind == .absent {
|
||||||
|
right_obj_var := right.obj as ast.Var
|
||||||
|
if right_obj_var.ct_type_var != .no_comptime {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if right is ast.DumpExpr && right.expr is ast.ComptimeSelector {
|
||||||
|
left.obj.ct_type_var = .field_var
|
||||||
|
left.obj.typ = c.comptime.comptime_for_field_type
|
||||||
|
} else if right is ast.CallExpr {
|
||||||
|
if right.left_type != 0 && c.table.type_kind(right.left_type) == .array
|
||||||
|
&& right.name == 'map' && right.args.len > 0 && right.args[0].expr is ast.AsCast
|
||||||
|
&& right.args[0].expr.typ.has_flag(.generic) {
|
||||||
|
left.obj.ct_type_var = .generic_var
|
||||||
|
} else 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.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1421,6 +1421,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
|||||||
}
|
}
|
||||||
// println / eprintln / panic can print anything
|
// println / eprintln / panic can print anything
|
||||||
if node.args.len > 0 && fn_name in print_everything_fns {
|
if node.args.len > 0 && fn_name in print_everything_fns {
|
||||||
|
node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr)
|
||||||
c.builtin_args(mut node, fn_name, func)
|
c.builtin_args(mut node, fn_name, func)
|
||||||
if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'math.bits'
|
if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'math.bits'
|
||||||
&& node.args[0].expr !is ast.StringLiteral {
|
&& node.args[0].expr !is ast.StringLiteral {
|
||||||
@ -1442,6 +1443,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
|||||||
if node.args.len == 1 && fn_name == 'error' {
|
if node.args.len == 1 && fn_name == 'error' {
|
||||||
mut arg := node.args[0]
|
mut arg := node.args[0]
|
||||||
node.args[0].typ = c.expr(mut arg.expr)
|
node.args[0].typ = c.expr(mut arg.expr)
|
||||||
|
node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr)
|
||||||
if node.args[0].typ == ast.error_type {
|
if node.args[0].typ == ast.error_type {
|
||||||
c.warn('`error(${arg})` can be shortened to just `${arg}`', node.pos)
|
c.warn('`error(${arg})` can be shortened to just `${arg}`', node.pos)
|
||||||
}
|
}
|
||||||
@ -1456,6 +1458,9 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
|||||||
if func.params.len == 0 {
|
if func.params.len == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if !c.inside_recheck {
|
||||||
|
call_arg.ct_expr = c.comptime.is_comptime(call_arg.expr)
|
||||||
|
}
|
||||||
if !func.is_variadic && has_decompose {
|
if !func.is_variadic && has_decompose {
|
||||||
c.error('cannot have parameter after array decompose', node.pos)
|
c.error('cannot have parameter after array decompose', node.pos)
|
||||||
}
|
}
|
||||||
@ -2383,6 +2388,9 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||||||
} else {
|
} else {
|
||||||
method.params[i + 1].typ
|
method.params[i + 1].typ
|
||||||
}
|
}
|
||||||
|
if !c.inside_recheck {
|
||||||
|
arg.ct_expr = c.comptime.is_comptime(arg.expr)
|
||||||
|
}
|
||||||
// If initialize a generic struct with short syntax,
|
// If initialize a generic struct with short syntax,
|
||||||
// need to get the parameter information from the original generic method
|
// need to get the parameter information from the original generic method
|
||||||
if is_method_from_embed && arg.expr is ast.StructInit {
|
if is_method_from_embed && arg.expr is ast.StructInit {
|
||||||
|
@ -481,8 +481,22 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return_type := if g.type_resolver.is_generic_expr(node.args[0].expr) {
|
return_type := if g.type_resolver.is_generic_expr(node.args[0].expr) {
|
||||||
ast.new_type(g.table.find_or_register_array(g.type_resolver.unwrap_generic_expr(node.args[0].expr,
|
mut ctyp := ast.void_type
|
||||||
node.return_type)))
|
if node.args[0].expr is ast.CallExpr && node.args[0].expr.return_type_generic != 0
|
||||||
|
&& node.args[0].expr.return_type_generic.has_flag(.generic) {
|
||||||
|
ctyp = g.resolve_return_type(node.args[0].expr)
|
||||||
|
if g.table.type_kind(node.args[0].expr.return_type_generic) in [.array, .array_fixed] {
|
||||||
|
ctyp = ast.new_type(g.table.find_or_register_array(ctyp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ctyp == ast.void_type {
|
||||||
|
ctyp = g.type_resolver.unwrap_generic_expr(node.args[0].expr, node.return_type)
|
||||||
|
}
|
||||||
|
if g.table.type_kind(g.unwrap_generic(ctyp)) !in [.array, .array_fixed] {
|
||||||
|
ast.new_type(g.table.find_or_register_array(ctyp))
|
||||||
|
} else {
|
||||||
|
ctyp
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
node.return_type
|
node.return_type
|
||||||
}
|
}
|
||||||
@ -498,7 +512,6 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||||||
(ret_sym.info as ast.ArrayFixed).elem_type
|
(ret_sym.info as ast.ArrayFixed).elem_type
|
||||||
}
|
}
|
||||||
mut ret_elem_styp := g.styp(ret_elem_type)
|
mut ret_elem_styp := g.styp(ret_elem_type)
|
||||||
|
|
||||||
inp_elem_type := if left_is_array {
|
inp_elem_type := if left_is_array {
|
||||||
(inp_sym.info as ast.Array).elem_type
|
(inp_sym.info as ast.Array).elem_type
|
||||||
} else {
|
} else {
|
||||||
|
@ -294,6 +294,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mut left.obj is ast.Var {
|
if mut left.obj is ast.Var {
|
||||||
|
if is_decl {
|
||||||
if val is ast.Ident && val.ct_expr {
|
if val is ast.Ident && val.ct_expr {
|
||||||
ctyp := g.unwrap_generic(g.type_resolver.get_type(val))
|
ctyp := g.unwrap_generic(g.type_resolver.get_type(val))
|
||||||
if ctyp != ast.void_type {
|
if ctyp != ast.void_type {
|
||||||
@ -324,7 +325,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
|||||||
var_type = g.type_resolver.get_ct_type_or_default(key_str, var_type)
|
var_type = g.type_resolver.get_ct_type_or_default(key_str, var_type)
|
||||||
left.obj.typ = var_type
|
left.obj.typ = var_type
|
||||||
g.assign_ct_type = var_type
|
g.assign_ct_type = var_type
|
||||||
} else if is_decl && val is ast.Ident && val.info is ast.IdentVar {
|
} else if val is ast.Ident && val.info is ast.IdentVar {
|
||||||
val_info := (val as ast.Ident).info
|
val_info := (val as ast.Ident).info
|
||||||
gen_or = val.or_expr.kind != .absent
|
gen_or = val.or_expr.kind != .absent
|
||||||
if val_info.is_option && gen_or {
|
if val_info.is_option && gen_or {
|
||||||
@ -350,7 +351,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
|||||||
g.assign_ct_type = var_type
|
g.assign_ct_type = var_type
|
||||||
}
|
}
|
||||||
} else if left.obj.ct_type_var == .generic_var && val is ast.CallExpr {
|
} else if left.obj.ct_type_var == .generic_var && val is ast.CallExpr {
|
||||||
if val.return_type_generic != 0 && val.return_type_generic.has_flag(.generic) {
|
if val.return_type_generic != 0
|
||||||
|
&& val.return_type_generic.has_flag(.generic) {
|
||||||
fn_ret_type := g.resolve_return_type(val)
|
fn_ret_type := g.resolve_return_type(val)
|
||||||
if fn_ret_type != ast.void_type {
|
if fn_ret_type != ast.void_type {
|
||||||
var_type = fn_ret_type
|
var_type = fn_ret_type
|
||||||
@ -364,7 +366,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
|||||||
left.obj.typ = var_type
|
left.obj.typ = var_type
|
||||||
g.assign_ct_type = var_type
|
g.assign_ct_type = var_type
|
||||||
} else if val.left_type != 0 && g.table.type_kind(val.left_type) == .array
|
} else if val.left_type != 0 && g.table.type_kind(val.left_type) == .array
|
||||||
&& val.name == 'map' && val.args.len > 0 && val.args[0].expr is ast.AsCast
|
&& val.name == 'map' && val.args.len > 0
|
||||||
|
&& val.args[0].expr is ast.AsCast
|
||||||
&& val.args[0].expr.typ.has_flag(.generic) {
|
&& val.args[0].expr.typ.has_flag(.generic) {
|
||||||
var_type = g.table.find_or_register_array(g.unwrap_generic((val.args[0].expr as ast.AsCast).typ))
|
var_type = g.table.find_or_register_array(g.unwrap_generic((val.args[0].expr as ast.AsCast).typ))
|
||||||
val_type = var_type
|
val_type = var_type
|
||||||
@ -385,6 +388,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
|||||||
g.assign_ct_type = var_type
|
g.assign_ct_type = var_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
is_auto_heap = left.obj.is_auto_heap
|
is_auto_heap = left.obj.is_auto_heap
|
||||||
}
|
}
|
||||||
} else if mut left is ast.ComptimeSelector {
|
} else if mut left is ast.ComptimeSelector {
|
||||||
|
@ -2028,8 +2028,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||||||
// Handle `print(x)`
|
// Handle `print(x)`
|
||||||
mut print_auto_str := false
|
mut print_auto_str := false
|
||||||
if is_print && (node.args[0].typ != ast.string_type
|
if is_print && (node.args[0].typ != ast.string_type
|
||||||
|| g.comptime.comptime_for_method != unsafe { nil }
|
|| g.comptime.comptime_for_method != unsafe { nil } || node.args[0].ct_expr) {
|
||||||
|| g.comptime.is_comptime(node.args[0].expr)) {
|
|
||||||
g.inside_interface_deref = true
|
g.inside_interface_deref = true
|
||||||
defer {
|
defer {
|
||||||
g.inside_interface_deref = false
|
g.inside_interface_deref = false
|
||||||
@ -2577,7 +2576,7 @@ fn (mut g Gen) keep_alive_call_postgen(node ast.CallExpr, tmp_cnt_save int) {
|
|||||||
|
|
||||||
@[inline]
|
@[inline]
|
||||||
fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang ast.Language, is_smartcast bool) {
|
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 {
|
arg_typ := if arg.ct_expr {
|
||||||
g.unwrap_generic(g.type_resolver.get_type(arg.expr))
|
g.unwrap_generic(g.type_resolver.get_type(arg.expr))
|
||||||
} else {
|
} else {
|
||||||
g.unwrap_generic(arg.typ)
|
g.unwrap_generic(arg.typ)
|
||||||
|
38
vlib/v/tests/comptime_generic_comptime_variant_test.v
Normal file
38
vlib/v/tests/comptime_generic_comptime_variant_test.v
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
pub type DesiredCapabilities = FireFox | Edge
|
||||||
|
|
||||||
|
struct FireFox {
|
||||||
|
browser_name string = 'firefox'
|
||||||
|
accept_insecure_certs bool = true
|
||||||
|
moz_debugger_address bool = true
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Edge {
|
||||||
|
browser_name string = 'MicrosoftEdge'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_values[T](s T) map[string]string {
|
||||||
|
mut res := map[string]string{}
|
||||||
|
$if T is $struct {
|
||||||
|
$for field in T.fields {
|
||||||
|
res[field.name] = s.$(field.name).str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn useit(dc DesiredCapabilities) string {
|
||||||
|
$for v in dc.variants {
|
||||||
|
if dc is v {
|
||||||
|
$if v is $struct {
|
||||||
|
result := struct_values(dc)
|
||||||
|
return result.str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
assert useit(Edge{}) == "{'browser_name': 'MicrosoftEdge'}"
|
||||||
|
assert useit(FireFox{}) == "{'browser_name': 'firefox', 'accept_insecure_certs': 'true', 'moz_debugger_address': 'true'}"
|
||||||
|
}
|
18
vlib/v/tests/generics/generic_var_loop_test.v
Normal file
18
vlib/v/tests/generics/generic_var_loop_test.v
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
fn t[T](a1 []int, a2 []int) T {
|
||||||
|
mut a := 0 * a1[0] - a2[0]
|
||||||
|
a = math.max(a, 10)
|
||||||
|
mut t := T{}
|
||||||
|
for i in a .. 20 {
|
||||||
|
t += i
|
||||||
|
for j in a .. 20 {
|
||||||
|
t += j
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
assert t[int]([1, 2, 3], [4, 5, 6]) == 1595
|
||||||
|
}
|
@ -47,7 +47,7 @@ pub fn (t &ResolverInfo) is_comptime(node ast.Expr) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
return node.expr is ast.Ident && node.expr.ct_expr
|
return node.expr is ast.Ident && node.expr.ct_expr && node.field_name != 'len'
|
||||||
}
|
}
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
return node.left_ct_expr || node.right_ct_expr
|
return node.left_ct_expr || node.right_ct_expr
|
||||||
@ -55,6 +55,9 @@ pub fn (t &ResolverInfo) is_comptime(node ast.Expr) bool {
|
|||||||
ast.ParExpr {
|
ast.ParExpr {
|
||||||
return t.is_comptime(node.expr)
|
return t.is_comptime(node.expr)
|
||||||
}
|
}
|
||||||
|
ast.ComptimeSelector {
|
||||||
|
return true
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,9 @@ pub fn (t &TypeResolver) is_generic_expr(node ast.Expr) bool {
|
|||||||
if node.is_static_method && node.left_type.has_flag(.generic) {
|
if node.is_static_method && node.left_type.has_flag(.generic) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if node.return_type_generic != 0 && node.return_type_generic.has_flag(.generic) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
// fn[T]() or generic_var.fn[T]()
|
// fn[T]() or generic_var.fn[T]()
|
||||||
node.concrete_types.any(it.has_flag(.generic))
|
node.concrete_types.any(it.has_flag(.generic))
|
||||||
}
|
}
|
||||||
@ -119,6 +122,7 @@ pub fn (mut t TypeResolver) resolve_args(cur_fn &ast.FnDecl, func &ast.Fn, mut n
|
|||||||
mut comptime_args := map[int]ast.Type{}
|
mut comptime_args := map[int]ast.Type{}
|
||||||
has_dynamic_vars := (cur_fn != unsafe { nil } && cur_fn.generic_names.len > 0)
|
has_dynamic_vars := (cur_fn != unsafe { nil } && cur_fn.generic_names.len > 0)
|
||||||
|| t.info.comptime_for_field_var != ''
|
|| t.info.comptime_for_field_var != ''
|
||||||
|
|| func.generic_names.len != node_.raw_concrete_types.len
|
||||||
if !has_dynamic_vars {
|
if !has_dynamic_vars {
|
||||||
return comptime_args
|
return comptime_args
|
||||||
}
|
}
|
||||||
|
@ -101,15 +101,10 @@ pub fn (mut t TypeResolver) get_type_or_default(node ast.Expr, default_typ ast.T
|
|||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
if node.expr is ast.Ident && node.expr.ct_expr {
|
if node.expr is ast.Ident && node.expr.ct_expr {
|
||||||
struct_typ := t.resolver.unwrap_generic(t.get_type(node.expr))
|
ctyp := t.get_type(node)
|
||||||
struct_sym := t.table.final_sym(struct_typ)
|
return if ctyp != ast.void_type { ctyp } else { default_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 := t.table.find_field(struct_sym, node.field_name) {
|
|
||||||
return field.typ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return default_typ
|
||||||
}
|
}
|
||||||
ast.ParExpr {
|
ast.ParExpr {
|
||||||
return t.get_type_or_default(node.expr, default_typ)
|
return t.get_type_or_default(node.expr, default_typ)
|
||||||
@ -189,8 +184,21 @@ pub fn (mut t TypeResolver) get_type(node ast.Expr) ast.Type {
|
|||||||
} else if node is ast.ComptimeSelector {
|
} else if node is ast.ComptimeSelector {
|
||||||
// val.$(field.name)
|
// val.$(field.name)
|
||||||
return t.get_comptime_selector_type(node, ast.void_type)
|
return t.get_comptime_selector_type(node, ast.void_type)
|
||||||
} else if node is ast.SelectorExpr && t.info.is_comptime_selector_type(node) {
|
} else if node is ast.SelectorExpr {
|
||||||
|
if t.info.is_comptime_selector_type(node) {
|
||||||
return t.get_type_from_comptime_var(node.expr as ast.Ident)
|
return t.get_type_from_comptime_var(node.expr as ast.Ident)
|
||||||
|
}
|
||||||
|
if node.expr is ast.Ident && node.expr.ct_expr {
|
||||||
|
struct_typ := t.resolver.unwrap_generic(t.get_type(node.expr))
|
||||||
|
struct_sym := t.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 := t.table.find_field(struct_sym, node.field_name) {
|
||||||
|
return field.typ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node.typ
|
||||||
} else if node is ast.ComptimeCall {
|
} else if node is ast.ComptimeCall {
|
||||||
method_name := t.info.comptime_for_method.name
|
method_name := t.info.comptime_for_method.name
|
||||||
left_sym := t.table.sym(t.resolver.unwrap_generic(node.left_type))
|
left_sym := t.table.sym(t.resolver.unwrap_generic(node.left_type))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user