checker: add check_expected() which returns an optional error (#6623)
parent
0dfd51408e
commit
3c336b566d
|
@ -278,6 +278,15 @@ pub fn (mut c Checker) check_types(got table.Type, expected table.Type) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) check_expected(got table.Type, expected table.Type) ? {
|
||||
if c.check_types(got, expected) {
|
||||
return
|
||||
}
|
||||
exps := c.table.type_to_str(expected)
|
||||
gots := c.table.type_to_str(got)
|
||||
return error('expected `$exps`, not `$gots`')
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) symmetric_check(left table.Type, right table.Type) bool {
|
||||
// allow direct int-literal assignment for pointers for now
|
||||
// maybe in the future optionals should be used for that
|
||||
|
|
|
@ -373,12 +373,8 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
|
|||
if field.has_default_expr {
|
||||
c.expected_type = field.typ
|
||||
field_expr_type := c.expr(field.default_expr)
|
||||
if !c.check_types(field_expr_type, field.typ) {
|
||||
field_expr_type_sym := c.table.get_type_symbol(field_expr_type)
|
||||
field_type_sym := c.table.get_type_symbol(field.typ)
|
||||
c.error('default expression for field `$field.name` ' +
|
||||
'has type `$field_expr_type_sym.source_name`, but should be `$field_type_sym.source_name`',
|
||||
field.default_expr.position())
|
||||
c.check_expected(field_expr_type, field.typ) or {
|
||||
c.error('incompatible initializer for field `$field.name`: $err', field.default_expr.position())
|
||||
}
|
||||
// Check for unnecessary inits like ` = 0` and ` = ''`
|
||||
if field.typ.is_ptr() {
|
||||
|
@ -507,11 +503,10 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
|||
c.expected_type = info_field.typ
|
||||
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) && expr_type != table.void_type &&
|
||||
expr_type_sym.kind != .placeholder {
|
||||
c.error('cannot assign $expr_type_sym.kind `$expr_type_sym.source_name` as `$field_type_sym.source_name` for field `$info_field.name`',
|
||||
field.pos)
|
||||
if expr_type != table.void_type && expr_type_sym.kind != .placeholder {
|
||||
c.check_expected(expr_type, info_field.typ) or {
|
||||
c.error('cannot assign to field `$info_field.name`: $err', field.pos)
|
||||
}
|
||||
}
|
||||
if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_pointer() &&
|
||||
!expr_type.is_number() {
|
||||
|
@ -566,7 +561,6 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
infix_expr.right_type = right_type
|
||||
mut right := c.table.get_type_symbol(right_type)
|
||||
mut 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()
|
||||
if (left_type.is_ptr() || left.is_pointer()) &&
|
||||
|
@ -584,23 +578,22 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
match right.kind {
|
||||
.array {
|
||||
elem_type := right.array_info().elem_type
|
||||
right_sym := c.table.get_type_symbol(c.table.mktyp(right.array_info().elem_type))
|
||||
// if left_default.kind != right_sym.kind {
|
||||
if !c.check_types(left_type, elem_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.source_name`)',
|
||||
c.check_expected(left_type, elem_type) or {
|
||||
c.error('left operand to `$infix_expr.op` does not match the array element type: $err',
|
||||
infix_expr.pos)
|
||||
}
|
||||
}
|
||||
.map {
|
||||
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.source_name`',
|
||||
elem_type := right.map_info().key_type
|
||||
c.check_expected(left_type, elem_type) or {
|
||||
c.error('left operand to `$infix_expr.op` does not match the map key type: $err',
|
||||
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 (is `$left.name`)',
|
||||
c.check_expected(left_type, right_type) or {
|
||||
c.error('left operand to `$infix_expr.op` does not match: $err',
|
||||
infix_expr.pos)
|
||||
}
|
||||
}
|
||||
|
@ -1950,7 +1943,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
if is_decl {
|
||||
c.check_valid_snake_case(left.name, 'variable name', left.pos)
|
||||
}
|
||||
mut ident_var_info := left.var_info()
|
||||
mut ident_var_info := left.info as ast.IdentVar
|
||||
if ident_var_info.share == .shared_t {
|
||||
left_type = left_type.set_flag(.shared_f)
|
||||
}
|
||||
|
@ -1995,6 +1988,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
right_sym := c.table.get_type_symbol(right_type_unwrapped)
|
||||
if (left_type.is_ptr() || left_sym.is_pointer()) &&
|
||||
assign_stmt.op !in [.assign, .decl_assign] && !c.inside_unsafe {
|
||||
// ptr op=
|
||||
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', assign_stmt.pos)
|
||||
}
|
||||
if c.pref.translated {
|
||||
|
@ -2054,10 +2048,10 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
else {}
|
||||
}
|
||||
// Dual sides check (compatibility check)
|
||||
if !is_blank_ident && !c.check_types(right_type_unwrapped, left_type_unwrapped) &&
|
||||
right_sym.kind != .placeholder {
|
||||
c.error('cannot assign `$right_sym.source_name` to `$left.str()` of type `$left_sym.source_name`',
|
||||
right.position())
|
||||
if !is_blank_ident && right_sym.kind != .placeholder {
|
||||
c.check_expected(right_type_unwrapped, left_type_unwrapped) or {
|
||||
c.error('cannot assign to `$left`: $err', right.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.vv:4:8: error: cannot assign `string` to `obj` of type `int`
|
||||
vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.vv:4:8: error: cannot assign to `obj`: expected `int`, not `string`
|
||||
2 | ch := chan string{}
|
||||
3 | mut obj := 9
|
||||
4 | obj = <-ch
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vlib/v/checker/tests/assign_expr_type_err_i.vv:3:9: error: cannot assign `string` to `foo` of type `f64`
|
||||
vlib/v/checker/tests/assign_expr_type_err_i.vv:3:9: error: cannot assign to `foo`: expected `f64`, not `string`
|
||||
1 | fn main() {
|
||||
2 | mut foo := 1.5
|
||||
3 | foo += 'hello'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vlib/v/checker/tests/cannot_assign_array.vv:9:11: error: cannot assign `[8]f64` to `ctx.vb` of type `string`
|
||||
vlib/v/checker/tests/cannot_assign_array.vv:9:11: error: cannot assign to `ctx.vb`: expected `string`, not `[8]f64`
|
||||
7 | mut ctx := Context{}
|
||||
8 | x := 2.32
|
||||
9 | ctx.vb = [1.1, x, 3.3, 4.4, 5.0, 6.0, 7.0, 8.9]!!
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
vlib/v/checker/tests/in_mismatch_type.vv:10:7: error: the data type on the left of `in` (`any_int`) does not match the array item type (`string`)
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:10:7: error: left operand to `in` does not match the array element type: expected `string`, not `any_int`
|
||||
8 | }
|
||||
9 | s := 'abcd'
|
||||
10 | if 1 in a_s {
|
||||
| ~~
|
||||
11 | println('ok')
|
||||
12 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:13:7: error: the data type on the left of `in` (`any_int`) does not match the map key type `string`
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:13:7: error: left operand to `in` does not match the map key type: expected `string`, not `any_int`
|
||||
11 | println('ok')
|
||||
12 | }
|
||||
13 | if 2 in m {
|
||||
| ~~
|
||||
14 | println('yeah')
|
||||
15 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:16:7: error: the data type on the left of `in` must be a string (is `any_int`)
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:16:7: error: left operand to `in` does not match: expected `string`, not `any_int`
|
||||
14 | println('yeah')
|
||||
15 | }
|
||||
16 | if 3 in s {
|
||||
| ~~
|
||||
17 | println('dope')
|
||||
18 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:19:9: error: the data type on the left of `in` must be a string (is `rune`)
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:19:9: error: left operand to `in` does not match: expected `string`, not `rune`
|
||||
17 | println('dope')
|
||||
18 | }
|
||||
19 | if `a` in s {
|
||||
|
@ -33,42 +33,42 @@ vlib/v/checker/tests/in_mismatch_type.vv:22:7: error: `in` can only be used with
|
|||
| ~~
|
||||
23 | println('right')
|
||||
24 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:25:12: error: the data type on the left of `in` (`Int`) does not match the map key type `string`
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:25:12: error: left operand to `in` does not match the map key type: expected `string`, not `Int`
|
||||
23 | println('right')
|
||||
24 | }
|
||||
25 | if Int(2) in m {
|
||||
| ~~
|
||||
26 | println('yeah')
|
||||
27 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:28:9: error: the data type on the left of `in` (`string`) does not match the array item type (`int`)
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:28:9: error: left operand to `in` does not match the array element type: expected `int`, not `string`
|
||||
26 | println('yeah')
|
||||
27 | }
|
||||
28 | if '3' in a_i {
|
||||
| ~~
|
||||
29 | println('sure')
|
||||
30 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:31:9: error: the data type on the left of `in` (`string`) does not match the array item type (`int`)
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:31:9: error: left operand to `in` does not match the array element type: expected `int`, not `string`
|
||||
29 | println('sure')
|
||||
30 | }
|
||||
31 | if '2' in a_i {
|
||||
| ~~
|
||||
32 | println('all right')
|
||||
33 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:34:7: error: the data type on the left of `!in` (`any_int`) does not match the array item type (`string`)
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:34:7: error: left operand to `!in` does not match the array element type: expected `string`, not `any_int`
|
||||
32 | println('all right')
|
||||
33 | }
|
||||
34 | if 1 !in a_s {
|
||||
| ~~~
|
||||
35 | println('ok')
|
||||
36 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:37:9: error: the data type on the left of `!in` (`string`) does not match the array item type (`int`)
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:37:9: error: left operand to `!in` does not match the array element type: expected `int`, not `string`
|
||||
35 | println('ok')
|
||||
36 | }
|
||||
37 | if '1' !in a_i {
|
||||
| ~~~
|
||||
38 | println('good')
|
||||
39 | }
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:41:7: error: the data type on the left of `!in` (`any_int`) does not match the map key type `string`
|
||||
vlib/v/checker/tests/in_mismatch_type.vv:41:7: error: left operand to `!in` does not match the map key type: expected `string`, not `any_int`
|
||||
39 | }
|
||||
40 |
|
||||
41 | if 5 !in m {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vlib/v/checker/tests/map_init_wrong_type.vv:3:10: error: cannot assign `map[string]f64` to `a` of type `map[string]f32`
|
||||
vlib/v/checker/tests/map_init_wrong_type.vv:3:10: error: cannot assign to `a`: expected `map[string]f32`, not `map[string]f64`
|
||||
1 | fn main() {
|
||||
2 | mut a := map[string]f32{}
|
||||
3 | a = { 'x': 12.3 }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vlib/v/checker/tests/modules/overload_return_type/main.v:8:11: error: cannot assign `int` to `two` of type `Point`
|
||||
vlib/v/checker/tests/modules/overload_return_type/main.v:8:11: error: cannot assign to `two`: expected `Point`, not `int`
|
||||
6 | one := Point {x:1, y:2}
|
||||
7 | mut two := Point {x:5, y:1}
|
||||
8 | two = one + two
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vlib/v/checker/tests/overload_return_type.vv:14:11: error: cannot assign `int` to `two` of type `Point`
|
||||
vlib/v/checker/tests/overload_return_type.vv:14:11: error: cannot assign to `two`: expected `Point`, not `int`
|
||||
12 | mut one := Point {x:1, y:2}
|
||||
13 | mut two := Point {x:5, y:1}
|
||||
14 | two = one + two
|
||||
|
|
|
@ -19,7 +19,7 @@ vlib/v/checker/tests/sum.vv:10:11: error: cannot cast `rune` to `Var`
|
|||
| ~~~
|
||||
11 | mut s2 := Var('')
|
||||
12 | s2 = true
|
||||
vlib/v/checker/tests/sum.vv:12:7: error: cannot assign `bool` to `s2` of type `Var`
|
||||
vlib/v/checker/tests/sum.vv:12:7: error: cannot assign to `s2`: expected `Var`, not `bool`
|
||||
10 | _ := Var(`J`)
|
||||
11 | mut s2 := Var('')
|
||||
12 | s2 = true
|
||||
|
|
Loading…
Reference in New Issue