diff --git a/.github/workflows/wasm_backend_ci.yml b/.github/workflows/wasm_backend_ci.yml index f0689d2d5a6553..ecda008c92cecd 100644 --- a/.github/workflows/wasm_backend_ci.yml +++ b/.github/workflows/wasm_backend_ci.yml @@ -47,9 +47,9 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04, macos-12, windows-2022] + os: [ubuntu-22.04, windows-2022] fail-fast: false - timeout-minutes: 121 + timeout-minutes: 10 env: VTEST_ONLY: wasm steps: diff --git a/GNUmakefile b/GNUmakefile index 60be65369a3e0a..4779b3d75fc120 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -144,7 +144,10 @@ fresh_vc: ifndef local latest_tcc: $(TMPTCC)/.git/config cd $(TMPTCC) && $(GITCLEANPULL) +ifneq (,$(wildcard ./tcc.exe)) @$(MAKE) --quiet check_for_working_tcc 2> /dev/null +endif + else latest_tcc: @echo "Using local tcc" @@ -161,7 +164,6 @@ ifneq (,$(findstring thirdparty-$(TCCOS)-$(TCCARCH), $(shell git ls-remote --hea else @echo 'Pre-built TCC not available for thirdparty-$(TCCOS)-$(TCCARCH) at $(TCCREPO), will use the system compiler: $(CC)' $(GITFASTCLONE) --branch thirdparty-unknown-unknown $(TCCREPO) $(TMPTCC) - @$(MAKE) --quiet check_for_working_tcc 2> /dev/null endif else @echo "Using local tccbin" diff --git a/cmd/tools/vtest-all.v b/cmd/tools/vtest-all.v index e00b5d16162c4d..3ac76c4ea9ece0 100644 --- a/cmd/tools/vtest-all.v +++ b/cmd/tools/vtest-all.v @@ -402,6 +402,13 @@ fn get_all_commands() []Command { rmfile: 'v.c' } } + $if linux || macos { + res << Command{ + line: '${vexe} -gc none -no-retry-compilation -cc tcc -d use_openssl -showcc examples/veb/todo/main.v' + okmsg: 'A simple veb app, compiles with `-gc none -no-retry-compilation -cc tcc -d use_openssl` on macos and linux' + rmfile: 'examples/veb/todo/main' + } + } $if linux { res << Command{ line: '${vexe} vlib/v/tests/bench/bench_stbi_load.v && prlimit -v10485760 vlib/v/tests/bench/bench_stbi_load' diff --git a/doc/docs.md b/doc/docs.md index 454735e36878ad..f98c800683af72 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -5632,6 +5632,40 @@ fn main() { } ``` +```v +// @[_allow_multiple_values] allows an enum to have multiple duplicate values. +// Use it carefully, only when you really need it. + +@[_allow_multiple_values] +enum ButtonStyle { + primary = 1 + secondary = 2 + success = 3 + + blurple = 1 + grey = 2 + gray = 2 + green = 3 +} + +fn main() { + assert int(ButtonStyle.primary) == 1 + assert int(ButtonStyle.blurple) == 1 + + assert int(ButtonStyle.secondary) == 2 + assert int(ButtonStyle.gray) == 2 + assert int(ButtonStyle.grey) == 2 + + assert int(ButtonStyle.success) == 3 + assert int(ButtonStyle.green) == 3 + + assert ButtonStyle.primary == ButtonStyle.blurple + assert ButtonStyle.secondary == ButtonStyle.grey + assert ButtonStyle.secondary == ButtonStyle.gray + assert ButtonStyle.success == ButtonStyle.green +} +``` + Struct field deprecations: ```v oksyntax diff --git a/thirdparty/mbedtls/include/mbedtls/check_config.h b/thirdparty/mbedtls/include/mbedtls/check_config.h index 04e43e39d7d8be..8a8f098f293be5 100644 --- a/thirdparty/mbedtls/include/mbedtls/check_config.h +++ b/thirdparty/mbedtls/include/mbedtls/check_config.h @@ -23,6 +23,12 @@ #ifndef MBEDTLS_CHECK_CONFIG_H #define MBEDTLS_CHECK_CONFIG_H +#if ( defined(__TINYC__) && defined(__APPLE__) && defined(__arm64__) ) +#undef MBEDTLS_HAVE_ASM +#undef MBEDTLS_AESNI_C +#undef MBEDTLS_PADLOCK_C +#endif + /* * We assume CHAR_BIT is 8 in many places. In practice, this is true on our * target platforms, so not an issue, but let's just be extra sure. diff --git a/thirdparty/zip/miniz.h b/thirdparty/zip/miniz.h index d120ce8726a6b5..aa5f991f456f6f 100644 --- a/thirdparty/zip/miniz.h +++ b/thirdparty/zip/miniz.h @@ -5026,7 +5026,7 @@ static int mz_mkdir(const char *pDirname) { } #ifndef MINIZ_NO_TIME -#if (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)) && !defined(FREEBSD) +#if ( defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)) && !defined(FREEBSD) #include #else #include @@ -5073,7 +5073,7 @@ static int mz_mkdir(const char *pDirname) { #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME -#if (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)) && !defined(FREEBSD) +#if ( defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)) && !defined(FREEBSD) #include #else #include diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index bcf8067414777e..32d37a2a6d3918 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -1721,9 +1721,9 @@ pub fn (s string) trim(cutset string) string { return s.clone() } if cutset.len_utf8() == cutset.len { - return s.trim_chars(cutset) + return s.trim_chars(cutset, .trim_both) } else { - return s.trim_runes(cutset) + return s.trim_runes(cutset, .trim_both) } } @@ -1757,25 +1757,35 @@ pub fn (s string) trim_indexes(cutset string) (int, int) { return pos_left, pos_right + 1 } +enum TrimMode { + trim_left + trim_right + trim_both +} + @[direct_array_access] -fn (s string) trim_chars(cutset string) string { +fn (s string) trim_chars(cutset string, mode TrimMode) string { mut pos_left := 0 mut pos_right := s.len - 1 mut cs_match := true for pos_left <= s.len && pos_right >= -1 && cs_match { cs_match = false - for cs in cutset { - if s[pos_left] == cs { - pos_left++ - cs_match = true - break + if mode in [.trim_left, .trim_both] { + for cs in cutset { + if s[pos_left] == cs { + pos_left++ + cs_match = true + break + } } } - for cs in cutset { - if s[pos_right] == cs { - pos_right-- - cs_match = true - break + if mode in [.trim_right, .trim_both] { + for cs in cutset { + if s[pos_right] == cs { + pos_right-- + cs_match = true + break + } } } if pos_left > pos_right { @@ -1786,7 +1796,7 @@ fn (s string) trim_chars(cutset string) string { } @[direct_array_access] -fn (s string) trim_runes(cutset string) string { +fn (s string) trim_runes(cutset string, mode TrimMode) string { s_runes := s.runes() c_runes := cutset.runes() mut pos_left := 0 @@ -1794,18 +1804,22 @@ fn (s string) trim_runes(cutset string) string { mut cs_match := true for pos_left <= s_runes.len && pos_right >= -1 && cs_match { cs_match = false - for cs in c_runes { - if s_runes[pos_left] == cs { - pos_left++ - cs_match = true - break + if mode in [.trim_left, .trim_both] { + for cs in c_runes { + if s_runes[pos_left] == cs { + pos_left++ + cs_match = true + break + } } } - for cs in c_runes { - if s_runes[pos_right] == cs { - pos_right-- - cs_match = true - break + if mode in [.trim_right, .trim_both] { + for cs in c_runes { + if s_runes[pos_right] == cs { + pos_right-- + cs_match = true + break + } } } if pos_left > pos_right { @@ -1822,21 +1836,11 @@ pub fn (s string) trim_left(cutset string) string { if s == '' || cutset == '' { return s.clone() } - mut pos := 0 - for pos < s.len { - mut found := false - for cs in cutset { - if s[pos] == cs { - found = true - break - } - } - if !found { - break - } - pos++ + if cutset.len_utf8() == cutset.len { + return s.trim_chars(cutset, .trim_left) + } else { + return s.trim_runes(cutset, .trim_left) } - return s[pos..] } // trim_right strips any of the characters given in `cutset` from the right of the string. @@ -1846,23 +1850,11 @@ pub fn (s string) trim_right(cutset string) string { if s.len < 1 || cutset.len < 1 { return s.clone() } - mut pos := s.len - 1 - for pos >= 0 { - mut found := false - for cs in cutset { - if s[pos] == cs { - found = true - } - } - if !found { - break - } - pos-- - } - if pos < 0 { - return '' + if cutset.len_utf8() == cutset.len { + return s.trim_chars(cutset, .trim_right) + } else { + return s.trim_runes(cutset, .trim_right) } - return s[..pos + 1] } // trim_string_left strips `str` from the start of the string. diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index 0ca43da0d4ef3b..23fe52d51bc7e5 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -943,6 +943,7 @@ fn test_trim_left() { s = 'banana' assert s.trim_left('ba') == 'nana' assert s.trim_left('ban') == '' + assert 'あいうえお'.trim_left('あい') == 'うえお' } fn test_trim_right() { @@ -954,6 +955,7 @@ fn test_trim_right() { s = 'banana' assert s.trim_right('na') == 'b' assert s.trim_right('ban') == '' + assert 'あいうえお'.trim_right('うえお') == 'あい' } fn test_all_before() { diff --git a/vlib/crypto/rand/rand_darwin.c.v b/vlib/crypto/rand/rand_darwin.c.v index 1053753c657ddb..60158af3164225 100644 --- a/vlib/crypto/rand/rand_darwin.c.v +++ b/vlib/crypto/rand/rand_darwin.c.v @@ -4,16 +4,14 @@ module rand -#include +#include -#flag darwin -framework Security - -fn C.SecRandomCopyBytes(rnd C.SecRandomRef, count usize, bytes voidptr) int +fn C.getentropy(buf voidptr, buflen usize) int // read returns an array of `bytes_needed` random bytes read from the OS. pub fn read(bytes_needed int) ![]u8 { mut buffer := []u8{len: bytes_needed} - status := C.SecRandomCopyBytes(C.SecRandomRef(0), bytes_needed, buffer.data) + status := C.getentropy(buffer.data, bytes_needed) if status != 0 { return &ReadError{} } diff --git a/vlib/crypto/scrypt/scrypt_test.v b/vlib/crypto/scrypt/scrypt_test.v index a1020b5da61ce3..1c5c9dcd1588a0 100644 --- a/vlib/crypto/scrypt/scrypt_test.v +++ b/vlib/crypto/scrypt/scrypt_test.v @@ -203,6 +203,9 @@ struct ScryptTestData { expected_result []u8 } +// The scrypt test vectors are taken from +// [RFC7914](https://datatracker.ietf.org/doc/html/rfc7914#section-12) +// section 12. const scrypt_test_cases = [ ScryptTestData{ name: 'test case 1' diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 10f3c8e7780723..022f5ab0acaf44 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1975,6 +1975,7 @@ fn (mut c Checker) enum_decl(mut node ast.EnumDecl) { field.pos) } else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed && ilast + 1 in iseen { + c.add_error_detail('use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed') c.error('enum value `${ilast + 1}` already exists', field.pos) } iseen << ilast + 1 @@ -1989,6 +1990,7 @@ fn (mut c Checker) enum_decl(mut node ast.EnumDecl) { field.pos) } else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed && ulast + 1 in useen { + c.add_error_detail('use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed') c.error('enum value `${ulast + 1}` already exists', field.pos) } useen << ulast + 1 @@ -2038,6 +2040,7 @@ fn (mut c Checker) check_enum_field_integer_literal(expr ast.IntegerLiteral, is_ } if !overflows && !c.pref.translated && !c.file.is_translated && !is_multi_allowed { if (is_signed && ival in iseen) || (!is_signed && uval in useen) { + c.add_error_detail('use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed') c.error('enum value `${expr.val}` already exists', pos) } } diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index d1ca514c0e2cfb..4c12e7816d6e54 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -350,6 +350,8 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { } } } + } else { + c.error('`${t_sym.name}` is not an interface type', t.pos) } c.type_implements(struct_type, t.typ, node.pos) } diff --git a/vlib/v/checker/tests/enum_field_value_duplicate_a.out b/vlib/v/checker/tests/enum_field_value_duplicate_a.out index ce72e698673eb7..5d8651cede64da 100644 --- a/vlib/v/checker/tests/enum_field_value_duplicate_a.out +++ b/vlib/v/checker/tests/enum_field_value_duplicate_a.out @@ -5,9 +5,11 @@ vlib/v/checker/tests/enum_field_value_duplicate_a.vv:3:10: error: enum value `0` | ^ 4 | blue = 1 5 | alpha = 1 +Details: use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed vlib/v/checker/tests/enum_field_value_duplicate_a.vv:5:10: error: enum value `1` already exists 3 | green = 0 4 | blue = 1 5 | alpha = 1 | ^ 6 | } +Details: use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed diff --git a/vlib/v/checker/tests/enum_field_value_duplicate_b.out b/vlib/v/checker/tests/enum_field_value_duplicate_b.out index c1a9ae2ab8cb68..c9e20ab46b82cc 100644 --- a/vlib/v/checker/tests/enum_field_value_duplicate_b.out +++ b/vlib/v/checker/tests/enum_field_value_duplicate_b.out @@ -4,3 +4,4 @@ vlib/v/checker/tests/enum_field_value_duplicate_b.vv:4:2: error: enum value `0` 4 | blue // -1 + 1 = 0 | ~~~~ 5 | } +Details: use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed diff --git a/vlib/v/checker/tests/enum_field_value_duplicate_c.out b/vlib/v/checker/tests/enum_field_value_duplicate_c.out index 65bbc0b2cf3a60..27b908dc0ca818 100644 --- a/vlib/v/checker/tests/enum_field_value_duplicate_c.out +++ b/vlib/v/checker/tests/enum_field_value_duplicate_c.out @@ -5,3 +5,4 @@ vlib/v/checker/tests/enum_field_value_duplicate_c.vv:6:12: error: enum value `1` | ~~~~~~~~ 7 | all = 0xFFFFFFFF 8 | } +Details: use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed diff --git a/vlib/v/checker/tests/enum_field_value_duplicate_d.out b/vlib/v/checker/tests/enum_field_value_duplicate_d.out index b4350c326e08a8..b8b1071ce1770d 100644 --- a/vlib/v/checker/tests/enum_field_value_duplicate_d.out +++ b/vlib/v/checker/tests/enum_field_value_duplicate_d.out @@ -5,3 +5,4 @@ vlib/v/checker/tests/enum_field_value_duplicate_d.vv:6:6: error: enum value `1` | ~~~ 7 | } 8 | +Details: use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed diff --git a/vlib/v/checker/tests/enum_field_value_duplicate_e.out b/vlib/v/checker/tests/enum_field_value_duplicate_e.out index 93314f28d6b647..4e9db5ec0918ac 100644 --- a/vlib/v/checker/tests/enum_field_value_duplicate_e.out +++ b/vlib/v/checker/tests/enum_field_value_duplicate_e.out @@ -5,3 +5,4 @@ vlib/v/checker/tests/enum_field_value_duplicate_e.vv:4:6: error: enum value `2` | ~~~ 5 | } 6 | +Details: use `@[_allow_multiple_values]` attribute to allow multiple enum values. Use only when it is needed diff --git a/vlib/v/checker/tests/struct_implements_non_interface_err.out b/vlib/v/checker/tests/struct_implements_non_interface_err.out new file mode 100644 index 00000000000000..d0f5f88c590120 --- /dev/null +++ b/vlib/v/checker/tests/struct_implements_non_interface_err.out @@ -0,0 +1,5 @@ +vlib/v/checker/tests/struct_implements_non_interface_err.vv:1:26: error: `Abcde` is not an interface type + 1 | struct Walker implements Abcde { + | ~~~~~ + 2 | aaa string + 3 | } diff --git a/vlib/v/checker/tests/struct_implements_non_interface_err.vv b/vlib/v/checker/tests/struct_implements_non_interface_err.vv new file mode 100644 index 00000000000000..55d570d5e56608 --- /dev/null +++ b/vlib/v/checker/tests/struct_implements_non_interface_err.vv @@ -0,0 +1,5 @@ +struct Walker implements Abcde { + aaa string +} + +fn main() {}