checker: improve checking of a << b, when a and b are numbers (#12589)

pull/12608/head
Delyan Angelov 2021-11-29 02:48:49 +02:00 committed by GitHub
parent fe37da31a8
commit 6d97b0a407
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 436 additions and 148 deletions

View File

@ -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)
}

View File

@ -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--

View File

@ -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()
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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)")

View File

@ -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
}
}

View File

@ -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 (

View File

@ -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.

View File

@ -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]
}

View File

@ -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

View File

@ -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')

View File

@ -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()
}
// ++, --

View File

@ -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]
)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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 | }

View File

@ -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)
}

View File

@ -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

View File

@ -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()
}

View File

@ -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]

View File

@ -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')
}

View File

@ -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) {

View File

@ -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())
}
}
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}