From 682db6685219d63d808fda329fb16224a682394e Mon Sep 17 00:00:00 2001 From: Larsimusrex Date: Thu, 4 Sep 2025 10:39:24 +0200 Subject: [PATCH 1/6] builtin, checker, cgen: expose is_embed in FieldData (#25232) --- vlib/builtin/builtin.v | 7 ++++--- vlib/v/checker/comptime.v | 2 +- vlib/v/gen/c/comptime.v | 1 + vlib/v/tests/comptime/comptime_for_test.v | 12 +++++++++--- vlib/v/type_resolver/comptime_resolver.v | 1 + 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/vlib/builtin/builtin.v b/vlib/builtin/builtin.v index 73a8a93371..3a8347f815 100644 --- a/vlib/builtin/builtin.v +++ b/vlib/builtin/builtin.v @@ -124,9 +124,10 @@ pub: typ int // the internal TypeID of the field f, unaliased_typ int // if f's type was an alias of int, this will be TypeID(int) - attrs []string // the attributes of the field f - is_pub bool // f is in a `pub:` section - is_mut bool // f is in a `mut:` section + attrs []string // the attributes of the field f + is_pub bool // f is in a `pub:` section + is_mut bool // f is in a `mut:` section + is_embed bool // f is a embedded struct is_shared bool // `f shared Abc` is_atomic bool // `f atomic int` , TODO diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 6d855fbe0c..e8d99be0df 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -1398,7 +1398,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, mut sb strings.Builder) ( } ast.SelectorExpr { if c.comptime.comptime_for_field_var != '' && cond.expr is ast.Ident { - if (cond.expr as ast.Ident).name == c.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'] { + if (cond.expr as ast.Ident).name == c.comptime.comptime_for_field_var && cond.field_name in ['is_mut', 'is_pub', 'is_embed', 'is_shared', 'is_atomic', 'is_option', 'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias', 'is_enum'] { is_true = c.type_resolver.get_comptime_selector_bool_field(cond.field_name) sb.write_string('${is_true}') return is_true, true diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 88571cd09a..cb55c5841f 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -740,6 +740,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { g.writeln('\t${node.val_var}.unaliased_typ = ${int(unaliased_styp.idx())};\t// ${g.table.type_to_str(unaliased_styp)}') g.writeln('\t${node.val_var}.is_pub = ${field.is_pub};') g.writeln('\t${node.val_var}.is_mut = ${field.is_mut};') + g.writeln('\t${node.val_var}.is_embed = ${field.is_embed};') g.writeln('\t${node.val_var}.is_shared = ${field.typ.has_flag(.shared_f)};') g.writeln('\t${node.val_var}.is_atomic = ${field.typ.has_flag(.atomic_f)};') diff --git a/vlib/v/tests/comptime/comptime_for_test.v b/vlib/v/tests/comptime/comptime_for_test.v index 7a02f16b9c..ee2482ec14 100644 --- a/vlib/v/tests/comptime/comptime_for_test.v +++ b/vlib/v/tests/comptime/comptime_for_test.v @@ -1,4 +1,5 @@ struct App { + Inner a string b string mut: @@ -12,6 +13,8 @@ pub mut: h u8 } +struct Inner {} + @['foo/bar/three'] fn (mut app App) run() { } @@ -85,13 +88,16 @@ fn test_comptime_for_fields() { assert field.name in ['d', 'e'] } if field.is_mut { - assert field.name in ['c', 'd', 'g', 'h'] + assert field.name in ['c', 'd', 'g', 'h', 'Inner'] } if field.is_pub { - assert field.name in ['e', 'f', 'g', 'h'] + assert field.name in ['e', 'f', 'g', 'h', 'Inner'] } if field.is_pub && field.is_mut { - assert field.name in ['g', 'h'] + assert field.name in ['g', 'h', 'Inner'] + } + if field.is_embed { + assert field.name == 'Inner' } if field.name == 'f' { assert sizeof(field) == 8 diff --git a/vlib/v/type_resolver/comptime_resolver.v b/vlib/v/type_resolver/comptime_resolver.v index 79f296e19d..c33cff5365 100644 --- a/vlib/v/type_resolver/comptime_resolver.v +++ b/vlib/v/type_resolver/comptime_resolver.v @@ -224,6 +224,7 @@ pub fn (mut t TypeResolver) get_comptime_selector_bool_field(field_name string) match field_name { 'is_pub' { return field.is_pub } 'is_mut' { return field.is_mut } + 'is_embed' { return field.is_embed } '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) } From 88686960174103fd7755fb736869f500d36a78fc Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 4 Sep 2025 11:46:16 +0300 Subject: [PATCH 2/6] repl: fix handling of lines with comments like `math.pi // comment` (fix #25229) --- cmd/tools/vrepl.v | 2 +- vlib/v/slow_tests/repl/line_comment.repl | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 vlib/v/slow_tests/repl/line_comment.repl diff --git a/cmd/tools/vrepl.v b/cmd/tools/vrepl.v index 4c5eb36239..ada995bda0 100644 --- a/cmd/tools/vrepl.v +++ b/cmd/tools/vrepl.v @@ -441,7 +441,7 @@ fn run_repl(workdir string, vrepl_prefix string) int { prompt = '... ' } oline := r.get_one_line(prompt) or { break } - line := oline.trim_space() + line := oline.all_before('//').trim_space() if line == '' { continue } diff --git a/vlib/v/slow_tests/repl/line_comment.repl b/vlib/v/slow_tests/repl/line_comment.repl new file mode 100644 index 0000000000..9218e2c41a --- /dev/null +++ b/vlib/v/slow_tests/repl/line_comment.repl @@ -0,0 +1,5 @@ +math.pi +math.pi // some comment +===output=== +3.141592653589793 +3.141592653589793 From dabc08b6ee58157be58e5a1c06df83ddb2a7c47e Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Thu, 4 Sep 2025 15:27:25 +0530 Subject: [PATCH 3/6] cgen: fix alias enum used in comptime `$for` (fix #25211) (#25212) --- vlib/v/gen/c/comptime.v | 7 ++++++- .../comptime/comptime_enum_values_test.v | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index cb55c5841f..c44b33b04d 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -781,7 +781,12 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) { if g.pref.translated && node.typ.is_number() { g.writeln('_const_main__${val};') } else { - g.writeln('${g.styp(node.typ)}__${val};') + node_sym := g.table.sym(node.typ) + if node_sym.info is ast.Alias { + g.writeln('${g.styp(node_sym.info.parent_type)}__${val};') + } else { + g.writeln('${g.styp(node.typ)}__${val};') + } } enum_attrs := sym.info.attrs[val] if enum_attrs.len == 0 { diff --git a/vlib/v/tests/comptime/comptime_enum_values_test.v b/vlib/v/tests/comptime/comptime_enum_values_test.v index 912fee9e73..a652798bd3 100644 --- a/vlib/v/tests/comptime/comptime_enum_values_test.v +++ b/vlib/v/tests/comptime/comptime_enum_values_test.v @@ -5,6 +5,8 @@ enum CharacterGroup { special } +type AnotherCharGroup = CharacterGroup + fn (self CharacterGroup) value() string { return match self { .chars { 'first' } @@ -33,3 +35,21 @@ fn test_main() { assert values == [CharacterGroup.chars, CharacterGroup.alphanumerics, CharacterGroup.numeric, CharacterGroup.special] } + +fn test_alias_enum() { + mut values := []EnumData{} + $for entry in AnotherCharGroup.values { + values << entry + } + assert values[0].value == int(CharacterGroup.chars) + assert values[0].name == CharacterGroup.chars.str() + + assert values[1].value == int(CharacterGroup.alphanumerics) + assert values[1].name == CharacterGroup.alphanumerics.str() + + assert values[2].value == int(CharacterGroup.numeric) + assert values[2].name == CharacterGroup.numeric.str() + + assert values[3].value == int(CharacterGroup.special) + assert values[3].name == CharacterGroup.special.str() +} From f17e0fd52b12f3d4b81f79a14253fb2e1d2d3a7d Mon Sep 17 00:00:00 2001 From: CreeperFace <165158232+dy-tea@users.noreply.github.com> Date: Thu, 4 Sep 2025 11:04:57 +0100 Subject: [PATCH 4/6] cgen: ensure variable names do not conflict with builtin methods (fix #25063) (#25178) --- vlib/v/gen/c/assign.v | 128 ++++++++++++ vlib/v/gen/c/autofree.v | 3 +- vlib/v/gen/c/cgen.v | 2 + vlib/v/tests/clash_var_fn_name_test.v | 284 ++++++++++++++++++++++++++ 4 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/clash_var_fn_name_test.v diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 2b4a158437..31c9749de9 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -7,6 +7,126 @@ import v.ast import v.util import v.token +fn (mut g Gen) resolve_var_method_conflict(var_name string, val ast.Expr) string { + mut method_call := ast.CallExpr{} + mut has_method_call := false + mut receiver_type := ast.Type(0) + mut method_name := '' + match val { + ast.ArrayInit { + if var_name == 'new_array_from_c_array_noscan' { + return '_var_${var_name}' + } + } + ast.MapInit { + if var_name == 'new_map_noscan_key_value' { + return '_var_${var_name}' + } + } + ast.CallExpr { + if val.is_method { + method_call = val + has_method_call = true + } + } + ast.UnsafeExpr { + if val.expr is ast.CallExpr { + call_expr := val.expr as ast.CallExpr + if call_expr.is_method { + method_call = call_expr + has_method_call = true + } + } else if val.expr is ast.IndexExpr { + index_expr := val.expr as ast.IndexExpr + left_type := g.unwrap_generic(index_expr.left_type) + left_sym := g.table.sym(left_type) + type_name := left_sym.kind.str() + if (index_expr.index is ast.RangeExpr && var_name == '${type_name}_slice') + || var_name in ['${type_name}_get', '${type_name}_at'] { + return '_var_${var_name}' + } + } + } + ast.InfixExpr { + receiver_type = val.left_type + method_name = match val.op { + .eq { '_eq' } + .ne { '_ne' } + .lt { '_lt' } + .le { '_le' } + .gt { '_gt' } + .ge { '_ge' } + .plus { '_plus' } + .minus { '_minus' } + .mul { '_mul' } + .div { '_div' } + .mod { '_mod' } + else { '' } + } + has_method_call = method_name != '' && receiver_type != 0 + } + ast.IndexExpr { + left_type := g.unwrap_generic(val.left_type) + left_sym := g.table.sym(left_type) + type_name := left_sym.kind.str() + if (val.index is ast.RangeExpr && var_name == '${type_name}_slice') + || var_name in ['${type_name}_get', '${type_name}_at'] { + return '_var_${var_name}' + } + } + else {} + } + if has_method_call { + mut left_type := ast.Type(0) + if method_call.left_type != 0 { + left_type = g.unwrap_generic(method_call.left_type) + method_name = method_call.name + } else if receiver_type != 0 { + left_type = g.unwrap_generic(receiver_type) + } + if left_type != 0 { + left_sym := g.table.sym(left_type) + final_left_sym := g.table.final_sym(left_type) + if var_name == '${left_sym.cname}_${method_name}' { + return '_var_${var_name}' + } + if final_left_sym.kind == .array && !(left_sym.kind == .alias + && left_sym.has_method(method_name)) { + actual_method_name := match method_name { + 'repeat' { + 'repeat_to_depth' + } + 'clone' { + 'clone_to_depth' + } + 'pop_left' { + 'pop_left_noscan' + } + 'pop' { + 'pop_noscan' + } + else { + method_name + } + } + if var_name == 'array_${actual_method_name}' { + return '_var_${var_name}' + } + } + if final_left_sym.kind == .map && !(left_sym.kind == .alias + && left_sym.has_method(method_name)) { + if method_name in ['clone', 'move'] && var_name == 'map_${method_name}' { + return '_var_${var_name}' + } + if method_name in ['keys', 'values'] && var_name == 'map_${method_name}' { + return '_var_${var_name}' + } + } + } + } + return var_name +} + fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr ast.Expr, ret_typ ast.Type, in_heap bool) { gen_or := expr is ast.Ident && expr.or_expr.kind != .absent @@ -305,6 +425,14 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { is_va_list = left_sym.language == .c && left_sym.name == 'C.va_list' if mut left is ast.Ident { ident = left + if is_decl && i < node.right.len { + resolved_name := g.resolve_var_method_conflict(ident.name, node.right[i]) + if resolved_name != ident.name { + g.transformed_var_names[ident.name] = resolved_name + ident.name = resolved_name + node.left[i] = ident + } + } g.curr_var_name << ident.name // id_info := ident.var_info() // var_type = id_info.typ diff --git a/vlib/v/gen/c/autofree.v b/vlib/v/gen/c/autofree.v index a4f88ae12a..941934b280 100644 --- a/vlib/v/gen/c/autofree.v +++ b/vlib/v/gen/c/autofree.v @@ -242,7 +242,8 @@ fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) { af.writeln('\t\t${free_fn_name}((${base_type}*)${c_name(v.name)}.data); // autofreed option var ${g.cur_mod.name} ${g.is_builtin_mod}') af.writeln('\t}') } else if v.typ.idx() != ast.u8_type_idx { - af.writeln('\t${free_fn_name}(&${c_name(v.name)}); // autofreed var ${g.cur_mod.name} ${g.is_builtin_mod}') + var_name := g.transformed_var_names[v.name] or { v.name } + af.writeln('\t${free_fn_name}(&${c_name(var_name)}); // autofreed var ${g.cur_mod.name} ${g.is_builtin_mod}') } } g.autofree_scope_stmts << af.str() diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index c1e0368510..00dc97b7ff 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -258,6 +258,7 @@ mut: autofree_methods map[ast.Type]string generated_free_methods map[ast.Type]bool autofree_scope_stmts []string + transformed_var_names map[string]string use_segfault_handler bool = true test_function_names []string ///////// @@ -5261,6 +5262,7 @@ fn (mut g Gen) ident(node ast.Ident) { return } mut name := if node.kind == .function { c_fn_name(node.name) } else { c_name(node.name) } + name = g.transformed_var_names[node.name] or { name } if node.kind == .constant { if g.pref.translated && !g.is_builtin_mod && !util.module_is_builtin(node.name.all_before_last('.')) { diff --git a/vlib/v/tests/clash_var_fn_name_test.v b/vlib/v/tests/clash_var_fn_name_test.v new file mode 100644 index 0000000000..3b1b249bd6 --- /dev/null +++ b/vlib/v/tests/clash_var_fn_name_test.v @@ -0,0 +1,284 @@ +fn test_bool() { + b := bool(false) + bool_str := b.str() +} + +fn test_byteptr() { + b0 := byteptr(c'a') + b1 := byteptr(c'b') + b2 := byteptr(c'c') + b3 := byteptr(c'd') + b4 := byteptr(c'e') + byteptr_str := b0.str() + byteptr_vbytes := unsafe { b0.vbytes(1) } + byteptr_vstring := unsafe { b1.vstring() } + byteptr_vstring_literal := unsafe { b2.vstring_literal() } + byteptr_vstring_literal_with_len := unsafe { b3.vstring_literal_with_len(1) } + byteptr_vstring_with_len := unsafe { b4.vstring_with_len(1) } +} + +fn test_string() { + s := 'vstring' + s1 := ' other' + string_after := s.after('v') + string_after_char := s.after_char(`v`) + string_all_after := s.all_after('v') + string_all_after_first := s.all_after_first('v') + string_all_after_last := s.all_after_last('v') + string_all_before := s.all_before('v') + string_all_before_last := s.all_before_last('v') + string_before := s.before('v') + string_bool := s.bool() + string_bytes := s.bytes() + string_camel_to_snake := s.camel_to_snake() + string_capitalize := s.capitalize() + string_clone := s.clone() + string_compare := s.compare(s1) + string_contains := s.contains('v') + string_contains_any := s.contains_any('vs') + string_contains_any_substr := s.contains_any_substr(['v', 'ing']) + string_contains_only := s.contains_only('s') + string_contains_u8 := s.contains_u8(`g`) + string_count := s.count('i') + string_ends_with := s.ends_with('ing') + string_expand_tabs := s.expand_tabs(4) + string_f32 := s.f32() + string_f64 := s.f64() + string_fields := s.fields() + string_find_between := s.find_between('v', 'g') + string_hash := s.hash() + string_i16 := s.i16() + string_i32 := s.i32() + string_i64 := s.i64() + string_i8 := s.i8() + string_indent_width := s.indent_width() + string_index := s.index('g') + string_index_after_ := s.index_after_('n', 3) + string_index_any := s.index_any('g') + string_index_u8 := s.index_u8(`g`) + string_int := s.int() + string_is_ascii := s.is_ascii() + string_is_bin := s.is_bin() + string_is_blank := s.is_blank() + string_is_capital := s.is_capital() + string_is_hex := s.is_hex() + string_is_identifier := s.is_identifier() + string_is_int := s.is_int() + string_is_lower := s.is_lower() + string_is_oct := s.is_oct() + string_is_pure_ascii := s.is_pure_ascii() + string_is_title := s.is_title() + string_is_upper := s.is_upper() + string_last_index := s.last_index('g') + string_last_index_u8 := s.last_index_u8(`g`) + string_len_utf8 := s.len_utf8() + string_limit := s.limit(5) + string_match_glob := s.match_glob('*') + string_normalize_tabs := s.normalize_tabs(2) + string_parse_int := s.parse_int(10, 32) or { 0 } + string_parse_uint := s.parse_uint(10, 32) or { 0 } + string_repeat := s.repeat(2) + string_replace := s.replace('v', 'V') + string_replace_char := s.replace_char(`v`, `V`, 1) + string_replace_each := s.replace_each(['v', 'V']) + string_replace_once := s.replace_once('v', 'V') + string_reverse := s.reverse() + string_rsplit := s.rsplit('g') + string_rsplit_any := s.rsplit_any('g') + string_rsplit_nth := s.rsplit_nth('g', 1) + string_rsplit_once, tmp := s.rsplit_once('g') or { '', '' } + string_runes := s.runes() + string_runes_iterator := s.runes_iterator() + string_snake_to_camel := s.snake_to_camel() + string_split := s.split('r') + string_split_any := s.split_any('r') + string_split_by_space := s.split_by_space() + string_split_into_lines := s.split_into_lines() + string_split_n := s.split_n('g', 2) + string_split_nth := s.split_nth('ri', 2) + string_split_once, tmp1 := s.split_once('g') or { '', '' } + string_starts_with := s.starts_with('v') + string_starts_with_captial := s.starts_with_capital() + string_str := s.str() + string_strip_margin := s.strip_margin() + string_strip_margin_custom := s.strip_margin_custom(`v`) + string_substr := s.substr(1, 3) + string_substr_ni := s.substr_ni(0, 1) + string_substr_unsafe := unsafe { s[0..2] } + string_substr_with_check := s.substr_with_check(0, 1) or { '' } + string_title := s.title() + string_to_lower := s.to_lower() + string_to_lower_ascii := s.to_lower_ascii() + string_to_upper := s.to_upper() + string_to_upper_ascii := s.to_upper_ascii() + string_to_wide := s.to_wide() + string_trim_chars := s.trim('string') + string_trim_indent := s.trim_indent() + string_trim_indexes, tmp3 := s.trim_indexes('in') + string_trim_left := s.trim_left('g') + string_trim_right := s.trim_right('g') + string_trim_space := s.trim_space() + string_trim_space_left := s.trim_space_left() + string_trim_space_right := s.trim_space_right() + string_trim_string_left := s.trim_string_left('v') + string_trim_string_right := s.trim_string_right('g') + string_u16 := s.u16() + string_u32 := s.u32() + string_u64 := s.u64() + string_u8 := s.u8() + string_u8_array := s.u8_array() + string_uncapitalize := s.uncapitalize() + string_utf32_code := s.utf32_code() + string_wrap := s.wrap(width: 20) + string__eq := s == s1 + string__lt := s < s1 + string__plus := s + s1 + string_at := s[3] +} + +fn test_i8() { + i8_ := i8(0) + i8_str := i8_.str() +} + +fn test_i16() { + i16_ := i16(0) + i16_str := i16_.str() +} + +fn test_i32() { + i32_ := i32(0) + i32_str := i32_.str() +} + +fn test_int() { + int_ := int(0) + int_str := int_.str() + int_literal_str := 0.str() +} + +fn test_i64() { + i64_ := i64(0) + i64_str := i64_.str() +} + +fn test_u8() { + u8_ := u8(0) + u8_str := u8_.str() + u8_ascii_str := u8_.ascii_str() +} + +fn test_u16() { + u16_ := u16(0) + u16_str := u16_.str() +} + +fn test_u32() { + u32_ := u32(0) + u32_str := u32_.str() +} + +fn test_u64() { + u64_ := u64(0) + u64_str := u64_.str() + u64_hex := u64_.hex() +} + +fn test_isize() { + isize_ := isize(0) + isize_str := isize_.str() +} + +fn test_usize() { + usize_ := usize(0) + usize_str := usize_.str() +} + +fn test_f32() { + f32_ := f32(0) + f32_str := f32_.str() + f32_strg := f32_.strg() + f32_strsci := f32_.strsci(2) + f32_strlong := f32_.strlong() + f32_eq_epsilon := f32_.eq_epsilon(0.000001) +} + +fn test_f64() { + f64_ := f64(0) + f64_str := f64_.str() + f64_strg := f64_.strg() + f64_strsci := f64_.strsci(2) + f64_strlong := f64_.strlong() + f64_eq_epsilon := f64_.eq_epsilon(0.000001) +} + +fn test_float() { + float_literal_str := 0.1.str() +} + +fn test_rune() { + r := rune(0) + rune_bytes := r.bytes() + rune_str := r.str() + rune_to_upper := r.to_upper() +} + +fn test_ptr() { + ptr := unsafe { voidptr(nil) } + voidptr_hex_full := ptr.hex_full() + voidptr_str := ptr.str() + voidptr_vbytes := unsafe { ptr.vbytes(1) } +} + +fn test_char() { + char_ := unsafe { &char(c'a') } + char_str := char_.str() + char_vstring := unsafe { char_.vstring() } + char_vstring_literal_with_len := unsafe { char_.vstring_with_len(1) } + char_vstring_with_len := unsafe { char_.vstring_with_len(1) } +} + +fn test_cstring() { + cstring := c'cstring' + u8_vstring := unsafe { cstring.vstring() } +} + +fn test_array() { + new_array_from_c_array_noscan := [1, 2, 3] + mut a := [1, 2, 3] + array_repeat_to_depth := a.repeat(2) + array_first := a.first() + array_last := a.last() + array_pop_left_noscan := a.pop_left() + array_pop_noscan := a.pop() + array_get := a[0] + array_clone_to_depth := a.clone() + array_reverse := a.reverse() + array_filter := a.filter(it < 2) + array_any := a.any(it % 2 == 1) + array_count := a.count(it > 1) + array_all := a.all(it > 0) + array_slice := unsafe { a[0..1] } +} + +fn test_map() { + new_map_noscan_key_value := map[int]int{} + new_map_noscan_value := { + 'test': 10 + } + mut m := { + 'test': 10 + } + map_clone := m.clone() + map_keys := m.keys() + map_values := m.values() + map_get := m['test'] + map_move := m.move() +} + +fn test_assign() { + r := rune(0) + mut rune_bytes := r.bytes() + rb := rune_bytes + _ = rune_bytes +} From e15d8fcf493613f1c75d4b9c21ed7851f58308e0 Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Thu, 4 Sep 2025 18:33:39 +0800 Subject: [PATCH 5/6] checker: comptime match only eval true branch (fix #25223) (#25225) --- vlib/v/checker/match.v | 11 +++++++---- .../comptime_match_eval_only_true_branch_test.v | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 vlib/v/tests/comptime/comptime_match_eval_only_true_branch_test.v diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index 6d3530d00d..3fb651d6d9 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -221,10 +221,13 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } } } - if node.is_expr { - c.stmts_ending_with_expression(mut branch.stmts, c.expected_or_type) - } else { - c.stmts(mut branch.stmts) + + if !node.is_comptime || (node.is_comptime && comptime_match_branch_result) { + if node.is_expr { + c.stmts_ending_with_expression(mut branch.stmts, c.expected_or_type) + } else { + c.stmts(mut branch.stmts) + } } c.smartcast_mut_pos = token.Pos{} c.smartcast_cond_pos = token.Pos{} diff --git a/vlib/v/tests/comptime/comptime_match_eval_only_true_branch_test.v b/vlib/v/tests/comptime/comptime_match_eval_only_true_branch_test.v new file mode 100644 index 0000000000..74ca289ed2 --- /dev/null +++ b/vlib/v/tests/comptime/comptime_match_eval_only_true_branch_test.v @@ -0,0 +1,17 @@ +module main + +fn func[T]() bool { + $match T { + u8, u16 { + return true + } + $else { + // return false + $compile_error('fail') + } + } +} + +fn test_comptime_match_eval_only_true_branch() { + assert func[u8]() +} From dbd5b5f56cb7451949eaa72ec8534eac7b6a6cd1 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 4 Sep 2025 13:47:53 +0300 Subject: [PATCH 6/6] Revert "cgen: ensure variable names do not conflict with builtin methods (fix #25063) (#25178)" This reverts commit f17e0fd52b12f3d4b81f79a14253fb2e1d2d3a7d. --- vlib/v/gen/c/assign.v | 128 ------------ vlib/v/gen/c/autofree.v | 3 +- vlib/v/gen/c/cgen.v | 2 - vlib/v/tests/clash_var_fn_name_test.v | 284 -------------------------- 4 files changed, 1 insertion(+), 416 deletions(-) delete mode 100644 vlib/v/tests/clash_var_fn_name_test.v diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 31c9749de9..2b4a158437 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -7,126 +7,6 @@ import v.ast import v.util import v.token -fn (mut g Gen) resolve_var_method_conflict(var_name string, val ast.Expr) string { - mut method_call := ast.CallExpr{} - mut has_method_call := false - mut receiver_type := ast.Type(0) - mut method_name := '' - match val { - ast.ArrayInit { - if var_name == 'new_array_from_c_array_noscan' { - return '_var_${var_name}' - } - } - ast.MapInit { - if var_name == 'new_map_noscan_key_value' { - return '_var_${var_name}' - } - } - ast.CallExpr { - if val.is_method { - method_call = val - has_method_call = true - } - } - ast.UnsafeExpr { - if val.expr is ast.CallExpr { - call_expr := val.expr as ast.CallExpr - if call_expr.is_method { - method_call = call_expr - has_method_call = true - } - } else if val.expr is ast.IndexExpr { - index_expr := val.expr as ast.IndexExpr - left_type := g.unwrap_generic(index_expr.left_type) - left_sym := g.table.sym(left_type) - type_name := left_sym.kind.str() - if (index_expr.index is ast.RangeExpr && var_name == '${type_name}_slice') - || var_name in ['${type_name}_get', '${type_name}_at'] { - return '_var_${var_name}' - } - } - } - ast.InfixExpr { - receiver_type = val.left_type - method_name = match val.op { - .eq { '_eq' } - .ne { '_ne' } - .lt { '_lt' } - .le { '_le' } - .gt { '_gt' } - .ge { '_ge' } - .plus { '_plus' } - .minus { '_minus' } - .mul { '_mul' } - .div { '_div' } - .mod { '_mod' } - else { '' } - } - has_method_call = method_name != '' && receiver_type != 0 - } - ast.IndexExpr { - left_type := g.unwrap_generic(val.left_type) - left_sym := g.table.sym(left_type) - type_name := left_sym.kind.str() - if (val.index is ast.RangeExpr && var_name == '${type_name}_slice') - || var_name in ['${type_name}_get', '${type_name}_at'] { - return '_var_${var_name}' - } - } - else {} - } - if has_method_call { - mut left_type := ast.Type(0) - if method_call.left_type != 0 { - left_type = g.unwrap_generic(method_call.left_type) - method_name = method_call.name - } else if receiver_type != 0 { - left_type = g.unwrap_generic(receiver_type) - } - if left_type != 0 { - left_sym := g.table.sym(left_type) - final_left_sym := g.table.final_sym(left_type) - if var_name == '${left_sym.cname}_${method_name}' { - return '_var_${var_name}' - } - if final_left_sym.kind == .array && !(left_sym.kind == .alias - && left_sym.has_method(method_name)) { - actual_method_name := match method_name { - 'repeat' { - 'repeat_to_depth' - } - 'clone' { - 'clone_to_depth' - } - 'pop_left' { - 'pop_left_noscan' - } - 'pop' { - 'pop_noscan' - } - else { - method_name - } - } - if var_name == 'array_${actual_method_name}' { - return '_var_${var_name}' - } - } - if final_left_sym.kind == .map && !(left_sym.kind == .alias - && left_sym.has_method(method_name)) { - if method_name in ['clone', 'move'] && var_name == 'map_${method_name}' { - return '_var_${var_name}' - } - if method_name in ['keys', 'values'] && var_name == 'map_${method_name}' { - return '_var_${var_name}' - } - } - } - } - return var_name -} - fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr ast.Expr, ret_typ ast.Type, in_heap bool) { gen_or := expr is ast.Ident && expr.or_expr.kind != .absent @@ -425,14 +305,6 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { is_va_list = left_sym.language == .c && left_sym.name == 'C.va_list' if mut left is ast.Ident { ident = left - if is_decl && i < node.right.len { - resolved_name := g.resolve_var_method_conflict(ident.name, node.right[i]) - if resolved_name != ident.name { - g.transformed_var_names[ident.name] = resolved_name - ident.name = resolved_name - node.left[i] = ident - } - } g.curr_var_name << ident.name // id_info := ident.var_info() // var_type = id_info.typ diff --git a/vlib/v/gen/c/autofree.v b/vlib/v/gen/c/autofree.v index 941934b280..a4f88ae12a 100644 --- a/vlib/v/gen/c/autofree.v +++ b/vlib/v/gen/c/autofree.v @@ -242,8 +242,7 @@ fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) { af.writeln('\t\t${free_fn_name}((${base_type}*)${c_name(v.name)}.data); // autofreed option var ${g.cur_mod.name} ${g.is_builtin_mod}') af.writeln('\t}') } else if v.typ.idx() != ast.u8_type_idx { - var_name := g.transformed_var_names[v.name] or { v.name } - af.writeln('\t${free_fn_name}(&${c_name(var_name)}); // autofreed var ${g.cur_mod.name} ${g.is_builtin_mod}') + af.writeln('\t${free_fn_name}(&${c_name(v.name)}); // autofreed var ${g.cur_mod.name} ${g.is_builtin_mod}') } } g.autofree_scope_stmts << af.str() diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 00dc97b7ff..c1e0368510 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -258,7 +258,6 @@ mut: autofree_methods map[ast.Type]string generated_free_methods map[ast.Type]bool autofree_scope_stmts []string - transformed_var_names map[string]string use_segfault_handler bool = true test_function_names []string ///////// @@ -5262,7 +5261,6 @@ fn (mut g Gen) ident(node ast.Ident) { return } mut name := if node.kind == .function { c_fn_name(node.name) } else { c_name(node.name) } - name = g.transformed_var_names[node.name] or { name } if node.kind == .constant { if g.pref.translated && !g.is_builtin_mod && !util.module_is_builtin(node.name.all_before_last('.')) { diff --git a/vlib/v/tests/clash_var_fn_name_test.v b/vlib/v/tests/clash_var_fn_name_test.v deleted file mode 100644 index 3b1b249bd6..0000000000 --- a/vlib/v/tests/clash_var_fn_name_test.v +++ /dev/null @@ -1,284 +0,0 @@ -fn test_bool() { - b := bool(false) - bool_str := b.str() -} - -fn test_byteptr() { - b0 := byteptr(c'a') - b1 := byteptr(c'b') - b2 := byteptr(c'c') - b3 := byteptr(c'd') - b4 := byteptr(c'e') - byteptr_str := b0.str() - byteptr_vbytes := unsafe { b0.vbytes(1) } - byteptr_vstring := unsafe { b1.vstring() } - byteptr_vstring_literal := unsafe { b2.vstring_literal() } - byteptr_vstring_literal_with_len := unsafe { b3.vstring_literal_with_len(1) } - byteptr_vstring_with_len := unsafe { b4.vstring_with_len(1) } -} - -fn test_string() { - s := 'vstring' - s1 := ' other' - string_after := s.after('v') - string_after_char := s.after_char(`v`) - string_all_after := s.all_after('v') - string_all_after_first := s.all_after_first('v') - string_all_after_last := s.all_after_last('v') - string_all_before := s.all_before('v') - string_all_before_last := s.all_before_last('v') - string_before := s.before('v') - string_bool := s.bool() - string_bytes := s.bytes() - string_camel_to_snake := s.camel_to_snake() - string_capitalize := s.capitalize() - string_clone := s.clone() - string_compare := s.compare(s1) - string_contains := s.contains('v') - string_contains_any := s.contains_any('vs') - string_contains_any_substr := s.contains_any_substr(['v', 'ing']) - string_contains_only := s.contains_only('s') - string_contains_u8 := s.contains_u8(`g`) - string_count := s.count('i') - string_ends_with := s.ends_with('ing') - string_expand_tabs := s.expand_tabs(4) - string_f32 := s.f32() - string_f64 := s.f64() - string_fields := s.fields() - string_find_between := s.find_between('v', 'g') - string_hash := s.hash() - string_i16 := s.i16() - string_i32 := s.i32() - string_i64 := s.i64() - string_i8 := s.i8() - string_indent_width := s.indent_width() - string_index := s.index('g') - string_index_after_ := s.index_after_('n', 3) - string_index_any := s.index_any('g') - string_index_u8 := s.index_u8(`g`) - string_int := s.int() - string_is_ascii := s.is_ascii() - string_is_bin := s.is_bin() - string_is_blank := s.is_blank() - string_is_capital := s.is_capital() - string_is_hex := s.is_hex() - string_is_identifier := s.is_identifier() - string_is_int := s.is_int() - string_is_lower := s.is_lower() - string_is_oct := s.is_oct() - string_is_pure_ascii := s.is_pure_ascii() - string_is_title := s.is_title() - string_is_upper := s.is_upper() - string_last_index := s.last_index('g') - string_last_index_u8 := s.last_index_u8(`g`) - string_len_utf8 := s.len_utf8() - string_limit := s.limit(5) - string_match_glob := s.match_glob('*') - string_normalize_tabs := s.normalize_tabs(2) - string_parse_int := s.parse_int(10, 32) or { 0 } - string_parse_uint := s.parse_uint(10, 32) or { 0 } - string_repeat := s.repeat(2) - string_replace := s.replace('v', 'V') - string_replace_char := s.replace_char(`v`, `V`, 1) - string_replace_each := s.replace_each(['v', 'V']) - string_replace_once := s.replace_once('v', 'V') - string_reverse := s.reverse() - string_rsplit := s.rsplit('g') - string_rsplit_any := s.rsplit_any('g') - string_rsplit_nth := s.rsplit_nth('g', 1) - string_rsplit_once, tmp := s.rsplit_once('g') or { '', '' } - string_runes := s.runes() - string_runes_iterator := s.runes_iterator() - string_snake_to_camel := s.snake_to_camel() - string_split := s.split('r') - string_split_any := s.split_any('r') - string_split_by_space := s.split_by_space() - string_split_into_lines := s.split_into_lines() - string_split_n := s.split_n('g', 2) - string_split_nth := s.split_nth('ri', 2) - string_split_once, tmp1 := s.split_once('g') or { '', '' } - string_starts_with := s.starts_with('v') - string_starts_with_captial := s.starts_with_capital() - string_str := s.str() - string_strip_margin := s.strip_margin() - string_strip_margin_custom := s.strip_margin_custom(`v`) - string_substr := s.substr(1, 3) - string_substr_ni := s.substr_ni(0, 1) - string_substr_unsafe := unsafe { s[0..2] } - string_substr_with_check := s.substr_with_check(0, 1) or { '' } - string_title := s.title() - string_to_lower := s.to_lower() - string_to_lower_ascii := s.to_lower_ascii() - string_to_upper := s.to_upper() - string_to_upper_ascii := s.to_upper_ascii() - string_to_wide := s.to_wide() - string_trim_chars := s.trim('string') - string_trim_indent := s.trim_indent() - string_trim_indexes, tmp3 := s.trim_indexes('in') - string_trim_left := s.trim_left('g') - string_trim_right := s.trim_right('g') - string_trim_space := s.trim_space() - string_trim_space_left := s.trim_space_left() - string_trim_space_right := s.trim_space_right() - string_trim_string_left := s.trim_string_left('v') - string_trim_string_right := s.trim_string_right('g') - string_u16 := s.u16() - string_u32 := s.u32() - string_u64 := s.u64() - string_u8 := s.u8() - string_u8_array := s.u8_array() - string_uncapitalize := s.uncapitalize() - string_utf32_code := s.utf32_code() - string_wrap := s.wrap(width: 20) - string__eq := s == s1 - string__lt := s < s1 - string__plus := s + s1 - string_at := s[3] -} - -fn test_i8() { - i8_ := i8(0) - i8_str := i8_.str() -} - -fn test_i16() { - i16_ := i16(0) - i16_str := i16_.str() -} - -fn test_i32() { - i32_ := i32(0) - i32_str := i32_.str() -} - -fn test_int() { - int_ := int(0) - int_str := int_.str() - int_literal_str := 0.str() -} - -fn test_i64() { - i64_ := i64(0) - i64_str := i64_.str() -} - -fn test_u8() { - u8_ := u8(0) - u8_str := u8_.str() - u8_ascii_str := u8_.ascii_str() -} - -fn test_u16() { - u16_ := u16(0) - u16_str := u16_.str() -} - -fn test_u32() { - u32_ := u32(0) - u32_str := u32_.str() -} - -fn test_u64() { - u64_ := u64(0) - u64_str := u64_.str() - u64_hex := u64_.hex() -} - -fn test_isize() { - isize_ := isize(0) - isize_str := isize_.str() -} - -fn test_usize() { - usize_ := usize(0) - usize_str := usize_.str() -} - -fn test_f32() { - f32_ := f32(0) - f32_str := f32_.str() - f32_strg := f32_.strg() - f32_strsci := f32_.strsci(2) - f32_strlong := f32_.strlong() - f32_eq_epsilon := f32_.eq_epsilon(0.000001) -} - -fn test_f64() { - f64_ := f64(0) - f64_str := f64_.str() - f64_strg := f64_.strg() - f64_strsci := f64_.strsci(2) - f64_strlong := f64_.strlong() - f64_eq_epsilon := f64_.eq_epsilon(0.000001) -} - -fn test_float() { - float_literal_str := 0.1.str() -} - -fn test_rune() { - r := rune(0) - rune_bytes := r.bytes() - rune_str := r.str() - rune_to_upper := r.to_upper() -} - -fn test_ptr() { - ptr := unsafe { voidptr(nil) } - voidptr_hex_full := ptr.hex_full() - voidptr_str := ptr.str() - voidptr_vbytes := unsafe { ptr.vbytes(1) } -} - -fn test_char() { - char_ := unsafe { &char(c'a') } - char_str := char_.str() - char_vstring := unsafe { char_.vstring() } - char_vstring_literal_with_len := unsafe { char_.vstring_with_len(1) } - char_vstring_with_len := unsafe { char_.vstring_with_len(1) } -} - -fn test_cstring() { - cstring := c'cstring' - u8_vstring := unsafe { cstring.vstring() } -} - -fn test_array() { - new_array_from_c_array_noscan := [1, 2, 3] - mut a := [1, 2, 3] - array_repeat_to_depth := a.repeat(2) - array_first := a.first() - array_last := a.last() - array_pop_left_noscan := a.pop_left() - array_pop_noscan := a.pop() - array_get := a[0] - array_clone_to_depth := a.clone() - array_reverse := a.reverse() - array_filter := a.filter(it < 2) - array_any := a.any(it % 2 == 1) - array_count := a.count(it > 1) - array_all := a.all(it > 0) - array_slice := unsafe { a[0..1] } -} - -fn test_map() { - new_map_noscan_key_value := map[int]int{} - new_map_noscan_value := { - 'test': 10 - } - mut m := { - 'test': 10 - } - map_clone := m.clone() - map_keys := m.keys() - map_values := m.values() - map_get := m['test'] - map_move := m.move() -} - -fn test_assign() { - r := rune(0) - mut rune_bytes := r.bytes() - rb := rune_bytes - _ = rune_bytes -}