checker: check `in` left type
parent
fa4739794f
commit
a924defb94
|
@ -310,14 +310,22 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if infix_expr.op in [.key_in, .not_in] {
|
if infix_expr.op in [.key_in, .not_in] {
|
||||||
if !(right.kind in [.array, .map, .string]) {
|
|
||||||
c.error('`in` can only be used with an array/map/string', infix_expr.pos)
|
|
||||||
}
|
|
||||||
if right.kind == .array {
|
if right.kind == .array {
|
||||||
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
|
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
|
||||||
if left.kind != .alias && left.kind != right_sym.kind {
|
if left.kind != right_sym.kind {
|
||||||
c.error('the data type on the left of `in` does not match the array item type', infix_expr.pos)
|
c.error('the data type on the left of `in` does not match the array item type', infix_expr.pos)
|
||||||
}
|
}
|
||||||
|
} else if right.kind == .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 `in` does not match the map key type', infix_expr.pos)
|
||||||
|
}
|
||||||
|
} else if right.kind == .string {
|
||||||
|
if left.kind != .string {
|
||||||
|
c.error('the data type on the left of `in` must be a string', infix_expr.pos)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.error('`in` can only be used with an array/map/string', infix_expr.pos)
|
||||||
}
|
}
|
||||||
return table.bool_type
|
return table.bool_type
|
||||||
}
|
}
|
||||||
|
@ -1156,15 +1164,16 @@ fn (c mut Checker) stmt(node ast.Stmt) {
|
||||||
ast.ForInStmt {
|
ast.ForInStmt {
|
||||||
c.in_for_count++
|
c.in_for_count++
|
||||||
typ := c.expr(it.cond)
|
typ := c.expr(it.cond)
|
||||||
|
typ_idx := table.type_idx(typ)
|
||||||
if it.is_range {
|
if it.is_range {
|
||||||
high_type := c.expr(it.high)
|
high_type_idx := table.type_idx(c.expr(it.high))
|
||||||
if typ in table.integer_type_idxs && high_type !in table.integer_type_idxs {
|
if typ_idx in table.integer_type_idxs && high_type_idx !in table.integer_type_idxs {
|
||||||
c.error('range types do not match', it.cond.position())
|
c.error('range types do not match', it.cond.position())
|
||||||
} else if typ in table.float_type_idxs || high_type in table.float_type_idxs {
|
} else if typ_idx in table.float_type_idxs || high_type_idx in table.float_type_idxs {
|
||||||
c.error('range type can not be float', it.cond.position())
|
c.error('range type can not be float', it.cond.position())
|
||||||
} else if typ == table.bool_type_idx || high_type == table.bool_type_idx {
|
} else if typ_idx == table.bool_type_idx || high_type_idx == table.bool_type_idx {
|
||||||
c.error('range type can not be bool', it.cond.position())
|
c.error('range type can not be bool', it.cond.position())
|
||||||
} else if typ == table.string_type_idx || high_type == table.string_type_idx {
|
} else if typ_idx == table.string_type_idx || high_type_idx == table.string_type_idx {
|
||||||
c.error('range type can not be string', it.cond.position())
|
c.error('range type can not be string', it.cond.position())
|
||||||
}
|
}
|
||||||
c.expr(it.high)
|
c.expr(it.high)
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
vlib/v/checker/tests/inout/in_array_mismatch_type.v:2:7: error: the data type on the left of `in` does not match the array item type
|
|
||||||
1| fn main() {
|
|
||||||
2| if 1 in ['1', '2'] {
|
|
||||||
~~
|
|
||||||
3| println('ok')
|
|
||||||
4| }
|
|
|
@ -1,5 +0,0 @@
|
||||||
fn main() {
|
|
||||||
if 1 in ['1', '2'] {
|
|
||||||
println('ok')
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
vlib/v/checker/tests/inout/in_mismatch_type.v:13:7: error: the data type on the left of `in` does not match the array item type
|
||||||
|
11| }
|
||||||
|
12| s := 'abcd'
|
||||||
|
13| if 1 in a_s {
|
||||||
|
~~
|
||||||
|
14| println('ok')
|
||||||
|
15| }
|
||||||
|
vlib/v/checker/tests/inout/in_mismatch_type.v:16:7: error: the data type on the left of `in` does not match the map key type
|
||||||
|
14| println('ok')
|
||||||
|
15| }
|
||||||
|
16| if 2 in m {
|
||||||
|
~~
|
||||||
|
17| println('yeah')
|
||||||
|
18| }
|
||||||
|
vlib/v/checker/tests/inout/in_mismatch_type.v:19:7: error: the data type on the left of `in` must be a string
|
||||||
|
17| println('yeah')
|
||||||
|
18| }
|
||||||
|
19| if 3 in s {
|
||||||
|
~~
|
||||||
|
20| println('dope')
|
||||||
|
21| }
|
||||||
|
vlib/v/checker/tests/inout/in_mismatch_type.v:22:9: error: the data type on the left of `in` must be a string
|
||||||
|
20| println('dope')
|
||||||
|
21| }
|
||||||
|
22| if `a` in s {
|
||||||
|
~~
|
||||||
|
23| println("oh no :'(")
|
||||||
|
24| }
|
||||||
|
vlib/v/checker/tests/inout/in_mismatch_type.v:25:7: error: `in` can only be used with an array/map/string
|
||||||
|
23| println("oh no :'(")
|
||||||
|
24| }
|
||||||
|
25| if 1 in 12 {
|
||||||
|
~~
|
||||||
|
26| println('right')
|
||||||
|
27| }
|
||||||
|
vlib/v/checker/tests/inout/in_mismatch_type.v:28:12: error: the data type on the left of `in` does not match the map key type
|
||||||
|
26| println('right')
|
||||||
|
27| }
|
||||||
|
28| if Int(2) in m {
|
||||||
|
~~
|
||||||
|
29| println('yeah')
|
||||||
|
30| }
|
||||||
|
vlib/v/checker/tests/inout/in_mismatch_type.v:31:15: error: the data type on the left of `in` does not match the array item type
|
||||||
|
29| println('yeah')
|
||||||
|
30| }
|
||||||
|
31| if Str2('3') in a_i {
|
||||||
|
~~
|
||||||
|
32| println('sure')
|
||||||
|
33| }
|
||||||
|
vlib/v/checker/tests/inout/in_mismatch_type.v:34:15: error: the data type on the left of `in` does not match the array item type
|
||||||
|
32| println('sure')
|
||||||
|
33| }
|
||||||
|
34| if Str3('2') in a_i {
|
||||||
|
~~
|
||||||
|
35| println('all right')
|
||||||
|
36| }
|
|
@ -0,0 +1,37 @@
|
||||||
|
type Int = int
|
||||||
|
|
||||||
|
type Str2 = string
|
||||||
|
type Str3 = Str2
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
a_i := [1, 2, 3]
|
||||||
|
a_s := ['1', '2', '3']
|
||||||
|
m := {
|
||||||
|
'test': 1
|
||||||
|
}
|
||||||
|
s := 'abcd'
|
||||||
|
if 1 in a_s {
|
||||||
|
println('ok')
|
||||||
|
}
|
||||||
|
if 2 in m {
|
||||||
|
println('yeah')
|
||||||
|
}
|
||||||
|
if 3 in s {
|
||||||
|
println('dope')
|
||||||
|
}
|
||||||
|
if `a` in s {
|
||||||
|
println("oh no :'(")
|
||||||
|
}
|
||||||
|
if 1 in 12 {
|
||||||
|
println('right')
|
||||||
|
}
|
||||||
|
if Int(2) in m {
|
||||||
|
println('yeah')
|
||||||
|
}
|
||||||
|
if Str2('3') in a_i {
|
||||||
|
println('sure')
|
||||||
|
}
|
||||||
|
if Str3('2') in a_i {
|
||||||
|
println('all right')
|
||||||
|
}
|
||||||
|
}
|
|
@ -1397,9 +1397,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
g.expr_with_cast(node.right, node.right_type, info.elem_type)
|
g.expr_with_cast(node.right, node.right_type, info.elem_type)
|
||||||
g.write(' })')
|
g.write(' })')
|
||||||
}
|
}
|
||||||
} else if (node.left_type == node.right_type) && node.left_type in [table.f32_type_idx,
|
} else if (node.left_type == node.right_type) && table.is_float(node.left_type) && node.op in [.eq, .ne] {
|
||||||
table.f64_type_idx
|
|
||||||
] && node.op in [.eq, .ne] {
|
|
||||||
// floats should be compared with epsilon
|
// floats should be compared with epsilon
|
||||||
if node.left_type == table.f64_type_idx {
|
if node.left_type == table.f64_type_idx {
|
||||||
if node.op == .eq {
|
if node.op == .eq {
|
||||||
|
|
|
@ -130,6 +130,17 @@ pub fn new_type_ptr(idx, nr_muls int) Type {
|
||||||
return (nr_muls << 16) | u16(idx)
|
return (nr_muls << 16) | u16(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn is_float(typ Type) bool {
|
||||||
|
return type_idx(typ) in float_type_idxs
|
||||||
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn is_int(typ Type) bool {
|
||||||
|
return type_idx(typ) in integer_type_idxs
|
||||||
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
pub fn is_number(typ Type) bool {
|
pub fn is_number(typ Type) bool {
|
||||||
return type_idx(typ) in number_type_idxs
|
return type_idx(typ) in number_type_idxs
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,24 @@ fn test_in_expression_with_string() {
|
||||||
assert a == false
|
assert a == false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_in_expression_in_map() {
|
||||||
|
m := {
|
||||||
|
'one': 1
|
||||||
|
'two': 2
|
||||||
|
'three': 3
|
||||||
|
}
|
||||||
|
assert 'one' in m
|
||||||
|
assert 'four' !in m
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_in_expression_in_string() {
|
||||||
|
s := 'abcd'
|
||||||
|
assert 'a' in s
|
||||||
|
assert 'ab' in s
|
||||||
|
assert 'abcd' in s
|
||||||
|
assert 'dbca' !in s
|
||||||
|
}
|
||||||
|
|
||||||
fn test_optimized_in_expression() {
|
fn test_optimized_in_expression() {
|
||||||
mut a := false
|
mut a := false
|
||||||
a = true && 2 in [1, 2]
|
a = true && 2 in [1, 2]
|
||||||
|
|
Loading…
Reference in New Issue