checker: restrict numeric promotions to cases where no data is lost

pull/5062/head
Uwe Krüger 2020-05-27 05:42:48 +02:00 committed by GitHub
parent fc67046bac
commit 013fdb8a4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 510 additions and 247 deletions

View File

@ -50,7 +50,7 @@ pub fn new_test_session(_vargs string) TestSession {
skip_files: skip_files skip_files: skip_files
vargs: vargs vargs: vargs
show_ok_tests: !_vargs.contains('-silent') show_ok_tests: !_vargs.contains('-silent')
message_handler: 0 message_handler: &TestMessageHandler(0)
} }
} }

View File

@ -269,6 +269,8 @@ rune // represents a Unicode code point
f32 f64 f32 f64
any_int, any_float // internal intermediate types of number literals
byteptr // these two are mostly used for C interop byteptr // these two are mostly used for C interop
voidptr voidptr
@ -277,6 +279,27 @@ any // similar to C's void* and Go's interface{}
Please note that unlike C and Go, `int` is always a 32 bit integer. Please note that unlike C and Go, `int` is always a 32 bit integer.
There is an exceptions to the rule that all operators
in V must have values of the same type on both sides. A small primitive type
on one side can be automatically promoted if it fits
completely into the data range of the type on the other side, i.e. when
the promotion does not result in any data loss.
These are the allowed possibilities:
```
i8 → i16 → int → i64
↘ ↘
f32 → f64
↗ ↗
byte → u16 → u32 → u64 ⬎
↘ ↘ ↘ ptr
i8 → i16 → int → i64 ⬏
```
An `int` value for example can be automatically promoted to `f64`
or `i64` but not to `f32` or `u32`. (`f32` would mean precission
loss for large values and `u32` would mean loss of the sign for
negative values).
## Strings ## Strings
```v ```v

View File

@ -360,9 +360,9 @@ pub fn (b []byte) hex() string {
mut dst_i := 0 mut dst_i := 0
for i in b { for i in b {
n0 := i >> 4 n0 := i >> 4
hex[dst_i++] = if n0 < 10 { n0 + `0` } else { n0 + 87 } hex[dst_i++] = if n0 < 10 { n0 + `0` } else { n0 + byte(87) }
n1 := i & 0xF n1 := i & 0xF
hex[dst_i++] = if n1 < 10 { n1 + `0` } else { n1 + 87 } hex[dst_i++] = if n1 < 10 { n1 + `0` } else { n1 + byte(87) }
} }
hex[dst_i] = `\0` hex[dst_i] = `\0`
return tos(hex,dst_i) return tos(hex,dst_i)

View File

@ -468,6 +468,10 @@ fn test_in() {
assert !(0 in a) assert !(0 in a)
assert 0 !in a assert 0 !in a
assert 4 !in a assert 4 !in a
b := [1, 4, 0]
c := [3, 6, 2, 0]
assert 0 in b
assert 0 in c
} }
fn sum(prev int, curr int) int { fn sum(prev int, curr int) int {
@ -557,7 +561,7 @@ fn test_map() {
assert strs.map(it.to_upper()) == ['V', 'IS', 'AWESOME'] assert strs.map(it.to_upper()) == ['V', 'IS', 'AWESOME']
assert strs.map(it == 'awesome') == [false, false, true] assert strs.map(it == 'awesome') == [false, false, true]
assert strs.map(it.len in nums) == [true, true, false] assert strs.map(it.len in nums) == [true, true, false]
assert strs.map(7) == [7, 7, 7] assert strs.map(int(7)) == [7, 7, 7]
// external func // external func
assert nums.map(map_test_helper_1(it)) == [1, 4, 9, 16, 25, 36] assert nums.map(map_test_helper_1(it)) == [1, 4, 9, 16, 25, 36]
@ -568,9 +572,9 @@ fn test_map() {
assert []int{len:0}.map(it * 2) == [] assert []int{len:0}.map(it * 2) == []
// nested maps (where it is of same type) // nested maps (where it is of same type)
assert nums.map( strs.map(7) == [7, 7, 7] ) == [true, true, true, true, true, true] assert nums.map( strs.map(int(7)) == [7, 7, 7] ) == [true, true, true, true, true, true]
assert nums.map( '$it' + strs.map('a')[0] ) == ['1a', '2a', '3a', '4a', '5a', '6a'] assert nums.map( '$it' + strs.map('a')[0] ) == ['1a', '2a', '3a', '4a', '5a', '6a']
assert nums.map( it + strs.map(7)[0] ) == [8, 9, 10, 11, 12, 13] assert nums.map( it + strs.map(int(7))[0] ) == [8, 9, 10, 11, 12, 13]
assert nums.map( it + strs.map(it.len)[0] ) == [2, 3, 4, 5, 6, 7] assert nums.map( it + strs.map(it.len)[0] ) == [2, 3, 4, 5, 6, 7]
assert strs.map( it.len + strs.map(it.len)[0] ) == [2, 3, 8] assert strs.map( it.len + strs.map(it.len)[0] ) == [2, 3, 8]

View File

@ -13,6 +13,17 @@ pub fn (d f64) str() string {
return ftoa.ftoa_64(d) return ftoa.ftoa_64(d)
} }
[inline]
pub fn (d any_float) str() string {
x := f64(d)
abs_x := f64_abs(x)
if abs_x >= 0.01 && abs_x < 1.0e16 {
return ftoa.f64_to_str_l(x)
} else {
return ftoa.ftoa_64(x)
}
}
// return a string of the input f64 in scientific notation with digit_num deciamals displayed, max 17 digits // return a string of the input f64 in scientific notation with digit_num deciamals displayed, max 17 digits
[inline] [inline]
pub fn (x f64) strsci(digit_num int) string { pub fn (x f64) strsci(digit_num int) string {
@ -84,7 +95,7 @@ pub fn (a f64) eq(b f64) bool {
[inline] [inline]
pub fn (a f32) eq(b f32) bool { pub fn (a f32) eq(b f32) bool {
return f32_abs(a - b) <= C.FLT_EPSILON return f32_abs(a - b) <= f32(C.FLT_EPSILON)
} }
pub fn (a f64) eqbit(b f64) bool { pub fn (a f64) eqbit(b f64) bool {

View File

@ -144,6 +144,11 @@ pub fn (nn u32) str() string {
//return tos(buf + index, (max-index)) //return tos(buf + index, (max-index))
} }
[inline]
pub fn (n any_int) str() string {
return i64(n).str()
}
pub fn (nn i64) str() string { pub fn (nn i64) str() string {
mut n := nn mut n := nn
mut d := i64(0) mut d := i64(0)
@ -188,7 +193,7 @@ pub fn (nn i64) str() string {
pub fn (nn u64) str() string { pub fn (nn u64) str() string {
mut n := nn mut n := nn
mut d := 0 mut d := u64(0)
if n == 0 { if n == 0 {
return '0' return '0'
} }
@ -274,7 +279,7 @@ pub fn (nn u16) hex() string {
mut index := max mut index := max
buf[index--] = `\0` buf[index--] = `\0`
for n > 0 { for n > 0 {
d := n & 0xF d := byte(n & 0xF)
n = n >> 4 n = n >> 4
buf[index--] = if d < 10 { d + `0` } else { d + 87 } buf[index--] = if d < 10 { d + `0` } else { d + 87 }
} }
@ -301,7 +306,7 @@ pub fn (nn u32) hex() string {
mut index := max mut index := max
buf[index--] = `\0` buf[index--] = `\0`
for n > 0 { for n > 0 {
d := n & 0xF d := byte(n & 0xF)
n = n >> 4 n = n >> 4
buf[index--] = if d < 10 { d + `0` } else { d + 87 } buf[index--] = if d < 10 { d + `0` } else { d + 87 }
} }
@ -328,7 +333,7 @@ pub fn (nn u64) hex() string {
mut index := max mut index := max
buf[index--] = `\0` buf[index--] = `\0`
for n > 0 { for n > 0 {
d := n & 0xF d := byte(n & 0xF)
n = n >> 4 n = n >> 4
buf[index--] = if d < 10 { d + `0` } else { d + 87 } buf[index--] = if d < 10 { d + `0` } else { d + 87 }
} }
@ -345,6 +350,10 @@ pub fn (nn i64) hex() string {
return u64(nn).hex() return u64(nn).hex()
} }
pub fn (nn any_int) hex() string {
return u64(nn).hex()
}
pub fn (nn voidptr) str() string { pub fn (nn voidptr) str() string {
return u64(nn).hex() return u64(nn).hex()
} }

View File

@ -214,7 +214,7 @@ fn test_int_to_hex() {
assert u32(c0).hex() == 'c' assert u32(c0).hex() == 'c'
assert 2147483647.hex() == '7fffffff' assert 2147483647.hex() == '7fffffff'
assert u32(2147483647).hex() == '7fffffff' assert u32(2147483647).hex() == '7fffffff'
assert (-1).hex() == 'ffffffff' assert (-1).hex() == 'ffffffffffffffff'
assert u32(4294967295).hex() == 'ffffffff' assert u32(4294967295).hex() == 'ffffffff'
// 64 bit // 64 bit
assert u64(0).hex() == '0' assert u64(0).hex() == '0'

View File

@ -123,22 +123,22 @@ fn (mut d DenseArray) push(key string, value voidptr) u32 {
if d.cap == d.size { if d.cap == d.size {
d.cap += d.cap >> 3 d.cap += d.cap >> 3
d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap)) d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
d.values = C.realloc(d.values, d.value_bytes * d.cap) d.values = C.realloc(d.values, u32(d.value_bytes) * d.cap)
} }
push_index := d.size push_index := d.size
d.keys[push_index] = key d.keys[push_index] = key
C.memcpy(d.values + push_index * d.value_bytes, value, d.value_bytes) C.memcpy(d.values + push_index * u32(d.value_bytes), value, d.value_bytes)
d.size++ d.size++
return push_index return push_index
} }
fn (d DenseArray) get(i int) voidptr { fn (d DenseArray) get(i int) voidptr {
$if !no_bounds_checking? { $if !no_bounds_checking? {
if i < 0 || i >= d.size { if i < 0 || i >= int(d.size) {
panic('DenseArray.get: index out of range (i == $i, d.len == $d.size)') panic('DenseArray.get: index out of range (i == $i, d.len == $d.size)')
} }
} }
return byteptr(d.keys) + i * sizeof(string) return byteptr(d.keys) + i * int(sizeof(string))
} }
// Move all zeros to the end of the array // Move all zeros to the end of the array
@ -153,8 +153,8 @@ fn (mut d DenseArray) zeros_to_end() {
d.keys[count] = d.keys[i] d.keys[count] = d.keys[i]
d.keys[i] = tmp_key d.keys[i] = tmp_key
// swap values (TODO: optimize) // swap values (TODO: optimize)
C.memcpy(tmp_value, d.values + count * d.value_bytes, d.value_bytes) C.memcpy(tmp_value, d.values + count * u32(d.value_bytes), d.value_bytes)
C.memcpy(d.values + count * d.value_bytes, d.values + i * d.value_bytes, d.value_bytes) C.memcpy(d.values + count * u32(d.value_bytes), d.values + i * d.value_bytes, d.value_bytes)
C.memcpy(d.values + i * d.value_bytes, tmp_value, d.value_bytes) C.memcpy(d.values + i * d.value_bytes, tmp_value, d.value_bytes)
count++ count++
} }
@ -164,7 +164,7 @@ fn (mut d DenseArray) zeros_to_end() {
d.size = count d.size = count
d.cap = if count < 8 { u32(8) } else { count } d.cap = if count < 8 { u32(8) } else { count }
d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap)) d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
d.values = C.realloc(d.values, d.value_bytes * d.cap) d.values = C.realloc(d.values, u32(d.value_bytes) * d.cap)
} }
pub struct map { pub struct map {
@ -280,7 +280,7 @@ fn (mut m map) set(k string, value voidptr) {
for meta == m.metas[index] { for meta == m.metas[index] {
kv_index := m.metas[index + 1] kv_index := m.metas[index + 1]
if fast_string_eq(key, m.key_values.keys[kv_index]) { if fast_string_eq(key, m.key_values.keys[kv_index]) {
C.memcpy(m.key_values.values + kv_index * m.value_bytes , value, m.value_bytes) C.memcpy(m.key_values.values + kv_index * u32(m.value_bytes), value, m.value_bytes)
return return
} }
index += 2 index += 2
@ -349,7 +349,7 @@ fn (m map) get3(key string, zero voidptr) voidptr {
if meta == m.metas[index] { if meta == m.metas[index] {
kv_index := m.metas[index + 1] kv_index := m.metas[index + 1]
if fast_string_eq(key, m.key_values.keys[kv_index]) { if fast_string_eq(key, m.key_values.keys[kv_index]) {
return voidptr(m.key_values.values + kv_index * m.value_bytes) return voidptr(m.key_values.values + kv_index * u32(m.value_bytes))
} }
} }
index += 2 index += 2
@ -431,10 +431,10 @@ pub fn (d DenseArray) clone() DenseArray {
size: d.size size: d.size
deletes: d.deletes deletes: d.deletes
keys: &string(malloc(d.cap * sizeof(string))) keys: &string(malloc(d.cap * sizeof(string)))
values: byteptr(malloc(d.cap * d.value_bytes)) values: byteptr(malloc(d.cap * u32(d.value_bytes)))
} }
C.memcpy(res.keys, d.keys, d.cap * sizeof(string)) C.memcpy(res.keys, d.keys, d.cap * sizeof(string))
C.memcpy(res.values, d.values, d.cap * d.value_bytes) C.memcpy(res.values, d.values, d.cap * u32(d.value_bytes))
return res return res
} }

View File

@ -750,7 +750,7 @@ pub fn (s string) ends_with(p string) bool {
pub fn (s string) to_lower() string { pub fn (s string) to_lower() string {
mut b := malloc(s.len + 1) mut b := malloc(s.len + 1)
for i in 0..s.len { for i in 0..s.len {
b[i] = C.tolower(s.str[i]) b[i] = byte(C.tolower(s.str[i]))
} }
return tos(b, s.len) return tos(b, s.len)
} }
@ -767,7 +767,7 @@ pub fn (s string) is_lower() bool {
pub fn (s string) to_upper() string { pub fn (s string) to_upper() string {
mut b := malloc(s.len + 1) mut b := malloc(s.len + 1)
for i in 0..s.len { for i in 0..s.len {
b[i] = C.toupper(s.str[i]) b[i] = byte(C.toupper(s.str[i]))
} }
return tos(b, s.len) return tos(b, s.len)
} }

View File

@ -13,33 +13,33 @@ pub fn utf32_to_str(code u32) string {
icode := int(code) // Prevents doing casts everywhere icode := int(code) // Prevents doing casts everywhere
mut buffer := malloc(5) mut buffer := malloc(5)
if icode <= 127/* 0x7F */ { if icode <= 127/* 0x7F */ {
buffer[0] = icode buffer[0] = byte(icode)
return tos(buffer, 1) return tos(buffer, 1)
} }
if icode <= 2047/* 0x7FF */ { if icode <= 2047/* 0x7FF */ {
buffer[0] = 192/*0xC0*/ | (icode>>6)/* 110xxxxx */ buffer[0] = 192/*0xC0*/ | byte(icode>>6)/* 110xxxxx */
buffer[1] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */ buffer[1] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 2) return tos(buffer, 2)
} }
if icode <= 65535/* 0xFFFF */ { if icode <= 65535/* 0xFFFF */ {
buffer[0] = 224/*0xE0*/ | (icode>>12)/* 1110xxxx */ buffer[0] = 224/*0xE0*/ | byte(icode>>12)/* 1110xxxx */
buffer[1] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ buffer[1] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
buffer[2] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */ buffer[2] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 3) return tos(buffer, 3)
} }
if icode <= 1114111/* 0x10FFFF */ { if icode <= 1114111/* 0x10FFFF */ {
buffer[0] = 240/*0xF0*/ | (icode>>18)/* 11110xxx */ buffer[0] = 240/*0xF0*/ | byte(icode>>18)/* 11110xxx */
buffer[1] = 128/*0x80*/ | ((icode>>12) & 63/*0x3F*/)/* 10xxxxxx */ buffer[1] = 128/*0x80*/ | (byte(icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
buffer[2] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ buffer[2] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
buffer[3] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */ buffer[3] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 4) return tos(buffer, 4)
} }
@ -51,33 +51,33 @@ pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string {
icode := int(code) // Prevents doing casts everywhere icode := int(code) // Prevents doing casts everywhere
mut buffer := byteptr(buf) mut buffer := byteptr(buf)
if icode <= 127/* 0x7F */ { if icode <= 127/* 0x7F */ {
buffer[0] = icode buffer[0] = byte(icode)
return tos(buffer, 1) return tos(buffer, 1)
} }
if icode <= 2047/* 0x7FF */ { if icode <= 2047/* 0x7FF */ {
buffer[0] = 192/*0xC0*/ | (icode>>6)/* 110xxxxx */ buffer[0] = 192/*0xC0*/ | byte(icode>>6)/* 110xxxxx */
buffer[1] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */ buffer[1] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 2) return tos(buffer, 2)
} }
if icode <= 65535/* 0xFFFF */ { if icode <= 65535/* 0xFFFF */ {
buffer[0] = 224/*0xE0*/ | (icode>>12)/* 1110xxxx */ buffer[0] = 224/*0xE0*/ | byte(icode>>12)/* 1110xxxx */
buffer[1] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ buffer[1] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
buffer[2] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */ buffer[2] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 3) return tos(buffer, 3)
} }
if icode <= 1114111/* 0x10FFFF */ { if icode <= 1114111/* 0x10FFFF */ {
buffer[0] = 240/*0xF0*/ | (icode>>18)/* 11110xxx */ buffer[0] = 240/*0xF0*/ | byte(icode>>18)/* 11110xxx */
buffer[1] = 128/*0x80*/ | ((icode>>12) & 63/*0x3F*/)/* 10xxxxxx */ buffer[1] = 128/*0x80*/ | (byte(icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
buffer[2] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ buffer[2] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
buffer[3] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */ buffer[3] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 4) return tos(buffer, 4)
} }

View File

@ -127,7 +127,7 @@ fn (mut cb Clipboard) free() {
fn to_wide(text string) &C.HGLOBAL { fn to_wide(text string) &C.HGLOBAL {
len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len +
1, C.NULL, 0) 1, C.NULL, 0)
buf := C.GlobalAlloc(C.GMEM_MOVEABLE, sizeof(u16) * len_required) buf := C.GlobalAlloc(C.GMEM_MOVEABLE, i64(sizeof(u16)) * len_required)
if buf != C.HGLOBAL(C.NULL) { if buf != C.HGLOBAL(C.NULL) {
mut locked := &u16(C.GlobalLock(buf)) mut locked := &u16(C.GlobalLock(buf))
C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, locked, len_required) C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, locked, len_required)

View File

@ -152,8 +152,8 @@ fn ft_load_char(face &C.FT_FaceRec, code i64) Character {
horizontal_bearing_px: gg.vec2((*face).glyph.metrics.horiBearingX >> 6, (*face).glyph.metrics.horiBearingY >> 6) horizontal_bearing_px: gg.vec2((*face).glyph.metrics.horiBearingX >> 6, (*face).glyph.metrics.horiBearingY >> 6)
vertical_bearing_px: gg.vec2((*face).glyph.metrics.vertBearingX >> 6, (*face).glyph.metrics.vertBearingY >> 6) // not used for now vertical_bearing_px: gg.vec2((*face).glyph.metrics.vertBearingX >> 6, (*face).glyph.metrics.vertBearingY >> 6) // not used for now
horizontal_advance_px: (*face).glyph.metrics.horiAdvance >> 6 horizontal_advance_px: u32((*face).glyph.metrics.horiAdvance) >> 6
vertical_advance_px: (*face).glyph.metrics.vertAdvance >> 6 vertical_advance_px: u32((*face).glyph.metrics.vertAdvance) >> 6
} }
} }
@ -203,7 +203,7 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
} }
if !os.exists(font_path) { if !os.exists(font_path) {
eprintln('freetype: font "$font_path" does not exist') eprintln('freetype: font "$font_path" does not exist')
return 0 return voidptr(0)
} }
face := &C.FT_FaceRec{ face := &C.FT_FaceRec{
glyph: 0 glyph: 0
@ -289,11 +289,11 @@ fn (mut ctx FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
if cfg.align == gx.align_right { if cfg.align == gx.align_right {
// width := utext.len * 7 // width := utext.len * 7
width := wx width := wx
x -= width + 10 x -= f32(width + 10)
} }
x *= ctx.scale x *= f32(ctx.scale)
y *= ctx.scale y *= f32(ctx.scale)
y += yoffset y += f32(yoffset)
y = f32(ctx.height) - y // invert y direction y = f32(ctx.height) - y // invert y direction
color := cfg.color color := cfg.color
// Activate corresponding render state // Activate corresponding render state

View File

@ -8,7 +8,7 @@ fn arc_vertices(x, y, r, start_angle, end_angle f32, segments int) []f32 {
mut vertices := []f32{} mut vertices := []f32{}
start_rads := start_angle * 0.0174533 // deg -> rad approx start_rads := start_angle * 0.0174533 // deg -> rad approx
end_rads := end_angle * 0.0174533 end_rads := end_angle * 0.0174533
increment := (end_rads - start_rads) / segments increment := (end_rads - start_rads) / f32(segments)
vertices << [x + f32(math.cos(start_rads)) * r, y + f32(math.sin(start_rads)) * r] ! vertices << [x + f32(math.cos(start_rads)) * r, y + f32(math.sin(start_rads)) * r] !
mut i := 1 mut i := 1
for i < segments { for i < segments {

View File

@ -183,12 +183,12 @@ pub fn buffer_data(typ, size int, arr voidptr, draw_typ int) {
} }
pub fn buffer_data_int(typ int, vertices []int, draw_typ int) { pub fn buffer_data_int(typ int, vertices []int, draw_typ int) {
size := sizeof(int) * vertices.len size := sizeof(int) * u32(vertices.len)
C.glBufferData(typ, size, vertices.data, draw_typ) C.glBufferData(typ, size, vertices.data, draw_typ)
} }
pub fn buffer_data_f32(typ int, vertices []f32, draw_typ int) { pub fn buffer_data_f32(typ int, vertices []f32, draw_typ int) {
size := sizeof(f32) * vertices.len size := sizeof(f32) * u32(vertices.len)
C.glBufferData(typ, size, vertices.data, draw_typ) C.glBufferData(typ, size, vertices.data, draw_typ)
} }
@ -263,11 +263,11 @@ pub fn gen_buffer() u32 {
} }
pub fn vertex_attrib_pointer(index, size int, typ int, normalized bool, _stride int, _ptr int) { pub fn vertex_attrib_pointer(index, size int, typ int, normalized bool, _stride int, _ptr int) {
mut stride := _stride mut stride := u32(_stride)
mut ptr := _ptr mut ptr := _ptr
if typ == C.GL_FLOAT { if typ == C.GL_FLOAT {
stride *= sizeof(f32) stride *= sizeof(f32)
ptr *= sizeof(f32) ptr *= int(sizeof(f32))
} }
C.glVertexAttribPointer(index, size, typ, normalized, stride, ptr) C.glVertexAttribPointer(index, size, typ, normalized, stride, ptr)
} }
@ -311,4 +311,4 @@ pub fn set_bool(loc int, val bool) {
} else { } else {
set_f32(loc, 0) set_f32(loc, 0)
} }
} }

View File

@ -191,8 +191,8 @@ pub fn (mut ws Client) close(code int, message string) {
code_ := C.htons(code) code_ := C.htons(code)
message_len := message.len + 2 message_len := message.len + 2
mut close_frame := [`0`].repeat(message_len) mut close_frame := [`0`].repeat(message_len)
close_frame[0] = code_ & 0xFF close_frame[0] = byte(code_ & 0xFF)
close_frame[1] = (code_ >> 8) close_frame[1] = byte(code_ >> 8)
code32 = (close_frame[0] << 8) + close_frame[1] code32 = (close_frame[0] << 8) + close_frame[1]
for i in 0 .. message.len { for i in 0 .. message.len {
close_frame[i + 2] = message[i] close_frame[i + 2] = message[i]
@ -248,9 +248,9 @@ pub fn (mut ws Client) write(payload byteptr, payload_len int, code OPCode) int
fbdata := byteptr( frame_buf.data ) fbdata := byteptr( frame_buf.data )
masking_key := create_masking_key() masking_key := create_masking_key()
mut header := [`0`].repeat(header_len) mut header := [`0`].repeat(header_len)
header[0] = (int(code) | 0x80) header[0] = byte(code) | 0x80
if payload_len <= 125 { if payload_len <= 125 {
header[1] = (payload_len | 0x80) header[1] = byte(payload_len | 0x80)
header[2] = masking_key[0] header[2] = masking_key[0]
header[3] = masking_key[1] header[3] = masking_key[1]
header[4] = masking_key[2] header[4] = masking_key[2]
@ -417,7 +417,7 @@ pub fn (mut ws Client) read() int {
} else if frame.opcode in [.text_frame, .binary_frame] { } else if frame.opcode in [.text_frame, .binary_frame] {
data_node: data_node:
l.d('read: recieved text_frame or binary_frame') l.d('read: recieved text_frame or binary_frame')
mut payload := malloc(sizeof(byte) * int(payload_len) + 1) mut payload := malloc(sizeof(byte) * u32(payload_len) + 1)
if payload == 0 { if payload == 0 {
l.f('out of memory') l.f('out of memory')
} }
@ -437,7 +437,7 @@ pub fn (mut ws Client) read() int {
size += f.len size += f.len
} }
} }
mut pl := malloc(sizeof(byte) * int(size)) mut pl := malloc(sizeof(byte) * u32(size))
if pl == 0 { if pl == 0 {
l.f('out of memory') l.f('out of memory')
} }
@ -581,8 +581,8 @@ fn (mut ws Client) send_control_frame(code OPCode, frame_typ string, payload []b
frame_len := header_len + payload.len frame_len := header_len + payload.len
mut control_frame := [`0`].repeat(frame_len) mut control_frame := [`0`].repeat(frame_len)
masking_key := create_masking_key() masking_key := create_masking_key()
control_frame[0] = (int(code) | 0x80) control_frame[0] = byte(code | 0x80)
control_frame[1] = (payload.len | 0x80) control_frame[1] = byte(payload.len | 0x80)
control_frame[2] = masking_key[0] control_frame[2] = masking_key[0]
control_frame[3] = masking_key[1] control_frame[3] = masking_key[1]
control_frame[4] = masking_key[2] control_frame[4] = masking_key[2]

View File

@ -19,7 +19,7 @@ pub fn getenv(key string) string {
return string_from_wide(s) return string_from_wide(s)
} $else { } $else {
s := C.getenv(key.str) s := C.getenv(key.str)
if s == 0 { if s == voidptr(0) {
return '' return ''
} }
// NB: C.getenv *requires* that the result be copied. // NB: C.getenv *requires* that the result be copied.

View File

@ -35,19 +35,19 @@ pub fn inode(path string) FileMode {
C.stat(path.str, &attr) C.stat(path.str, &attr)
mut typ := FileType.regular mut typ := FileType.regular
if attr.st_mode & C.S_IFMT == C.S_IFDIR { if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFDIR) {
typ = .directory typ = .directory
} }
$if !windows { $if !windows {
if attr.st_mode & C.S_IFMT == C.S_IFCHR { if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFCHR) {
typ = .character_device typ = .character_device
} else if attr.st_mode & C.S_IFMT == C.S_IFBLK { } else if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFBLK) {
typ = .block_device typ = .block_device
} else if attr.st_mode & C.S_IFMT == C.S_IFIFO { } else if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFIFO) {
typ = .fifo typ = .fifo
} else if attr.st_mode & C.S_IFMT == C.S_IFLNK { } else if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFLNK) {
typ = .symbolic_link typ = .symbolic_link
} else if attr.st_mode & C.S_IFMT == C.S_IFSOCK { } else if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFSOCK) {
typ = .socket typ = .socket
} }
} }
@ -56,38 +56,38 @@ pub fn inode(path string) FileMode {
return FileMode{ return FileMode{
typ: typ typ: typ
owner: FilePermission{ owner: FilePermission{
read: bool(attr.st_mode & C.S_IREAD) read: bool(attr.st_mode & u32(C.S_IREAD))
write: bool(attr.st_mode & C.S_IWRITE) write: bool(attr.st_mode & u32(C.S_IWRITE))
execute: bool(attr.st_mode & C.S_IEXEC) execute: bool(attr.st_mode & u32(C.S_IEXEC))
} }
group: FilePermission{ group: FilePermission{
read: bool(attr.st_mode & C.S_IREAD) read: bool(attr.st_mode & u32(C.S_IREAD))
write: bool(attr.st_mode & C.S_IWRITE) write: bool(attr.st_mode & u32(C.S_IWRITE))
execute: bool(attr.st_mode & C.S_IEXEC) execute: bool(attr.st_mode & u32(C.S_IEXEC))
} }
others: FilePermission{ others: FilePermission{
read: bool(attr.st_mode & C.S_IREAD) read: bool(attr.st_mode & u32(C.S_IREAD))
write: bool(attr.st_mode & C.S_IWRITE) write: bool(attr.st_mode & u32(C.S_IWRITE))
execute: bool(attr.st_mode & C.S_IEXEC) execute: bool(attr.st_mode & u32(C.S_IEXEC))
} }
} }
} $else { } $else {
return FileMode{ return FileMode{
typ: typ typ: typ
owner: FilePermission{ owner: FilePermission{
read: bool(attr.st_mode & C.S_IRUSR) read: bool(attr.st_mode & u32(C.S_IRUSR))
write: bool(attr.st_mode & C.S_IWUSR) write: bool(attr.st_mode & u32(C.S_IWUSR))
execute: bool(attr.st_mode & C.S_IXUSR) execute: bool(attr.st_mode & u32(C.S_IXUSR))
} }
group: FilePermission{ group: FilePermission{
read: bool(attr.st_mode & C.S_IRGRP) read: bool(attr.st_mode & u32(C.S_IRGRP))
write: bool(attr.st_mode & C.S_IWGRP) write: bool(attr.st_mode & u32(C.S_IWGRP))
execute: bool(attr.st_mode & C.S_IXGRP) execute: bool(attr.st_mode & u32(C.S_IXGRP))
} }
others: FilePermission{ others: FilePermission{
read: bool(attr.st_mode & C.S_IROTH) read: bool(attr.st_mode & u32(C.S_IROTH))
write: bool(attr.st_mode & C.S_IWOTH) write: bool(attr.st_mode & u32(C.S_IWOTH))
execute: bool(attr.st_mode & C.S_IXOTH) execute: bool(attr.st_mode & u32(C.S_IXOTH))
} }
} }
} }

View File

@ -1090,12 +1090,12 @@ pub fn real_path(fpath string) string {
mut fullpath := vcalloc(max_path_len) mut fullpath := vcalloc(max_path_len)
mut ret := charptr(0) mut ret := charptr(0)
$if windows { $if windows {
ret = C._fullpath(fullpath, fpath.str, max_path_len) ret = charptr(C._fullpath(fullpath, fpath.str, max_path_len))
if ret == 0 { if ret == 0 {
return fpath return fpath
} }
} $else { } $else {
ret = C.realpath(fpath.str, fullpath) ret = charptr(C.realpath(fpath.str, fullpath))
if ret == 0 { if ret == 0 {
return fpath return fpath
} }
@ -1324,7 +1324,7 @@ pub fn open(path string) ?File {
} }
*/ */
cfile := vfopen(path, 'rb') cfile := vfopen(path, 'rb')
if cfile == 0 { if cfile == voidptr(0) {
return error('failed to open file "$path"') return error('failed to open file "$path"')
} }
fd := fileno(cfile) fd := fileno(cfile)
@ -1361,7 +1361,7 @@ pub fn create(path string) ?File {
} }
*/ */
cfile := vfopen(path, 'wb') cfile := vfopen(path, 'wb')
if cfile == 0 { if cfile == voidptr(0) {
return error('failed to create file "$path"') return error('failed to create file "$path"')
} }
fd := fileno(cfile) fd := fileno(cfile)

View File

@ -146,7 +146,7 @@ pub fn mkdir(path string) ?bool {
// get_file_handle retrieves the operating-system file handle that is associated with the specified file descriptor. // get_file_handle retrieves the operating-system file handle that is associated with the specified file descriptor.
pub fn get_file_handle(path string) HANDLE { pub fn get_file_handle(path string) HANDLE {
cfile := vfopen(path, 'rb') cfile := vfopen(path, 'rb')
if cfile == 0 { if cfile == voidptr(0) {
return HANDLE(invalid_handle_value) return HANDLE(invalid_handle_value)
} }
handle := HANDLE(C._get_osfhandle(fileno(cfile))) // CreateFile? - hah, no -_- handle := HANDLE(C._get_osfhandle(fileno(cfile))) // CreateFile? - hah, no -_-

View File

@ -59,7 +59,7 @@ const(
const( const(
mantbits32 = u32(23) mantbits32 = u32(23)
expbits32 = u32(8) expbits32 = u32(8)
bias32 = u32(127) // f32 exponent bias bias32 = 127 // f32 exponent bias
maxexp32 = 255 maxexp32 = 255
) )
@ -189,10 +189,10 @@ pub fn f32_to_decimal(mant u32, exp u32) Dec32 {
if exp == 0 { if exp == 0 {
// We subtract 2 so that the bounds computation has // We subtract 2 so that the bounds computation has
// 2 additional bits. // 2 additional bits.
e2 = 1 - bias32 - mantbits32 - 2 e2 = 1 - bias32 - int(mantbits32) - 2
m2 = mant m2 = mant
} else { } else {
e2 = int(exp) - bias32 - mantbits32 - 2 e2 = int(exp) - bias32 - int(mantbits32) - 2
m2 = (u32(1) << mantbits32) | mant m2 = (u32(1) << mantbits32) | mant
} }
even := (m2 & 1) == 0 even := (m2 & 1) == 0

View File

@ -73,7 +73,7 @@ const(
const( const(
mantbits64 = u32(52) mantbits64 = u32(52)
expbits64 = u32(11) expbits64 = u32(11)
bias64 = u32(1023) // f64 exponent bias bias64 = 1023 // f64 exponent bias
maxexp64 = 2047 maxexp64 = 2047
) )
@ -220,10 +220,10 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
if exp == 0 { if exp == 0 {
// We subtract 2 so that the bounds computation has // We subtract 2 so that the bounds computation has
// 2 additional bits. // 2 additional bits.
e2 = 1 - bias64 - mantbits64 - 2 e2 = 1 - bias64 - int(mantbits64) - 2
m2 = mant m2 = mant
} else { } else {
e2 = int(exp) - bias64 - mantbits64 - 2 e2 = int(exp) - bias64 - int(mantbits64) - 2
m2 = (u64(1)<<mantbits64) | mant m2 = (u64(1)<<mantbits64) | mant
} }
even := (m2 & 1) == 0 even := (m2 & 1) == 0

View File

@ -65,6 +65,6 @@ pub fn dice_coefficient(s1, s2 string) f32 {
intersection_size++ intersection_size++
} }
} }
return (2.0 * intersection_size) / (f32(a.len) + f32(b.len) - 2) return (2.0 * f32(intersection_size)) / (f32(a.len) + f32(b.len) - 2)
} }

View File

@ -79,7 +79,7 @@ pub fn new_pool_processor(context PoolProcessorConfig) &PoolProcessor {
ntask: 0 ntask: 0
ntask_mtx: new_mutex() ntask_mtx: new_mutex()
waitgroup: new_waitgroup() waitgroup: new_waitgroup()
thread_cb: context.callback thread_cb: voidptr(context.callback)
} }
return pool return pool
} }

View File

@ -32,7 +32,7 @@ pub fn new_mutex() &Mutex {
sm := &Mutex{} sm := &Mutex{}
unsafe { unsafe {
mut m := sm mut m := sm
m.mx = C.CreateMutex(0, false, 0) m.mx = MHANDLE(C.CreateMutex(0, false, 0))
if isnil(m.mx) { if isnil(m.mx) {
m.state = .broken // handle broken and mutex state are broken m.state = .broken // handle broken and mutex state are broken
return sm return sm
@ -44,7 +44,7 @@ pub fn new_mutex() &Mutex {
pub fn (mut m Mutex) lock() { pub fn (mut m Mutex) lock() {
// if mutex handle not initalized // if mutex handle not initalized
if isnil(m.mx) { if isnil(m.mx) {
m.mx = C.CreateMutex(0, false, 0) m.mx = MHANDLE(C.CreateMutex(0, false, 0))
if isnil(m.mx) { if isnil(m.mx) {
m.state = .broken // handle broken and mutex state are broken m.state = .broken // handle broken and mutex state are broken
return return

View File

@ -106,7 +106,7 @@ pub fn new_time(t Time) Time {
hour: t.hour hour: t.hour
minute: t.minute minute: t.minute
second: t.second second: t.second
unix: t.unix_time() unix: u64(t.unix_time())
} }
// TODO Use the syntax below when it works with reserved keywords like `unix` // TODO Use the syntax below when it works with reserved keywords like `unix`
// return { // return {
@ -134,12 +134,12 @@ pub fn (t Time) unix_time() int {
// add_seconds returns a new time struct with an added number of seconds. // add_seconds returns a new time struct with an added number of seconds.
pub fn (t Time) add_seconds(seconds int) Time { pub fn (t Time) add_seconds(seconds int) Time {
// TODO Add(d time.Duration) // TODO Add(d time.Duration)
return unix(t.unix + seconds) return unix(t.unix + u64(seconds))
} }
// add_days returns a new time struct with an added number of days. // add_days returns a new time struct with an added number of days.
pub fn (t Time) add_days(days int) Time { pub fn (t Time) add_days(days int) Time {
return unix(t.unix + days * 3600 * 24) return unix(t.unix + u64(i64(days) * 3600 * 24))
} }
// since returns a number of seconds elapsed since a given time. // since returns a number of seconds elapsed since a given time.
@ -272,7 +272,7 @@ fn convert_ctime(t C.tm) Time {
hour: t.tm_hour hour: t.tm_hour
minute: t.tm_min minute: t.tm_min
second: t.tm_sec second: t.tm_sec
unix: make_unix_time(t) unix: u64(make_unix_time(t))
} }
} }

View File

@ -20,7 +20,7 @@ pub fn unix(abs int) Time {
hour: hr hour: hr
minute: min minute: min
second: sec second: sec
unix: abs unix: u64(abs)
} }
} }

View File

@ -7,8 +7,8 @@ import v.table
pub fn (c &Checker) check_types(got, expected table.Type) bool { pub fn (c &Checker) check_types(got, expected table.Type) bool {
t := c.table t := c.table
got_idx := got.idx() got_idx := t.unalias_num_type(got).idx()
exp_idx := expected.idx() exp_idx := t.unalias_num_type(expected).idx()
// got_is_ptr := got.is_ptr() // got_is_ptr := got.is_ptr()
exp_is_ptr := expected.is_ptr() exp_is_ptr := expected.is_ptr()
// println('check: $got_type_sym.name, $exp_type_sym.name') // println('check: $got_type_sym.name, $exp_type_sym.name')
@ -125,3 +125,119 @@ pub fn (c &Checker) check_types(got, expected table.Type) bool {
} }
return false return false
} }
pub fn (c &Checker) promote(left_type, right_type table.Type) table.Type {
if left_type.is_ptr() || left_type.is_pointer() {
if right_type.is_int() {
return left_type
} else {
return table.void_type
}
} else if right_type.is_ptr() || right_type.is_pointer() {
if left_type.is_int() {
return right_type
} else {
return table.void_type
}
}
if left_type == right_type {
return left_type // strings, self defined operators
}
if right_type.is_number() && left_type.is_number() {
// sort the operands to save time
mut type_hi := left_type
mut type_lo := right_type
if type_hi.idx() < type_lo.idx() {
tmp := type_hi
type_hi = type_lo
type_lo = tmp
}
idx_hi := type_hi.idx()
idx_lo := type_lo.idx()
// the following comparisons rely on the order of the indices in atypes.v
if idx_hi == table.any_int_type_idx {
return type_lo
} else if idx_hi == table.any_flt_type_idx {
if idx_lo in table.float_type_idxs {
return type_lo
} else {
return table.void_type
}
} else if type_hi.is_float() {
if idx_hi == table.f32_type_idx {
if idx_lo in [table.int_type_idx, table.i64_type_idx, table.u32_type_idx, table.u64_type_idx] {
return table.void_type
} else {
return idx_hi
}
} else { // f64, any_flt
if idx_lo in [table.i64_type_idx, table.u64_type_idx] {
return table.void_type
} else {
return type_hi
}
}
} else if idx_lo >= table.byte_type_idx { // both operands are unsigned
return type_hi
} else if idx_lo >= table.i8_type_idx && idx_hi <= table.i64_type_idx { // both signed
return type_hi
} else if idx_hi - idx_lo < (table.byte_type_idx - table.i8_type_idx) {
return type_lo // conversion unsigned -> signed if signed type is larger
} else {
return table.void_type // conversion signed -> unsigned not allowed
}
} else {
return left_type // default to left if not automatic promotion possible
}
}
// TODO: promote(), assign_check(), symmetric_check() and check() overlap - should be rearranged
pub fn (c &Checker) assign_check(got, expected table.Type) bool {
exp_idx := expected.idx()
got_idx := got.idx()
if exp_idx == got_idx {
return true
}
if exp_idx == table.voidptr_type_idx || exp_idx == table.byteptr_type_idx {
if got.is_ptr() || got.is_pointer() {
return true
}
}
// allow direct int-literal assignment for pointers for now
// maybe in the future optionals should be used for that
if expected.is_ptr() || expected.is_pointer() {
if got == table.any_int_type {
return true
}
}
if got_idx == table.voidptr_type_idx || got_idx == table.byteptr_type_idx {
if expected.is_ptr() || expected.is_pointer() {
return true
}
}
if !c.check_types(got, expected) { // TODO: this should go away...
return false
}
if c.promote(expected, got) != expected {
println('could not promote ${c.table.get_type_symbol(got).name} to ${c.table.get_type_symbol(expected).name}')
return false
}
return true
}
pub fn (c &Checker) symmetric_check(left, right table.Type) bool {
// allow direct int-literal assignment for pointers for now
// maybe in the future optionals should be used for that
if right.is_ptr() || right.is_pointer() {
if left == table.any_int_type {
return true
}
}
// allow direct int-literal assignment for pointers for now
if left.is_ptr() || left.is_pointer() {
if right == table.any_int_type {
return true
}
}
return c.check_types(left, right)
}

View File

@ -362,11 +362,11 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
expr_type := c.expr(field.expr) expr_type := c.expr(field.expr)
expr_type_sym := c.table.get_type_symbol(expr_type) expr_type_sym := c.table.get_type_symbol(expr_type)
field_type_sym := c.table.get_type_symbol(info_field.typ) field_type_sym := c.table.get_type_symbol(info_field.typ)
if !c.check_types(expr_type, info_field.typ) { if !c.assign_check(expr_type, info_field.typ) {
c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`', c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
field.pos) field.pos)
} }
if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_number() { if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_pointer() && !expr_type.is_number() {
c.error('ref', field.pos) c.error('ref', field.pos)
} }
struct_init.fields[i].typ = expr_type struct_init.fields[i].typ = expr_type
@ -408,6 +408,10 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
infix_expr.right_type = right_type infix_expr.right_type = right_type
right := c.table.get_type_symbol(right_type) right := c.table.get_type_symbol(right_type)
left := c.table.get_type_symbol(left_type) left := c.table.get_type_symbol(left_type)
left_default := c.table.get_type_symbol(c.table.mktyp(left_type))
left_pos := infix_expr.left.position()
right_pos := infix_expr.right.position()
mut return_type := left_type
// Single side check // Single side check
// Place these branches according to ops' usage frequency to accelerate. // Place these branches according to ops' usage frequency to accelerate.
// TODO: First branch includes ops where single side check is not needed, or needed but hasn't been implemented. // TODO: First branch includes ops where single side check is not needed, or needed but hasn't been implemented.
@ -417,22 +421,22 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
.key_in, .not_in { .key_in, .not_in {
match right.kind { match right.kind {
.array { .array {
right_sym := c.table.get_type_symbol(right.array_info().elem_type) right_sym := c.table.get_type_symbol(c.table.mktyp(right.array_info().elem_type))
if left.kind != right_sym.kind { if left_default.kind != right_sym.kind {
c.error('the data type on the left of `$infix_expr.op.str()` does not match the array item type', c.error('the data type on the left of `$infix_expr.op.str()` (`$left.name`) does not match the array item type (`$right_sym.name`)',
infix_expr.pos) infix_expr.pos)
} }
} }
.map { .map {
key_sym := c.table.get_type_symbol(right.map_info().key_type) key_sym := c.table.get_type_symbol(c.table.mktyp(right.map_info().key_type))
if left.kind != key_sym.kind { if left_default.kind != key_sym.kind {
c.error('the data type on the left of `$infix_expr.op.str()` does not match the map key type', c.error('the data type on the left of `$infix_expr.op.str()` (`$left.name`) does not match the map key type `$key_sym.name`',
infix_expr.pos) infix_expr.pos)
} }
} }
.string { .string {
if left.kind != .string { if left.kind != .string {
c.error('the data type on the left of `$infix_expr.op.str()` must be a string', c.error('the data type on the left of `$infix_expr.op.str()` must be a string (is `$left.name`)',
infix_expr.pos) infix_expr.pos)
} }
} }
@ -443,15 +447,43 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
} }
return table.bool_type return table.bool_type
} }
.plus, .minus, .mul, .div { .plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe { // binary operators that expect matching types
if infix_expr.op == .div && (infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() == if left.kind in [.array, .array_fixed, .map, .struct_] {
'0' || infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) { if left.has_method(infix_expr.op.str()) {
c.error('division by zero', infix_expr.right.position()) return_type = left_type
} } else {
if left.kind in [.array, .array_fixed, .map, .struct_] && !left.has_method(infix_expr.op.str()) { c.error('mismatched types `$left.name` and `$right.name`', left_pos)
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position()) }
} else if right.kind in [.array, .array_fixed, .map, .struct_] && !right.has_method(infix_expr.op.str()) { } else if right.kind in [.array, .array_fixed, .map, .struct_] {
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position()) if right.has_method(infix_expr.op.str()) {
return_type = right_type
} else {
c.error('mismatched types `$left.name` and `$right.name`', right_pos)
}
} else {
promoted_type := c.promote(c.table.unalias_num_type(left_type), c.table.unalias_num_type(right_type))
if promoted_type.idx() == table.void_type_idx {
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.pos)
} else if promoted_type.is_float() {
if infix_expr.op in [.mod, .xor, .amp, .pipe] {
side := if left_type == promoted_type { 'left' } else { 'right' }
pos := if left_type == promoted_type { left_pos } else { right_pos }
name := if left_type == promoted_type { left.name } else { right.name }
if infix_expr.op == .mod {
c.error('float modulo not allowed, use math.fmod() instead', pos)
} else {
c.error('$side type of `${infix_expr.op.str()}` cannot be non-integer type $name', pos)
}
}
}
if infix_expr.op in [.div, .mod] {
if infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() == '0' ||
infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0 {
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
c.error('$oper by zero', right_pos)
}
}
return_type = promoted_type
} }
} }
.left_shift { .left_shift {
@ -463,11 +495,10 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
if left_value_sym.kind == .interface_ { if left_value_sym.kind == .interface_ {
if right.kind != .array { if right.kind != .array {
// []Animal << Cat // []Animal << Cat
c.type_implements(right_type, left_value_type, infix_expr.right.position()) c.type_implements(right_type, left_value_type, right_pos)
} else { } else {
// []Animal << Cat // []Animal << Cat
c.type_implements(c.table.value_type(right_type), left_value_type, c.type_implements(c.table.value_type(right_type), left_value_type, right_pos)
infix_expr.right.position())
} }
return table.void_type return table.void_type
} }
@ -481,13 +512,13 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
return table.void_type return table.void_type
} }
s := left.name.replace('array_', '[]') s := left.name.replace('array_', '[]')
c.error('cannot append `$right.name` to `$s`', infix_expr.right.position()) c.error('cannot append `$right.name` to `$s`', right_pos)
return table.void_type return table.void_type
} else if !left.is_int() { } else if !left.is_int() {
c.error('cannot shift type $right.name into non-integer type $left.name', infix_expr.left.position()) c.error('cannot shift type $right.name into non-integer type $left.name', left_pos)
return table.void_type return table.void_type
} else if !right.is_int() { } else if !right.is_int() {
c.error('cannot shift non-integer type $right.name into type $left.name', infix_expr.right.position()) c.error('cannot shift non-integer type $right.name into type $left.name', right_pos)
return table.void_type return table.void_type
} }
} }
@ -499,33 +530,6 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
} }
return table.bool_type return table.bool_type
} }
.amp, .pipe, .xor {
if !left.is_int() {
c.error('left type of `${infix_expr.op.str()}` cannot be non-integer type $left.name',
infix_expr.left.position())
} else if !right.is_int() {
c.error('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name',
infix_expr.right.position())
}
}
.mod {
if left.is_int() && !right.is_int() {
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
} else if !left.is_int() && right.is_int() {
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
} else if left.kind == .f32 && right.kind == .f32 || left.kind == .f64 && right.kind ==
.f64 {
c.error('float modulo not allowed, use math.fmod() instead', infix_expr.left.position())
} else if left.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
!left.has_method(infix_expr.op.str()) {
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
} else if right.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
!right.has_method(infix_expr.op.str()) {
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
} else if infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() == '0' {
c.error('modulo by zero', infix_expr.right.position())
}
}
else {} else {}
} }
// TODO: Absorb this block into the above single side check block to accelerate. // TODO: Absorb this block into the above single side check block to accelerate.
@ -539,7 +543,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
infix_expr.pos) infix_expr.pos)
} }
// Dual sides check (compatibility check) // Dual sides check (compatibility check)
if !c.check_types(right_type, left_type) { if !c.symmetric_check(right_type, left_type) {
// for type-unresolved consts // for type-unresolved consts
if left_type == table.void_type || right_type == table.void_type { if left_type == table.void_type || right_type == table.void_type {
return table.void_type return table.void_type
@ -550,7 +554,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
return if infix_expr.op.is_relational() { return if infix_expr.op.is_relational() {
table.bool_type table.bool_type
} else { } else {
left_type return_type
} }
} }
@ -678,7 +682,7 @@ fn (mut c Checker) assign_expr(mut assign_expr ast.AssignExpr) {
else {} else {}
} }
// Dual sides check (compatibility check) // Dual sides check (compatibility check)
if !c.check_types(right_type, left_type) { if !c.assign_check(right_type, left_type) {
left_type_sym := c.table.get_type_symbol(left_type) left_type_sym := c.table.get_type_symbol(left_type)
right_type_sym := c.table.get_type_symbol(right_type) right_type_sym := c.table.get_type_symbol(right_type)
c.error('cannot assign `$right_type_sym.name` to variable `${assign_expr.left.str()}` of type `$left_type_sym.name`', c.error('cannot assign `$right_type_sym.name` to variable `${assign_expr.left.str()}` of type `$left_type_sym.name`',
@ -1268,12 +1272,15 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
} else if i < assign_stmt.right.len { // only once for multi return } else if i < assign_stmt.right.len { // only once for multi return
c.check_expr_opt_call(assign_stmt.right[i], assign_stmt.right_types[i]) c.check_expr_opt_call(assign_stmt.right[i], assign_stmt.right_types[i])
} }
val_type := assign_stmt.right_types[i] mut val_type := assign_stmt.right_types[i]
// check variable name for beginning with capital letter 'Abc' // check variable name for beginning with capital letter 'Abc'
is_decl := assign_stmt.op == .decl_assign is_decl := assign_stmt.op == .decl_assign
if is_decl && ident.name != '_' { if is_decl && ident.name != '_' {
c.check_valid_snake_case(ident.name, 'variable name', ident.pos) c.check_valid_snake_case(ident.name, 'variable name', ident.pos)
} }
if assign_stmt.op == .decl_assign {
val_type = c.table.mktyp(val_type)
}
mut ident_var_info := ident.var_info() mut ident_var_info := ident.var_info()
if assign_stmt.op == .assign { if assign_stmt.op == .assign {
c.fail_if_immutable(ident) c.fail_if_immutable(ident)
@ -1301,12 +1308,12 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
if array_init.typ != table.void_type { if array_init.typ != table.void_type {
if array_init.exprs.len == 0 { if array_init.exprs.len == 0 {
if array_init.has_cap { if array_init.has_cap {
if c.expr(array_init.cap_expr) != table.int_type { if c.expr(array_init.cap_expr) !in [table.int_type, table.any_int_type] {
c.error('array cap needs to be an int', array_init.pos) c.error('array cap needs to be an int', array_init.pos)
} }
} }
if array_init.has_len { if array_init.has_len {
if c.expr(array_init.len_expr) != table.int_type { if c.expr(array_init.len_expr) !in [table.int_type, table.any_int_type] {
c.error('array len needs to be an int', array_init.pos) c.error('array len needs to be an int', array_init.pos)
} }
} }
@ -1316,12 +1323,12 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
// a = [] // a = []
if array_init.exprs.len == 0 { if array_init.exprs.len == 0 {
if array_init.has_cap { if array_init.has_cap {
if c.expr(array_init.cap_expr) != table.int_type { if c.expr(array_init.cap_expr) !in [table.int_type, table.any_int_type] {
c.error('array cap needs to be an int', array_init.pos) c.error('array cap needs to be an int', array_init.pos)
} }
} }
if array_init.has_len { if array_init.has_len {
if c.expr(array_init.len_expr) != table.int_type { if c.expr(array_init.len_expr) !in [table.int_type, table.any_int_type] {
c.error('array len needs to be an int', array_init.pos) c.error('array len needs to be an int', array_init.pos)
} }
} }
@ -1372,8 +1379,8 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
} }
// The first element's type // The first element's type
if i == 0 { if i == 0 {
elem_type = typ elem_type = c.table.mktyp(typ)
c.expected_type = typ c.expected_type = elem_type
continue continue
} }
if !c.check_types(elem_type, typ) { if !c.check_types(elem_type, typ) {
@ -1492,7 +1499,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.const_decl = field.name c.const_decl = field.name
c.const_deps << field.name c.const_deps << field.name
typ := c.expr(field.expr) typ := c.expr(field.expr)
it.fields[i].typ = typ it.fields[i].typ = c.table.mktyp(typ)
for cd in c.const_deps { for cd in c.const_deps {
for j, f in it.fields { for j, f in it.fields {
if j != i && cd in field_names && cd == f.name && j !in done_fields { if j != i && cd in field_names && cd == f.name && j !in done_fields {
@ -1748,7 +1755,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return c.enum_val(mut it) return c.enum_val(mut it)
} }
ast.FloatLiteral { ast.FloatLiteral {
return table.f64_type return table.any_flt_type
} }
ast.Ident { ast.Ident {
// c.checked_ident = it.name // c.checked_ident = it.name
@ -1770,7 +1777,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return c.infix_expr(mut it) return c.infix_expr(mut it)
} }
ast.IntegerLiteral { ast.IntegerLiteral {
return table.int_type return table.any_int_type
} }
ast.MapInit { ast.MapInit {
return c.map_init(mut it) return c.map_init(mut it)
@ -1805,7 +1812,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return c.selector_expr(mut it) return c.selector_expr(mut it)
} }
ast.SizeOf { ast.SizeOf {
return table.int_type return table.u32_type
} }
ast.StringLiteral { ast.StringLiteral {
if it.language == .c { if it.language == .c {
@ -2140,10 +2147,33 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
// first branch of if expression // first branch of if expression
node.is_expr = true node.is_expr = true
node.typ = last_expr.typ node.typ = last_expr.typ
} else { continue
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`', } else if node.typ in [table.any_flt_type, table.any_int_type] {
node.pos) if node.typ == table.any_int_type {
if last_expr.typ.is_int() || last_expr.typ.is_float() {
node.typ = last_expr.typ
continue
}
} else { // node.typ == any_float
if last_expr.typ.is_float() {
node.typ = last_expr.typ
continue
}
}
} }
if last_expr.typ in [table.any_flt_type, table.any_int_type] {
if last_expr.typ == table.any_int_type {
if node.typ.is_int() || node.typ.is_float() {
continue
}
} else { // expr_type == any_float
if node.typ.is_float() {
continue
}
}
}
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
node.pos)
} }
} else { } else {
c.error('`if` expression requires an expression as the last statement of every branch', c.error('`if` expression requires an expression as the last statement of every branch',
@ -2151,6 +2181,12 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
} }
} }
} }
// if only untyped literals were given default to int/f64
if node.typ == table.any_int_type {
node.typ = table.int_type
} else if node.typ == table.any_flt_type {
node.typ = table.f64_type
}
if expr_required { if expr_required {
if !node.has_else { if !node.has_else {
c.error('`if` expression needs `else` clause', node.pos) c.error('`if` expression needs `else` clause', node.pos)

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/add_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `int` vlib/v/checker/tests/add_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `any_int`
1 | struct A{} 1 | struct A{}
2 | fn main() { 2 | fn main() {
3 | A{} + 10 3 | A{} + 10

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/add_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `int` vlib/v/checker/tests/add_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | [1,2,3] + 10 2 | [1,2,3] + 10
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/add_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `int` vlib/v/checker/tests/add_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | a + 10 3 | a + 10

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/add_op_wrong_right_type_err_a.v:3:10: error: mismatched types `int` and `A` vlib/v/checker/tests/add_op_wrong_right_type_err_a.v:3:10: error: mismatched types `any_int` and `A`
1 | struct A{} 1 | struct A{}
2 | fn main() { 2 | fn main() {
3 | 10 + A{} 3 | 10 + A{}

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/add_op_wrong_right_type_err_b.v:2:10: error: mismatched types `int` and `array_int` vlib/v/checker/tests/add_op_wrong_right_type_err_b.v:2:10: error: mismatched types `any_int` and `array_int`
1 | fn main() { 1 | fn main() {
2 | 10 + [1,2,3] 2 | 10 + [1,2,3]
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/add_op_wrong_right_type_err_c.v:3:10: error: mismatched types `int` and `map_string_int` vlib/v/checker/tests/add_op_wrong_right_type_err_c.v:3:10: error: mismatched types `any_int` and `map_string_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | 10 + a 3 | 10 + a

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/bit_op_wrong_left_type_err.v:2:2: error: left type of `&` cannot be non-integer type f64 vlib/v/checker/tests/bit_op_wrong_left_type_err.v:2:2: error: left type of `&` cannot be non-integer type any_float
1 | fn main() { 1 | fn main() {
2 | 0.5 & 1 2 | 0.5 & 1
| ~~~ | ~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/bit_op_wrong_right_type_err.v:2:6: error: right type of `|` cannot be non-integer type f64 vlib/v/checker/tests/bit_op_wrong_right_type_err.v:2:6: error: right type of `|` cannot be non-integer type any_float
1 | fn main() { 1 | fn main() {
2 | 1 | 0.5 2 | 1 | 0.5
| ~~~ | ~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/cast_string_err.v:2:14: error: cannot cast type `int` to string, use `x.str()` instead vlib/v/checker/tests/cast_string_err.v:2:14: error: cannot cast type `any_int` to string, use `x.str()` instead
1 | fn main() { 1 | fn main() {
2 | a := string(1) 2 | a := string(1)
| ^ | ^

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/div_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `int` vlib/v/checker/tests/div_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `any_int`
1 | struct A{} 1 | struct A{}
2 | fn main() { 2 | fn main() {
3 | A{} / 10 3 | A{} / 10

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/div_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `int` vlib/v/checker/tests/div_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | [1,2,3] / 10 2 | [1,2,3] / 10
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/div_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `int` vlib/v/checker/tests/div_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | a / 10 3 | a / 10

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/div_op_wrong_right_type_err_a.v:3:10: error: mismatched types `int` and `A` vlib/v/checker/tests/div_op_wrong_right_type_err_a.v:3:10: error: mismatched types `any_int` and `A`
1 | struct A{} 1 | struct A{}
2 | fn main() { 2 | fn main() {
3 | 10 / A{} 3 | 10 / A{}

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/div_op_wrong_right_type_err_b.v:2:10: error: mismatched types `int` and `array_int` vlib/v/checker/tests/div_op_wrong_right_type_err_b.v:2:10: error: mismatched types `any_int` and `array_int`
1 | fn main() { 1 | fn main() {
2 | 10 / [1,2,3] 2 | 10 / [1,2,3]
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/div_op_wrong_right_type_err_c.v:3:10: error: mismatched types `int` and `map_string_int` vlib/v/checker/tests/div_op_wrong_right_type_err_c.v:3:10: error: mismatched types `any_int` and `map_string_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | 10 / a 3 | 10 / a

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/for-in-index-type.v:2:11: error: for in: cannot index `int` vlib/v/checker/tests/for-in-index-type.v:2:11: error: for in: cannot index `any_int`
1 | fn main() { 1 | fn main() {
2 | for a in 52 { 2 | for a in 52 {
| ~~ | ~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/if_expr_mismatch.v:2:7: error: mismatched types `string` and `int` vlib/v/checker/tests/if_expr_mismatch.v:2:7: error: mismatched types `string` and `any_int`
1 | fn main() { 1 | fn main() {
2 | s := if true { '12' } else { 12 } 2 | s := if true { '12' } else { 12 }
| ~~ | ~~

View File

@ -1,76 +1,76 @@
vlib/v/checker/tests/in_mismatch_type.v:10:7: error: the data type on the left of `in` does not match the array item type vlib/v/checker/tests/in_mismatch_type.v:10:7: error: the data type on the left of `in` (`any_int`) does not match the array item type (`string`)
8 | } 8 | }
9 | s := 'abcd' 9 | s := 'abcd'
10 | if 1 in a_s { 10 | if 1 in a_s {
| ~~ | ~~
11 | println('ok') 11 | println('ok')
12 | } 12 | }
vlib/v/checker/tests/in_mismatch_type.v:13:7: error: the data type on the left of `in` does not match the map key type vlib/v/checker/tests/in_mismatch_type.v:13:7: error: the data type on the left of `in` (`any_int`) does not match the map key type `string`
11 | println('ok') 11 | println('ok')
12 | } 12 | }
13 | if 2 in m { 13 | if 2 in m {
| ~~ | ~~
14 | println('yeah') 14 | println('yeah')
15 | } 15 | }
vlib/v/checker/tests/in_mismatch_type.v:16:7: error: the data type on the left of `in` must be a string vlib/v/checker/tests/in_mismatch_type.v:16:7: error: the data type on the left of `in` must be a string (is `any_int`)
14 | println('yeah') 14 | println('yeah')
15 | } 15 | }
16 | if 3 in s { 16 | if 3 in s {
| ~~ | ~~
17 | println('dope') 17 | println('dope')
18 | } 18 | }
vlib/v/checker/tests/in_mismatch_type.v:19:9: error: the data type on the left of `in` must be a string vlib/v/checker/tests/in_mismatch_type.v:19:9: error: the data type on the left of `in` must be a string (is `byte`)
17 | println('dope') 17 | println('dope')
18 | } 18 | }
19 | if `a` in s { 19 | if `a` in s {
| ~~ | ~~
20 | println("oh no :'(") 20 | println("oh no :'(")
21 | } 21 | }
vlib/v/checker/tests/in_mismatch_type.v:22:7: error: `in` can only be used with an array/map/string vlib/v/checker/tests/in_mismatch_type.v:22:7: error: `in` can only be used with an array/map/string
20 | println("oh no :'(") 20 | println("oh no :'(")
21 | } 21 | }
22 | if 1 in 12 { 22 | if 1 in 12 {
| ~~ | ~~
23 | println('right') 23 | println('right')
24 | } 24 | }
vlib/v/checker/tests/in_mismatch_type.v:25:12: error: the data type on the left of `in` does not match the map key type vlib/v/checker/tests/in_mismatch_type.v:25:12: error: the data type on the left of `in` (`Int`) does not match the map key type `string`
23 | println('right') 23 | println('right')
24 | } 24 | }
25 | if Int(2) in m { 25 | if Int(2) in m {
| ~~ | ~~
26 | println('yeah') 26 | println('yeah')
27 | } 27 | }
vlib/v/checker/tests/in_mismatch_type.v:28:9: error: the data type on the left of `in` does not match the array item type vlib/v/checker/tests/in_mismatch_type.v:28:9: error: the data type on the left of `in` (`string`) does not match the array item type (`int`)
26 | println('yeah') 26 | println('yeah')
27 | } 27 | }
28 | if '3' in a_i { 28 | if '3' in a_i {
| ~~ | ~~
29 | println('sure') 29 | println('sure')
30 | } 30 | }
vlib/v/checker/tests/in_mismatch_type.v:31:9: error: the data type on the left of `in` does not match the array item type vlib/v/checker/tests/in_mismatch_type.v:31:9: error: the data type on the left of `in` (`string`) does not match the array item type (`int`)
29 | println('sure') 29 | println('sure')
30 | } 30 | }
31 | if '2' in a_i { 31 | if '2' in a_i {
| ~~ | ~~
32 | println('all right') 32 | println('all right')
33 | } 33 | }
vlib/v/checker/tests/in_mismatch_type.v:34:7: error: the data type on the left of `!in` does not match the array item type vlib/v/checker/tests/in_mismatch_type.v:34:7: error: the data type on the left of `!in` (`any_int`) does not match the array item type (`string`)
32 | println('all right') 32 | println('all right')
33 | } 33 | }
34 | if 1 !in a_s { 34 | if 1 !in a_s {
| ~~~ | ~~~
35 | println('ok') 35 | println('ok')
36 | } 36 | }
vlib/v/checker/tests/in_mismatch_type.v:37:9: error: the data type on the left of `!in` does not match the array item type vlib/v/checker/tests/in_mismatch_type.v:37:9: error: the data type on the left of `!in` (`string`) does not match the array item type (`int`)
35 | println('ok') 35 | println('ok')
36 | } 36 | }
37 | if '1' !in a_i { 37 | if '1' !in a_i {
| ~~~ | ~~~
38 | println('good') 38 | println('good')
39 | } 39 | }
vlib/v/checker/tests/in_mismatch_type.v:41:7: error: the data type on the left of `!in` does not match the map key type vlib/v/checker/tests/in_mismatch_type.v:41:7: error: the data type on the left of `!in` (`any_int`) does not match the map key type `string`
39 | } 39 | }
40 | 40 |
41 | if 5 !in m { 41 | if 5 !in m {
| ~~~ | ~~~
42 | println('yay') 42 | println('yay')

View File

@ -1,5 +1,12 @@
vlib/v/checker/tests/is_type_not_exist.v:8:10: error: is: type `SomethingThatDontExist` does not exist vlib/v/checker/tests/is_type_not_exist.v:4:2: error: cannot use type `any_int` as type `Integer` in argument 1 to `fn_with_sum_type_param`
2 |
3 | fn main() {
4 | fn_with_sum_type_param(1)
| ~~~~~~~~~~~~~~~~~~~~~~~~~
5 | }
6 | 6 |
vlib/v/checker/tests/is_type_not_exist.v:8:10: error: is: type `SomethingThatDontExist` does not exist
6 |
7 | fn fn_with_sum_type_param(i Integer) { 7 | fn fn_with_sum_type_param(i Integer) {
8 | if i is SomethingThatDontExist { 8 | if i is SomethingThatDontExist {
| ~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/minus_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `int` vlib/v/checker/tests/minus_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `any_int`
1 | struct A{} 1 | struct A{}
2 | fn main() { 2 | fn main() {
3 | A{} - 10 3 | A{} - 10

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/minus_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `int` vlib/v/checker/tests/minus_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | [1,2,3] - 10 2 | [1,2,3] - 10
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/minus_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `int` vlib/v/checker/tests/minus_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | a - 10 3 | a - 10

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/minus_op_wrong_right_type_err_a.v:3:10: error: mismatched types `int` and `A` vlib/v/checker/tests/minus_op_wrong_right_type_err_a.v:3:10: error: mismatched types `any_int` and `A`
1 | struct A{} 1 | struct A{}
2 | fn main() { 2 | fn main() {
3 | 10 - A{} 3 | 10 - A{}

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/minus_op_wrong_right_type_err_b.v:2:10: error: mismatched types `int` and `array_int` vlib/v/checker/tests/minus_op_wrong_right_type_err_b.v:2:10: error: mismatched types `any_int` and `array_int`
1 | fn main() { 1 | fn main() {
2 | 10 - [1,2,3] 2 | 10 - [1,2,3]
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/minus_op_wrong_right_type_err_c.v:3:10: error: mismatched types `int` and `map_string_int` vlib/v/checker/tests/minus_op_wrong_right_type_err_c.v:3:10: error: mismatched types `any_int` and `map_string_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | 10 - a 3 | 10 - a

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mod_op_wrong_left_type_err_a.v:2:2: error: mismatched types `f64` and `int` vlib/v/checker/tests/mod_op_wrong_left_type_err_a.v:2:2: error: float modulo not allowed, use math.fmod() instead
1 | fn main() { 1 | fn main() {
2 | 0.5 % 1 2 | 0.5 % 1
| ~~~ | ~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mod_op_wrong_left_type_err_b.v:2:2: error: mismatched types `array_int` and `int` vlib/v/checker/tests/mod_op_wrong_left_type_err_b.v:2:2: error: mismatched types `array_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | [1,2,3] % 1 2 | [1,2,3] % 1
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mod_op_wrong_left_type_err_c.v:4:2: error: mismatched types `A` and `int` vlib/v/checker/tests/mod_op_wrong_left_type_err_c.v:4:2: error: mismatched types `A` and `any_int`
2 | fn main() { 2 | fn main() {
3 | a := A{} 3 | a := A{}
4 | a % 1 4 | a % 1

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mod_op_wrong_left_type_err_d.v:3:2: error: mismatched types `map_string_int` and `int` vlib/v/checker/tests/mod_op_wrong_left_type_err_d.v:3:2: error: mismatched types `map_string_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | a % 1 3 | a % 1

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mod_op_wrong_right_type_err_a.v:2:6: error: mismatched types `int` and `f64` vlib/v/checker/tests/mod_op_wrong_right_type_err_a.v:2:6: error: float modulo not allowed, use math.fmod() instead
1 | fn main() { 1 | fn main() {
2 | 1 % 0.5 2 | 1 % 0.5
| ~~~ | ~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mod_op_wrong_right_type_err_b.v:2:6: error: mismatched types `int` and `array_int` vlib/v/checker/tests/mod_op_wrong_right_type_err_b.v:2:6: error: mismatched types `any_int` and `array_int`
1 | fn main() { 1 | fn main() {
2 | 1 % [1,2,3] 2 | 1 % [1,2,3]
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mod_op_wrong_right_type_err_c.v:4:6: error: mismatched types `int` and `A` vlib/v/checker/tests/mod_op_wrong_right_type_err_c.v:4:6: error: mismatched types `any_int` and `A`
2 | fn main() { 2 | fn main() {
3 | a := A{} 3 | a := A{}
4 | 1 % a 4 | 1 % a

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mod_op_wrong_right_type_err_d.v:3:6: error: mismatched types `int` and `map_string_int` vlib/v/checker/tests/mod_op_wrong_right_type_err_d.v:3:6: error: mismatched types `any_int` and `map_string_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | 1 % a 3 | 1 % a

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mul_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `int` vlib/v/checker/tests/mul_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `any_int`
1 | struct A{} 1 | struct A{}
2 | fn main() { 2 | fn main() {
3 | A{} * 10 3 | A{} * 10

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mul_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `int` vlib/v/checker/tests/mul_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | [1,2,3] * 10 2 | [1,2,3] * 10
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mul_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `int` vlib/v/checker/tests/mul_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `any_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | a * 10 3 | a * 10

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/mul_op_wrong_left_type_err_d.v:6:11: error: infix expr: cannot use `any_float` (right expression) as `math.complex.Complex`
4 | fn main() {
5 | c1 := cmplx.complex(1,-2)
6 | c2 := c1 * 2.0
| ^
7 | println(c2)
8 | }

View File

@ -0,0 +1,8 @@
import math
import math.complex as cmplx
fn main() {
c1 := cmplx.complex(1,-2)
c2 := c1 * 2.0
println(c2)
}

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mul_op_wrong_right_type_err_a.v:3:10: error: mismatched types `int` and `A` vlib/v/checker/tests/mul_op_wrong_right_type_err_a.v:3:10: error: mismatched types `any_int` and `A`
1 | struct A{} 1 | struct A{}
2 | fn main() { 2 | fn main() {
3 | 10 * A{} 3 | 10 * A{}

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mul_op_wrong_right_type_err_b.v:2:10: error: mismatched types `int` and `array_int` vlib/v/checker/tests/mul_op_wrong_right_type_err_b.v:2:10: error: mismatched types `any_int` and `array_int`
1 | fn main() { 1 | fn main() {
2 | 10 * [1,2,3] 2 | 10 * [1,2,3]
| ~~~~~~~ | ~~~~~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mul_op_wrong_right_type_err_c.v:3:10: error: mismatched types `int` and `map_string_int` vlib/v/checker/tests/mul_op_wrong_right_type_err_c.v:3:10: error: mismatched types `any_int` and `map_string_int`
1 | fn main() { 1 | fn main() {
2 | a := map[string]int 2 | a := map[string]int
3 | 10 * a 3 | 10 * a

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/mul_op_wrong_right_type_err_d.v:6:12: error: infix expr: cannot use `math.complex.Complex` (right expression) as `any_float`
4 | fn main() {
5 | c1 := cmplx.complex(1,-2)
6 | c2 := 2.0 * c1
| ^
7 | println(c2)
8 | }

View File

@ -0,0 +1,8 @@
import math
import math.complex as cmplx
fn main() {
c1 := cmplx.complex(1,-2)
c2 := 2.0 * c1
println(c2)
}

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/return_type.v:2:9: error: cannot use `int` as type `bool` in return argument vlib/v/checker/tests/return_type.v:2:9: error: cannot use `any_int` as type `bool` in return argument
1 | fn test() bool { 1 | fn test() bool {
2 | return 100 2 | return 100
| ~~~ | ~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/shift_op_wrong_left_type_err.v:2:2: error: cannot shift type int into non-integer type f64 vlib/v/checker/tests/shift_op_wrong_left_type_err.v:2:2: error: cannot shift type any_int into non-integer type any_float
1 | fn main() { 1 | fn main() {
2 | 0.5 << 1 2 | 0.5 << 1
| ~~~ | ~~~

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/shift_op_wrong_right_type_err.v:2:7: error: cannot shift non-integer type f64 into type int vlib/v/checker/tests/shift_op_wrong_right_type_err.v:2:7: error: cannot shift non-integer type any_float into type any_int
1 | fn main() { 1 | fn main() {
2 | 1 << 0.5 2 | 1 << 0.5
| ~~~ | ~~~

View File

@ -272,7 +272,7 @@ pub fn (mut g Gen) finish() {
if g.pref.is_livemain || g.pref.is_liveshared { if g.pref.is_livemain || g.pref.is_liveshared {
g.generate_hotcode_reloader_code() g.generate_hotcode_reloader_code()
} }
if g.fn_main != 0 { if g.fn_main != voidptr(0) {
g.out.writeln('') g.out.writeln('')
g.fn_decl = g.fn_main g.fn_decl = g.fn_main
g.gen_fn_decl(g.fn_main) g.gen_fn_decl(g.fn_main)
@ -1728,7 +1728,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
} }
else {} else {}
} }
styp := g.typ(left_type) styp := g.typ(g.table.mktyp(left_type))
g.write('_IN($styp, ') g.write('_IN($styp, ')
g.expr(node.left) g.expr(node.left)
g.write(', ') g.write(', ')

View File

@ -847,7 +847,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
g.writeln('') g.writeln('')
} }
g.fn_decl = 0 g.fn_decl = voidptr(0)
} }
fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) { fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) {

View File

@ -65,14 +65,14 @@ pub fn (mut g Gen) generate_elf_header() {
g.write64(0) // p_offset g.write64(0) // p_offset
g.write64(segment_start) // p_vaddr addr:050 g.write64(segment_start) // p_vaddr addr:050
g.write64(segment_start) // g.write64(segment_start) //
g.file_size_pos = g.buf.len g.file_size_pos = i64(g.buf.len)
g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060 g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060
g.write64(0) // p_memsz g.write64(0) // p_memsz
g.write64(0x1000) // p_align g.write64(0x1000) // p_align
// user code starts here at // user code starts here at
// address: 00070 and a half // address: 00070 and a half
println('code_start_pos = $g.buf.len.hex()') println('code_start_pos = $g.buf.len.hex()')
g.code_start_pos = g.buf.len g.code_start_pos = i64(g.buf.len)
g.debug_pos = g.buf.len g.debug_pos = g.buf.len
g.call(placeholder) // call main function, it's not guaranteed to be the first, we don't know its address yet g.call(placeholder) // call main function, it's not guaranteed to be the first, we don't know its address yet
g.println('call fn main') g.println('call fn main')

View File

@ -402,7 +402,7 @@ pub fn (mut g Gen) gen_loop_end(to, label int) {
} }
pub fn (mut g Gen) save_main_fn_addr() { pub fn (mut g Gen) save_main_fn_addr() {
g.main_fn_addr = g.buf.len g.main_fn_addr = i64(g.buf.len)
} }
pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, newline bool) { pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, newline bool) {

View File

@ -58,7 +58,7 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode) &Scanner {
} }
raw_text := util.read_file( file_path ) or { raw_text := util.read_file( file_path ) or {
verror(err) verror(err)
return 0 return voidptr(0)
} }
mut s := new_scanner(raw_text, comments_mode) // .skip_comments) mut s := new_scanner(raw_text, comments_mode) // .skip_comments)
// s.init_fmt() // s.init_fmt()

View File

@ -195,6 +195,18 @@ pub fn (t &Table) get_type_name(typ Type) string {
return typ_sym.name return typ_sym.name
} }
[inline]
pub fn (t &Table) unalias_num_type(typ Type) Type {
sym := t.get_type_symbol(typ)
if sym.kind == .alias {
pt := (sym.info as Alias).parent_typ
if pt <= f64_type && pt >= void_type {
return pt
}
}
return typ
}
// this will override or register builtin type // this will override or register builtin type
// allows prexisitng types added in register_builtins // allows prexisitng types added in register_builtins
// to be overriden with their real type info // to be overriden with their real type info
@ -438,6 +450,21 @@ pub fn (t &Table) value_type(typ Type) Type {
return void_type return void_type
} }
[inline]
pub fn (t &Table) mktyp(typ Type) Type {
match typ {
any_flt_type {
return table.f64_type
}
any_int_type {
return table.int_type
}
else {
return typ
}
}
}
// Once we have a module format we can read from module file instead // Once we have a module format we can read from module file instead
// this is not optimal // this is not optimal
pub fn (table &Table) qualify_module(mod, file_path string) string { pub fn (table &Table) qualify_module(mod, file_path string) string {

View File

@ -13,16 +13,16 @@ fn test_int_lit_call_method() {
fn test_float_lit_call_method() { fn test_float_lit_call_method() {
x1 := -123.66.str() x1 := -123.66.str()
assert x1 == '-1.2366e+02' assert x1 == '-123.66'
x2 := 12.5e-2.str() x2 := 12.5e-2.str()
assert x2 == '1.25e-01' assert x2 == '0.125'
x3 := .789.str() x3 := .789.str()
assert x3 == '7.89e-01' assert x3 == '0.789'
x4 := .003e2.str() x4 := .003e2.str()
assert x4 == '3.e-01' assert x4 == '0.3'
x5 := 2.e-3.str() x5 := 2.e-3.str()
assert x5 == '2.e-03' assert x5 == '2.e-03'
x6 := 5.0.str() x6 := 5.0.str()
assert x6 == '5.e+00' assert x6 == '5.'
// x7 := 5..str() Syntax `5.` is allowed, but do not call method on it (`5..str()` is parsed as a range). Use `5.0.str()` instead. // x7 := 5..str() Syntax `5.` is allowed, but do not call method on it (`5..str()` is parsed as a range). Use `5.0.str()` instead.
} }