checker: more infix checks

pull/4528/head
yuyi 2020-04-20 20:49:26 +08:00 committed by GitHub
parent 07f69fab19
commit 717e26b45e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 92 additions and 80 deletions

View File

@ -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{} }
}
}

View File

@ -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
}

View File

@ -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| }

View File

@ -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| }

View File

@ -1,3 +1,3 @@
fn main() {
1 | 0.5
fn main() {
1 | 0.5
}

View File

@ -0,0 +1,3 @@
fn main() {
1 | 0.5
}

View File

@ -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| }

View File

@ -0,0 +1,3 @@
fn main() {
0.5 % 1
}

View File

@ -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| }

View File

@ -0,0 +1,3 @@
fn main() {
1 % 0.5
}

View File

@ -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| }

View File

@ -0,0 +1,3 @@
fn main() {
0.5 << 1
}

View File

@ -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| }

View File

@ -0,0 +1,3 @@
fn main() {
1 << 0.5
}

View File

@ -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| }

View File

@ -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)
}

View File

@ -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()
}