From ed874ffc5bc3ebbfba2da2785ee1f2bb2198435d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=C3=A4schle?= Date: Tue, 17 Nov 2020 21:26:40 +0100 Subject: [PATCH] checker: fix sum type operator check (#6815) --- vlib/v/checker/checker.v | 6 ++++++ vlib/v/checker/tests/sum_type_infix_err.out | 14 ++++++++++++++ vlib/v/checker/tests/sum_type_infix_err.vv | 8 ++++++++ vlib/v/checker/tests/sum_type_mutable_cast_err.out | 6 +++--- vlib/v/table/atypes.v | 12 +++++++++++- 5 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 vlib/v/checker/tests/sum_type_infix_err.out create mode 100644 vlib/v/checker/tests/sum_type_infix_err.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 189ec9d6fa..d661e8ba0f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -861,6 +861,12 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type { c.error('string types only have the following operators defined: `==`, `!=`, `<`, `>`, `<=`, `>=`, and `+`', infix_expr.pos) } + // sum types can't have any infix operation except of "is", is is checked before and doesn't reach this + if c.table.type_kind(left_type) == .union_sum_type { + c.error('cannot use operator `$infix_expr.op` with `$left.name`', infix_expr.pos) + } else if c.table.type_kind(right_type) == .union_sum_type { + c.error('cannot use operator `$infix_expr.op` with `$right.name`', infix_expr.pos) + } // Dual sides check (compatibility check) if !c.symmetric_check(right_type, left_type) && !c.pref.translated { // for type-unresolved consts diff --git a/vlib/v/checker/tests/sum_type_infix_err.out b/vlib/v/checker/tests/sum_type_infix_err.out new file mode 100644 index 0000000000..e969913089 --- /dev/null +++ b/vlib/v/checker/tests/sum_type_infix_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/sum_type_infix_err.vv:5:9: error: cannot use operator `+` with `Abc` + 3 | fn main() { + 4 | x := Abc(0) + 5 | _ := x + Abc(5) + | ^ + 6 | _ := 'test' + x + 7 | _ = unsafe{&x + 5} +vlib/v/checker/tests/sum_type_infix_err.vv:6:14: error: cannot use operator `+` with `Abc` + 4 | x := Abc(0) + 5 | _ := x + Abc(5) + 6 | _ := 'test' + x + | ^ + 7 | _ = unsafe{&x + 5} + 8 | } \ No newline at end of file diff --git a/vlib/v/checker/tests/sum_type_infix_err.vv b/vlib/v/checker/tests/sum_type_infix_err.vv new file mode 100644 index 0000000000..ff8a352710 --- /dev/null +++ b/vlib/v/checker/tests/sum_type_infix_err.vv @@ -0,0 +1,8 @@ +__type Abc = int | string + +fn main() { + x := Abc(0) + _ := x + Abc(5) + _ := 'test' + x + _ = unsafe{&x + 5} +} \ No newline at end of file diff --git a/vlib/v/checker/tests/sum_type_mutable_cast_err.out b/vlib/v/checker/tests/sum_type_mutable_cast_err.out index 4f9e94529f..6de52c7f59 100644 --- a/vlib/v/checker/tests/sum_type_mutable_cast_err.out +++ b/vlib/v/checker/tests/sum_type_mutable_cast_err.out @@ -1,18 +1,18 @@ -vlib/v/checker/tests/sum_type_mutable_cast_err.vv:23:10: error: infix expr: cannot use `any_int` (right expression) as `Abc` +vlib/v/checker/tests/sum_type_mutable_cast_err.vv:23:10: error: cannot use operator `+` with `Abc` 21 | mut x := Abc(0) 22 | if x is int { 23 | _ := x + 5 | ^ 24 | } 25 | f := Foo{Bar{Abc(0)}} -vlib/v/checker/tests/sum_type_mutable_cast_err.vv:27:14: error: infix expr: cannot use `any_int` (right expression) as `Abc` +vlib/v/checker/tests/sum_type_mutable_cast_err.vv:27:14: error: cannot use operator `+` with `Abc` 25 | f := Foo{Bar{Abc(0)}} 26 | if f.b.a is int { 27 | _ := f.b.a + 5 | ^ 28 | } 29 | mut f2 := Foo2{Bar2{Abc(0)}} -vlib/v/checker/tests/sum_type_mutable_cast_err.vv:31:14: error: infix expr: cannot use `any_int` (right expression) as `Abc` +vlib/v/checker/tests/sum_type_mutable_cast_err.vv:31:14: error: cannot use operator `+` with `Abc` 29 | mut f2 := Foo2{Bar2{Abc(0)}} 30 | if f2.b.a is int { 31 | _ := f.b.a + 5 diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 3879a8a91c..4b56529abc 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -26,7 +26,9 @@ pub enum Language { // Represents a type that only needs an identifier, e.g. int, array_int. // A pointer type `&T` would have a TypeSymbol `T`. -// Note: For a Type, use Table.type_to_str(typ) not TypeSymbol.name. +// Note: For a Type, use: +// * Table.type_to_str(typ) not TypeSymbol.name. +// * Table.type_kind(typ) not TypeSymbol.kind. // Each TypeSymbol is entered into `Table.types`. // See also: Table.get_type_symbol. pub struct TypeSymbol { @@ -363,6 +365,14 @@ pub: func Fn } +// returns TypeSymbol kind only if there are no type modifiers +pub fn (table &Table) type_kind(typ Type) Kind { + if typ.nr_muls() > 0 || typ.has_flag(.optional) { + return Kind.placeholder + } + return table.get_type_symbol(typ).kind +} + pub enum Kind { placeholder void