checker: more infix checks
parent
07f69fab19
commit
717e26b45e
|
@ -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{} }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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| }
|
||||
|
|
|
@ -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| }
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
fn main() {
|
||||
1 | 0.5
|
||||
fn main() {
|
||||
1 | 0.5
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
1 | 0.5
|
||||
}
|
|
@ -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| }
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
0.5 % 1
|
||||
}
|
|
@ -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| }
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
1 % 0.5
|
||||
}
|
|
@ -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| }
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
0.5 << 1
|
||||
}
|
|
@ -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| }
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
1 << 0.5
|
||||
}
|
|
@ -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| }
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue