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 struct FloatLiteral {
pub: pub:
val string val string
pos token.Position
} }
pub struct StringLiteral { pub struct StringLiteral {
@ -73,11 +74,13 @@ mut:
pub struct CharLiteral { pub struct CharLiteral {
pub: pub:
val string val string
pos token.Position
} }
pub struct BoolLiteral { pub struct BoolLiteral {
pub: pub:
val bool val bool
pos token.Position
} }
// `foo.bar` // `foo.bar`
@ -737,36 +740,20 @@ pub fn expr_is_call(expr Expr) bool {
fn (expr Expr) position() token.Position { fn (expr Expr) position() token.Position {
// all uncommented have to be implemented // all uncommented have to be implemented
match var expr { match var expr {
ArrayInit { ArrayInit { return it.pos }
return it.pos AsCast { return it.pos }
}
AsCast {
return it.pos
}
// ast.Ident { } // ast.Ident { }
AssignExpr { AssignExpr { return it.pos }
return it.pos
}
// ast.CastExpr { } // ast.CastExpr { }
Assoc { Assoc { return it.pos }
return it.pos BoolLiteral { return it.pos }
} CallExpr { return it.pos }
// ast.BoolLiteral { } CharLiteral { return it.pos }
CallExpr { EnumVal { return it.pos }
return it.pos FloatLiteral { return it.pos }
} IfExpr { return it.pos }
// ast.CharLiteral { }
EnumVal {
return it.pos
}
// ast.FloatLiteral { }
IfExpr {
return it.pos
}
// ast.IfGuardExpr { } // ast.IfGuardExpr { }
IndexExpr { IndexExpr { return it.pos }
return it.pos
}
InfixExpr { InfixExpr {
left_pos := it.left.position() left_pos := it.left.position()
right_pos := it.right.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 len: right_pos.pos - left_pos.pos + right_pos.len
} }
} }
IntegerLiteral { IntegerLiteral { return it.pos }
return it.pos MapInit { return it.pos }
} MatchExpr { return it.pos }
MapInit { PostfixExpr { return it.pos }
return it.pos
}
MatchExpr {
return it.pos
}
PostfixExpr {
return it.pos
}
// ast.None { } // ast.None { }
PrefixExpr { PrefixExpr { return it.pos }
return it.pos
}
// ast.ParExpr { } // ast.ParExpr { }
SelectorExpr { SelectorExpr { return it.pos }
return it.pos
}
// ast.SizeOf { } // ast.SizeOf { }
StringLiteral { StringLiteral { return it.pos }
return it.pos StringInterLiteral { return it.pos }
}
StringInterLiteral {
return it.pos
}
// ast.Type { } // ast.Type { }
StructInit { StructInit { return it.pos }
return it.pos
}
// ast.TypeOf { } // ast.TypeOf { }
else { else { return token.Position{} }
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) right := c.table.get_type_symbol(right_type)
left := c.table.get_type_symbol(left_type) left := c.table.get_type_symbol(left_type)
if infix_expr.op == .left_shift { 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 { if left.kind == .array {
// `array << elm` // `array << elm`
// the expressions have different types (array_x and x) // 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()) c.error('cannot shift type $right.name into $left.name', infix_expr.right.position())
return table.void_type 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] { 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 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 infix_expr.op in [.amp, .pipe, .xor] {
if !left.is_int() { 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() { 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]) { 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 `&&`', c.error('string types only have the following operators defined: `==`, `!=`, `<`, `>`, `<=`, `>=`, and `&&`',
infix_expr.pos) 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() { if infix_expr.op.is_relational() {
return table.bool_type 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() { 1| fn main() {
2| 0.5 & 1 2| 0.5 & 1
^ ~~~
3| } 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() { 1| fn main() {
2| 1 | 0.5 2| 1 | 0.5
^ ~~~
3| } 3| }

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{ 6| t := Test{
7| foo: true 7| foo: true
8| bar: false 8| bar: false
^ ~~~~~~~~~~
9| } 9| }
10| } 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'] { if lit.index_any('.eE') >= 0 && lit[..2] !in ['0x', '0X', '0o', '0O', '0b', '0B'] {
node = ast.FloatLiteral{ node = ast.FloatLiteral{
val: lit val: lit
pos: pos
} }
} else { } else {
node = ast.IntegerLiteral{ node = ast.IntegerLiteral{
@ -1210,10 +1211,10 @@ fn (var p Parser) assoc() ast.Assoc {
fn (p &Parser) new_true_expr() ast.Expr { fn (p &Parser) new_true_expr() ast.Expr {
return ast.BoolLiteral{ return ast.BoolLiteral{
val: true val: true
pos: p.tok.position()
} }
} }
fn verror(s string) { fn verror(s string) {
util.verror('parser error', s) util.verror('parser error', s)
} }

View File

@ -29,6 +29,7 @@ pub fn (var p Parser) expr(precedence int) ast.Expr {
.chartoken { .chartoken {
node = ast.CharLiteral{ node = ast.CharLiteral{
val: p.tok.lit val: p.tok.lit
pos: p.tok.position()
} }
p.next() p.next()
} }
@ -39,6 +40,7 @@ pub fn (var p Parser) expr(precedence int) ast.Expr {
.key_true, .key_false { .key_true, .key_false {
node = ast.BoolLiteral{ node = ast.BoolLiteral{
val: p.tok.kind == .key_true val: p.tok.kind == .key_true
pos: p.tok.position()
} }
p.next() p.next()
} }