1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

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

This commit is contained in:
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
vargs: vargs
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
any_int, any_float // internal intermediate types of number literals
byteptr // these two are mostly used for C interop
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.
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
```v

View File

@ -360,9 +360,9 @@ pub fn (b []byte) hex() string {
mut dst_i := 0
for i in b {
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
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`
return tos(hex,dst_i)

View File

@ -468,6 +468,10 @@ fn test_in() {
assert !(0 in a)
assert 0 !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 {
@ -557,7 +561,7 @@ fn test_map() {
assert strs.map(it.to_upper()) == ['V', 'IS', 'AWESOME']
assert strs.map(it == 'awesome') == [false, false, true]
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
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) == []
// 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(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 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)
}
[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
[inline]
pub fn (x f64) strsci(digit_num int) string {
@ -84,7 +95,7 @@ pub fn (a f64) eq(b f64) bool {
[inline]
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 {

View File

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

View File

@ -214,7 +214,7 @@ fn test_int_to_hex() {
assert u32(c0).hex() == 'c'
assert 2147483647.hex() == '7fffffff'
assert u32(2147483647).hex() == '7fffffff'
assert (-1).hex() == 'ffffffff'
assert (-1).hex() == 'ffffffffffffffff'
assert u32(4294967295).hex() == 'ffffffff'
// 64 bit
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 {
d.cap += d.cap >> 3
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
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++
return push_index
}
fn (d DenseArray) get(i int) voidptr {
$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)')
}
}
return byteptr(d.keys) + i * sizeof(string)
return byteptr(d.keys) + i * int(sizeof(string))
}
// 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[i] = tmp_key
// swap values (TODO: optimize)
C.memcpy(tmp_value, d.values + count * 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(tmp_value, d.values + count * u32(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)
count++
}
@ -164,7 +164,7 @@ fn (mut d DenseArray) zeros_to_end() {
d.size = count
d.cap = if count < 8 { u32(8) } else { count }
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 {
@ -280,7 +280,7 @@ fn (mut m map) set(k string, value voidptr) {
for meta == m.metas[index] {
kv_index := m.metas[index + 1]
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
}
index += 2
@ -349,7 +349,7 @@ fn (m map) get3(key string, zero voidptr) voidptr {
if meta == m.metas[index] {
kv_index := m.metas[index + 1]
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
@ -431,10 +431,10 @@ pub fn (d DenseArray) clone() DenseArray {
size: d.size
deletes: d.deletes
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.values, d.values, d.cap * d.value_bytes)
C.memcpy(res.values, d.values, d.cap * u32(d.value_bytes))
return res
}

View File

@ -750,7 +750,7 @@ pub fn (s string) ends_with(p string) bool {
pub fn (s string) to_lower() string {
mut b := malloc(s.len + 1)
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)
}
@ -767,7 +767,7 @@ pub fn (s string) is_lower() bool {
pub fn (s string) to_upper() string {
mut b := malloc(s.len + 1)
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)
}

View File

@ -13,33 +13,33 @@ pub fn utf32_to_str(code u32) string {
icode := int(code) // Prevents doing casts everywhere
mut buffer := malloc(5)
if icode <= 127/* 0x7F */ {
buffer[0] = icode
buffer[0] = byte(icode)
return tos(buffer, 1)
}
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)
}
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)
}
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)
}
@ -51,33 +51,33 @@ pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string {
icode := int(code) // Prevents doing casts everywhere
mut buffer := byteptr(buf)
if icode <= 127/* 0x7F */ {
buffer[0] = icode
buffer[0] = byte(icode)
return tos(buffer, 1)
}
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)
}
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)
}
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)
}

View File

@ -127,7 +127,7 @@ fn (mut cb Clipboard) free() {
fn to_wide(text string) &C.HGLOBAL {
len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len +
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) {
mut locked := &u16(C.GlobalLock(buf))
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)
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
vertical_advance_px: (*face).glyph.metrics.vertAdvance >> 6
horizontal_advance_px: u32((*face).glyph.metrics.horiAdvance) >> 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) {
eprintln('freetype: font "$font_path" does not exist')
return 0
return voidptr(0)
}
face := &C.FT_FaceRec{
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 {
// width := utext.len * 7
width := wx
x -= width + 10
x -= f32(width + 10)
}
x *= ctx.scale
y *= ctx.scale
y += yoffset
x *= f32(ctx.scale)
y *= f32(ctx.scale)
y += f32(yoffset)
y = f32(ctx.height) - y // invert y direction
color := cfg.color
// 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{}
start_rads := start_angle * 0.0174533 // deg -> rad approx
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] !
mut i := 1
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) {
size := sizeof(int) * vertices.len
size := sizeof(int) * u32(vertices.len)
C.glBufferData(typ, size, vertices.data, draw_typ)
}
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)
}
@ -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) {
mut stride := _stride
mut stride := u32(_stride)
mut ptr := _ptr
if typ == C.GL_FLOAT {
stride *= sizeof(f32)
ptr *= sizeof(f32)
ptr *= int(sizeof(f32))
}
C.glVertexAttribPointer(index, size, typ, normalized, stride, ptr)
}
@ -311,4 +311,4 @@ pub fn set_bool(loc int, val bool) {
} else {
set_f32(loc, 0)
}
}
}

View File

@ -191,8 +191,8 @@ pub fn (mut ws Client) close(code int, message string) {
code_ := C.htons(code)
message_len := message.len + 2
mut close_frame := [`0`].repeat(message_len)
close_frame[0] = code_ & 0xFF
close_frame[1] = (code_ >> 8)
close_frame[0] = byte(code_ & 0xFF)
close_frame[1] = byte(code_ >> 8)
code32 = (close_frame[0] << 8) + close_frame[1]
for i in 0 .. message.len {
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 )
masking_key := create_masking_key()
mut header := [`0`].repeat(header_len)
header[0] = (int(code) | 0x80)
header[0] = byte(code) | 0x80
if payload_len <= 125 {
header[1] = (payload_len | 0x80)
header[1] = byte(payload_len | 0x80)
header[2] = masking_key[0]
header[3] = masking_key[1]
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] {
data_node:
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 {
l.f('out of memory')
}
@ -437,7 +437,7 @@ pub fn (mut ws Client) read() int {
size += f.len
}
}
mut pl := malloc(sizeof(byte) * int(size))
mut pl := malloc(sizeof(byte) * u32(size))
if pl == 0 {
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
mut control_frame := [`0`].repeat(frame_len)
masking_key := create_masking_key()
control_frame[0] = (int(code) | 0x80)
control_frame[1] = (payload.len | 0x80)
control_frame[0] = byte(code | 0x80)
control_frame[1] = byte(payload.len | 0x80)
control_frame[2] = masking_key[0]
control_frame[3] = masking_key[1]
control_frame[4] = masking_key[2]

View File

@ -19,7 +19,7 @@ pub fn getenv(key string) string {
return string_from_wide(s)
} $else {
s := C.getenv(key.str)
if s == 0 {
if s == voidptr(0) {
return ''
}
// 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)
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
}
$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
} 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
} 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
} 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
} 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
}
}
@ -56,38 +56,38 @@ pub fn inode(path string) FileMode {
return FileMode{
typ: typ
owner: FilePermission{
read: bool(attr.st_mode & C.S_IREAD)
write: bool(attr.st_mode & C.S_IWRITE)
execute: bool(attr.st_mode & C.S_IEXEC)
read: bool(attr.st_mode & u32(C.S_IREAD))
write: bool(attr.st_mode & u32(C.S_IWRITE))
execute: bool(attr.st_mode & u32(C.S_IEXEC))
}
group: FilePermission{
read: bool(attr.st_mode & C.S_IREAD)
write: bool(attr.st_mode & C.S_IWRITE)
execute: bool(attr.st_mode & C.S_IEXEC)
read: bool(attr.st_mode & u32(C.S_IREAD))
write: bool(attr.st_mode & u32(C.S_IWRITE))
execute: bool(attr.st_mode & u32(C.S_IEXEC))
}
others: FilePermission{
read: bool(attr.st_mode & C.S_IREAD)
write: bool(attr.st_mode & C.S_IWRITE)
execute: bool(attr.st_mode & C.S_IEXEC)
read: bool(attr.st_mode & u32(C.S_IREAD))
write: bool(attr.st_mode & u32(C.S_IWRITE))
execute: bool(attr.st_mode & u32(C.S_IEXEC))
}
}
} $else {
return FileMode{
typ: typ
owner: FilePermission{
read: bool(attr.st_mode & C.S_IRUSR)
write: bool(attr.st_mode & C.S_IWUSR)
execute: bool(attr.st_mode & C.S_IXUSR)
read: bool(attr.st_mode & u32(C.S_IRUSR))
write: bool(attr.st_mode & u32(C.S_IWUSR))
execute: bool(attr.st_mode & u32(C.S_IXUSR))
}
group: FilePermission{
read: bool(attr.st_mode & C.S_IRGRP)
write: bool(attr.st_mode & C.S_IWGRP)
execute: bool(attr.st_mode & C.S_IXGRP)
read: bool(attr.st_mode & u32(C.S_IRGRP))
write: bool(attr.st_mode & u32(C.S_IWGRP))
execute: bool(attr.st_mode & u32(C.S_IXGRP))
}
others: FilePermission{
read: bool(attr.st_mode & C.S_IROTH)
write: bool(attr.st_mode & C.S_IWOTH)
execute: bool(attr.st_mode & C.S_IXOTH)
read: bool(attr.st_mode & u32(C.S_IROTH))
write: bool(attr.st_mode & u32(C.S_IWOTH))
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 ret := charptr(0)
$if windows {
ret = C._fullpath(fullpath, fpath.str, max_path_len)
ret = charptr(C._fullpath(fullpath, fpath.str, max_path_len))
if ret == 0 {
return fpath
}
} $else {
ret = C.realpath(fpath.str, fullpath)
ret = charptr(C.realpath(fpath.str, fullpath))
if ret == 0 {
return fpath
}
@ -1324,7 +1324,7 @@ pub fn open(path string) ?File {
}
*/
cfile := vfopen(path, 'rb')
if cfile == 0 {
if cfile == voidptr(0) {
return error('failed to open file "$path"')
}
fd := fileno(cfile)
@ -1361,7 +1361,7 @@ pub fn create(path string) ?File {
}
*/
cfile := vfopen(path, 'wb')
if cfile == 0 {
if cfile == voidptr(0) {
return error('failed to create file "$path"')
}
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.
pub fn get_file_handle(path string) HANDLE {
cfile := vfopen(path, 'rb')
if cfile == 0 {
if cfile == voidptr(0) {
return HANDLE(invalid_handle_value)
}
handle := HANDLE(C._get_osfhandle(fileno(cfile))) // CreateFile? - hah, no -_-

View File

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

View File

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

View File

@ -65,6 +65,6 @@ pub fn dice_coefficient(s1, s2 string) f32 {
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_mtx: new_mutex()
waitgroup: new_waitgroup()
thread_cb: context.callback
thread_cb: voidptr(context.callback)
}
return pool
}

View File

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

View File

@ -106,7 +106,7 @@ pub fn new_time(t Time) Time {
hour: t.hour
minute: t.minute
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`
// 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.
pub fn (t Time) add_seconds(seconds int) Time {
// 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.
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.
@ -272,7 +272,7 @@ fn convert_ctime(t C.tm) Time {
hour: t.tm_hour
minute: t.tm_min
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
minute: min
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 {
t := c.table
got_idx := got.idx()
exp_idx := expected.idx()
got_idx := t.unalias_num_type(got).idx()
exp_idx := t.unalias_num_type(expected).idx()
// got_is_ptr := got.is_ptr()
exp_is_ptr := expected.is_ptr()
// 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
}
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_sym := c.table.get_type_symbol(expr_type)
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`',
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)
}
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
right := c.table.get_type_symbol(right_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
// 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.
@ -417,22 +421,22 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
.key_in, .not_in {
match right.kind {
.array {
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
if left.kind != right_sym.kind {
c.error('the data type on the left of `$infix_expr.op.str()` does not match the array item type',
right_sym := c.table.get_type_symbol(c.table.mktyp(right.array_info().elem_type))
if left_default.kind != right_sym.kind {
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)
}
}
.map {
key_sym := c.table.get_type_symbol(right.map_info().key_type)
if left.kind != key_sym.kind {
c.error('the data type on the left of `$infix_expr.op.str()` does not match the map key type',
key_sym := c.table.get_type_symbol(c.table.mktyp(right.map_info().key_type))
if left_default.kind != key_sym.kind {
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)
}
}
.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)
}
}
@ -443,15 +447,43 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
}
return table.bool_type
}
.plus, .minus, .mul, .div {
if infix_expr.op == .div && (infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() ==
'0' || infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) {
c.error('division by zero', infix_expr.right.position())
}
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`', infix_expr.left.position())
} else if right.kind in [.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())
.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe { // binary operators that expect matching types
if left.kind in [.array, .array_fixed, .map, .struct_] {
if left.has_method(infix_expr.op.str()) {
return_type = left_type
} else {
c.error('mismatched types `$left.name` and `$right.name`', left_pos)
}
} else if right.kind in [.array, .array_fixed, .map, .struct_] {
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 {
@ -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 right.kind != .array {
// []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 {
// []Animal << Cat
c.type_implements(c.table.value_type(right_type), left_value_type,
infix_expr.right.position())
c.type_implements(c.table.value_type(right_type), left_value_type, right_pos)
}
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
}
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
} 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
} 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
}
}
@ -499,33 +530,6 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.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 {}
}
// 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)
}
// 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
if left_type == table.void_type || right_type == 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() {
table.bool_type
} else {
left_type
return_type
}
}
@ -678,7 +682,7 @@ fn (mut c Checker) assign_expr(mut assign_expr ast.AssignExpr) {
else {}
}
// 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)
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`',
@ -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
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'
is_decl := assign_stmt.op == .decl_assign
if is_decl && ident.name != '_' {
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()
if assign_stmt.op == .assign {
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.exprs.len == 0 {
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)
}
}
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)
}
}
@ -1316,12 +1323,12 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
// a = []
if array_init.exprs.len == 0 {
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)
}
}
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)
}
}
@ -1372,8 +1379,8 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
}
// The first element's type
if i == 0 {
elem_type = typ
c.expected_type = typ
elem_type = c.table.mktyp(typ)
c.expected_type = elem_type
continue
}
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_deps << field.name
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 j, f in it.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)
}
ast.FloatLiteral {
return table.f64_type
return table.any_flt_type
}
ast.Ident {
// 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)
}
ast.IntegerLiteral {
return table.int_type
return table.any_int_type
}
ast.MapInit {
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)
}
ast.SizeOf {
return table.int_type
return table.u32_type
}
ast.StringLiteral {
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
node.is_expr = true
node.typ = last_expr.typ
} else {
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
node.pos)
continue
} else if node.typ in [table.any_flt_type, table.any_int_type] {
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 {
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 !node.has_else {
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{}
2 | fn main() {
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() {
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() {
2 | a := map[string]int
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{}
2 | fn main() {
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() {
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() {
2 | a := map[string]int
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() {
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() {
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() {
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{}
2 | fn main() {
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() {
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() {
2 | a := map[string]int
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{}
2 | fn main() {
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() {
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() {
2 | a := map[string]int
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() {
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() {
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 | }
9 | s := 'abcd'
10 | if 1 in a_s {
| ~~
11 | println('ok')
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')
12 | }
13 | if 2 in m {
| ~~
14 | println('yeah')
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')
15 | }
16 | if 3 in s {
| ~~
17 | println('dope')
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')
18 | }
19 | if `a` in s {
| ~~
20 | println("oh no :'(")
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 :'(")
21 | }
22 | if 1 in 12 {
| ~~
23 | println('right')
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')
24 | }
25 | if Int(2) in m {
| ~~
26 | println('yeah')
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')
27 | }
28 | if '3' in a_i {
| ~~
29 | println('sure')
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')
30 | }
31 | if '2' in a_i {
| ~~
32 | println('all right')
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')
33 | }
34 | if 1 !in a_s {
| ~~~
35 | println('ok')
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')
36 | }
37 | if '1' !in a_i {
| ~~~
38 | println('good')
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 | }
40 |
40 |
41 | if 5 !in m {
| ~~~
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 |
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) {
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{}
2 | fn main() {
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() {
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() {
2 | a := map[string]int
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{}
2 | fn main() {
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() {
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() {
2 | a := map[string]int
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() {
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() {
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() {
3 | a := A{}
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() {
2 | a := map[string]int
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() {
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() {
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() {
3 | a := 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() {
2 | a := map[string]int
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{}
2 | fn main() {
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() {
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() {
2 | a := map[string]int
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{}
2 | fn main() {
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() {
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() {
2 | a := map[string]int
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 {
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() {
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() {
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 {
g.generate_hotcode_reloader_code()
}
if g.fn_main != 0 {
if g.fn_main != voidptr(0) {
g.out.writeln('')
g.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 {}
}
styp := g.typ(left_type)
styp := g.typ(g.table.mktyp(left_type))
g.write('_IN($styp, ')
g.expr(node.left)
g.write(', ')

View File

@ -847,7 +847,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
g.writeln('')
}
g.fn_decl = 0
g.fn_decl = voidptr(0)
}
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(segment_start) // p_vaddr addr:050
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_memsz
g.write64(0x1000) // p_align
// user code starts here at
// address: 00070 and a half
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.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')

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

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 {
verror(err)
return 0
return voidptr(0)
}
mut s := new_scanner(raw_text, comments_mode) // .skip_comments)
// s.init_fmt()

View File

@ -195,6 +195,18 @@ pub fn (t &Table) get_type_name(typ Type) string {
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
// allows prexisitng types added in register_builtins
// to be overriden with their real type info
@ -438,6 +450,21 @@ pub fn (t &Table) value_type(typ Type) 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
// this is not optimal
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() {
x1 := -123.66.str()
assert x1 == '-1.2366e+02'
assert x1 == '-123.66'
x2 := 12.5e-2.str()
assert x2 == '1.25e-01'
assert x2 == '0.125'
x3 := .789.str()
assert x3 == '7.89e-01'
assert x3 == '0.789'
x4 := .003e2.str()
assert x4 == '3.e-01'
assert x4 == '0.3'
x5 := 2.e-3.str()
assert x5 == '2.e-03'
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.
}