diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index b6b82b7985ffc9..f5680eabe5d0d3 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -85,7 +85,8 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type { c.error('no known default format for type `${c.table.get_type_name(ftyp)}`', node.fmt_poss[i]) } - } else if c.comptime.is_comptime(expr) && c.comptime.get_type(expr) != ast.void_type { + } else if c.comptime.is_comptime(expr) + && c.comptime.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 index 2de799a049c2b1..156ab624c3ef47 100644 --- a/vlib/v/comptime/comptimeinfo.v +++ b/vlib/v/comptime/comptimeinfo.v @@ -61,6 +61,15 @@ pub fn (mut ct ComptimeInfo) is_comptime(node ast.Expr) bool { 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 } @@ -120,6 +129,26 @@ pub fn (mut ct ComptimeInfo) get_type_or_default(node ast.Expr, default_typ ast. 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 } diff --git a/vlib/v/gen/c/infix.v b/vlib/v/gen/c/infix.v index c33b40a131d79b..9f1888f1e54fda 100644 --- a/vlib/v/gen/c/infix.v +++ b/vlib/v/gen/c/infix.v @@ -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(node.left_type) - right := g.unwrap(node.right_type) + 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)) 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) @@ -1188,7 +1188,11 @@ fn (mut g Gen) gen_plain_infix_expr(node ast.InfixExpr) { && node.op in [.plus, .minus, .mul, .div, .mod] && !(g.pref.translated || g.file.is_translated) if needs_cast { - typ_str := g.styp(node.promoted_type) + typ_str := if g.comptime.is_comptime(node.left) { + g.styp(g.comptime.get_type_or_default(node.left, node.promoted_type)) + } else { + g.styp(node.promoted_type) + } g.write('(${typ_str})(') } if node.left_type.is_ptr() && node.left.is_auto_deref_var() && !node.right_type.is_pointer() { diff --git a/vlib/v/gen/c/str_intp.v b/vlib/v/gen/c/str_intp.v index 219b1f6e8a1b88..52d9149ac493cd 100644 --- a/vlib/v/gen/c/str_intp.v +++ b/vlib/v/gen/c/str_intp.v @@ -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(expr) + ctyp := g.comptime.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/parser/fn.v b/vlib/v/parser/fn.v index f265820c7347f3..7df0d5372c77b0 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -512,7 +512,7 @@ run them via `v file.v` instead', pos: param.pos is_used: is_pub || no_body || (is_method && k == 0) || p.builtin_mod is_arg: true - ct_type_var: if (!is_method || k > 0) && param.typ.has_flag(.generic) + ct_type_var: if (!is_method || k >= 0) && param.typ.has_flag(.generic) && !param.typ.has_flag(.variadic) { .generic_param } else { diff --git a/vlib/v/tests/generics/generic_selector_type_test.v b/vlib/v/tests/generics/generic_selector_type_test.v new file mode 100644 index 00000000000000..6643b4cef0e3e7 --- /dev/null +++ b/vlib/v/tests/generics/generic_selector_type_test.v @@ -0,0 +1,12 @@ +import math.vec + +type UnusedType = vec.Vec3[f32] + +fn (n UnusedType) unused_function() f32 { + return n.mul_scalar(2).magnitude() +} + +fn test_main() { + assert vec.Vec3[f32]{0.5, 0.5, 0.5}.magnitude() == f32(0.8660254) + assert vec.Vec3[f32]{1.5, 1.5, 1.5}.magnitude() == f32(2.598076) +}