From 052e5af8f3f4b742d5afa3e59125134572d73193 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Fri, 20 Dec 2024 14:39:11 -0300 Subject: [PATCH] checker: fix assign check, when rechecking for another concrete type (#23212) --- vlib/v/checker/assign.v | 12 ++++- vlib/v/checker/checker.v | 3 +- vlib/v/comptime/comptimeinfo.v | 12 +++++ .../generic_selector_indexexpr_test.v | 44 +++++++++++++++++++ vlib/x/json2/decoder2/decode_sumtype.v | 12 +++-- 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 vlib/v/tests/generics/generic_selector_indexexpr_test.v diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index b47c9e1dc..4886dfdb7 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -182,6 +182,17 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { node.right_types << c.check_expr_option_or_result_call(node.right[i], right_type) } + } else { + // on generic recheck phase it might be needed to resolve the rhs again + if i < node.right.len && c.comptime.has_comptime_expr(node.right[i]) { + mut expr := mut node.right[i] + old_inside_recheck := c.inside_recheck + c.inside_recheck = true + right_type := c.expr(mut expr) + node.right_types[i] = c.check_expr_option_or_result_call(node.right[i], + right_type) + c.inside_recheck = old_inside_recheck + } } mut right := if i < node.right.len { node.right[i] } else { node.right[0] } mut right_type := node.right_types[i] @@ -494,7 +505,6 @@ 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) } if mut left is ast.InfixExpr { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 142835f85..0c2bcaa97 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -77,6 +77,7 @@ pub mut: is_builtin_mod bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this is_just_builtin_mod bool // true only inside 'builtin' is_generated bool // true for `@[generated] module xyz` .v files + inside_recheck bool // true when rechecking rhs assign statement inside_unsafe bool // true inside `unsafe {}` blocks inside_const bool // true inside `const ( ... )` blocks inside_anon_fn bool // true inside `fn() { ... }()` @@ -1774,7 +1775,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { } if has_field { - is_used_outside := sym.mod != c.mod + is_used_outside := !c.inside_recheck && sym.mod != c.mod if is_used_outside && !field.is_pub && sym.language != .c { unwrapped_sym := c.table.sym(c.unwrap_generic(typ)) c.error('field `${unwrapped_sym.name}.${field_name}` is not public', node.pos) diff --git a/vlib/v/comptime/comptimeinfo.v b/vlib/v/comptime/comptimeinfo.v index 9f9dfe8d5..2de799a04 100644 --- a/vlib/v/comptime/comptimeinfo.v +++ b/vlib/v/comptime/comptimeinfo.v @@ -36,6 +36,17 @@ pub fn (mut ct ComptimeInfo) is_comptime_expr(node ast.Expr) bool { || 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 { @@ -100,6 +111,7 @@ pub fn (mut ct ComptimeInfo) get_expr_type_or_default(node ast.Expr, 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 { diff --git a/vlib/v/tests/generics/generic_selector_indexexpr_test.v b/vlib/v/tests/generics/generic_selector_indexexpr_test.v new file mode 100644 index 000000000..fedb59b3c --- /dev/null +++ b/vlib/v/tests/generics/generic_selector_indexexpr_test.v @@ -0,0 +1,44 @@ +module main + +pub struct Vector[T] { + n int + values []T +} + +pub fn Vector.new[T](v []T) Vector[T] { + return Vector[T]{ + n: v.len + values: v + } +} + +pub fn (v Vector[T]) str() string { + return v.values.str() +} + +pub fn (v Vector[T]) + (u Vector[T]) Vector[T] { + assert v.n == u.n + return Vector[T]{ + n: v.n + values: []T{len: v.n, init: T(v.values[index] + u.values[index])} + } +} + +pub fn (v Vector[T]) dot(u Vector[T]) T { + assert v.n == u.n + mut sum := T(0) + for i in 0 .. v.n { + sum += v.values[i] * u.values[i] + } + return sum +} + +fn test_main() { + v := Vector.new[f64]([1.0, 2, 3]) + vdotv := v.dot(v) + assert vdotv == 14.0 + + u := Vector.new[int]([1, 2, 3]) + udotu := u.dot(u) + assert udotu == 14 +} diff --git a/vlib/x/json2/decoder2/decode_sumtype.v b/vlib/x/json2/decoder2/decode_sumtype.v index 52e6535e6..423cedf90 100644 --- a/vlib/x/json2/decoder2/decode_sumtype.v +++ b/vlib/x/json2/decoder2/decode_sumtype.v @@ -8,9 +8,15 @@ fn (mut decoder Decoder) get_decoded_sumtype_workaround[T](initialized_sumtype T if initialized_sumtype is v { // workaround for auto generated function considering sumtype as array unsafe { - mut val := initialized_sumtype - decoder.decode_value(mut val)! - return T(val) + $if initialized_sumtype is $map { + mut val := initialized_sumtype.clone() + decoder.decode_value(mut val)! + return T(val) + } $else { + mut val := initialized_sumtype + decoder.decode_value(mut val)! + return T(val) + } } } } -- 2.39.5