checker: clean up infix_expr

pull/4594/head
Ruofan XU 2020-04-26 02:28:49 +08:00 committed by GitHub
parent d72e401378
commit d86539c4f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 91 additions and 80 deletions

View File

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