checker: check casting struct -> interface; disallow casting struct -> interface pointer (#8110)
parent
c39f0a7cb7
commit
c80cc917c7
|
@ -3481,10 +3481,13 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) table.Type {
|
||||||
} else if node.expr_type == table.none_type {
|
} else if node.expr_type == table.none_type {
|
||||||
type_name := c.table.type_to_str(node.typ)
|
type_name := c.table.type_to_str(node.typ)
|
||||||
c.error('cannot cast `none` to `$type_name`', node.pos)
|
c.error('cannot cast `none` to `$type_name`', node.pos)
|
||||||
} else if from_type_sym.kind == .struct_ && !node.expr_type.is_ptr() && to_type_sym.kind !in
|
} else if from_type_sym.kind == .struct_ && !node.expr_type.is_ptr() {
|
||||||
[.sum_type, .interface_] && !c.is_builtin_mod {
|
if (node.typ.is_ptr() || to_type_sym.kind !in [.sum_type, .interface_]) && !c.is_builtin_mod {
|
||||||
type_name := c.table.type_to_str(node.typ)
|
type_name := c.table.type_to_str(node.typ)
|
||||||
c.error('cannot cast `struct` to `$type_name`', node.pos)
|
c.error('cannot cast struct to `$type_name`', node.pos)
|
||||||
|
} else if to_type_sym.kind == .interface_ {
|
||||||
|
c.type_implements(node.expr_type, node.typ, node.pos)
|
||||||
|
}
|
||||||
} else if node.expr_type.has_flag(.optional) || node.expr_type.has_flag(.variadic) {
|
} else if node.expr_type.has_flag(.optional) || node.expr_type.has_flag(.variadic) {
|
||||||
// variadic case can happen when arrays are converted into variadic
|
// variadic case can happen when arrays are converted into variadic
|
||||||
msg := if node.expr_type.has_flag(.optional) { 'an optional' } else { 'a variadic' }
|
msg := if node.expr_type.has_flag(.optional) { 'an optional' } else { 'a variadic' }
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:5:10: error: cannot cast `struct` to `string`
|
vlib/v/checker/tests/struct_type_cast_err.vv:5:10: error: cannot cast struct to `string`
|
||||||
3 | fn main() {
|
3 | fn main() {
|
||||||
4 | foo := Foo{}
|
4 | foo := Foo{}
|
||||||
5 | _ := string(foo)
|
5 | _ := string(foo)
|
||||||
| ~~~~~~~~~~~
|
| ~~~~~~~~~~~
|
||||||
6 | _ := int(foo)
|
6 | _ := int(foo)
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:6:10: error: cannot cast `struct` to `int`
|
vlib/v/checker/tests/struct_type_cast_err.vv:6:10: error: cannot cast struct to `int`
|
||||||
4 | foo := Foo{}
|
4 | foo := Foo{}
|
||||||
5 | _ := string(foo)
|
5 | _ := string(foo)
|
||||||
6 | _ := int(foo)
|
6 | _ := int(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:7:10: error: cannot cast `struct` to `u64`
|
vlib/v/checker/tests/struct_type_cast_err.vv:7:10: error: cannot cast struct to `u64`
|
||||||
5 | _ := string(foo)
|
5 | _ := string(foo)
|
||||||
6 | _ := int(foo)
|
6 | _ := int(foo)
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:8:10: error: cannot cast `struct` to `u32`
|
vlib/v/checker/tests/struct_type_cast_err.vv:8:10: error: cannot cast struct to `u32`
|
||||||
6 | _ := int(foo)
|
6 | _ := int(foo)
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
10 | _ := byte(foo)
|
10 | _ := byte(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:9:10: error: cannot cast `struct` to `rune`
|
vlib/v/checker/tests/struct_type_cast_err.vv:9:10: error: cannot cast struct to `rune`
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
|
@ -40,24 +40,31 @@ vlib/v/checker/tests/struct_type_cast_err.vv:10:10: error: cannot cast type `Foo
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
12 | _ := i64(foo)
|
12 | _ := i64(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:11:10: error: cannot cast `struct` to `i8`
|
vlib/v/checker/tests/struct_type_cast_err.vv:11:10: error: cannot cast struct to `i8`
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
10 | _ := byte(foo)
|
10 | _ := byte(foo)
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
12 | _ := i64(foo)
|
12 | _ := i64(foo)
|
||||||
13 | _ := int(foo)
|
13 | _ := int(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:12:10: error: cannot cast `struct` to `i64`
|
vlib/v/checker/tests/struct_type_cast_err.vv:12:10: error: cannot cast struct to `i64`
|
||||||
10 | _ := byte(foo)
|
10 | _ := byte(foo)
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
12 | _ := i64(foo)
|
12 | _ := i64(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
13 | _ := int(foo)
|
13 | _ := int(foo)
|
||||||
14 | }
|
14 | _ = &I1(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:13:10: error: cannot cast `struct` to `int`
|
vlib/v/checker/tests/struct_type_cast_err.vv:13:10: error: cannot cast struct to `int`
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
12 | _ := i64(foo)
|
12 | _ := i64(foo)
|
||||||
13 | _ := int(foo)
|
13 | _ := int(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
14 | }
|
14 | _ = &I1(foo)
|
||||||
15 |
|
15 | }
|
||||||
|
vlib/v/checker/tests/struct_type_cast_err.vv:14:10: error: cannot cast struct to `&I1`
|
||||||
|
12 | _ := i64(foo)
|
||||||
|
13 | _ := int(foo)
|
||||||
|
14 | _ = &I1(foo)
|
||||||
|
| ~~~~~~~
|
||||||
|
15 | }
|
||||||
|
16 |
|
||||||
|
|
|
@ -11,5 +11,7 @@ fn main() {
|
||||||
_ := i8(foo)
|
_ := i8(foo)
|
||||||
_ := i64(foo)
|
_ := i64(foo)
|
||||||
_ := int(foo)
|
_ := int(foo)
|
||||||
|
_ = &I1(foo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface I1{}
|
||||||
|
|
|
@ -3,5 +3,13 @@ vlib/v/checker/tests/unimplemented_interface_e.vv:12:6: error: `Cat` incorrectly
|
||||||
11 | fn main() {
|
11 | fn main() {
|
||||||
12 | foo(Cat{})
|
12 | foo(Cat{})
|
||||||
| ~~~~~
|
| ~~~~~
|
||||||
13 | }
|
13 | _ = Animal(Cat{})
|
||||||
|
14 | }
|
||||||
|
details: main.Animal has `speak(s string)`
|
||||||
|
vlib/v/checker/tests/unimplemented_interface_e.vv:13:6: error: `Cat` incorrectly implements method `speak` of interface `Animal`: expected `string`, not `&string` for parameter 1
|
||||||
|
11 | fn main() {
|
||||||
|
12 | foo(Cat{})
|
||||||
|
13 | _ = Animal(Cat{})
|
||||||
|
| ~~~~~~~~~~~~~
|
||||||
|
14 | }
|
||||||
details: main.Animal has `speak(s string)`
|
details: main.Animal has `speak(s string)`
|
||||||
|
|
|
@ -10,4 +10,5 @@ fn foo(a Animal) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo(Cat{})
|
foo(Cat{})
|
||||||
|
_ = Animal(Cat{})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue