From 6d97b0a4075ebd8d85da8b604aa24cf529cbb24a Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 29 Nov 2021 02:48:49 +0200 Subject: [PATCH] checker: improve checking of a << b, when a and b are numbers (#12589) --- examples/ttf_font/example_ttf.v | 2 +- vlib/builtin/int.v | 4 +- vlib/builtin/map.v | 2 +- vlib/builtin/string_interpolation.v | 4 +- vlib/builtin/utf8.v | 8 +- vlib/crypto/aes/block_generic.v | 18 +-- vlib/crypto/sha1/sha1block_generic.v | 2 +- vlib/crypto/sha256/sha256block_generic.v | 2 +- vlib/encoding/utf8/utf8_util.v | 4 +- vlib/gg/m4/matrix.v | 4 +- vlib/gx/color.v | 6 +- vlib/math/bits.v | 6 +- vlib/net/http/chunked/dechunk.v | 10 +- vlib/net/websocket/message.v | 4 +- vlib/net/websocket/websocket_client.v | 2 +- vlib/v/ast/ast.v | 5 + vlib/v/ast/types.v | 23 +-- vlib/v/builder/builder.v | 7 +- vlib/v/builder/c.v | 7 +- vlib/v/checker/check_types.v | 105 ++++++++++++-- vlib/v/checker/checker.v | 83 ++++++++--- .../tests/left_shift_op_expr_not_used.out | 49 ------- .../tests/selector_expr_optional_err.out | 12 +- .../tests/selector_expr_optional_err.vv | 10 +- .../v/checker/tests/shift_ops_expressions.out | 133 ++++++++++++++++++ ...r_not_used.vv => shift_ops_expressions.vv} | 36 ++++- vlib/v/gen/c/cgen.v | 12 +- vlib/v/gen/native/arm64.v | 4 +- vlib/v/gen/native/gen.v | 3 +- vlib/v/parser/parser.v | 11 +- vlib/v/transformer/transformer.v | 2 +- vlib/x/ttf/common.v | 2 +- vlib/x/ttf/ttf.v | 2 +- 33 files changed, 436 insertions(+), 148 deletions(-) delete mode 100644 vlib/v/checker/tests/left_shift_op_expr_not_used.out create mode 100644 vlib/v/checker/tests/shift_ops_expressions.out rename vlib/v/checker/tests/{left_shift_op_expr_not_used.vv => shift_ops_expressions.vv} (54%) diff --git a/examples/ttf_font/example_ttf.v b/examples/ttf_font/example_ttf.v index 02e43cd60b..e59ef06c08 100644 --- a/examples/ttf_font/example_ttf.v +++ b/examples/ttf_font/example_ttf.v @@ -99,7 +99,7 @@ But Vwill prevail for sure, V is the way!! txt1.create_texture() r := app.mouse_x % 255 g := app.mouse_y % 255 - color := u32(r << 24) | u32(g << 16) | 0xFF + color := u32(r) << 24 | u32(g) << 16 | 0xFF txt1.bmp.color = color txt1.draw_text_bmp(app.gg, app.mouse_x, app.mouse_y) } diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 43e66566a7..dfd623aa8c 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -57,7 +57,7 @@ fn (nn int) str_l(max int) string { for n > 0 { n1 := int(n / 100) // calculate the digit_pairs start index - d = ((int(n) - (n1 * 100)) << 1) + d = int(u32(int(n) - (n1 * 100)) << 1) n = n1 buf[index] = digit_pairs.str[d] index-- @@ -182,7 +182,7 @@ pub fn (nn i64) str() string { index-- for n > 0 { n1 := n / i64(100) - d = ((n - (n1 * i64(100))) << i64(1)) + d = (u32(n - (n1 * i64(100))) << i64(1)) n = n1 buf[index] = digit_pairs[d] index-- diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 8548d14ccb..a396d52105 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -363,7 +363,7 @@ fn (mut m map) ensure_extra_metas(probe_count u32) { // not equivalent to the key of any other element already in the container. // If the key already exists, its value is changed to the value of the new element. fn (mut m map) set(key voidptr, value voidptr) { - load_factor := f32(m.len << 1) / f32(m.even_index) + load_factor := f32(u32(m.len) << 1) / f32(m.even_index) if load_factor > max_load_factor { m.expand() } diff --git a/vlib/builtin/string_interpolation.v b/vlib/builtin/string_interpolation.v index ff2633dd13..b4ca6c21b9 100644 --- a/vlib/builtin/string_interpolation.v +++ b/vlib/builtin/string_interpolation.v @@ -130,7 +130,7 @@ pub fn get_str_intp_u64_format(fmt_type StrIntpType, in_width int, in_precision u64(0x7F) << 9 } tail_zeros := if in_tail_zeros { u32(1) << 16 } else { u32(0) } - base := u64((in_base & 0xf) << 27) + base := u64(u32(in_base & 0xf) << 27) res := u64((u64(fmt_type) & 0x1F) | allign | upper_case | sign | precision | tail_zeros | (u64(width & 0x3FF) << 17) | base | (u64(in_pad_ch) << 31)) return res } @@ -147,7 +147,7 @@ pub fn get_str_intp_u32_format(fmt_type StrIntpType, in_width int, in_precision u32(0x7F) << 9 } tail_zeros := if in_tail_zeros { u32(1) << 16 } else { u32(0) } - base := u32((in_base & 0xf) << 27) + base := u32(u32(in_base & 0xf) << 27) res := u32((u32(fmt_type) & 0x1F) | allign | upper_case | sign | precision | tail_zeros | (u32(width & 0x3FF) << 17) | base | (u32(in_pad_ch & 1) << 31)) return res } diff --git a/vlib/builtin/utf8.v b/vlib/builtin/utf8.v index 839c249d26..decf5724ac 100644 --- a/vlib/builtin/utf8.v +++ b/vlib/builtin/utf8.v @@ -71,15 +71,15 @@ pub fn (_rune string) utf32_code() int { // TODO should be // res := int( rune[0] << rune.len) b = b << _rune.len - mut res := int(b) + mut res := u32(b) mut shift := 6 - _rune.len for i := 1; i < _rune.len; i++ { - c := int(_rune[i]) - res = res << shift + c := u32(_rune[i]) + res = u32(res) << shift res |= c & 63 // 0x3f shift = 6 } - return res + return int(res) } // Calculate length to read from the first byte diff --git a/vlib/crypto/aes/block_generic.v b/vlib/crypto/aes/block_generic.v index 5da938e0d8..0219644e0f 100644 --- a/vlib/crypto/aes/block_generic.v +++ b/vlib/crypto/aes/block_generic.v @@ -69,10 +69,10 @@ fn encrypt_block_generic(xk []u32, mut dst []byte, src []byte) { s3 = t3 } // Last round uses s-box directly and XORs to produce output. - s0 = s_box0[t0 >> 24] << 24 | s_box0[t1 >> 16 & 0xff] << 16 | u32(s_box0[t2 >> 8 & 0xff] << 8) | s_box0[t3 & u32(0xff)] - s1 = s_box0[t1 >> 24] << 24 | s_box0[t2 >> 16 & 0xff] << 16 | u32(s_box0[t3 >> 8 & 0xff] << 8) | s_box0[t0 & u32(0xff)] - s2 = s_box0[t2 >> 24] << 24 | s_box0[t3 >> 16 & 0xff] << 16 | u32(s_box0[t0 >> 8 & 0xff] << 8) | s_box0[t1 & u32(0xff)] - s3 = s_box0[t3 >> 24] << 24 | s_box0[t0 >> 16 & 0xff] << 16 | u32(s_box0[t1 >> 8 & 0xff] << 8) | s_box0[t2 & u32(0xff)] + s0 = u32(s_box0[t0 >> 24]) << 24 | u32(s_box0[t1 >> 16 & 0xff]) << 16 | u32(s_box0[t2 >> 8 & 0xff]) << 8 | u32(s_box0[t3 & u32(0xff)]) + s1 = u32(s_box0[t1 >> 24]) << 24 | u32(s_box0[t2 >> 16 & 0xff]) << 16 | u32(s_box0[t3 >> 8 & 0xff]) << 8 | u32(s_box0[t0 & u32(0xff)]) + s2 = u32(s_box0[t2 >> 24]) << 24 | u32(s_box0[t3 >> 16 & 0xff]) << 16 | u32(s_box0[t0 >> 8 & 0xff]) << 8 | u32(s_box0[t1 & u32(0xff)]) + s3 = u32(s_box0[t3 >> 24]) << 24 | u32(s_box0[t0 >> 16 & 0xff]) << 16 | u32(s_box0[t1 >> 8 & 0xff]) << 8 | u32(s_box0[t2 & u32(0xff)]) s0 ^= xk[k + 0] s1 ^= xk[k + 1] s2 ^= xk[k + 2] @@ -116,10 +116,10 @@ fn decrypt_block_generic(xk []u32, mut dst []byte, src []byte) { s3 = t3 } // Last round uses s-box directly and XORs to produce output. - s0 = u32(s_box1[t0 >> 24]) << 24 | u32(s_box1[t3 >> 16 & 0xff]) << 16 | u32(s_box1[t2 >> 8 & 0xff] << 8) | u32(s_box1[t1 & u32(0xff)]) - s1 = u32(s_box1[t1 >> 24]) << 24 | u32(s_box1[t0 >> 16 & 0xff]) << 16 | u32(s_box1[t3 >> 8 & 0xff] << 8) | u32(s_box1[t2 & u32(0xff)]) - s2 = u32(s_box1[t2 >> 24]) << 24 | u32(s_box1[t1 >> 16 & 0xff]) << 16 | u32(s_box1[t0 >> 8 & 0xff] << 8) | u32(s_box1[t3 & u32(0xff)]) - s3 = u32(s_box1[t3 >> 24]) << 24 | u32(s_box1[t2 >> 16 & 0xff]) << 16 | u32(s_box1[t1 >> 8 & 0xff] << 8) | u32(s_box1[t0 & u32(0xff)]) + s0 = u32(s_box1[t0 >> 24]) << 24 | u32(s_box1[t3 >> 16 & 0xff]) << 16 | u32(s_box1[t2 >> 8 & 0xff]) << 8 | u32(s_box1[t1 & u32(0xff)]) + s1 = u32(s_box1[t1 >> 24]) << 24 | u32(s_box1[t0 >> 16 & 0xff]) << 16 | u32(s_box1[t3 >> 8 & 0xff]) << 8 | u32(s_box1[t2 & u32(0xff)]) + s2 = u32(s_box1[t2 >> 24]) << 24 | u32(s_box1[t1 >> 16 & 0xff]) << 16 | u32(s_box1[t0 >> 8 & 0xff]) << 8 | u32(s_box1[t3 & u32(0xff)]) + s3 = u32(s_box1[t3 >> 24]) << 24 | u32(s_box1[t2 >> 16 & 0xff]) << 16 | u32(s_box1[t1 >> 8 & 0xff]) << 8 | u32(s_box1[t0 & u32(0xff)]) s0 ^= xk[k + 0] s1 ^= xk[k + 1] s2 ^= xk[k + 2] @@ -133,7 +133,7 @@ fn decrypt_block_generic(xk []u32, mut dst []byte, src []byte) { // Apply s_box0 to each byte in w. fn subw(w u32) u32 { - return u32(s_box0[w >> 24]) << 24 | u32(s_box0[w >> 16 & 0xff] << 16) | u32(s_box0[w >> 8 & 0xff] << 8) | u32(s_box0[w & u32(0xff)]) + return u32(s_box0[w >> 24]) << 24 | u32(s_box0[w >> 16 & 0xff]) << 16 | u32(s_box0[w >> 8 & 0xff]) << 8 | u32(s_box0[w & u32(0xff)]) } // Rotate diff --git a/vlib/crypto/sha1/sha1block_generic.v b/vlib/crypto/sha1/sha1block_generic.v index a0dc92cb7a..1469bf0bf7 100644 --- a/vlib/crypto/sha1/sha1block_generic.v +++ b/vlib/crypto/sha1/sha1block_generic.v @@ -29,7 +29,7 @@ fn block_generic(mut dig Digest, p_ []byte) { // rounds below if needed for speed. for i in 0 .. 16 { j := i * 4 - w[i] = u32(p[j] << 24) | u32(p[j + 1] << 16) | u32(p[j + 2] << 8) | u32(p[j + 3]) + w[i] = u32(p[j]) << 24 | u32(p[j + 1]) << 16 | u32(p[j + 2]) << 8 | u32(p[j + 3]) } mut a := h0 mut b := h1 diff --git a/vlib/crypto/sha256/sha256block_generic.v b/vlib/crypto/sha256/sha256block_generic.v index e3989ccdba..f8d949fd26 100644 --- a/vlib/crypto/sha256/sha256block_generic.v +++ b/vlib/crypto/sha256/sha256block_generic.v @@ -95,7 +95,7 @@ fn block_generic(mut dig Digest, p_ []byte) { // rounds below if needed for speed. for i in 0 .. 16 { j := i * 4 - w[i] = u32(p[j] << 24) | u32(p[j + 1] << 16) | u32(p[j + 2] << 8) | u32(p[j + 3]) + w[i] = u32(p[j]) << 24 | u32(p[j + 1]) << 16 | u32(p[j + 2]) << 8 | u32(p[j + 3]) } for i := 16; i < 64; i++ { v1 := w[i - 2] diff --git a/vlib/encoding/utf8/utf8_util.v b/vlib/encoding/utf8/utf8_util.v index 88d2858eda..6b08caa213 100644 --- a/vlib/encoding/utf8/utf8_util.v +++ b/vlib/encoding/utf8/utf8_util.v @@ -46,7 +46,7 @@ pub fn get_uchar(s string, index int) int { if ch_len > 1 && ch_len < 5 { mut lword := 0 for i := 0; i < ch_len; i++ { - lword = (lword << 8) | int(s[index + i]) + lword = int(u32(lword) << 8 | u32(s[index + i])) } // 2 byte utf-8 @@ -416,7 +416,7 @@ fn up_low(s string, upper_flag bool) string { mut lword := 0 for i := 0; i < ch_len; i++ { - lword = (lword << 8) | int(s[index + i]) + lword = int(u32(lword) << 8 | u32(s[index + i])) } // println("#${index} ($lword)") diff --git a/vlib/gg/m4/matrix.v b/vlib/gg/m4/matrix.v index c839b9de48..2fa4ddfb9e 100644 --- a/vlib/gg/m4/matrix.v +++ b/vlib/gg/m4/matrix.v @@ -88,7 +88,7 @@ pub fn (x Mat4) get_e(elem_index int) f32 { // Get an element of the matrix using [0..3][0..3] indexes, two dimension pub fn (x Mat4) get_f(index_col int, index_row int) f32 { unsafe { - return x.e[(index_row << 2) + index_col] + return x.e[int(u32(index_row) << 2) + index_col] } } @@ -102,7 +102,7 @@ pub fn (mut x Mat4) set_e(index int, value f32) { // Set an element of the matrix using [0..3][0..3] indexes, two dimension pub fn (mut x Mat4) set_f(index_col int, index_row int, value f32) { unsafe { - x.e[(index_row << 2) + index_col] = value + x.e[int(u32(index_row) << 2) + index_col] = value } } diff --git a/vlib/gx/color.v b/vlib/gx/color.v index e50d9325db..aaec4016e5 100644 --- a/vlib/gx/color.v +++ b/vlib/gx/color.v @@ -187,21 +187,21 @@ pub fn (c Color) str() string { // see https://developer.apple.com/documentation/coreimage/ciformat [inline] pub fn (c Color) rgba8() int { - return (int(c.r) << 24) + (int(c.g) << 16) + (int(c.b) << 8) + int(c.a) + return int(u32(c.r) << 24 | u32(c.g) << 16 | u32(c.b) << 8 | u32(c.a)) } // bgra8 - convert a color value to an int in the BGRA8 order. // see https://developer.apple.com/documentation/coreimage/ciformat [inline] pub fn (c Color) bgra8() int { - return (int(c.b) << 24) + (int(c.g) << 16) + (int(c.r) << 8) + int(c.a) + return int(u32(c.b) << 24 | u32(c.g) << 16 | u32(c.r) << 8 | u32(c.a)) } // abgr8 - convert a color value to an int in the ABGR8 order. // see https://developer.apple.com/documentation/coreimage/ciformat [inline] pub fn (c Color) abgr8() int { - return (int(c.a) << 24) + (int(c.b) << 16) + (int(c.g) << 8) + int(c.r) + return int(u32(c.a) << 24 | u32(c.b) << 16 | u32(c.g) << 8 | u32(c.r)) } const ( diff --git a/vlib/math/bits.v b/vlib/math/bits.v index deaf96256b..f3795538ab 100644 --- a/vlib/math/bits.v +++ b/vlib/math/bits.v @@ -11,9 +11,9 @@ const ( mask = 0x7FF shift = 64 - 11 - 1 bias = 1023 - normalize_smallest_mask = (u64(1) << 52) - sign_mask = (u64(1) << 63) - frac_mask = ((u64(1) << u64(shift)) - u64(1)) + normalize_smallest_mask = u64(u64(1) << 52) + sign_mask = u64(0x8000000000000000) // (u64(1) << 63) + frac_mask = u64((u64(1) << u64(shift)) - u64(1)) ) // inf returns positive infinity if sign >= 0, negative infinity if sign < 0. diff --git a/vlib/net/http/chunked/dechunk.v b/vlib/net/http/chunked/dechunk.v index 0e82586e4c..d4507ebb77 100644 --- a/vlib/net/http/chunked/dechunk.v +++ b/vlib/net/http/chunked/dechunk.v @@ -14,8 +14,8 @@ mut: text string } -fn (mut s ChunkScanner) read_chunk_size() int { - mut n := 0 +fn (mut s ChunkScanner) read_chunk_size() u32 { + mut n := u32(0) for { if s.pos >= s.text.len { break @@ -25,7 +25,7 @@ fn (mut s ChunkScanner) read_chunk_size() int { break } n = n << 4 - n += int(unhex(c)) + n += u32(unhex(c)) s.pos++ } return n @@ -46,9 +46,9 @@ fn (mut s ChunkScanner) skip_crlf() { s.pos += 2 } -fn (mut s ChunkScanner) read_chunk(chunksize int) string { +fn (mut s ChunkScanner) read_chunk(chunksize u32) string { startpos := s.pos - s.pos += chunksize + s.pos += int(chunksize) return s.text[startpos..s.pos] } diff --git a/vlib/net/websocket/message.v b/vlib/net/websocket/message.v index 4c57232e92..1e45d04e47 100644 --- a/vlib/net/websocket/message.v +++ b/vlib/net/websocket/message.v @@ -252,8 +252,8 @@ pub fn (mut ws Client) parse_frame_header() ?Frame { if frame.payload_len == 126 && bytes_read == u64(websocket.extended_payload16_end_byte) { frame.header_len += 2 frame.payload_len = 0 - frame.payload_len |= buffer[2] << 8 - frame.payload_len |= buffer[3] + frame.payload_len |= int(u32(buffer[2]) << 8) + frame.payload_len |= int(buffer[3]) frame.frame_size = frame.header_len + frame.payload_len if !frame.has_mask { break diff --git a/vlib/net/websocket/websocket_client.v b/vlib/net/websocket/websocket_client.v index 48f8c5c8b1..4671175edb 100644 --- a/vlib/net/websocket/websocket_client.v +++ b/vlib/net/websocket/websocket_client.v @@ -177,7 +177,7 @@ pub fn (mut ws Client) listen() ? { ws.close(1002, 'close payload cannot be 1 byte') ? return error('close payload cannot be 1 byte') } - code := (int(msg.payload[0]) << 8) + int(msg.payload[1]) + code := u16(msg.payload[0]) << 8 | u16(msg.payload[1]) if code in invalid_close_codes { ws.close(1002, 'invalid close code: $code') ? return error('invalid close code: $code') diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index f2507e9a1d..a1846891de 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -767,6 +767,11 @@ pub mut: right_type Type auto_locked string or_block OrExpr + // + ct_left_value_evaled bool + ct_left_value ComptTimeConstValue = empty_comptime_const_expr() + ct_right_value_evaled bool + ct_right_value ComptTimeConstValue = empty_comptime_const_expr() } // ++, -- diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 135d0e3994..8888b7d85e 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -135,7 +135,7 @@ pub fn (t Type) atomic_typename() string { } pub fn sharetype_from_flags(is_shared bool, is_atomic bool) ShareType { - return ShareType((int(is_atomic) << 1) | int(is_shared)) + return ShareType(int(u32(is_atomic) << 1) | int(is_shared)) } pub fn (t Type) share() ShareType { @@ -183,7 +183,7 @@ pub fn (t Type) set_nr_muls(nr_muls int) Type { if nr_muls < 0 || nr_muls > 255 { panic('set_nr_muls: nr_muls must be between 0 & 255') } - return int(t) & 0xff00ffff | (nr_muls << 16) + return int(t) & 0xff00ffff | int(u32(nr_muls) << 16) } // increments nr_muls on `t` and return it @@ -193,7 +193,7 @@ pub fn (t Type) ref() Type { if nr_muls == 255 { panic('ref: nr_muls is already at max of 255') } - return int(t) & 0xff00ffff | ((nr_muls + 1) << 16) + return int(t) & 0xff00ffff | int(u32(nr_muls + 1) << 16) } // decrement nr_muls on `t` and return it @@ -203,7 +203,7 @@ pub fn (t Type) deref() Type { if nr_muls == 0 { panic('deref: type `$t` is not a pointer') } - return int(t) & 0xff00ffff | ((nr_muls - 1) << 16) + return int(t) & 0xff00ffff | int(u32(nr_muls - 1) << 16) } // set `flag` on `t` and return `t` @@ -320,7 +320,7 @@ pub fn new_type_ptr(idx int, nr_muls int) Type { if nr_muls < 0 || nr_muls > 255 { panic('new_type_ptr: nr_muls must be between 0 & 255') } - return (nr_muls << 16) | u16(idx) + return (u32(nr_muls) << 16) | u16(idx) } [inline] @@ -438,14 +438,15 @@ pub const ( integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, u8_type_idx, u16_type_idx, u32_type_idx, u64_type_idx, isize_type_idx, usize_type_idx, int_literal_type_idx, rune_type_idx] - signed_integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, - isize_type_idx] - unsigned_integer_type_idxs = [byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx, - usize_type_idx] + signed_integer_type_idxs = [char_type_idx, i8_type_idx, i16_type_idx, int_type_idx, + i64_type_idx, isize_type_idx] + unsigned_integer_type_idxs = [byte_type_idx, u8_type_idx, u16_type_idx, u32_type_idx, + u64_type_idx, usize_type_idx] float_type_idxs = [f32_type_idx, f64_type_idx, float_literal_type_idx] number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, - byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx, isize_type_idx, usize_type_idx, - f32_type_idx, f64_type_idx, int_literal_type_idx, float_literal_type_idx, rune_type_idx] + byte_type_idx, char_type_idx, u16_type_idx, u32_type_idx, u64_type_idx, isize_type_idx, + usize_type_idx, f32_type_idx, f64_type_idx, int_literal_type_idx, float_literal_type_idx, + rune_type_idx] pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx] string_type_idxs = [string_type_idx] ) diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index 200a32ae09..2c02e875e7 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -90,7 +90,7 @@ pub fn (mut b Builder) front_stages(v_files []string) ? { timers.show('PARSE') timers.show_if_exists('PARSE stmt') if b.pref.only_check_syntax { - return error('stop_after_parser') + return error_with_code('stop_after_parser', 9999) } } @@ -104,8 +104,11 @@ pub fn (mut b Builder) middle_stages() ? { b.checker.check_files(b.parsed_files) util.timing_measure('CHECK') b.print_warnings_and_errors() + if b.checker.should_abort { + return error('too many errors/warnings/notices') + } if b.pref.check_only { - return error('stop_after_checker') + return error_with_code('stop_after_checker', 9999) } util.timing_start('TRANSFORM') b.transformer.transform_files(b.parsed_files) diff --git a/vlib/v/builder/c.v b/vlib/v/builder/c.v index 4058923dec..977fbc868c 100644 --- a/vlib/v/builder/c.v +++ b/vlib/v/builder/c.v @@ -6,7 +6,12 @@ import v.util import v.gen.c pub fn (mut b Builder) gen_c(v_files []string) string { - b.front_and_middle_stages(v_files) or { return '' } + b.front_and_middle_stages(v_files) or { + if err.code != 9999 { + verror(err.msg) + } + return '' + } // TODO: move gen.cgen() to c.gen() util.timing_start('C GEN') res := c.gen(b.parsed_files, b.table, b.pref) diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 736c17dba1..3e121eab0d 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -176,25 +176,113 @@ pub fn (mut c Checker) check_matching_function_symbols(got_type_sym &ast.TypeSym return true } -[inline] -fn (mut c Checker) check_shift(left_type ast.Type, right_type ast.Type, left_pos token.Position, right_pos token.Position) ast.Type { +fn (mut c Checker) check_shift(mut node ast.InfixExpr, left_type ast.Type, right_type ast.Type) ast.Type { if !left_type.is_int() { + left_sym := c.table.get_type_symbol(left_type) // maybe it's an int alias? TODO move this to is_int() ? - sym := c.table.get_type_symbol(left_type) - if sym.kind == .alias && (sym.info as ast.Alias).parent_type.is_int() { + if left_sym.kind == .alias && (left_sym.info as ast.Alias).parent_type.is_int() { return left_type } if c.pref.translated && left_type == ast.bool_type { // allow `bool << 2` in translated C code return ast.int_type } - c.error('invalid operation: shift on type `$sym.name`', left_pos) + c.error('invalid operation: shift on type `$left_sym.name`', node.left.position()) return ast.void_type - } else if !right_type.is_int() { - c.error('cannot shift non-integer type `${c.table.get_type_symbol(right_type).name}` into type `${c.table.get_type_symbol(left_type).name}`', - right_pos) + } + if !right_type.is_int() { + left_sym := c.table.get_type_symbol(left_type) + right_sym := c.table.get_type_symbol(right_type) + c.error('cannot shift non-integer type `$right_sym.name` into type `$left_sym.name`', + node.right.position()) return ast.void_type } + // At this point, it is guaranteed that we have a `number1 << number2`, or `number1 >> number2`, or `number1 >>> number2`: + if !node.ct_left_value_evaled { + if lval := c.eval_comptime_const_expr(node.left, 0) { + node.ct_left_value_evaled = true + node.ct_left_value = lval + } + } + if !node.ct_right_value_evaled { + if rval := c.eval_comptime_const_expr(node.right, 0) { + node.ct_right_value_evaled = true + node.ct_right_value = rval + } + } + // if node.ct_left_value_evaled && node.ct_right_value_evaled { + // c.note('>>> node.ct_left_value: $node.ct_left_value | node.ct_right_value: $node.ct_right_value', node.pos) + // } + match node.op { + .left_shift, .right_shift, .unsigned_right_shift { + // The following code tries to disallow C UBs and IDs at the V level. + // From the C++ standart (see https://pvs-studio.com/en/docs/warnings/v610/): + // 1. The type of the result is that of the promoted left operand. + // The behavior is undefined (UB), if the right operand is negative, + // or greater than or equal to the length in bits of the promoted left operand. + // 2. The value of E1 << E2 is E1 left-shifted E2 bit positions; + // vacated bits are zero-filled. If E1 has an unsigned type, + // the value of the result is E1 * 2^E2, reduced modulo one more + // than the maximum value representable in the result type. + // Otherwise, if E1 has a signed type and non-negative value, + // and E1*2^E2 is representable in the result type, then that is + // the resulting value; otherwise, the behavior is undefined (UB). + // 3. The value of E1 >> E2 is E1 right-shifted E2 bit positions. + // If E1 has an unsigned type, or if E1 has a signed type and a + // non-negative value, the value of the result is the integral + // part of the quotient of E1/2^E2. If E1 has a signed type and + // a negative value, the resulting value is implementation-defined (ID). + left_sym_final := c.table.get_final_type_symbol(left_type) + left_type_final := ast.Type(left_sym_final.idx) + if node.op == .left_shift && left_type_final.is_signed() { + c.note('shifting a value from a signed type `$left_sym_final.name` can change the sign', + node.left.position()) + } + if node.ct_right_value_evaled { + if node.ct_right_value !is ast.EmptyExpr { + ival := node.ct_right_value.i64() or { -999 } + if ival < 0 { + c.error('invalid negative shift count', node.right.position()) + return left_type + } + moffset := match left_type_final { + ast.char_type { 7 } + ast.i8_type { 7 } + ast.i16_type { 15 } + ast.int_type { 31 } + ast.i64_type { 63 } + // + ast.byte_type { 7 } + ast.u8_type { 7 } + ast.u16_type { 15 } + ast.u32_type { 31 } + ast.u64_type { 63 } + else { 64 } + } + if ival > moffset { + c.error('shift count for type `$left_sym_final.name` too large (maximum: $moffset bits)', + node.right.position()) + return left_type + } + if node.ct_left_value_evaled { + if lval := node.ct_left_value.i64() { + if lval < 0 { + c.error('invalid bitshift of a negative number', node.left.position()) + return left_type + } + } + } + } else { + // c.note('can not evaluate "$node.right" at comptime, err: $err', node.pos) + return left_type + } + } + } + else { + c.error('unknown shift operator: $node.op', node.pos) + return left_type + } + } return left_type } @@ -339,7 +427,6 @@ pub fn (mut c Checker) check_expected(got ast.Type, expected ast.Type) ? { } } -[inline] fn (c &Checker) expected_msg(got ast.Type, expected ast.Type) string { exps := c.table.type_to_str(expected) gots := c.table.type_to_str(got) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 1081b343b7..daeeeeba39 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1370,11 +1370,11 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { c.error('cannot append `$right_sym.name` to `$left_sym.name`', right_pos) return ast.void_type } else { - return c.check_shift(left_type, right_type, left_pos, right_pos) + return c.check_shift(mut node, left_type, right_type) } } .right_shift { - return c.check_shift(left_type, right_type, left_pos, right_pos) + return c.check_shift(mut node, left_type, right_type) } .unsigned_right_shift { modified_left_type := if !left_type.is_int() { @@ -1418,7 +1418,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { or_block: node.or_block } - return c.check_shift(left_type, right_type, left_pos, right_pos) + return c.check_shift(mut node, left_type, right_type) } .key_is, .not_is { right_expr := node.right @@ -3700,7 +3700,7 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) { c.const_decl = field.name c.const_deps << field.name mut typ := c.check_expr_opt_call(field.expr, c.expr(field.expr)) - if ct_value := eval_comptime_const_expr(field.expr, 0) { + if ct_value := c.eval_comptime_const_expr(field.expr, 0) { field.comptime_expr_value = ct_value if ct_value is u64 { typ = ast.u64_type @@ -4539,7 +4539,7 @@ pub fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { } ast.Ident { if init_expr.obj is ast.ConstField { - if comptime_value := eval_comptime_const_expr(init_expr.obj.expr, + if comptime_value := c.eval_comptime_const_expr(init_expr.obj.expr, 0) { fixed_size = comptime_value.i64() or { fixed_size } @@ -4549,7 +4549,7 @@ pub fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { } } ast.InfixExpr { - if comptime_value := eval_comptime_const_expr(init_expr, 0) { + if comptime_value := c.eval_comptime_const_expr(init_expr, 0) { fixed_size = comptime_value.i64() or { fixed_size } } } @@ -5294,6 +5294,9 @@ fn (mut c Checker) stmts_ending_with_expression(stmts []ast.Stmt) { } c.scope_returns = false } + if c.should_abort { + return + } } c.stmt_level-- if unreachable.line_nr >= 0 { @@ -8590,12 +8593,49 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Position) ? { } // comptime const eval -fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue { +fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue { if nlevel > 100 { // protect against a too deep comptime eval recursion return none } match expr { + ast.ParExpr { + return c.eval_comptime_const_expr(expr.expr, nlevel + 1) + } + // ast.EnumVal { + // c.note('>>>>>>>> expr: $expr', expr.pos) + // return expr.val.i64() + // } + ast.SizeOf { + xtype := expr.typ + if xtype.is_real_pointer() { + if c.pref.m64 { + return 8 // 64bit platform + } + return 4 // 32bit platform + } + if int(xtype) == xtype.idx() { + match xtype { + ast.char_type { return 1 } + ast.i8_type { return 1 } + ast.i16_type { return 2 } + ast.int_type { return 4 } + ast.i64_type { return 8 } + // + ast.byte_type { return 1 } + ast.u8_type { return 1 } + ast.u16_type { return 2 } + ast.u32_type { return 4 } + ast.u64_type { return 8 } + else {} + } + } + return none + } + ast.FloatLiteral { + x := expr.val.f64() + return x + } ast.IntegerLiteral { x := expr.val.u64() if x > 9223372036854775807 { @@ -8616,11 +8656,11 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue ast.Ident { if expr.obj is ast.ConstField { // an existing constant? - return eval_comptime_const_expr(expr.obj.expr, nlevel + 1) + return c.eval_comptime_const_expr(expr.obj.expr, nlevel + 1) } } ast.CastExpr { - cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none } + cast_expr_value := c.eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none } if expr.typ == ast.i8_type { return cast_expr_value.i8() or { return none } } @@ -8655,8 +8695,8 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue } } ast.InfixExpr { - left := eval_comptime_const_expr(expr.left, nlevel + 1) ? - right := eval_comptime_const_expr(expr.right, nlevel + 1) ? + left := c.eval_comptime_const_expr(expr.left, nlevel + 1) ? + right := c.eval_comptime_const_expr(expr.right, nlevel + 1) ? if left is string && right is string { match expr.op { .plus { @@ -8676,8 +8716,9 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue .xor { return i64(left) ^ i64(right) } .pipe { return i64(left) | i64(right) } .amp { return i64(left) & i64(right) } - .left_shift { return i64(left) << i64(right) } - .right_shift { return i64(left) >> i64(right) } + .left_shift { return i64(u64(left) << i64(right)) } + .right_shift { return i64(u64(left) >> i64(right)) } + .unsigned_right_shift { return i64(u64(left) >>> i64(right)) } else { return none } } } else if left is i64 && right is u64 { @@ -8690,8 +8731,9 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue .xor { return i64(left) ^ i64(right) } .pipe { return i64(left) | i64(right) } .amp { return i64(left) & i64(right) } - .left_shift { return i64(left) << i64(right) } - .right_shift { return i64(left) >> i64(right) } + .left_shift { return i64(u64(left) << i64(right)) } + .right_shift { return i64(u64(left) >> i64(right)) } + .unsigned_right_shift { return i64(u64(left) >>> i64(right)) } else { return none } } } else if left is u64 && right is u64 { @@ -8706,6 +8748,7 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue .amp { return left & right } .left_shift { return left << right } .right_shift { return left >> right } + .unsigned_right_shift { return left >>> right } else { return none } } } else if left is i64 && right is i64 { @@ -8718,8 +8761,9 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue .xor { return left ^ right } .pipe { return left | right } .amp { return left & right } - .left_shift { return left << right } - .right_shift { return left >> right } + .left_shift { return i64(u64(left) << right) } + .right_shift { return i64(u64(left) >> right) } + .unsigned_right_shift { return i64(u64(left) >>> right) } else { return none } } } else if left is byte && right is byte { @@ -8734,10 +8778,15 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue .amp { return left & right } .left_shift { return left << right } .right_shift { return left >> right } + .unsigned_right_shift { return left >>> right } else { return none } } } } + // ast.ArrayInit {} + // ast.PrefixExpr { + // c.note('prefixexpr: $expr', expr.pos) + // } else { // eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ') return none diff --git a/vlib/v/checker/tests/left_shift_op_expr_not_used.out b/vlib/v/checker/tests/left_shift_op_expr_not_used.out deleted file mode 100644 index 5f2390efd1..0000000000 --- a/vlib/v/checker/tests/left_shift_op_expr_not_used.out +++ /dev/null @@ -1,49 +0,0 @@ -vlib/v/checker/tests/left_shift_op_expr_not_used.vv:4:2: error: unused expression - 2 | mut a := 12 - 3 | mut arr := []int{} - 4 | a << 1 - | ~~~~~~ - 5 | if true { - 6 | a << 2 -vlib/v/checker/tests/left_shift_op_expr_not_used.vv:6:3: error: unused expression - 4 | a << 1 - 5 | if true { - 6 | a << 2 - | ~~~~~~ - 7 | } - 8 | c := if true { a << 111 } else { a << 333 } -vlib/v/checker/tests/left_shift_op_expr_not_used.vv:10:2: error: unused expression - 8 | c := if true { a << 111 } else { a << 333 } - 9 | println(c) - 10 | a << 1 - | ~~~~~~ - 11 | println(a) - 12 | 5 << 9 -vlib/v/checker/tests/left_shift_op_expr_not_used.vv:12:2: error: unused expression - 10 | a << 1 - 11 | println(a) - 12 | 5 << 9 - | ~~~~~~ - 13 | for i in 0 .. 10 { - 14 | z := i << 5 -vlib/v/checker/tests/left_shift_op_expr_not_used.vv:15:3: error: unused expression - 13 | for i in 0 .. 10 { - 14 | z := i << 5 - 15 | i << 5 - | ~~~~~~ - 16 | println(z) - 17 | } -vlib/v/checker/tests/left_shift_op_expr_not_used.vv:33:3: error: unused expression - 31 | // - 32 | x := if true { - 33 | a << 1 - | ~~~~~~ - 34 | 999 - 35 | } else { -vlib/v/checker/tests/left_shift_op_expr_not_used.vv:37:3: error: unused expression - 35 | } else { - 36 | println('---') - 37 | a << 9999 - | ~~~~~~~~~ - 38 | println('---') - 39 | 555 diff --git a/vlib/v/checker/tests/selector_expr_optional_err.out b/vlib/v/checker/tests/selector_expr_optional_err.out index 51065b74a6..f79a9fb5ac 100644 --- a/vlib/v/checker/tests/selector_expr_optional_err.out +++ b/vlib/v/checker/tests/selector_expr_optional_err.out @@ -1,6 +1,6 @@ -vlib/v/checker/tests/selector_expr_optional_err.vv:4:46: error: cannot access fields of an optional, handle the error with `or {...}` or propagate it with `?` - 2 | - 3 | fn main() { - 4 | println(http.get('https://httpbin.org/').status_code) - | ~~~~~~~~~~~ - 5 | } +vlib/v/checker/tests/selector_expr_optional_err.vv:10:16: error: cannot access fields of an optional, handle the error with `or {...}` or propagate it with `?` + 8 | + 9 | fn main() { + 10 | println(abc().status_code) + | ~~~~~~~~~~~ + 11 | } diff --git a/vlib/v/checker/tests/selector_expr_optional_err.vv b/vlib/v/checker/tests/selector_expr_optional_err.vv index d277787b7a..4bee55b40a 100644 --- a/vlib/v/checker/tests/selector_expr_optional_err.vv +++ b/vlib/v/checker/tests/selector_expr_optional_err.vv @@ -1,5 +1,11 @@ -import net.http +struct HttpResult { + status_code int +} + +fn abc() ?HttpResult { + return HttpResult{} +} fn main() { - println(http.get('https://httpbin.org/').status_code) + println(abc().status_code) } diff --git a/vlib/v/checker/tests/shift_ops_expressions.out b/vlib/v/checker/tests/shift_ops_expressions.out new file mode 100644 index 0000000000..7823c17689 --- /dev/null +++ b/vlib/v/checker/tests/shift_ops_expressions.out @@ -0,0 +1,133 @@ +vlib/v/checker/tests/shift_ops_expressions.vv:4:2: notice: shifting a value from a signed type `int` can change the sign + 2 | mut a := 12 + 3 | mut arr := []int{} + 4 | a << 1 + | ^ + 5 | if true { + 6 | a << 2 +vlib/v/checker/tests/shift_ops_expressions.vv:6:3: notice: shifting a value from a signed type `int` can change the sign + 4 | a << 1 + 5 | if true { + 6 | a << 2 + | ^ + 7 | } + 8 | c := if true { a << 111 } else { a << 333 } +vlib/v/checker/tests/shift_ops_expressions.vv:8:17: notice: shifting a value from a signed type `int` can change the sign + 6 | a << 2 + 7 | } + 8 | c := if true { a << 111 } else { a << 333 } + | ^ + 9 | println(c) + 10 | a << 1 +vlib/v/checker/tests/shift_ops_expressions.vv:8:17: notice: shifting a value from a signed type `int` can change the sign + 6 | a << 2 + 7 | } + 8 | c := if true { a << 111 } else { a << 333 } + | ^ + 9 | println(c) + 10 | a << 1 +vlib/v/checker/tests/shift_ops_expressions.vv:8:35: notice: shifting a value from a signed type `int` can change the sign + 6 | a << 2 + 7 | } + 8 | c := if true { a << 111 } else { a << 333 } + | ^ + 9 | println(c) + 10 | a << 1 +vlib/v/checker/tests/shift_ops_expressions.vv:8:35: notice: shifting a value from a signed type `int` can change the sign + 6 | a << 2 + 7 | } + 8 | c := if true { a << 111 } else { a << 333 } + | ^ + 9 | println(c) + 10 | a << 1 +vlib/v/checker/tests/shift_ops_expressions.vv:10:2: notice: shifting a value from a signed type `int` can change the sign + 8 | c := if true { a << 111 } else { a << 333 } + 9 | println(c) + 10 | a << 1 + | ^ + 11 | println(a) + 12 | 5 << 9 +vlib/v/checker/tests/shift_ops_expressions.vv:33:3: notice: shifting a value from a signed type `int` can change the sign + 31 | // + 32 | x := if true { + 33 | a << 1 + | ^ + 34 | 999 + 35 | } else { +vlib/v/checker/tests/shift_ops_expressions.vv:37:3: notice: shifting a value from a signed type `int` can change the sign + 35 | } else { + 36 | println('---') + 37 | a << 9999 + | ^ + 38 | println('---') + 39 | 555 +vlib/v/checker/tests/shift_ops_expressions.vv:4:2: error: unused expression + 2 | mut a := 12 + 3 | mut arr := []int{} + 4 | a << 1 + | ~~~~~~ + 5 | if true { + 6 | a << 2 +vlib/v/checker/tests/shift_ops_expressions.vv:6:3: error: unused expression + 4 | a << 1 + 5 | if true { + 6 | a << 2 + | ~~~~~~ + 7 | } + 8 | c := if true { a << 111 } else { a << 333 } +vlib/v/checker/tests/shift_ops_expressions.vv:8:22: error: shift count for type `int` too large (maximum: 31 bits) + 6 | a << 2 + 7 | } + 8 | c := if true { a << 111 } else { a << 333 } + | ~~~ + 9 | println(c) + 10 | a << 1 +vlib/v/checker/tests/shift_ops_expressions.vv:10:2: error: unused expression + 8 | c := if true { a << 111 } else { a << 333 } + 9 | println(c) + 10 | a << 1 + | ~~~~~~ + 11 | println(a) + 12 | 5 << 9 +vlib/v/checker/tests/shift_ops_expressions.vv:12:2: error: unused expression + 10 | a << 1 + 11 | println(a) + 12 | 5 << 9 + | ~~~~~~ + 13 | for i in 0 .. 10 { + 14 | z := i << 5 +vlib/v/checker/tests/shift_ops_expressions.vv:15:3: error: unused expression + 13 | for i in 0 .. 10 { + 14 | z := i << 5 + 15 | i << 5 + | ~~~~~~ + 16 | println(z) + 17 | } +vlib/v/checker/tests/shift_ops_expressions.vv:33:3: error: unused expression + 31 | // + 32 | x := if true { + 33 | a << 1 + | ~~~~~~ + 34 | 999 + 35 | } else { +vlib/v/checker/tests/shift_ops_expressions.vv:37:8: error: shift count for type `int` too large (maximum: 31 bits) + 35 | } else { + 36 | println('---') + 37 | a << 9999 + | ~~~~ + 38 | println('---') + 39 | 555 +vlib/v/checker/tests/shift_ops_expressions.vv:50:23: error: shift count for type `int` too large (maximum: 31 bits) + 48 | rr >> 2 + 49 | } + 50 | c := if true { rr >> 111 } else { rr >> 333 } + | ~~~ + 51 | println(c) + 52 | rr >> 1 +vlib/v/checker/tests/shift_ops_expressions.vv:66:9: error: shift count for type `int` too large (maximum: 31 bits) + 64 | } else { + 65 | println('---') + 66 | rr >> 9999 + | ~~~~ + 67 | println('---') + 68 | 555 diff --git a/vlib/v/checker/tests/left_shift_op_expr_not_used.vv b/vlib/v/checker/tests/shift_ops_expressions.vv similarity index 54% rename from vlib/v/checker/tests/left_shift_op_expr_not_used.vv rename to vlib/v/checker/tests/shift_ops_expressions.vv index 82eb2324ad..709aac155b 100644 --- a/vlib/v/checker/tests/left_shift_op_expr_not_used.vv +++ b/vlib/v/checker/tests/shift_ops_expressions.vv @@ -1,4 +1,4 @@ -fn main() { +fn left_shifts() { mut a := 12 mut arr := []int{} a << 1 @@ -40,3 +40,37 @@ fn main() { } println(x) } + +fn right_shifts() { + mut rr := 12 + rr >> 1 + if true { + rr >> 2 + } + c := if true { rr >> 111 } else { rr >> 333 } + println(c) + rr >> 1 + println(rr) + 5 >> 9 + for i in 0 .. 10 { + z := i >> 5 + i >> 5 + println(z) + } + // + x := if true { + rr >> 1 + 999 + } else { + println('---') + rr >> 9999 + println('---') + 555 + } + println(x) +} + +fn main() { + left_shifts() + right_shifts() +} diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 1a06979ca1..c49e645b39 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2220,7 +2220,7 @@ struct SumtypeCastingFn { fn (mut g Gen) get_sumtype_casting_fn(got_ ast.Type, exp_ ast.Type) string { got, exp := got_.idx(), exp_.idx() - i := got | (exp << 16) + i := got | int(u32(exp) << 16) got_cname, exp_cname := g.table.get_type_symbol(got).cname, g.table.get_type_symbol(exp).cname fn_name := '${got_cname}_to_sumtype_$exp_cname' if got == exp || g.sumtype_definitions[i] { @@ -2961,6 +2961,16 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { } } // `a := 1` | `a,b := 1,2` + if assign_stmt.right.len < assign_stmt.left.len { + g.checker_bug('assign_stmt.right.len < assign_stmt.left.len', assign_stmt.pos) + } + if assign_stmt.right_types.len < assign_stmt.left.len { + g.checker_bug('assign_stmt.right_types.len < assign_stmt.left.len', assign_stmt.pos) + } + if assign_stmt.left_types.len < assign_stmt.left.len { + g.checker_bug('assign_stmt.left_types.len < assign_stmt.left.len', assign_stmt.pos) + } + for i, left in assign_stmt.left { mut is_auto_heap := false mut var_type := assign_stmt.left_types[i] diff --git a/vlib/v/gen/native/arm64.v b/vlib/v/gen/native/arm64.v index 74b8f8ccea..0a1e11bb5f 100644 --- a/vlib/v/gen/native/arm64.v +++ b/vlib/v/gen/native/arm64.v @@ -58,7 +58,7 @@ fn (mut g Gen) mov_arm(reg Arm64Register, val u64) { g.write32(0xd2800020) g.println('mov x0, 1') } else if r >= 0 && r <= 16 { - g.write32(0xd2800000 + int(r) + (int(val) << 5)) + g.write32(int(u32(0xd2800000 + int(r) + int(val)) << 5)) g.println('mov x$r, $val') } else { g.n_error('mov_arm unsupported values') @@ -143,7 +143,7 @@ fn (mut g Gen) gen_arm64_helloworld() { } fn (mut g Gen) adr(r Arm64Register, delta int) { - g.write32(0x10000000 | int(r) | (delta << 4)) + g.write32(int(0x10000000 | int(r) | int(u32(delta) << 4))) g.println('adr $r, $delta') } diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 74911f37fe..f412cb19e2 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -200,7 +200,8 @@ fn (mut g Gen) write16(n int) { } fn (mut g Gen) read32_at(at int) int { - return int(g.buf[at] | (g.buf[at + 1] << 8) | (g.buf[at + 2] << 16) | (g.buf[at + 3] << 24)) + return int(u32(g.buf[at]) | (u32(g.buf[at + 1]) << 8) | (u32(g.buf[at + 2]) << 16) | (u32(g.buf[ + at + 3]) << 24)) } fn (mut g Gen) write32(n int) { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 727ac76234..0fbf91e99b 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1808,11 +1808,14 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt { } else if !p.pref.translated && !p.pref.is_fmt && tok.kind !in [.key_if, .key_match, .key_lock, .key_rlock, .key_select] { for node in left { - if node !is ast.CallExpr && (is_top_level || p.tok.kind != .rcbr) - && node !is ast.PostfixExpr && !(node is ast.InfixExpr - && (node as ast.InfixExpr).op in [.left_shift, .arrow]) && node !is ast.ComptimeCall + if (is_top_level || p.tok.kind != .rcbr) && node !is ast.CallExpr + && node !is ast.PostfixExpr && node !is ast.ComptimeCall && node !is ast.SelectorExpr && node !is ast.DumpExpr { - return p.error_with_pos('expression evaluated but not used', node.position()) + is_complex_infix_expr := node is ast.InfixExpr + && (node as ast.InfixExpr).op in [.left_shift, .right_shift, .unsigned_right_shift, .arrow] + if !is_complex_infix_expr { + return p.error_with_pos('expression evaluated but not used', node.position()) + } } } } diff --git a/vlib/v/transformer/transformer.v b/vlib/v/transformer/transformer.v index 06c5fa3fbb..5f7f0e7fa6 100644 --- a/vlib/v/transformer/transformer.v +++ b/vlib/v/transformer/transformer.v @@ -481,7 +481,7 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr { } .left_shift { return ast.IntegerLiteral{ - val: (left_val << right_val).str() + val: (u32(left_val) << right_val).str() pos: pos } } diff --git a/vlib/x/ttf/common.v b/vlib/x/ttf/common.v index ad88d33e3f..d83ac6dccf 100644 --- a/vlib/x/ttf/common.v +++ b/vlib/x/ttf/common.v @@ -72,7 +72,7 @@ fn (mut bmp BitMap) format_texture() { x[i + 1] = g x[i + 2] = b // alpha - x[i + 3] = byte((a * data) >> 8) + x[i + 3] = byte(u16(a * data) >> 8) } else { x[i + 0] = b_r x[i + 1] = b_g diff --git a/vlib/x/ttf/ttf.v b/vlib/x/ttf/ttf.v index f482cc56c7..8c719a4dda 100644 --- a/vlib/x/ttf/ttf.v +++ b/vlib/x/ttf/ttf.v @@ -501,7 +501,7 @@ fn (mut tf TTF_File) get_i8() i8 { } fn (mut tf TTF_File) get_u16() u16 { - x := u16(tf.buf[tf.pos] << u16(8)) | u16(tf.buf[tf.pos + 1]) + x := u16(tf.buf[tf.pos]) << 8 | u16(tf.buf[tf.pos + 1]) tf.pos += 2 return x }