Skip to content

Instantly share code, notes, and snippets.

@Delta456
Created October 17, 2020 14:37
Show Gist options
  • Save Delta456/e5ecb408eabb9a32e33d63cd1da04c79 to your computer and use it in GitHub Desktop.
Save Delta456/e5ecb408eabb9a32e33d63cd1da04c79 to your computer and use it in GitHub Desktop.
check_cast_type
pub fn (mut c Checker) can_type_cast(from table.Type, to table.Type) bool {
from_type_sym := c.table.get_type_symbol(from)
to_type_sym := c.table.get_type_symbol(to)
// check basic types
if c.check_types(from, to) {
return true
}
if to == table.bool_type || to_type_sym.kind == .none_ || from == table.none_type {
return false
}
if from == table.byte_type {
if to.is_int() || to.is_float() {
return true
}
return false
}
if to == table.string_type {
// nothing can be casted to string
return false
}
if to_type_sym.kind == .byte {
// TODO: check for rune overflow
if from.is_int() || from.is_float() || from == table.voidptr_type || from_type_sym.kind == .enum_ {
return true
}
return false
}
if to_type_sym.kind == .struct_ && !to.is_ptr() && !(to_type_sym.info as table.Struct).is_typedef {
// For now we ignore C typedef because of `C.Window(C.None)` in vlib/clipboard
if from_type_sym.kind == .struct_ && !from.is_ptr() {
from_type_info := from_type_sym.info as table.Struct
to_type_info := to_type_sym.info as table.Struct
return c.check_struct_signature(from_type_info, to_type_info)
}
return false
}
return true
}
node.expr_type = c.expr(node.expr)
from_type_sym := c.table.get_type_symbol(node.expr_type)
to_type_sym := c.table.get_type_symbol(node.typ)
expr_is_ptr := node.expr_type.is_ptr() || node.expr_type.idx() in table.pointer_type_idxs
if expr_is_ptr && to_type_sym.kind == .string && !node.in_prexpr {
if node.has_arg {
c.warn('to convert a C string buffer pointer to a V string, please use x.vstring_with_len(len) instead of string(x,len)',
node.pos)
} else {
c.warn('to convert a C string buffer pointer to a V string, please use x.vstring() instead of string(x)',
node.pos)
}
}
if !c.can_type_cast(node.expr_type, node.typ) {
if node.expr_type == table.byte_type {
c.error('can not cast type `byte` to string, use `${node.expr.str()}.str()` instead.',
node.pos)
}
if (node.typ == table.string_type && from_type_sym.kind in [.any_int, .int, .byte, .byteptr, .bool]) ||
(from_type_sym.kind == .array && from_type_sym.name == 'array_byte') {
type_name := c.table.type_to_str(node.expr_type)
c.error('cannot cast type `$type_name` to string, use `x.str()` instead',
node.pos)
}
/*node.expr_type == table.byte_type && to_type_sym.kind == .string {*/
}
if to_type_sym.kind == .sum_type {
if node.expr_type in [table.any_int_type, table.any_flt_type] {
node.expr_type = c.promote_num(node.expr_type, if node.expr_type == table.any_int_type { table.int_type } else { table.f64_type })
}
if !c.table.sumtype_has_variant(node.typ, node.expr_type) {
c.error('cannot cast `$from_type_sym.source_name` to `$to_type_sym.source_name`',
node.pos)
}
} /*else if node.typ == table.string_type &&
(from_type_sym.kind in [.any_int, .int, .byte, .byteptr] ||
(from_type_sym.kind == .array && from_type_sym.name == 'array_byte')) {
type_name := c.table.type_to_str(node.expr_type)
c.error('cannot cast type `$type_name` to string, use `x.str()` instead',
node.pos)
}*/ else if node.expr_type == table.string_type {
if to_type_sym.kind != .alias {
mut error_msg := 'cannot cast a string'
if node.expr is ast.StringLiteral {
str_lit := node.expr as ast.StringLiteral
if str_lit.val.len == 1 {
error_msg += ", for denoting characters use `$str_lit.val` instead of '$str_lit.val'"
}
}
c.error(error_msg, node.pos)
}
} else if !c.can_type_cast(node.expr_type, node.typ) {
/*else if to_type_sym.kind == .byte &&
node.expr_type != table.voidptr_type && from_type_sym.kind != .enum_ && !node.expr_type.is_int() &&
!node.expr_type.is_float() && !node.expr_type.is_ptr() {*/
type_name := c.table.type_to_str(node.expr_type)
c.error('cannot cast type `$type_name` to `byte`', node.pos)
} else if to_type_sym.kind == .struct_ && !node.typ.is_ptr() && !(to_type_sym.info as table.Struct).is_typedef {
// For now we ignore C typedef because of `C.Window(C.None)` in vlib/clipboard
if from_type_sym.kind == .struct_ && !node.expr_type.is_ptr() {
from_type_info := from_type_sym.info as table.Struct
to_type_info := to_type_sym.info as table.Struct
if !c.check_struct_signature(from_type_info, to_type_info) {
c.error('cannot convert struct `$from_type_sym.source_name` to struct `$to_type_sym.source_name`',
node.pos)
}
} else {
type_name := c.table.type_to_str(node.expr_type)
c.error('cannot cast `$type_name` to struct', node.pos)
}
} else if node.typ == table.bool_type {
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
} else if node.expr_type == table.none_type {
type_name := c.table.type_to_str(node.typ)
c.error('cannot cast `none` to `$type_name`', node.pos)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment