diff --git a/.gitattributes b/.gitattributes index 47a6d90d27..ef7f2882b7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,4 @@ v.mod linguist-language=V .vdocignore linguist-language=ignore Dockerfile.* linguist-language=Dockerfile +vlib/v/tests/runes.txt binary 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/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/builtin/input_rune_iterator.v b/vlib/builtin/input_rune_iterator.v new file mode 100644 index 0000000000..3091986879 --- /dev/null +++ b/vlib/builtin/input_rune_iterator.v @@ -0,0 +1,40 @@ +module builtin + +// input_rune returns a single rune from the standart input (an unicode codepoint). +// It expects, that the input is utf8 encoded. +// It will return `none` on EOF. +pub fn input_rune() ?rune { + x := input_character() + if x <= 0 { + return none + } + char_len := utf8_char_len(u8(x)) + if char_len == 1 { + return x + } + mut b := u8(x) + b = b << char_len + mut res := rune(b) + mut shift := 6 - char_len + for i := 1; i < char_len; i++ { + c := rune(input_character()) + res = rune(res) << shift + res |= c & 63 // 0x3f + shift = 6 + } + return res +} + +// InputRuneIterator is an iterator over the input runes. +pub struct InputRuneIterator {} + +// next returns the next rune from the input stream. +pub fn (mut self InputRuneIterator) next() ?rune { + return input_rune() +} + +// input_rune_iterator returns an iterator to allow for `for i, r in input_rune_iterator() {`. +// When the input stream is closed, the loop will break. +pub fn input_rune_iterator() InputRuneIterator { + return InputRuneIterator{} +} diff --git a/vlib/builtin/input_rune_iterator_test.v b/vlib/builtin/input_rune_iterator_test.v new file mode 100644 index 0000000000..f5667b0262 --- /dev/null +++ b/vlib/builtin/input_rune_iterator_test.v @@ -0,0 +1,51 @@ +// vtest build: !windows +import os +import time + +fn test_input_rune_iterator_with_unicode_input() { + mut p := os.new_process(@VEXE) + p.set_args(['-e', 'for i, r in input_rune_iterator() { println("> i: \${i:04} | r: `\${r}`") }']) + p.set_redirect_stdio() + p.run() + spawn fn [mut p] () { + time.sleep(10 * time.millisecond) + dump(p.pid) + p.stdin_write('Проба Abc 你好 🌍 123') + time.sleep(10 * time.millisecond) + p.stdin_write('\0x00') // 0 should break the input stream + time.sleep(10 * time.millisecond) + eprintln('>>> done') + }() + mut olines := []string{} + for p.is_alive() { + if oline := p.pipe_read(.stdout) { + olines << oline + } + time.sleep(1 * time.millisecond) + } + p.close() + p.wait() + assert p.code == 0 + eprintln('done') + solines := olines.join('\n').trim_space().replace('\r', '') + eprintln('solines.len: ${solines.len} | solines: ${solines}') + assert solines.len > 100 + assert solines == '> i: 0000 | r: `П` +> i: 0001 | r: `р` +> i: 0002 | r: `о` +> i: 0003 | r: `б` +> i: 0004 | r: `а` +> i: 0005 | r: ` ` +> i: 0006 | r: `A` +> i: 0007 | r: `b` +> i: 0008 | r: `c` +> i: 0009 | r: ` ` +> i: 0010 | r: `你` +> i: 0011 | r: `好` +> i: 0012 | r: ` ` +> i: 0013 | r: `🌍` +> i: 0014 | r: ` ` +> i: 0015 | r: `1` +> i: 0016 | r: `2` +> i: 0017 | r: `3`' +} diff --git a/vlib/builtin/string_charptr_byteptr_helpers.v b/vlib/builtin/string_charptr_byteptr_helpers.v index 8094db2a6c..a1a1226a8c 100644 --- a/vlib/builtin/string_charptr_byteptr_helpers.v +++ b/vlib/builtin/string_charptr_byteptr_helpers.v @@ -3,7 +3,7 @@ module builtin // Note: this file will be removed soon // byteptr.vbytes() - makes a V []u8 structure from a C style memory buffer. Note: the data is reused, NOT copied! -@[unsafe] +@[reused; unsafe] pub fn (data byteptr) vbytes(len int) []u8 { return unsafe { voidptr(data).vbytes(len) } } @@ -11,7 +11,7 @@ pub fn (data byteptr) vbytes(len int) []u8 { // vstring converts a C style string to a V string. Note: the string data is reused, NOT copied. // strings returned from this function will be normal V strings beside that (i.e. they would be // freed by V's -autofree mechanism, when they are no longer used). -@[unsafe] +@[reused; unsafe] pub fn (bp byteptr) vstring() string { return string{ str: bp @@ -21,7 +21,7 @@ pub fn (bp byteptr) vstring() string { // vstring_with_len converts a C style string to a V string. // Note: the string data is reused, NOT copied. -@[unsafe] +@[reused; unsafe] pub fn (bp byteptr) vstring_with_len(len int) string { return string{ str: bp @@ -32,7 +32,7 @@ pub fn (bp byteptr) vstring_with_len(len int) string { // vstring converts C char* to V string. // Note: the string data is reused, NOT copied. -@[unsafe] +@[reused; unsafe] pub fn (cp charptr) vstring() string { return string{ str: byteptr(cp) @@ -43,7 +43,7 @@ pub fn (cp charptr) vstring() string { // vstring_with_len converts C char* to V string. // Note: the string data is reused, NOT copied. -@[unsafe] +@[reused; unsafe] pub fn (cp charptr) vstring_with_len(len int) string { return string{ str: byteptr(cp) @@ -59,7 +59,7 @@ pub fn (cp charptr) vstring_with_len(len int) string { // This is suitable for readonly strings, C string literals etc, // that can be read by the V program, but that should not be // managed by it, for example `os.args` is implemented using it. -@[unsafe] +@[reused; unsafe] pub fn (bp byteptr) vstring_literal() string { return string{ str: bp @@ -70,7 +70,7 @@ pub fn (bp byteptr) vstring_literal() string { // vstring_with_len converts a C style string to a V string. // Note: the string data is reused, NOT copied. -@[unsafe] +@[reused; unsafe] pub fn (bp byteptr) vstring_literal_with_len(len int) string { return string{ str: bp @@ -82,7 +82,7 @@ pub fn (bp byteptr) vstring_literal_with_len(len int) string { // vstring_literal converts C char* to V string. // See also vstring_literal defined on byteptr for more details. // Note: the string data is reused, NOT copied. -@[unsafe] +@[reused; unsafe] pub fn (cp charptr) vstring_literal() string { return string{ str: byteptr(cp) @@ -94,7 +94,7 @@ pub fn (cp charptr) vstring_literal() string { // vstring_literal_with_len converts C char* to V string. // See also vstring_literal_with_len defined on byteptr. // Note: the string data is reused, NOT copied. -@[unsafe] +@[reused; unsafe] pub fn (cp charptr) vstring_literal_with_len(len int) string { return string{ str: byteptr(cp) diff --git a/vlib/orm/orm_test.v b/vlib/orm/orm_test.v index c6eebc747a..5b5be2180f 100644 --- a/vlib/orm/orm_test.v +++ b/vlib/orm/orm_test.v @@ -393,7 +393,9 @@ fn test_orm() { // Note: usually updated_time_mod.created != t, because t has // its microseconds set, while the value retrieved from the DB // has them zeroed, because the db field resolution is seconds. - assert modules.first().created.format_ss() == t.format_ss() + // Note: the database also stores the time in UTC, so the + // comparison must be done on the unix timestamp. + assert modules.first().created.unix() == t.unix() users = sql db { select from User where (name == 'Sam' && is_customer == true) || id == 1 diff --git a/vlib/os/os.c.v b/vlib/os/os.c.v index a2bef3f227..dceb76f5be 100644 --- a/vlib/os/os.c.v +++ b/vlib/os/os.c.v @@ -5,6 +5,10 @@ import strings #include // #include #include +$if macos { + #include +} + $if freebsd || openbsd { #include } @@ -715,7 +719,7 @@ pub fn executable() string { } $if macos { pid := C.getpid() - ret := proc_pidpath(pid, &result[0], max_path_len) + ret := C.proc_pidpath(pid, &result[0], max_path_len) if ret <= 0 { eprintln('os.executable() failed at calling proc_pidpath with pid: ${pid} . proc_pidpath returned ${ret} ') return executable_fallback() diff --git a/vlib/time/operator.v b/vlib/time/operator.v index 8c5fab8e89..8242e3444e 100644 --- a/vlib/time/operator.v +++ b/vlib/time/operator.v @@ -3,13 +3,16 @@ module time // operator `==` returns true if provided time is equal to time @[inline] pub fn (t1 Time) == (t2 Time) bool { - return t1.unix() == t2.unix() && t1.nanosecond == t2.nanosecond + return t1.is_local == t2.is_local && t1.local_unix() == t2.local_unix() + && t1.nanosecond == t2.nanosecond } // operator `<` returns true if provided time is less than time @[inline] pub fn (t1 Time) < (t2 Time) bool { - return t1.unix() < t2.unix() || (t1.unix() == t2.unix() && t1.nanosecond < t2.nanosecond) + t1u := t1.unix() + t2u := t2.unix() + return t1u < t2u || (t1u == t2u && t1.nanosecond < t2.nanosecond) } // Time subtract using operator overloading. diff --git a/vlib/time/private_test.c.v b/vlib/time/private_test.c.v deleted file mode 100644 index 7e69c40374..0000000000 --- a/vlib/time/private_test.c.v +++ /dev/null @@ -1,14 +0,0 @@ -// tests that use and test private functions -module time - -// test the old behavior is same as new, the unix time should always be local time -fn test_new_is_same_as_old_for_all_platforms() { - t := C.time(0) - tm := C.localtime(&t) - old_time := convert_ctime(tm, 0) - new_time := now() - diff := new_time.unix - old_time.unix - // could in very rare cases be that the second changed between calls - dump(diff) - assert (diff >= -2 && diff <= 2) == true -} diff --git a/vlib/time/time.v b/vlib/time/time.v index 9e18c8ef52..c9b1059a4d 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -106,6 +106,12 @@ pub fn (t Time) smonth() string { // unix returns the UNIX time with second resolution. @[inline] pub fn (t Time) unix() i64 { + return time_with_unix(t.local_to_utc()).unix +} + +// local_unix returns the UNIX local time with second resolution. +@[inline] +pub fn (t Time) local_unix() i64 { return time_with_unix(t).unix } @@ -135,14 +141,26 @@ pub fn (t Time) add(duration_in_nanosecond Duration) Time { // ... so instead, handle the addition manually in parts ¯\_(ツ)_/¯ mut increased_time_nanosecond := i64(t.nanosecond) + duration_in_nanosecond.nanoseconds() // increased_time_second - mut increased_time_second := t.unix() + (increased_time_nanosecond / second) + mut increased_time_second := t.local_unix() + (increased_time_nanosecond / second) increased_time_nanosecond = increased_time_nanosecond % second if increased_time_nanosecond < 0 { increased_time_second-- increased_time_nanosecond += second } res := unix_nanosecond(increased_time_second, int(increased_time_nanosecond)) - return if t.is_local { res.as_local() } else { res } + + if t.is_local { + // we need to reset unix to 0, because we don't know the offset + // and we can't calculate it without it without causing infinite recursion + // so unfortunately we need to recalculate unix next time it is needed + return Time{ + ...res + is_local: true + unix: 0 + } + } + + return res } // add_seconds returns a new time struct with an added number of seconds. @@ -177,7 +195,7 @@ pub fn since(t Time) Duration { // ``` pub fn (t Time) relative() string { znow := now() - mut secs := znow.unix - t.unix() + mut secs := znow.unix() - t.unix() mut prefix := '' mut suffix := '' if secs < 0 { @@ -239,7 +257,7 @@ pub fn (t Time) relative() string { // ``` pub fn (t Time) relative_short() string { znow := now() - mut secs := znow.unix - t.unix() + mut secs := znow.unix() - t.unix() mut prefix := '' mut suffix := '' if secs < 0 { @@ -364,9 +382,9 @@ pub fn days_in_month(month int, year int) !int { return res } -// debug returns detailed breakdown of time (`Time{ year: YYYY month: MM day: dd hour: HH: minute: mm second: ss nanosecond: nanos unix: unix }`). +// debug returns detailed breakdown of time (`Time{ year: YYYY month: MM day: dd hour: HH: minute: mm second: ss nanosecond: nanos unix: unix is_local: false }`). pub fn (t Time) debug() string { - return 'Time{ year: ${t.year:04} month: ${t.month:02} day: ${t.day:02} hour: ${t.hour:02} minute: ${t.minute:02} second: ${t.second:02} nanosecond: ${t.nanosecond:09} unix: ${t.unix:07} }' + return 'Time{ year: ${t.year:04} month: ${t.month:02} day: ${t.day:02} hour: ${t.hour:02} minute: ${t.minute:02} second: ${t.second:02} nanosecond: ${t.nanosecond:09} unix: ${t.unix:07} is_local: ${t.is_local} }' } // offset returns time zone UTC offset in seconds. diff --git a/vlib/time/time_format_test.v b/vlib/time/time_format_test.v index 8ca07ac5d4..f21be4061a 100644 --- a/vlib/time/time_format_test.v +++ b/vlib/time/time_format_test.v @@ -12,7 +12,7 @@ const time_to_test = time.Time{ fn test_now_format() { t := time.now() u := t.unix() - assert t.format() == time.unix(int(u)).format() + assert t.format() == time.unix(int(u)).utc_to_local().format() } fn test_format() { diff --git a/vlib/time/time_test.c.v b/vlib/time/time_test.c.v index 2222e1e2d6..7bf896608d 100644 --- a/vlib/time/time_test.c.v +++ b/vlib/time/time_test.c.v @@ -15,7 +15,7 @@ fn test_tm_gmtoff() { dump(t2) dump(t1.nanosecond) dump(t2.nanosecond) - diff := int(t1.unix() - t2.unix()) + diff := int(t1.local_unix() - t2.unix()) dump(diff) dump(info.tm_gmtoff) assert diff in [info.tm_gmtoff - 1, info.tm_gmtoff, info.tm_gmtoff + 1] diff --git a/vlib/time/time_test.v b/vlib/time/time_test.v index 34554cab82..e33b0e5c2e 100644 --- a/vlib/time/time_test.v +++ b/vlib/time/time_test.v @@ -90,17 +90,10 @@ fn test_unix() { assert t6.hour == 6 assert t6.minute == 9 assert t6.second == 29 - assert local_time_to_test.unix() == 332198622 assert utc_time_to_test.unix() == 332198622 } fn test_format_rfc3339() { - // assert '1980-07-11T19:23:42.123Z' - res := local_time_to_test.format_rfc3339() - assert res.ends_with('23:42.123Z') - assert res.starts_with('1980-07-1') - assert res.contains('T') - // assert '1980-07-11T19:23:42.123Z' utc_res := utc_time_to_test.format_rfc3339() assert utc_res.ends_with('23:42.123Z') @@ -109,11 +102,6 @@ fn test_format_rfc3339() { } fn test_format_rfc3339_micro() { - res := local_time_to_test.format_rfc3339_micro() - assert res.ends_with('23:42.123456Z') - assert res.starts_with('1980-07-1') - assert res.contains('T') - utc_res := utc_time_to_test.format_rfc3339_micro() assert utc_res.ends_with('23:42.123456Z') assert utc_res.starts_with('1980-07-1') @@ -121,11 +109,6 @@ fn test_format_rfc3339_micro() { } fn test_format_rfc3339_nano() { - res := local_time_to_test.format_rfc3339_nano() - assert res.ends_with('23:42.123456789Z') - assert res.starts_with('1980-07-1') - assert res.contains('T') - utc_res := utc_time_to_test.format_rfc3339_nano() assert utc_res.ends_with('23:42.123456789Z') assert utc_res.starts_with('1980-07-1') 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/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/gen/c/autofree.v b/vlib/v/gen/c/autofree.v index a4f88ae12a..21da98b50b 100644 --- a/vlib/v/gen/c/autofree.v +++ b/vlib/v/gen/c/autofree.v @@ -98,6 +98,21 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int if obj.expr is ast.IfGuardExpr { continue } + if obj.expr is ast.UnsafeExpr && obj.expr.expr is ast.CallExpr + && (obj.expr.expr as ast.CallExpr).is_method { + if left_var := scope.objects[obj.expr.expr.left.str()] { + if func := g.table.find_method(g.table.final_sym(left_var.typ), + obj.expr.expr.name) + { + if func.attrs.contains('reused') && left_var is ast.Var + && left_var.expr is ast.CastExpr { + if left_var.expr.expr.is_literal() { + continue + } + } + } + } + } g.autofree_variable(obj) } else {} diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 88571cd09a..c44b33b04d 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)};') @@ -780,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/gen/c/json.v b/vlib/v/gen/c/json.v index a7dccdd15f..e73cb202c6 100644 --- a/vlib/v/gen/c/json.v +++ b/vlib/v/gen/c/json.v @@ -417,7 +417,7 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st if variant_sym.kind == .enum { enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name('u64')}(*${var_data}${field_op}_${variant_typ}));') } else if variant_sym.name == 'time.Time' { - enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name('i64')}(${var_data}${field_op}_${variant_typ}->__v_unix));') + enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name('i64')}(time__Time_unix(*${var_data}${field_op}_${variant_typ})));') } else { enc.writeln('\t\tcJSON_AddItemToObject(o, "${unmangled_variant_name}", ${js_enc_name(variant_typ)}(*${var_data}${field_op}_${variant_typ}));') } @@ -442,7 +442,7 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st } } else if variant_sym.name == 'time.Time' { enc.writeln('\t\tcJSON_AddItemToObject(o, "_type", cJSON_CreateString("${unmangled_variant_name}"));') - enc.writeln('\t\tcJSON_AddItemToObject(o, "value", ${js_enc_name('i64')}(${var_data}${field_op}_${variant_typ}->__v_unix));') + enc.writeln('\t\tcJSON_AddItemToObject(o, "value", ${js_enc_name('i64')}(time__Time_unix(*${var_data}${field_op}_${variant_typ})));') } else { enc.writeln('\t\tcJSON_free(o);') enc.writeln('\t\to = ${js_enc_name(variant_typ)}(*${var_data}${field_op}_${variant_typ});') @@ -954,9 +954,9 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st // time struct requires special treatment // it has to be encoded as a unix timestamp number if is_option { - enc.writeln('${indent}cJSON_AddItemToObject(o, "${name}", json__encode_u64((*(${g.base_type(field.typ)}*)(${prefix_enc}${op}${c_name(field.name)}.data)).__v_unix));') + enc.writeln('${indent}cJSON_AddItemToObject(o, "${name}", json__encode_u64(time__Time_unix(*(${g.base_type(field.typ)}*)(${prefix_enc}${op}${c_name(field.name)}.data))));') } else { - enc.writeln('${indent}cJSON_AddItemToObject(o, "${name}", json__encode_u64(${prefix_enc}${op}${c_name(field.name)}.__v_unix));') + enc.writeln('${indent}cJSON_AddItemToObject(o, "${name}", json__encode_u64(time__Time_unix(${prefix_enc}${op}${c_name(field.name)})));') } } else { if !field.typ.is_any_kind_of_pointer() { diff --git a/vlib/v/gen/c/testdata/autofree_reused.c.must_have b/vlib/v/gen/c/testdata/autofree_reused.c.must_have new file mode 100644 index 0000000000..aa0d7004e1 --- /dev/null +++ b/vlib/v/gen/c/testdata/autofree_reused.c.must_have @@ -0,0 +1,10 @@ +VV_LOC void main__main(void) { + byteptr b = ((byteptr)("a")); + Array_u8 s = byteptr_vbytes(b, 1); + string _t1 = Array_u8_str(s); println(_t1); string_free(&_t1); + ; + byteptr bb = ((byteptr)("a")); + string ss = byteptr_vstring(bb); + println(ss); +} + diff --git a/vlib/v/gen/c/testdata/autofree_reused.out b/vlib/v/gen/c/testdata/autofree_reused.out new file mode 100644 index 0000000000..30ec3724e2 --- /dev/null +++ b/vlib/v/gen/c/testdata/autofree_reused.out @@ -0,0 +1,2 @@ +[97] +a diff --git a/vlib/v/gen/c/testdata/autofree_reused.vv b/vlib/v/gen/c/testdata/autofree_reused.vv new file mode 100644 index 0000000000..a4593f05db --- /dev/null +++ b/vlib/v/gen/c/testdata/autofree_reused.vv @@ -0,0 +1,10 @@ +// vtest vflags: -autofree +fn main() { + b := byteptr(c'a') + s := unsafe { b.vbytes(1) } + println(s) + + bb := byteptr(c'a') + ss := unsafe { bb.vstring() } + println(ss) +} 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 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() +} 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/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]() +} diff --git a/vlib/v/tests/runes.txt b/vlib/v/tests/runes.txt new file mode 100644 index 0000000000..6ab946b5e6 --- /dev/null +++ b/vlib/v/tests/runes.txt @@ -0,0 +1 @@ +Проба Abc 你好 🌍 123 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) }