checker: clean up infix_expr
parent
d72e401378
commit
d86539c4f5
|
@ -277,100 +277,114 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
|
|||
left_type := c.expr(infix_expr.left)
|
||||
infix_expr.left_type = left_type
|
||||
c.expected_type = left_type
|
||||
if infix_expr.op == .key_is {
|
||||
type_expr := infix_expr.right as ast.Type
|
||||
typ_sym := c.table.get_type_symbol(type_expr.typ)
|
||||
if typ_sym.kind == .placeholder {
|
||||
c.error('is: type `${typ_sym.name}` does not exist', type_expr.pos)
|
||||
}
|
||||
return table.bool_type
|
||||
}
|
||||
right_type := c.expr(infix_expr.right)
|
||||
infix_expr.right_type = right_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 {
|
||||
// `array << elm`
|
||||
// the expressions have different types (array_x and x)
|
||||
if c.table.check(c.table.value_type(left_type), right_type) {
|
||||
// []T << T
|
||||
// Single side check
|
||||
match infix_expr.op {
|
||||
// Place these branches according to ops' usage frequency to accelerate.
|
||||
// TODO: First branch includes ops where single side check is not needed, or needed but hasn't been implemented.
|
||||
.eq, .ne, .gt, .lt, .ge, .le, .and, .logical_or, .dot, .key_as, .right_shift { }
|
||||
// TODO: Some of the checks are not single side. Should find a better way to organize them.
|
||||
.key_in, .not_in {
|
||||
match right.kind {
|
||||
.array {
|
||||
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
|
||||
if left.kind != right_sym.kind {
|
||||
c.error('the data type on the left of `in` does not match the array item type',
|
||||
infix_expr.pos)
|
||||
}
|
||||
}
|
||||
.map {
|
||||
key_sym := c.table.get_type_symbol(right.map_info().key_type)
|
||||
if left.kind != key_sym.kind {
|
||||
c.error('the data type on the left of `in` does not match the map key type',
|
||||
infix_expr.pos)
|
||||
}
|
||||
}
|
||||
.string {
|
||||
if left.kind != .string {
|
||||
c.error('the data type on the left of `in` must be a string', infix_expr.pos)
|
||||
}
|
||||
}
|
||||
else {
|
||||
c.error('`in` can only be used with an array/map/string', infix_expr.pos)
|
||||
}
|
||||
}
|
||||
return table.bool_type
|
||||
}
|
||||
.plus, .minus, .mul, .div {
|
||||
if left.kind in [.array, .array_fixed, .map, .struct_] && !left.has_method(infix_expr.op.str()) {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
||||
} else if right.kind in [.array, .array_fixed, .map, .struct_] && !right.has_method(infix_expr.op.str()) {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
||||
}
|
||||
}
|
||||
.left_shift {
|
||||
if left.kind == .array {
|
||||
// `array << elm`
|
||||
// the expressions have different types (array_x and x)
|
||||
if c.table.check(c.table.value_type(left_type), right_type) {
|
||||
// []T << T
|
||||
return table.void_type
|
||||
}
|
||||
if right.kind == .array && c.table.check(c.table.value_type(left_type), c.table.value_type(right_type)) {
|
||||
// []T << []T
|
||||
return table.void_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 right.kind == .array && c.table.check(c.table.value_type(left_type), c.table.value_type(right_type)) {
|
||||
// []T << []T
|
||||
return table.void_type
|
||||
}
|
||||
.key_is {
|
||||
type_expr := infix_expr.right as ast.Type
|
||||
typ_sym := c.table.get_type_symbol(type_expr.typ)
|
||||
if typ_sym.kind == .placeholder {
|
||||
c.error('is: type `${typ_sym.name}` does not exist', type_expr.pos)
|
||||
}
|
||||
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
|
||||
return table.bool_type
|
||||
}
|
||||
}
|
||||
if infix_expr.op in [.key_in, .not_in] {
|
||||
if right.kind == .array {
|
||||
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
|
||||
if left.kind != right_sym.kind {
|
||||
c.error('the data type on the left of `in` does not match the array item type',
|
||||
infix_expr.pos)
|
||||
.amp, .pipe, .xor {
|
||||
if !left.is_int() {
|
||||
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('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name',
|
||||
infix_expr.right.position())
|
||||
}
|
||||
} else if right.kind == .map {
|
||||
key_sym := c.table.get_type_symbol(right.map_info().key_type)
|
||||
if left.kind != key_sym.kind {
|
||||
c.error('the data type on the left of `in` does not match the map key type',
|
||||
infix_expr.pos)
|
||||
}
|
||||
.mod {
|
||||
if left.is_int() && !right.is_int() {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
||||
} else if !left.is_int() && right.is_int() {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
||||
} else if left.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
||||
!left.has_method(infix_expr.op.str()) {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
||||
} else if right.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
||||
!right.has_method(infix_expr.op.str()) {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
||||
}
|
||||
} else if right.kind == .string {
|
||||
if left.kind != .string {
|
||||
c.error('the data type on the left of `in` must be a string', infix_expr.pos)
|
||||
}
|
||||
} else {
|
||||
c.error('`in` can only be used with an array/map/string', infix_expr.pos)
|
||||
}
|
||||
return table.bool_type
|
||||
}
|
||||
if infix_expr.op in [.amp, .pipe, .xor] {
|
||||
if !left.is_int() {
|
||||
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('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('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
||||
} else if !left.is_int() && right.is_int() {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
||||
} else if left.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
||||
!left.has_method(infix_expr.op.str()) {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
||||
} else if right.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
||||
!right.has_method(infix_expr.op.str()) {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
||||
}
|
||||
}
|
||||
if infix_expr.op in [.plus, .minus, .mul, .div] {
|
||||
if left.kind in [.array, .array_fixed, .map, .struct_] && !left.has_method(infix_expr.op.str()) {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
||||
} else if right.kind in [.array, .array_fixed, .map, .struct_] && !right.has_method(infix_expr.op.str()) {
|
||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
||||
}
|
||||
else { }
|
||||
}
|
||||
// TODO: Absorb this block into the above single side check block to accelerate.
|
||||
if left_type == table.bool_type && !(infix_expr.op in [.eq, .ne, .logical_or, .and]) {
|
||||
c.error('bool types only have the following operators defined: `==`, `!=`, `||`, and `&&`',
|
||||
c.error('bool types only have the following operators defined: `==`, `!=`, `||`, and `&&`',
|
||||
infix_expr.pos)
|
||||
} else if left_type == table.string_type && !(infix_expr.op in [.plus, .eq, .ne, .lt, .gt,
|
||||
.le, .ge]) {
|
||||
} else if left_type == table.string_type && !(infix_expr.op in [.plus, .eq, .ne, .lt, .gt, .le, .ge]) {
|
||||
// TODO broken !in
|
||||
c.error('string types only have the following operators defined: `==`, `!=`, `<`, `>`, `<=`, `>=`, and `&&`',
|
||||
infix_expr.pos)
|
||||
}
|
||||
// Dual sides check (compatibility check)
|
||||
if !c.table.check(right_type, left_type) {
|
||||
// for type-unresolved consts
|
||||
if left_type == table.void_type || right_type == table.void_type {
|
||||
|
@ -379,10 +393,7 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.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
|
||||
}
|
||||
return left_type
|
||||
return if infix_expr.op.is_relational() { table.bool_type } else { left_type }
|
||||
}
|
||||
|
||||
fn (mut c Checker) assign_expr(assign_expr mut ast.AssignExpr) {
|
||||
|
|
Loading…
Reference in New Issue