From 717e26b45e68b22ab79080327bd639d866b48ee5 Mon Sep 17 00:00:00 2001 From: yuyi Date: Mon, 20 Apr 2020 20:49:26 +0800 Subject: [PATCH] checker: more infix checks --- vlib/v/ast/ast.v | 81 ++++++------------- vlib/v/checker/checker.v | 37 +++++---- .../inout/bit_op_wrong_left_type_err.out | 4 +- .../inout/bit_op_wrong_right_type_err.out | 4 +- .../tests/inout/bit_op_wrong_right_type_err.v | 4 +- .../inout/bit_op_wrong_right_type_err.vv | 3 + .../inout/mod_op_wrong_left_type_err.out | 5 ++ .../tests/inout/mod_op_wrong_left_type_err.vv | 3 + .../inout/mod_op_wrong_right_type_err.out | 5 ++ .../inout/mod_op_wrong_right_type_err.vv | 3 + .../inout/shift_op_wrong_left_type_err.out | 5 ++ .../inout/shift_op_wrong_left_type_err.vv | 3 + .../inout/shift_op_wrong_right_type_err.out | 5 ++ .../inout/shift_op_wrong_right_type_err.vv | 3 + .../tests/inout/struct_unknown_field.out | 2 +- vlib/v/parser/parser.v | 3 +- vlib/v/parser/pratt.v | 2 + 17 files changed, 92 insertions(+), 80 deletions(-) create mode 100644 vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.vv create mode 100644 vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.out create mode 100644 vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.vv create mode 100644 vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.out create mode 100644 vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.vv create mode 100644 vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.out create mode 100644 vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.vv create mode 100644 vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.out create mode 100644 vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.vv diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index a94583c2ec..152ae6cfdc 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -48,6 +48,7 @@ pub: pub struct FloatLiteral { pub: val string + pos token.Position } pub struct StringLiteral { @@ -73,11 +74,13 @@ mut: pub struct CharLiteral { pub: val string + pos token.Position } pub struct BoolLiteral { pub: val bool + pos token.Position } // `foo.bar` @@ -737,36 +740,20 @@ pub fn expr_is_call(expr Expr) bool { fn (expr Expr) position() token.Position { // all uncommented have to be implemented match var expr { - ArrayInit { - return it.pos - } - AsCast { - return it.pos - } + ArrayInit { return it.pos } + AsCast { return it.pos } // ast.Ident { } - AssignExpr { - return it.pos - } + AssignExpr { return it.pos } // ast.CastExpr { } - Assoc { - return it.pos - } - // ast.BoolLiteral { } - CallExpr { - return it.pos - } - // ast.CharLiteral { } - EnumVal { - return it.pos - } - // ast.FloatLiteral { } - IfExpr { - return it.pos - } + Assoc { return it.pos } + BoolLiteral { return it.pos } + CallExpr { return it.pos } + CharLiteral { return it.pos } + EnumVal { return it.pos } + FloatLiteral { return it.pos } + IfExpr { return it.pos } // ast.IfGuardExpr { } - IndexExpr { - return it.pos - } + IndexExpr { return it.pos } InfixExpr { left_pos := it.left.position() right_pos := it.right.position() @@ -779,40 +766,20 @@ fn (expr Expr) position() token.Position { len: right_pos.pos - left_pos.pos + right_pos.len } } - IntegerLiteral { - return it.pos - } - MapInit { - return it.pos - } - MatchExpr { - return it.pos - } - PostfixExpr { - return it.pos - } + IntegerLiteral { return it.pos } + MapInit { return it.pos } + MatchExpr { return it.pos } + PostfixExpr { return it.pos } // ast.None { } - PrefixExpr { - return it.pos - } + PrefixExpr { return it.pos } // ast.ParExpr { } - SelectorExpr { - return it.pos - } + SelectorExpr { return it.pos } // ast.SizeOf { } - StringLiteral { - return it.pos - } - StringInterLiteral { - return it.pos - } + StringLiteral { return it.pos } + StringInterLiteral { return it.pos } // ast.Type { } - StructInit { - return it.pos - } + StructInit { return it.pos } // ast.TypeOf { } - else { - return token.Position{} - } + else { return token.Position{} } } } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 9ee4286f2e..03ee8b5eb0 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -270,11 +270,6 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { right := c.table.get_type_symbol(right_type) left := c.table.get_type_symbol(left_type) if infix_expr.op == .left_shift { - if left.kind != .array && !left.is_int() { - // c.error('<< can only be used with numbers and arrays', infix_expr.pos) - c.error('cannot shift type $right.name into $left.name', infix_expr.right.position()) - return table.void_type - } if left.kind == .array { // `array << elm` // the expressions have different types (array_x and x) @@ -288,6 +283,12 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { } c.error('cannot shift type $right.name into $left.name', infix_expr.right.position()) 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()) + 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()) + return table.void_type } } if infix_expr.op in [.key_in, .not_in] { @@ -302,20 +303,19 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { } return table.bool_type } - if !c.table.check(right_type, left_type) { - // for type-unresolved consts - if left_type == table.void_type || right_type == table.void_type { - return table.void_type - } - c.error('infix expr: cannot use `$right.name` (right expression) as `$left.name`', - infix_expr.pos) - } if infix_expr.op in [.amp, .pipe, .xor] { if !left.is_int() { - c.error('operator ${infix_expr.op.str()} not defined on left type `$left.name`', infix_expr.pos) + 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('operator ${infix_expr.op.str()} not defined on right type `$right.name`', infix_expr.pos) + c.error('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name', infix_expr.right.position()) + } + } + if infix_expr.op == .mod { + if left.is_int() && !right.is_int() { + c.error('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name', infix_expr.right.position()) + } else if !left.is_int() && right.is_int() { + c.error('left type of `${infix_expr.op.str()}` cannot be non-integer type $left.name', infix_expr.left.position()) } } if left_type == table.bool_type && !(infix_expr.op in [.eq, .ne, .logical_or, .and]) { @@ -327,6 +327,13 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { c.error('string types only have the following operators defined: `==`, `!=`, `<`, `>`, `<=`, `>=`, and `&&`', infix_expr.pos) } + if !c.table.check(right_type, left_type) { + // for type-unresolved consts + if left_type == table.void_type || right_type == table.void_type { + return table.void_type + } + c.error('infix expr: cannot use `$right.name` (right expression) as `$left.name`', infix_expr.pos) + } if infix_expr.op.is_relational() { return table.bool_type } diff --git a/vlib/v/checker/tests/inout/bit_op_wrong_left_type_err.out b/vlib/v/checker/tests/inout/bit_op_wrong_left_type_err.out index 98429e9a88..11c8992b64 100644 --- a/vlib/v/checker/tests/inout/bit_op_wrong_left_type_err.out +++ b/vlib/v/checker/tests/inout/bit_op_wrong_left_type_err.out @@ -1,5 +1,5 @@ -vlib/v/checker/tests/inout/bit_op_wrong_left_type_err.v:2:6: error: operator & not defined on left type `f64` +vlib/v/checker/tests/inout/bit_op_wrong_left_type_err.v:2:2: error: left type of `&` cannot be non-integer type f64 1| fn main() { 2| 0.5 & 1 - ^ + ~~~ 3| } diff --git a/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.out b/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.out index c37abc4908..668548cf69 100644 --- a/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.out +++ b/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.out @@ -1,5 +1,5 @@ -vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.v:2:4: error: operator | not defined on right type `f64` +vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.v:2:6: error: right type of `|` cannot be non-integer type f64 1| fn main() { 2| 1 | 0.5 - ^ + ~~~ 3| } diff --git a/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.v b/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.v index e46d383406..8bdcbc593f 100644 --- a/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.v +++ b/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.v @@ -1,3 +1,3 @@ -fn main() { - 1 | 0.5 +fn main() { + 1 | 0.5 } \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.vv b/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.vv new file mode 100644 index 0000000000..8bdcbc593f --- /dev/null +++ b/vlib/v/checker/tests/inout/bit_op_wrong_right_type_err.vv @@ -0,0 +1,3 @@ +fn main() { + 1 | 0.5 +} \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.out b/vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.out new file mode 100644 index 0000000000..15db2ffbe9 --- /dev/null +++ b/vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.out @@ -0,0 +1,5 @@ +vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.v:2:2: error: left type of `%` cannot be non-integer type f64 + 1| fn main() { + 2| 0.5 % 1 + ~~~ + 3| } diff --git a/vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.vv b/vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.vv new file mode 100644 index 0000000000..800b101fcd --- /dev/null +++ b/vlib/v/checker/tests/inout/mod_op_wrong_left_type_err.vv @@ -0,0 +1,3 @@ +fn main() { + 0.5 % 1 +} \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.out b/vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.out new file mode 100644 index 0000000000..e4d56aafac --- /dev/null +++ b/vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.out @@ -0,0 +1,5 @@ +vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.v:2:6: error: right type of `%` cannot be non-integer type f64 + 1| fn main() { + 2| 1 % 0.5 + ~~~ + 3| } diff --git a/vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.vv b/vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.vv new file mode 100644 index 0000000000..0ee36d9b9b --- /dev/null +++ b/vlib/v/checker/tests/inout/mod_op_wrong_right_type_err.vv @@ -0,0 +1,3 @@ +fn main() { + 1 % 0.5 +} \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.out b/vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.out new file mode 100644 index 0000000000..d4948c7920 --- /dev/null +++ b/vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.out @@ -0,0 +1,5 @@ +vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.v:2:2: error: cannot shift type int into non-integer type f64 + 1| fn main() { + 2| 0.5 << 1 + ~~~ + 3| } diff --git a/vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.vv b/vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.vv new file mode 100644 index 0000000000..5c0a8cb6fd --- /dev/null +++ b/vlib/v/checker/tests/inout/shift_op_wrong_left_type_err.vv @@ -0,0 +1,3 @@ +fn main() { + 0.5 << 1 +} \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.out b/vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.out new file mode 100644 index 0000000000..35af639b74 --- /dev/null +++ b/vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.out @@ -0,0 +1,5 @@ +vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.v:2:7: error: cannot shift non-integer type f64 into type int + 1| fn main() { + 2| 1 << 0.5 + ~~~ + 3| } diff --git a/vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.vv b/vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.vv new file mode 100644 index 0000000000..5e8a85d179 --- /dev/null +++ b/vlib/v/checker/tests/inout/shift_op_wrong_right_type_err.vv @@ -0,0 +1,3 @@ +fn main() { + 1 << 0.5 +} \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/struct_unknown_field.out b/vlib/v/checker/tests/inout/struct_unknown_field.out index 34010aff04..1e2d6577b7 100644 --- a/vlib/v/checker/tests/inout/struct_unknown_field.out +++ b/vlib/v/checker/tests/inout/struct_unknown_field.out @@ -2,6 +2,6 @@ vlib/v/checker/tests/inout/struct_unknown_field.v:8:9: error: unknown field `bar 6| t := Test{ 7| foo: true 8| bar: false - ^ + ~~~~~~~~~~ 9| } 10| } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 8063f76bda..685f71872f 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -875,6 +875,7 @@ fn (var p Parser) parse_number_literal() ast.Expr { if lit.index_any('.eE') >= 0 && lit[..2] !in ['0x', '0X', '0o', '0O', '0b', '0B'] { node = ast.FloatLiteral{ val: lit + pos: pos } } else { node = ast.IntegerLiteral{ @@ -1210,10 +1211,10 @@ fn (var p Parser) assoc() ast.Assoc { fn (p &Parser) new_true_expr() ast.Expr { return ast.BoolLiteral{ val: true + pos: p.tok.position() } } fn verror(s string) { util.verror('parser error', s) } - diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index 348a80bfef..36160892a9 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -29,6 +29,7 @@ pub fn (var p Parser) expr(precedence int) ast.Expr { .chartoken { node = ast.CharLiteral{ val: p.tok.lit + pos: p.tok.position() } p.next() } @@ -39,6 +40,7 @@ pub fn (var p Parser) expr(precedence int) ast.Expr { .key_true, .key_false { node = ast.BoolLiteral{ val: p.tok.kind == .key_true + pos: p.tok.position() } p.next() }