all: fix casting of `string(MyString('abc'))` and `byte(MyByte(123))`; improve TypeSymbol handling (#12617)
parent
519ca90cfa
commit
47aa2b1f93
|
@ -92,7 +92,7 @@ pub fn (mut b Builder) cut_to(pos int) string {
|
|||
|
||||
pub fn (mut b Builder) write_runes(runes []rune) {
|
||||
for r in runes {
|
||||
res := string(r)
|
||||
res := r.str()
|
||||
#res.str = String.fromCharCode(r.val)
|
||||
b << res.bytes()
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import v.util
|
|||
[heap]
|
||||
pub struct Table {
|
||||
pub mut:
|
||||
type_symbols []TypeSymbol
|
||||
type_symbols []&TypeSymbol
|
||||
type_idxs map[string]int
|
||||
fns map[string]Fn
|
||||
iface_types map[string][]Type
|
||||
|
@ -42,8 +42,11 @@ pub mut:
|
|||
// used by vls to avoid leaks
|
||||
// TODO remove manual memory management
|
||||
[unsafe]
|
||||
pub fn (t &Table) free() {
|
||||
pub fn (mut t Table) free() {
|
||||
unsafe {
|
||||
for s in t.type_symbols {
|
||||
s.free()
|
||||
}
|
||||
t.type_symbols.free()
|
||||
t.type_idxs.free()
|
||||
t.fns.free()
|
||||
|
@ -169,7 +172,6 @@ fn (p []Param) equals(o []Param) bool {
|
|||
|
||||
pub fn new_table() &Table {
|
||||
mut t := &Table{
|
||||
type_symbols: []TypeSymbol{cap: 64000}
|
||||
global_scope: &Scope{
|
||||
parent: 0
|
||||
}
|
||||
|
@ -348,7 +350,7 @@ pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn {
|
|||
if ts.parent_idx == 0 {
|
||||
break
|
||||
}
|
||||
ts = unsafe { &t.type_symbols[ts.parent_idx] }
|
||||
ts = t.type_symbols[ts.parent_idx]
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
@ -490,7 +492,7 @@ pub fn (t &Table) find_field(s &TypeSymbol, name string) ?StructField {
|
|||
if ts.parent_idx == 0 {
|
||||
break
|
||||
}
|
||||
ts = unsafe { &t.type_symbols[ts.parent_idx] }
|
||||
ts = t.type_symbols[ts.parent_idx]
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
@ -625,7 +627,7 @@ pub fn (t &Table) find_type_idx(name string) int {
|
|||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) find_type(name string) ?TypeSymbol {
|
||||
pub fn (t &Table) find_type(name string) ?&TypeSymbol {
|
||||
idx := t.type_idxs[name]
|
||||
if idx > 0 {
|
||||
return t.type_symbols[idx]
|
||||
|
@ -634,6 +636,7 @@ pub fn (t &Table) find_type(name string) ?TypeSymbol {
|
|||
}
|
||||
|
||||
pub const invalid_type_symbol = &TypeSymbol{
|
||||
idx: -1
|
||||
parent_idx: -1
|
||||
language: .v
|
||||
mod: 'builtin'
|
||||
|
@ -643,10 +646,14 @@ pub const invalid_type_symbol = &TypeSymbol{
|
|||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) get_type_symbol_by_idx(idx int) &TypeSymbol {
|
||||
return t.type_symbols[idx]
|
||||
}
|
||||
|
||||
pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
|
||||
idx := typ.idx()
|
||||
if idx > 0 {
|
||||
return unsafe { &t.type_symbols[idx] }
|
||||
return t.type_symbols[idx]
|
||||
}
|
||||
// this should never happen
|
||||
t.panic('get_type_symbol: invalid type (typ=$typ idx=$idx). Compiler bug. This should never happen. Please report the bug using `v bug file.v`.
|
||||
|
@ -659,11 +666,11 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
|
|||
pub fn (t &Table) get_final_type_symbol(typ Type) &TypeSymbol {
|
||||
mut idx := typ.idx()
|
||||
if idx > 0 {
|
||||
current_type := t.type_symbols[idx]
|
||||
if current_type.kind == .alias {
|
||||
idx = (current_type.info as Alias).parent_type.idx()
|
||||
current_symbol := t.type_symbols[idx]
|
||||
if current_symbol.kind == .alias {
|
||||
idx = (current_symbol.info as Alias).parent_type.idx()
|
||||
}
|
||||
return unsafe { &t.type_symbols[idx] }
|
||||
return t.type_symbols[idx]
|
||||
}
|
||||
// this should never happen
|
||||
t.panic('get_final_type_symbol: invalid type (typ=$typ idx=$idx). Compiler bug. This should never happen. Please report the bug using `v bug file.v`.')
|
||||
|
@ -672,8 +679,8 @@ pub fn (t &Table) get_final_type_symbol(typ Type) &TypeSymbol {
|
|||
|
||||
[inline]
|
||||
pub fn (t &Table) get_type_name(typ Type) string {
|
||||
typ_sym := t.get_type_symbol(typ)
|
||||
return typ_sym.name
|
||||
sym := t.get_type_symbol(typ)
|
||||
return sym.name
|
||||
}
|
||||
|
||||
[inline]
|
||||
|
@ -688,38 +695,36 @@ pub fn (t &Table) unalias_num_type(typ Type) Type {
|
|||
return typ
|
||||
}
|
||||
|
||||
fn (mut t Table) check_for_already_registered_symbol(typ TypeSymbol, existing_idx int) int {
|
||||
ex_type := t.type_symbols[existing_idx]
|
||||
match ex_type.kind {
|
||||
.placeholder {
|
||||
// override placeholder
|
||||
t.type_symbols[existing_idx] = TypeSymbol{
|
||||
...typ
|
||||
methods: ex_type.methods
|
||||
}
|
||||
return existing_idx
|
||||
}
|
||||
else {
|
||||
// builtin
|
||||
// this will override the already registered builtin types
|
||||
// with the actual v struct declaration in the source
|
||||
if (existing_idx >= string_type_idx && existing_idx <= map_type_idx)
|
||||
|| existing_idx == error_type_idx {
|
||||
if existing_idx == string_type_idx {
|
||||
// existing_type := t.type_symbols[existing_idx]
|
||||
t.type_symbols[existing_idx] = TypeSymbol{
|
||||
...typ
|
||||
kind: ex_type.kind
|
||||
}
|
||||
} else {
|
||||
t.type_symbols[existing_idx] = typ
|
||||
}
|
||||
return existing_idx
|
||||
}
|
||||
return -1
|
||||
fn (mut t Table) rewrite_already_registered_symbol(typ TypeSymbol, existing_idx int) int {
|
||||
existing_symbol := t.type_symbols[existing_idx]
|
||||
if existing_symbol.kind == .placeholder {
|
||||
// override placeholder
|
||||
t.type_symbols[existing_idx] = &TypeSymbol{
|
||||
...typ
|
||||
methods: existing_symbol.methods
|
||||
}
|
||||
return existing_idx
|
||||
}
|
||||
return -2
|
||||
// Override the already registered builtin types with the actual
|
||||
// v struct declarations in the vlib/builtin module sources:
|
||||
if (existing_idx >= string_type_idx && existing_idx <= map_type_idx)
|
||||
|| existing_idx == error_type_idx {
|
||||
if existing_idx == string_type_idx {
|
||||
// existing_type := t.type_symbols[existing_idx]
|
||||
unsafe {
|
||||
*existing_symbol = &TypeSymbol{
|
||||
...typ
|
||||
kind: existing_symbol.kind
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.type_symbols[existing_idx] = &TypeSymbol{
|
||||
...typ
|
||||
}
|
||||
}
|
||||
return existing_idx
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
[inline]
|
||||
|
@ -727,7 +732,7 @@ pub fn (mut t Table) register_type_symbol(sym TypeSymbol) int {
|
|||
mut idx := -2
|
||||
mut existing_idx := t.type_idxs[sym.name]
|
||||
if existing_idx > 0 {
|
||||
idx = t.check_for_already_registered_symbol(sym, existing_idx)
|
||||
idx = t.rewrite_already_registered_symbol(sym, existing_idx)
|
||||
if idx != -2 {
|
||||
return idx
|
||||
}
|
||||
|
@ -735,14 +740,16 @@ pub fn (mut t Table) register_type_symbol(sym TypeSymbol) int {
|
|||
if sym.mod == 'main' {
|
||||
existing_idx = t.type_idxs[sym.name.trim_prefix('main.')]
|
||||
if existing_idx > 0 {
|
||||
idx = t.check_for_already_registered_symbol(sym, existing_idx)
|
||||
idx = t.rewrite_already_registered_symbol(sym, existing_idx)
|
||||
if idx != -2 {
|
||||
return idx
|
||||
}
|
||||
}
|
||||
}
|
||||
idx = t.type_symbols.len
|
||||
t.type_symbols << sym
|
||||
t.type_symbols << &TypeSymbol{
|
||||
...sym
|
||||
}
|
||||
t.type_symbols[idx].idx = idx
|
||||
t.type_idxs[sym.name] = idx
|
||||
return idx
|
||||
|
@ -1088,31 +1095,31 @@ pub fn (mut t Table) add_placeholder_type(name string, language Language) int {
|
|||
|
||||
[inline]
|
||||
pub fn (t &Table) value_type(typ Type) Type {
|
||||
typ_sym := t.get_final_type_symbol(typ)
|
||||
sym := t.get_final_type_symbol(typ)
|
||||
if typ.has_flag(.variadic) {
|
||||
// ...string => string
|
||||
// return typ.clear_flag(.variadic)
|
||||
array_info := typ_sym.info as Array
|
||||
array_info := sym.info as Array
|
||||
return array_info.elem_type
|
||||
}
|
||||
if typ_sym.kind == .array {
|
||||
if sym.kind == .array {
|
||||
// Check index type
|
||||
info := typ_sym.info as Array
|
||||
info := sym.info as Array
|
||||
return info.elem_type
|
||||
}
|
||||
if typ_sym.kind == .array_fixed {
|
||||
info := typ_sym.info as ArrayFixed
|
||||
if sym.kind == .array_fixed {
|
||||
info := sym.info as ArrayFixed
|
||||
return info.elem_type
|
||||
}
|
||||
if typ_sym.kind == .map {
|
||||
info := typ_sym.info as Map
|
||||
if sym.kind == .map {
|
||||
info := sym.info as Map
|
||||
return info.value_type
|
||||
}
|
||||
if typ_sym.kind == .string && typ.is_ptr() {
|
||||
if sym.kind == .string && typ.is_ptr() {
|
||||
// (&string)[i] => string
|
||||
return string_type
|
||||
}
|
||||
if typ_sym.kind in [.byteptr, .string] {
|
||||
if sym.kind in [.byteptr, .string] {
|
||||
return byte_type
|
||||
}
|
||||
if typ.is_ptr() {
|
||||
|
@ -1277,18 +1284,18 @@ pub fn (t Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
|
|||
// `none` "implements" the Error interface
|
||||
return true
|
||||
}
|
||||
typ_sym := t.get_type_symbol(typ)
|
||||
if typ_sym.language != .v {
|
||||
sym := t.get_type_symbol(typ)
|
||||
if sym.language != .v {
|
||||
return false
|
||||
}
|
||||
// generic struct don't generate cast interface fn
|
||||
if typ_sym.info is Struct {
|
||||
if typ_sym.info.is_generic {
|
||||
if sym.info is Struct {
|
||||
if sym.info.is_generic {
|
||||
return false
|
||||
}
|
||||
}
|
||||
mut inter_sym := t.get_type_symbol(inter_typ)
|
||||
if typ_sym.kind == .interface_ && inter_sym.kind == .interface_ {
|
||||
if sym.kind == .interface_ && inter_sym.kind == .interface_ {
|
||||
return false
|
||||
}
|
||||
if mut inter_sym.info is Interface {
|
||||
|
@ -1306,7 +1313,7 @@ pub fn (t Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
|
|||
}
|
||||
// verify methods
|
||||
for imethod in inter_sym.info.methods {
|
||||
if method := typ_sym.find_method(imethod.name) {
|
||||
if method := sym.find_method(imethod.name) {
|
||||
msg := t.is_same_method(imethod, method)
|
||||
if msg.len > 0 {
|
||||
return false
|
||||
|
@ -1320,13 +1327,13 @@ pub fn (t Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
|
|||
if ifield.typ == voidptr_type {
|
||||
// Allow `voidptr` fields in interfaces for now. (for example
|
||||
// to enable .db check in vweb)
|
||||
if t.struct_has_field(typ_sym, ifield.name) {
|
||||
if t.struct_has_field(sym, ifield.name) {
|
||||
continue
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if field := t.find_field_with_embeds(typ_sym, ifield.name) {
|
||||
if field := t.find_field_with_embeds(sym, ifield.name) {
|
||||
if ifield.typ != field.typ {
|
||||
return false
|
||||
} else if ifield.is_mut && !(field.is_mut || field.is_global) {
|
||||
|
|
|
@ -664,7 +664,7 @@ pub fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
|
|||
if node.language == .v && !c.is_builtin_mod {
|
||||
c.check_valid_pascal_case(node.name, 'struct name', node.pos)
|
||||
}
|
||||
mut struct_sym := c.table.find_type(node.name) or { ast.TypeSymbol{} }
|
||||
mut struct_sym := c.table.find_type(node.name) or { ast.invalid_type_symbol }
|
||||
mut has_generic_types := false
|
||||
if mut struct_sym.info is ast.Struct {
|
||||
for embed in node.embeds {
|
||||
|
@ -5655,77 +5655,93 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
|
|||
// }
|
||||
|
||||
pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||
// Given: `Outside( Inside(xyz) )`,
|
||||
// node.expr_type: `Inside`
|
||||
// node.typ: `Outside`
|
||||
node.expr_type = c.expr(node.expr) // type to be casted
|
||||
from_type_sym := c.table.get_type_symbol(node.expr_type)
|
||||
to_type_sym := c.table.get_type_symbol(node.typ) // type to be used as cast
|
||||
|
||||
mut from_type := node.expr_type
|
||||
to_type := node.typ
|
||||
//
|
||||
from_type_sym := c.table.get_type_symbol(from_type)
|
||||
from_type_sym_final := c.table.get_final_type_symbol(from_type)
|
||||
to_type_sym := c.table.get_type_symbol(to_type) // type to be used as cast
|
||||
to_type_sym_final := c.table.get_final_type_symbol(to_type)
|
||||
//
|
||||
if (to_type_sym.is_number() && from_type_sym.name == 'JS.Number')
|
||||
|| (to_type_sym.is_number() && from_type_sym.name == 'JS.BigInt')
|
||||
|| (to_type_sym.is_string() && from_type_sym.name == 'JS.String')
|
||||
|| (node.typ.is_bool() && from_type_sym.name == 'JS.Boolean')
|
||||
|| (node.expr_type.is_bool() && to_type_sym.name == 'JS.Boolean')
|
||||
|| (to_type.is_bool() && from_type_sym.name == 'JS.Boolean')
|
||||
|| (from_type.is_bool() && to_type_sym.name == 'JS.Boolean')
|
||||
|| (from_type_sym.is_number() && to_type_sym.name == 'JS.Number')
|
||||
|| (from_type_sym.is_number() && to_type_sym.name == 'JS.BigInt')
|
||||
|| (from_type_sym.is_string() && to_type_sym.name == 'JS.String') {
|
||||
return node.typ
|
||||
return to_type
|
||||
}
|
||||
|
||||
if to_type_sym.language != .c {
|
||||
c.ensure_type_exists(node.typ, node.pos) or {}
|
||||
c.ensure_type_exists(to_type, node.pos) or {}
|
||||
}
|
||||
if from_type_sym.kind == .byte && node.expr_type.is_ptr() && to_type_sym.kind == .string
|
||||
&& !node.typ.is_ptr() {
|
||||
if from_type_sym.kind == .byte && from_type.is_ptr() && to_type_sym.kind == .string
|
||||
&& !to_type.is_ptr() {
|
||||
c.error('to convert a C string buffer pointer to a V string, use x.vstring() instead of string(x)',
|
||||
node.pos)
|
||||
}
|
||||
if node.expr_type == ast.void_type {
|
||||
if from_type == ast.void_type {
|
||||
c.error('expression does not return a value so it cannot be cast', node.expr.position())
|
||||
}
|
||||
if node.expr_type == ast.byte_type && to_type_sym.kind == .string {
|
||||
c.error('can not cast type `byte` to string, use `${node.expr.str()}.str()` instead.',
|
||||
node.pos)
|
||||
}
|
||||
if to_type_sym.kind == .sum_type {
|
||||
if node.expr_type in [ast.int_literal_type, ast.float_literal_type] {
|
||||
node.expr_type = c.promote_num(node.expr_type, if node.expr_type == ast.int_literal_type {
|
||||
ast.int_type
|
||||
} else {
|
||||
ast.f64_type
|
||||
})
|
||||
//
|
||||
if to_type == ast.string_type {
|
||||
if from_type in [ast.byte_type, ast.bool_type] {
|
||||
c.error('cannot cast type `$from_type_sym.name` to string, use `${node.expr.str()}.str()` instead.',
|
||||
node.pos)
|
||||
}
|
||||
if !c.table.sumtype_has_variant(node.typ, node.expr_type) && !node.typ.has_flag(.optional) {
|
||||
if from_type.is_real_pointer() {
|
||||
c.error('cannot cast pointer type `$from_type_sym.name` to string, use `&byte($node.expr.str()).vstring()` instead.',
|
||||
node.pos)
|
||||
}
|
||||
if from_type.is_number() {
|
||||
c.error('cannot cast number to string, use `${node.expr.str()}.str()` instead.',
|
||||
node.pos)
|
||||
}
|
||||
if from_type_sym.kind == .alias && from_type_sym_final.name != 'string' {
|
||||
c.error('cannot cast type `$from_type_sym.name` to string, use `x.str()` instead',
|
||||
node.pos)
|
||||
}
|
||||
}
|
||||
//
|
||||
if to_type_sym.kind == .sum_type {
|
||||
if from_type in [ast.int_literal_type, ast.float_literal_type] {
|
||||
xx := if from_type == ast.int_literal_type { ast.int_type } else { ast.f64_type }
|
||||
node.expr_type = c.promote_num(node.expr_type, xx)
|
||||
from_type = node.expr_type
|
||||
}
|
||||
if !c.table.sumtype_has_variant(to_type, from_type) && !to_type.has_flag(.optional) {
|
||||
c.error('cannot cast `$from_type_sym.name` to `$to_type_sym.name`', node.pos)
|
||||
}
|
||||
} else if mut to_type_sym.info is ast.Alias {
|
||||
if !c.check_types(node.expr_type, to_type_sym.info.parent_type) {
|
||||
parent_type_sym := c.table.get_type_symbol(to_type_sym.info.parent_type)
|
||||
c.error('cannot convert type `$from_type_sym.name` to `$to_type_sym.name` (alias to `$parent_type_sym.name`)',
|
||||
if !c.check_types(from_type, to_type_sym.info.parent_type) {
|
||||
c.error('cannot convert type `$from_type_sym.name` to `$to_type_sym.name` (alias to `$to_type_sym_final.name`)',
|
||||
node.pos)
|
||||
}
|
||||
} else if node.typ == ast.string_type
|
||||
&& (from_type_sym.kind in [.int_literal, .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)
|
||||
} else if node.expr_type == ast.string_type {
|
||||
if to_type_sym.kind != .alias {
|
||||
mut error_msg := 'cannot cast a string'
|
||||
if mut node.expr is ast.StringLiteral {
|
||||
if node.expr.val.len == 1 {
|
||||
error_msg += ", for denoting characters use `$node.expr.val` instead of '$node.expr.val'"
|
||||
}
|
||||
} else if to_type != ast.string_type && from_type == ast.string_type
|
||||
&& (!(to_type_sym.kind == .alias && to_type_sym_final.name == 'string')) {
|
||||
mut error_msg := 'cannot cast a string to a type `$to_type_sym_final.name`, that is not an alias of string'
|
||||
if mut node.expr is ast.StringLiteral {
|
||||
if node.expr.val.len == 1 {
|
||||
error_msg += ", for denoting characters use `$node.expr.val` instead of '$node.expr.val'"
|
||||
}
|
||||
c.error(error_msg, node.pos)
|
||||
}
|
||||
} else if to_type_sym.kind == .byte && node.expr_type != ast.voidptr_type
|
||||
&& from_type_sym.kind != .enum_ && !node.expr_type.is_int() && !node.expr_type.is_float()
|
||||
&& node.expr_type != ast.bool_type && !node.expr_type.is_ptr() {
|
||||
type_name := c.table.type_to_str(node.expr_type)
|
||||
c.error(error_msg, node.pos)
|
||||
} else if to_type_sym.kind == .byte && from_type != ast.voidptr_type
|
||||
&& from_type_sym.kind != .enum_ && !from_type.is_int() && !from_type.is_float()
|
||||
&& from_type != ast.bool_type && !from_type.is_ptr() && from_type_sym.kind == .alias
|
||||
&& from_type_sym_final.name != 'byte' {
|
||||
type_name := c.table.type_to_str(from_type)
|
||||
c.error('cannot cast type `$type_name` to `byte`', node.pos)
|
||||
} else if to_type_sym.kind == .struct_ && !node.typ.is_ptr()
|
||||
} else if to_type_sym.kind == .struct_ && !to_type.is_ptr()
|
||||
&& !(to_type_sym.info as ast.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() {
|
||||
if from_type_sym.kind == .struct_ && !from_type.is_ptr() {
|
||||
c.warn('casting to struct is deprecated, use e.g. `Struct{...expr}` instead',
|
||||
node.pos)
|
||||
from_type_info := from_type_sym.info as ast.Struct
|
||||
|
@ -5735,40 +5751,37 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
|||
node.pos)
|
||||
}
|
||||
} else {
|
||||
type_name := c.table.type_to_str(node.expr_type)
|
||||
// dump(node.typ)
|
||||
// dump(node.expr_type)
|
||||
// dump(type_name)
|
||||
// dump(to_type_sym.debug())
|
||||
type_name := c.table.type_to_str(from_type)
|
||||
c.error('cannot cast `$type_name` to struct', node.pos)
|
||||
}
|
||||
} else if to_type_sym.kind == .interface_ {
|
||||
if c.type_implements(node.expr_type, node.typ, node.pos) {
|
||||
if !node.expr_type.is_ptr() && !node.expr_type.is_pointer()
|
||||
&& from_type_sym.kind != .interface_ && !c.inside_unsafe {
|
||||
if c.type_implements(from_type, to_type, node.pos) {
|
||||
if !from_type.is_ptr() && !from_type.is_pointer() && from_type_sym.kind != .interface_
|
||||
&& !c.inside_unsafe {
|
||||
c.mark_as_referenced(mut &node.expr, true)
|
||||
}
|
||||
}
|
||||
} else if node.typ == ast.bool_type && node.expr_type != ast.bool_type && !c.inside_unsafe {
|
||||
} else if to_type == ast.bool_type && from_type != ast.bool_type && !c.inside_unsafe {
|
||||
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
|
||||
} else if node.expr_type == ast.none_type && !node.typ.has_flag(.optional) {
|
||||
type_name := c.table.type_to_str(node.typ)
|
||||
} else if from_type == ast.none_type && !to_type.has_flag(.optional) {
|
||||
type_name := c.table.type_to_str(to_type)
|
||||
c.error('cannot cast `none` to `$type_name`', node.pos)
|
||||
} else if from_type_sym.kind == .struct_ && !node.expr_type.is_ptr() {
|
||||
if (node.typ.is_ptr() || to_type_sym.kind !in [.sum_type, .interface_]) && !c.is_builtin_mod {
|
||||
type_name := c.table.type_to_str(node.typ)
|
||||
c.error('cannot cast struct to `$type_name`', node.pos)
|
||||
} else if from_type_sym.kind == .struct_ && !from_type.is_ptr() {
|
||||
if (to_type.is_ptr() || to_type_sym.kind !in [.sum_type, .interface_]) && !c.is_builtin_mod {
|
||||
from_type_name := c.table.type_to_str(from_type)
|
||||
type_name := c.table.type_to_str(to_type)
|
||||
c.error('cannot cast struct `$from_type_name` to `$type_name`', node.pos)
|
||||
}
|
||||
} else if node.expr_type.has_flag(.optional) || node.expr_type.has_flag(.variadic) {
|
||||
} else if from_type.has_flag(.optional) || from_type.has_flag(.variadic) {
|
||||
// variadic case can happen when arrays are converted into variadic
|
||||
msg := if node.expr_type.has_flag(.optional) { 'an optional' } else { 'a variadic' }
|
||||
msg := if from_type.has_flag(.optional) { 'an optional' } else { 'a variadic' }
|
||||
c.error('cannot type cast $msg', node.pos)
|
||||
} else if !c.inside_unsafe && node.typ.is_ptr() && node.expr_type.is_ptr()
|
||||
&& node.typ.deref() != ast.char_type && node.expr_type.deref() != ast.char_type {
|
||||
ft := c.table.type_to_str(node.expr_type)
|
||||
tt := c.table.type_to_str(node.typ)
|
||||
} else if !c.inside_unsafe && to_type.is_ptr() && from_type.is_ptr()
|
||||
&& to_type.deref() != ast.char_type && from_type.deref() != ast.char_type {
|
||||
ft := c.table.type_to_str(from_type)
|
||||
tt := c.table.type_to_str(to_type)
|
||||
c.warn('casting `$ft` to `$tt` is only allowed in `unsafe` code', node.pos)
|
||||
} else if from_type_sym.kind == .array_fixed && !node.expr_type.is_ptr() {
|
||||
} else if from_type_sym.kind == .array_fixed && !from_type.is_ptr() {
|
||||
c.warn('cannot cast a fixed array (use e.g. `&arr[0]` instead)', node.pos)
|
||||
}
|
||||
if node.has_arg {
|
||||
|
@ -5778,7 +5791,7 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
|||
// checks on int literal to enum cast if the value represents a value on the enum
|
||||
if to_type_sym.kind == .enum_ {
|
||||
if node.expr is ast.IntegerLiteral {
|
||||
enum_typ_name := c.table.get_type_name(node.typ)
|
||||
enum_typ_name := c.table.get_type_name(to_type)
|
||||
node_val := (node.expr as ast.IntegerLiteral).val.int()
|
||||
|
||||
if enum_decl := c.table.enum_decls[to_type_sym.name] {
|
||||
|
@ -5807,9 +5820,9 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
|||
}
|
||||
}
|
||||
|
||||
node.typname = c.table.get_type_symbol(node.typ).name
|
||||
node.typname = c.table.get_type_symbol(to_type).name
|
||||
|
||||
return node.typ
|
||||
return to_type
|
||||
}
|
||||
|
||||
fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
vlib/v/checker/tests/bool_string_cast_err.vv:2:13: error: cannot cast type `bool` to string, use `x.str()` instead
|
||||
vlib/v/checker/tests/bool_string_cast_err.vv:2:13: error: cannot cast type `bool` to string, use `true.str()` instead.
|
||||
1 | fn main() {
|
||||
2 | println(string(true))
|
||||
| ~~~~~~~~~~~~
|
||||
3 | println(string(false))
|
||||
4 | }
|
||||
vlib/v/checker/tests/bool_string_cast_err.vv:3:13: error: cannot cast type `bool` to string, use `x.str()` instead
|
||||
vlib/v/checker/tests/bool_string_cast_err.vv:3:13: error: cannot cast type `bool` to string, use `false.str()` instead.
|
||||
1 | fn main() {
|
||||
2 | println(string(true))
|
||||
3 | println(string(false))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vlib/v/checker/tests/cast_string_err.vv:2:7: error: cannot cast type `int literal` to string, use `x.str()` instead
|
||||
vlib/v/checker/tests/cast_string_err.vv:2:7: error: cannot cast number to string, use `1.str()` instead.
|
||||
1 | fn main() {
|
||||
2 | a := string(1)
|
||||
| ~~~~~~~~~
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vlib/v/checker/tests/cast_string_with_byte_err.vv:2:12: error: can not cast type `byte` to string, use `by.str()` instead.
|
||||
vlib/v/checker/tests/cast_string_with_byte_err.vv:2:12: error: cannot cast type `byte` to string, use `by.str()` instead.
|
||||
1 | for by in 'abc' {
|
||||
2 | println(string(by))
|
||||
| ~~~~~~~~~~
|
||||
|
|
|
@ -1,60 +1,60 @@
|
|||
vlib/v/checker/tests/struct_type_cast_err.vv:5:10: error: cannot cast struct to `string`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:5:10: error: cannot cast struct `Foo` to `string`
|
||||
3 | fn main() {
|
||||
4 | foo := Foo{}
|
||||
5 | _ := string(foo)
|
||||
| ~~~~~~~~~~~
|
||||
6 | _ := int(foo)
|
||||
7 | _ := u64(foo)
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:6:10: error: cannot cast struct to `int`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:6:10: error: cannot cast struct `Foo` to `int`
|
||||
4 | foo := Foo{}
|
||||
5 | _ := string(foo)
|
||||
6 | _ := int(foo)
|
||||
| ~~~~~~~~
|
||||
7 | _ := u64(foo)
|
||||
8 | _ := u32(foo)
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:7:10: error: cannot cast struct to `u64`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:7:10: error: cannot cast struct `Foo` to `u64`
|
||||
5 | _ := string(foo)
|
||||
6 | _ := int(foo)
|
||||
7 | _ := u64(foo)
|
||||
| ~~~~~~~~
|
||||
8 | _ := u32(foo)
|
||||
9 | _ := rune(foo)
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:8:10: error: cannot cast struct to `u32`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:8:10: error: cannot cast struct `Foo` to `u32`
|
||||
6 | _ := int(foo)
|
||||
7 | _ := u64(foo)
|
||||
8 | _ := u32(foo)
|
||||
| ~~~~~~~~
|
||||
9 | _ := rune(foo)
|
||||
10 | _ := byte(foo)
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:9:10: error: cannot cast struct to `rune`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:9:10: error: cannot cast struct `Foo` to `rune`
|
||||
7 | _ := u64(foo)
|
||||
8 | _ := u32(foo)
|
||||
9 | _ := rune(foo)
|
||||
| ~~~~~~~~~
|
||||
10 | _ := byte(foo)
|
||||
11 | _ := i8(foo)
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:10:10: error: cannot cast type `Foo` to `byte`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:10:10: error: cannot cast struct `Foo` to `byte`
|
||||
8 | _ := u32(foo)
|
||||
9 | _ := rune(foo)
|
||||
10 | _ := byte(foo)
|
||||
| ~~~~~~~~~
|
||||
11 | _ := i8(foo)
|
||||
12 | _ := i64(foo)
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:11:10: error: cannot cast struct to `i8`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:11:10: error: cannot cast struct `Foo` to `i8`
|
||||
9 | _ := rune(foo)
|
||||
10 | _ := byte(foo)
|
||||
11 | _ := i8(foo)
|
||||
| ~~~~~~~
|
||||
12 | _ := i64(foo)
|
||||
13 | _ := int(foo)
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:12:10: error: cannot cast struct to `i64`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:12:10: error: cannot cast struct `Foo` to `i64`
|
||||
10 | _ := byte(foo)
|
||||
11 | _ := i8(foo)
|
||||
12 | _ := i64(foo)
|
||||
| ~~~~~~~~
|
||||
13 | _ := int(foo)
|
||||
14 | _ = &I1(foo)
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:13:10: error: cannot cast struct to `int`
|
||||
vlib/v/checker/tests/struct_type_cast_err.vv:13:10: error: cannot cast struct `Foo` to `int`
|
||||
11 | _ := i8(foo)
|
||||
12 | _ := i64(foo)
|
||||
13 | _ := int(foo)
|
||||
|
|
|
@ -378,18 +378,18 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||
g.timers.start('cgen common')
|
||||
// to make sure type idx's are the same in cached mods
|
||||
if g.pref.build_mode == .build_module {
|
||||
for idx, typ in g.table.type_symbols {
|
||||
for idx, sym in g.table.type_symbols {
|
||||
if idx == 0 {
|
||||
continue
|
||||
}
|
||||
g.definitions.writeln('int _v_type_idx_${typ.cname}();')
|
||||
g.definitions.writeln('int _v_type_idx_${sym.cname}();')
|
||||
}
|
||||
} else if g.pref.use_cache {
|
||||
for idx, typ in g.table.type_symbols {
|
||||
for idx, sym in g.table.type_symbols {
|
||||
if idx == 0 {
|
||||
continue
|
||||
}
|
||||
g.definitions.writeln('int _v_type_idx_${typ.cname}() { return $idx; };')
|
||||
g.definitions.writeln('int _v_type_idx_${sym.cname}() { return $idx; };')
|
||||
}
|
||||
}
|
||||
//
|
||||
|
@ -745,43 +745,43 @@ pub fn (mut g Gen) finish() {
|
|||
pub fn (mut g Gen) write_typeof_functions() {
|
||||
g.writeln('')
|
||||
g.writeln('// >> typeof() support for sum types / interfaces')
|
||||
for ityp, typ in g.table.type_symbols {
|
||||
if typ.kind == .sum_type {
|
||||
sum_info := typ.info as ast.SumType
|
||||
for ityp, sym in g.table.type_symbols {
|
||||
if sym.kind == .sum_type {
|
||||
sum_info := sym.info as ast.SumType
|
||||
if sum_info.is_generic {
|
||||
continue
|
||||
}
|
||||
g.writeln('static char * v_typeof_sumtype_${typ.cname}(int sidx) { /* $typ.name */ ')
|
||||
g.writeln('static char * v_typeof_sumtype_${sym.cname}(int sidx) { /* $sym.name */ ')
|
||||
if g.pref.build_mode == .build_module {
|
||||
g.writeln('\t\tif( sidx == _v_type_idx_${typ.cname}() ) return "${util.strip_main_name(typ.name)}";')
|
||||
g.writeln('\t\tif( sidx == _v_type_idx_${sym.cname}() ) return "${util.strip_main_name(sym.name)}";')
|
||||
for v in sum_info.variants {
|
||||
subtype := g.table.get_type_symbol(v)
|
||||
g.writeln('\tif( sidx == _v_type_idx_${subtype.cname}() ) return "${util.strip_main_name(subtype.name)}";')
|
||||
}
|
||||
g.writeln('\treturn "unknown ${util.strip_main_name(typ.name)}";')
|
||||
g.writeln('\treturn "unknown ${util.strip_main_name(sym.name)}";')
|
||||
} else {
|
||||
tidx := g.table.find_type_idx(typ.name)
|
||||
tidx := g.table.find_type_idx(sym.name)
|
||||
g.writeln('\tswitch(sidx) {')
|
||||
g.writeln('\t\tcase $tidx: return "${util.strip_main_name(typ.name)}";')
|
||||
g.writeln('\t\tcase $tidx: return "${util.strip_main_name(sym.name)}";')
|
||||
for v in sum_info.variants {
|
||||
subtype := g.table.get_type_symbol(v)
|
||||
g.writeln('\t\tcase $v: return "${util.strip_main_name(subtype.name)}";')
|
||||
}
|
||||
g.writeln('\t\tdefault: return "unknown ${util.strip_main_name(typ.name)}";')
|
||||
g.writeln('\t\tdefault: return "unknown ${util.strip_main_name(sym.name)}";')
|
||||
g.writeln('\t}')
|
||||
}
|
||||
g.writeln('}')
|
||||
g.writeln('')
|
||||
g.writeln('int v_typeof_sumtype_idx_${typ.cname}(int sidx) { /* $typ.name */ ')
|
||||
g.writeln('int v_typeof_sumtype_idx_${sym.cname}(int sidx) { /* $sym.name */ ')
|
||||
if g.pref.build_mode == .build_module {
|
||||
g.writeln('\t\tif( sidx == _v_type_idx_${typ.cname}() ) return ${int(ityp)};')
|
||||
g.writeln('\t\tif( sidx == _v_type_idx_${sym.cname}() ) return ${int(ityp)};')
|
||||
for v in sum_info.variants {
|
||||
subtype := g.table.get_type_symbol(v)
|
||||
g.writeln('\tif( sidx == _v_type_idx_${subtype.cname}() ) return ${int(v)};')
|
||||
}
|
||||
g.writeln('\treturn ${int(ityp)};')
|
||||
} else {
|
||||
tidx := g.table.find_type_idx(typ.name)
|
||||
tidx := g.table.find_type_idx(sym.name)
|
||||
g.writeln('\tswitch(sidx) {')
|
||||
g.writeln('\t\tcase $tidx: return ${int(ityp)};')
|
||||
for v in sum_info.variants {
|
||||
|
@ -791,27 +791,27 @@ pub fn (mut g Gen) write_typeof_functions() {
|
|||
g.writeln('\t}')
|
||||
}
|
||||
g.writeln('}')
|
||||
} else if typ.kind == .interface_ {
|
||||
if typ.info !is ast.Interface {
|
||||
} else if sym.kind == .interface_ {
|
||||
if sym.info !is ast.Interface {
|
||||
continue
|
||||
}
|
||||
inter_info := typ.info as ast.Interface
|
||||
inter_info := sym.info as ast.Interface
|
||||
if inter_info.is_generic {
|
||||
continue
|
||||
}
|
||||
g.definitions.writeln('static char * v_typeof_interface_${typ.cname}(int sidx);')
|
||||
g.writeln('static char * v_typeof_interface_${typ.cname}(int sidx) { /* $typ.name */ ')
|
||||
g.definitions.writeln('static char * v_typeof_interface_${sym.cname}(int sidx);')
|
||||
g.writeln('static char * v_typeof_interface_${sym.cname}(int sidx) { /* $sym.name */ ')
|
||||
for t in inter_info.types {
|
||||
subtype := g.table.get_type_symbol(t)
|
||||
g.writeln('\tif (sidx == _${typ.cname}_${subtype.cname}_index) return "${util.strip_main_name(subtype.name)}";')
|
||||
g.writeln('\tif (sidx == _${sym.cname}_${subtype.cname}_index) return "${util.strip_main_name(subtype.name)}";')
|
||||
}
|
||||
g.writeln('\treturn "unknown ${util.strip_main_name(typ.name)}";')
|
||||
g.writeln('\treturn "unknown ${util.strip_main_name(sym.name)}";')
|
||||
g.writeln('}')
|
||||
g.writeln('')
|
||||
g.writeln('static int v_typeof_interface_idx_${typ.cname}(int sidx) { /* $typ.name */ ')
|
||||
g.writeln('static int v_typeof_interface_idx_${sym.cname}(int sidx) { /* $sym.name */ ')
|
||||
for t in inter_info.types {
|
||||
subtype := g.table.get_type_symbol(t)
|
||||
g.writeln('\tif (sidx == _${typ.cname}_${subtype.cname}_index) return ${int(t)};')
|
||||
g.writeln('\tif (sidx == _${sym.cname}_${subtype.cname}_index) return ${int(t)};')
|
||||
}
|
||||
g.writeln('\treturn ${int(ityp)};')
|
||||
g.writeln('}')
|
||||
|
@ -1097,24 +1097,24 @@ fn (g &Gen) type_sidx(t ast.Type) string {
|
|||
|
||||
//
|
||||
pub fn (mut g Gen) write_typedef_types() {
|
||||
for typ in g.table.type_symbols {
|
||||
if typ.name in c.builtins {
|
||||
for sym in g.table.type_symbols {
|
||||
if sym.name in c.builtins {
|
||||
continue
|
||||
}
|
||||
match typ.kind {
|
||||
match sym.kind {
|
||||
.array {
|
||||
info := typ.info as ast.Array
|
||||
info := sym.info as ast.Array
|
||||
elem_sym := g.table.get_type_symbol(info.elem_type)
|
||||
if elem_sym.kind != .placeholder && !info.elem_type.has_flag(.generic) {
|
||||
g.type_definitions.writeln('typedef array $typ.cname;')
|
||||
g.type_definitions.writeln('typedef array $sym.cname;')
|
||||
}
|
||||
}
|
||||
.array_fixed {
|
||||
info := typ.info as ast.ArrayFixed
|
||||
info := sym.info as ast.ArrayFixed
|
||||
elem_sym := g.table.get_type_symbol(info.elem_type)
|
||||
if elem_sym.is_builtin() {
|
||||
// .array_fixed {
|
||||
styp := typ.cname
|
||||
styp := sym.cname
|
||||
// array_fixed_char_300 => char x[300]
|
||||
mut fixed := styp[12..]
|
||||
len := styp.after('_')
|
||||
|
@ -1135,59 +1135,59 @@ pub fn (mut g Gen) write_typedef_types() {
|
|||
}
|
||||
}
|
||||
.chan {
|
||||
if typ.name != 'chan' {
|
||||
g.type_definitions.writeln('typedef chan $typ.cname;')
|
||||
chan_inf := typ.chan_info()
|
||||
if sym.name != 'chan' {
|
||||
g.type_definitions.writeln('typedef chan $sym.cname;')
|
||||
chan_inf := sym.chan_info()
|
||||
chan_elem_type := chan_inf.elem_type
|
||||
if !chan_elem_type.has_flag(.generic) {
|
||||
el_stype := g.typ(chan_elem_type)
|
||||
g.channel_definitions.writeln('
|
||||
static inline $el_stype __${typ.cname}_popval($typ.cname ch) {
|
||||
static inline $el_stype __${sym.cname}_popval($sym.cname ch) {
|
||||
$el_stype val;
|
||||
sync__Channel_try_pop_priv(ch, &val, false);
|
||||
return val;
|
||||
}')
|
||||
g.channel_definitions.writeln('
|
||||
static inline void __${typ.cname}_pushval($typ.cname ch, $el_stype val) {
|
||||
static inline void __${sym.cname}_pushval($sym.cname ch, $el_stype val) {
|
||||
sync__Channel_try_push_priv(ch, &val, false);
|
||||
}')
|
||||
}
|
||||
}
|
||||
}
|
||||
.map {
|
||||
g.type_definitions.writeln('typedef map $typ.cname;')
|
||||
g.type_definitions.writeln('typedef map $sym.cname;')
|
||||
}
|
||||
else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
for typ in g.table.type_symbols {
|
||||
if typ.kind == .alias && typ.name !in c.builtins {
|
||||
g.write_alias_typesymbol_declaration(typ)
|
||||
for sym in g.table.type_symbols {
|
||||
if sym.kind == .alias && sym.name !in c.builtins {
|
||||
g.write_alias_typesymbol_declaration(sym)
|
||||
}
|
||||
}
|
||||
for typ in g.table.type_symbols {
|
||||
if typ.kind == .function && typ.name !in c.builtins {
|
||||
g.write_fn_typesymbol_declaration(typ)
|
||||
for sym in g.table.type_symbols {
|
||||
if sym.kind == .function && sym.name !in c.builtins {
|
||||
g.write_fn_typesymbol_declaration(sym)
|
||||
}
|
||||
}
|
||||
// Generating interfaces after all the common types have been defined
|
||||
// to prevent generating interface struct before definition of field types
|
||||
for typ in g.table.type_symbols {
|
||||
if typ.kind == .interface_ && typ.name !in c.builtins {
|
||||
g.write_interface_typedef(typ)
|
||||
for sym in g.table.type_symbols {
|
||||
if sym.kind == .interface_ && sym.name !in c.builtins {
|
||||
g.write_interface_typedef(sym)
|
||||
}
|
||||
}
|
||||
for typ in g.table.type_symbols {
|
||||
if typ.kind == .interface_ && typ.name !in c.builtins {
|
||||
g.write_interface_typesymbol_declaration(typ)
|
||||
for sym in g.table.type_symbols {
|
||||
if sym.kind == .interface_ && sym.name !in c.builtins {
|
||||
g.write_interface_typesymbol_declaration(sym)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) write_alias_typesymbol_declaration(sym ast.TypeSymbol) {
|
||||
parent := unsafe { &g.table.type_symbols[sym.parent_idx] }
|
||||
parent := g.table.type_symbols[sym.parent_idx]
|
||||
is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.`
|
||||
mut is_typedef := false
|
||||
if parent.info is ast.Struct {
|
||||
|
@ -3679,9 +3679,9 @@ fn (mut g Gen) map_fn_ptrs(key_typ ast.TypeSymbol) (string, string, string, stri
|
|||
}
|
||||
.voidptr {
|
||||
ts := if g.pref.m64 {
|
||||
unsafe { &g.table.type_symbols[ast.u64_type_idx] }
|
||||
unsafe { g.table.get_type_symbol_by_idx(ast.u64_type_idx) }
|
||||
} else {
|
||||
unsafe { &g.table.type_symbols[ast.u32_type_idx] }
|
||||
unsafe { g.table.get_type_symbol_by_idx(ast.u32_type_idx) }
|
||||
}
|
||||
return g.map_fn_ptrs(ts)
|
||||
}
|
||||
|
@ -5102,27 +5102,7 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) {
|
|||
}
|
||||
g.is_amp = false
|
||||
sym := g.table.get_type_symbol(node.typ)
|
||||
if sym.kind == .string && !node.typ.is_ptr() {
|
||||
// `string(x)` needs `tos()`, but not `&string(x)
|
||||
// `tos(str, len)`, `tos2(str)`
|
||||
if node.has_arg {
|
||||
g.write('tos((byteptr)')
|
||||
} else {
|
||||
g.write('tos2((byteptr)')
|
||||
}
|
||||
g.expr(node.expr)
|
||||
expr_sym := g.table.get_type_symbol(node.expr_type)
|
||||
if expr_sym.kind == .array {
|
||||
// if we are casting an array, we need to add `.data`
|
||||
g.write('.data')
|
||||
}
|
||||
if node.has_arg {
|
||||
// len argument
|
||||
g.write(', ')
|
||||
g.expr(node.arg)
|
||||
}
|
||||
g.write(')')
|
||||
} else if sym.kind in [.sum_type, .interface_] {
|
||||
if sym.kind in [.sum_type, .interface_] {
|
||||
g.expr_with_cast(node.expr, node.expr_type, node.typ)
|
||||
} else if sym.kind == .struct_ && !node.typ.is_ptr() && !(sym.info as ast.Struct).is_typedef {
|
||||
// deprecated, replaced by Struct{...exr}
|
||||
|
@ -6328,11 +6308,11 @@ fn (mut g Gen) write_builtin_types() {
|
|||
if g.pref.no_builtin {
|
||||
return
|
||||
}
|
||||
mut builtin_types := []ast.TypeSymbol{} // builtin types
|
||||
mut builtin_types := []&ast.TypeSymbol{} // builtin types
|
||||
// builtin types need to be on top
|
||||
// everything except builtin will get sorted
|
||||
for builtin_name in c.builtins {
|
||||
sym := g.table.type_symbols[g.table.type_idxs[builtin_name]]
|
||||
sym := g.table.get_type_symbol_by_idx(g.table.type_idxs[builtin_name])
|
||||
if sym.kind == .interface_ {
|
||||
g.write_interface_typedef(sym)
|
||||
g.write_interface_typesymbol_declaration(sym)
|
||||
|
@ -6347,36 +6327,36 @@ fn (mut g Gen) write_builtin_types() {
|
|||
// Sort the types, make sure types that are referenced by other types
|
||||
// are added before them.
|
||||
fn (mut g Gen) write_sorted_types() {
|
||||
mut types := []ast.TypeSymbol{cap: g.table.type_symbols.len} // structs that need to be sorted
|
||||
for typ in g.table.type_symbols {
|
||||
if typ.name !in c.builtins {
|
||||
types << typ
|
||||
mut symbols := []&ast.TypeSymbol{cap: g.table.type_symbols.len} // structs that need to be sorted
|
||||
for sym in g.table.type_symbols {
|
||||
if sym.name !in c.builtins {
|
||||
symbols << sym
|
||||
}
|
||||
}
|
||||
// sort structs
|
||||
types_sorted := g.sort_structs(types)
|
||||
sorted_symbols := g.sort_structs(symbols)
|
||||
// Generate C code
|
||||
g.type_definitions.writeln('// builtin types:')
|
||||
g.type_definitions.writeln('//------------------ #endbuiltin')
|
||||
g.write_types(types_sorted)
|
||||
g.write_types(sorted_symbols)
|
||||
}
|
||||
|
||||
fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
||||
for typ in types {
|
||||
if typ.name.starts_with('C.') {
|
||||
fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
||||
for sym in symbols {
|
||||
if sym.name.starts_with('C.') {
|
||||
continue
|
||||
}
|
||||
if typ.kind == .none_ {
|
||||
if sym.kind == .none_ {
|
||||
g.type_definitions.writeln('struct none {')
|
||||
g.type_definitions.writeln('\tEMPTY_STRUCT_DECLARATION;')
|
||||
g.type_definitions.writeln('};')
|
||||
g.typedefs2.writeln('typedef struct none none;')
|
||||
}
|
||||
// sym := g.table.get_type_symbol(typ)
|
||||
mut name := typ.cname
|
||||
match mut typ.info {
|
||||
mut name := sym.cname
|
||||
match mut sym.info {
|
||||
ast.Struct {
|
||||
if typ.info.is_generic {
|
||||
if sym.info.is_generic {
|
||||
continue
|
||||
}
|
||||
if name.contains('_T_') {
|
||||
|
@ -6388,7 +6368,7 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
|||
mut pre_pragma := ''
|
||||
mut post_pragma := ''
|
||||
|
||||
for attr in typ.info.attrs {
|
||||
for attr in sym.info.attrs {
|
||||
match attr.name {
|
||||
'_pack' {
|
||||
pre_pragma += '#pragma pack(push, $attr.arg)\n'
|
||||
|
@ -6400,13 +6380,13 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
|||
|
||||
g.type_definitions.writeln(pre_pragma)
|
||||
|
||||
if typ.info.is_union {
|
||||
if sym.info.is_union {
|
||||
g.type_definitions.writeln('union $name {')
|
||||
} else {
|
||||
g.type_definitions.writeln('struct $name {')
|
||||
}
|
||||
if typ.info.fields.len > 0 || typ.info.embeds.len > 0 {
|
||||
for field in typ.info.fields {
|
||||
if sym.info.fields.len > 0 || sym.info.embeds.len > 0 {
|
||||
for field in sym.info.fields {
|
||||
// Some of these structs may want to contain
|
||||
// optionals that may not be defined at this point
|
||||
// if this is the case then we are going to
|
||||
|
@ -6439,7 +6419,7 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
|||
}
|
||||
// g.type_definitions.writeln('} $name;\n')
|
||||
//
|
||||
ti_attrs := if typ.info.attrs.contains('packed') {
|
||||
ti_attrs := if sym.info.attrs.contains('packed') {
|
||||
'__attribute__((__packed__))'
|
||||
} else {
|
||||
''
|
||||
|
@ -6469,26 +6449,26 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
|||
}
|
||||
}
|
||||
ast.SumType {
|
||||
if typ.info.is_generic {
|
||||
if sym.info.is_generic {
|
||||
continue
|
||||
}
|
||||
g.typedefs.writeln('typedef struct $name $name;')
|
||||
g.type_definitions.writeln('')
|
||||
g.type_definitions.writeln('// Union sum type $name = ')
|
||||
for variant in typ.info.variants {
|
||||
for variant in sym.info.variants {
|
||||
g.type_definitions.writeln('// | ${variant:4d} = ${g.typ(variant.idx()):-20s}')
|
||||
}
|
||||
g.type_definitions.writeln('struct $name {')
|
||||
g.type_definitions.writeln('\tunion {')
|
||||
for variant in typ.info.variants {
|
||||
for variant in sym.info.variants {
|
||||
variant_sym := g.table.get_type_symbol(variant)
|
||||
g.type_definitions.writeln('\t\t${g.typ(variant.ref())} _$variant_sym.cname;')
|
||||
}
|
||||
g.type_definitions.writeln('\t};')
|
||||
g.type_definitions.writeln('\tint _typ;')
|
||||
if typ.info.fields.len > 0 {
|
||||
if sym.info.fields.len > 0 {
|
||||
g.writeln('\t// pointers to common sumtype fields')
|
||||
for field in typ.info.fields {
|
||||
for field in sym.info.fields {
|
||||
g.type_definitions.writeln('\t${g.typ(field.typ.ref())} $field.name;')
|
||||
}
|
||||
}
|
||||
|
@ -6496,18 +6476,18 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
|||
g.type_definitions.writeln('')
|
||||
}
|
||||
ast.ArrayFixed {
|
||||
elem_sym := g.table.get_type_symbol(typ.info.elem_type)
|
||||
if !elem_sym.is_builtin() && !typ.info.elem_type.has_flag(.generic) {
|
||||
elem_sym := g.table.get_type_symbol(sym.info.elem_type)
|
||||
if !elem_sym.is_builtin() && !sym.info.elem_type.has_flag(.generic) {
|
||||
// .array_fixed {
|
||||
styp := typ.cname
|
||||
styp := sym.cname
|
||||
// array_fixed_char_300 => char x[300]
|
||||
// [16]&&&EventListener{} => Array_fixed_main__EventListener_16_ptr3
|
||||
// => typedef main__EventListener*** Array_fixed_main__EventListener_16_ptr3 [16]
|
||||
mut fixed_elem_name := g.typ(typ.info.elem_type.set_nr_muls(0))
|
||||
if typ.info.elem_type.is_ptr() {
|
||||
fixed_elem_name += '*'.repeat(typ.info.elem_type.nr_muls())
|
||||
mut fixed_elem_name := g.typ(sym.info.elem_type.set_nr_muls(0))
|
||||
if sym.info.elem_type.is_ptr() {
|
||||
fixed_elem_name += '*'.repeat(sym.info.elem_type.nr_muls())
|
||||
}
|
||||
len := typ.info.size
|
||||
len := sym.info.size
|
||||
if fixed_elem_name.starts_with('C__') {
|
||||
fixed_elem_name = fixed_elem_name[3..]
|
||||
}
|
||||
|
@ -6529,7 +6509,7 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
|||
}
|
||||
|
||||
// sort structs by dependant fields
|
||||
fn (g &Gen) sort_structs(typesa []ast.TypeSymbol) []ast.TypeSymbol {
|
||||
fn (g &Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol {
|
||||
util.timing_start(@METHOD)
|
||||
defer {
|
||||
util.timing_measure(@METHOD)
|
||||
|
@ -6537,26 +6517,26 @@ fn (g &Gen) sort_structs(typesa []ast.TypeSymbol) []ast.TypeSymbol {
|
|||
mut dep_graph := depgraph.new_dep_graph()
|
||||
// types name list
|
||||
mut type_names := []string{}
|
||||
for typ in typesa {
|
||||
type_names << typ.name
|
||||
for sym in typesa {
|
||||
type_names << sym.name
|
||||
}
|
||||
// loop over types
|
||||
for t in typesa {
|
||||
if t.kind == .interface_ {
|
||||
dep_graph.add(t.name, [])
|
||||
for sym in typesa {
|
||||
if sym.kind == .interface_ {
|
||||
dep_graph.add(sym.name, [])
|
||||
continue
|
||||
}
|
||||
// create list of deps
|
||||
mut field_deps := []string{}
|
||||
match mut t.info {
|
||||
match mut sym.info {
|
||||
ast.ArrayFixed {
|
||||
dep := g.table.get_type_symbol(t.info.elem_type).name
|
||||
dep := g.table.get_type_symbol(sym.info.elem_type).name
|
||||
if dep in type_names {
|
||||
field_deps << dep
|
||||
}
|
||||
}
|
||||
ast.Struct {
|
||||
for embed in t.info.embeds {
|
||||
for embed in sym.info.embeds {
|
||||
dep := g.table.get_type_symbol(embed).name
|
||||
// skip if not in types list or already in deps
|
||||
if dep !in type_names || dep in field_deps {
|
||||
|
@ -6564,7 +6544,7 @@ fn (g &Gen) sort_structs(typesa []ast.TypeSymbol) []ast.TypeSymbol {
|
|||
}
|
||||
field_deps << dep
|
||||
}
|
||||
for field in t.info.fields {
|
||||
for field in sym.info.fields {
|
||||
dep := g.table.get_type_symbol(field.typ).name
|
||||
// skip if not in types list or already in deps
|
||||
if dep !in type_names || dep in field_deps || field.typ.is_ptr() {
|
||||
|
@ -6577,7 +6557,7 @@ fn (g &Gen) sort_structs(typesa []ast.TypeSymbol) []ast.TypeSymbol {
|
|||
else {}
|
||||
}
|
||||
// add type and dependant types to graph
|
||||
dep_graph.add(t.name, field_deps)
|
||||
dep_graph.add(sym.name, field_deps)
|
||||
}
|
||||
// sort graph
|
||||
dep_graph_sorted := dep_graph.resolve()
|
||||
|
@ -6590,11 +6570,11 @@ fn (g &Gen) sort_structs(typesa []ast.TypeSymbol) []ast.TypeSymbol {
|
|||
'\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro')
|
||||
}
|
||||
// sort types
|
||||
mut types_sorted := []ast.TypeSymbol{cap: dep_graph_sorted.nodes.len}
|
||||
mut sorted_symbols := []&ast.TypeSymbol{cap: dep_graph_sorted.nodes.len}
|
||||
for node in dep_graph_sorted.nodes {
|
||||
types_sorted << g.table.type_symbols[g.table.type_idxs[node.name]]
|
||||
sorted_symbols << g.table.get_type_symbol_by_idx(g.table.type_idxs[node.name])
|
||||
}
|
||||
return types_sorted
|
||||
return sorted_symbols
|
||||
}
|
||||
|
||||
[inline]
|
||||
|
@ -7184,19 +7164,19 @@ fn (g Gen) as_cast_name_table() string {
|
|||
fn (mut g Gen) interface_table() string {
|
||||
mut sb := strings.new_builder(100)
|
||||
mut conversion_functions := strings.new_builder(100)
|
||||
for ityp in g.table.type_symbols {
|
||||
if ityp.kind != .interface_ {
|
||||
for isym in g.table.type_symbols {
|
||||
if isym.kind != .interface_ {
|
||||
continue
|
||||
}
|
||||
if ityp.info !is ast.Interface {
|
||||
if isym.info !is ast.Interface {
|
||||
continue
|
||||
}
|
||||
inter_info := ityp.info as ast.Interface
|
||||
inter_info := isym.info as ast.Interface
|
||||
if inter_info.is_generic {
|
||||
continue
|
||||
}
|
||||
// interface_name is for example Speaker
|
||||
interface_name := ityp.cname
|
||||
interface_name := isym.cname
|
||||
// generate a struct that references interface methods
|
||||
methods_struct_name := 'struct _${interface_name}_interface_methods'
|
||||
mut methods_struct_def := strings.new_builder(100)
|
||||
|
@ -7243,7 +7223,7 @@ fn (mut g Gen) interface_table() string {
|
|||
cctype := g.cc_type(st, true)
|
||||
$if debug_interface_table ? {
|
||||
eprintln(
|
||||
'>> interface name: $ityp.name | concrete type: $st.debug() | st symname: ' +
|
||||
'>> interface name: $isym.name | concrete type: $st.debug() | st symname: ' +
|
||||
st_sym.name)
|
||||
}
|
||||
// Speaker_Cat_index = 0
|
||||
|
@ -7253,7 +7233,7 @@ fn (mut g Gen) interface_table() string {
|
|||
}
|
||||
already_generated_mwrappers[interface_index_name] = current_iinidx
|
||||
current_iinidx++
|
||||
if ityp.name != 'vweb.DbInterface' { // TODO remove this
|
||||
if isym.name != 'vweb.DbInterface' { // TODO remove this
|
||||
// eprintln('>>> current_iinidx: ${current_iinidx-iinidx_minimum_base} | interface_index_name: $interface_index_name')
|
||||
sb.writeln('static $interface_name I_${cctype}_to_Interface_${interface_name}($cctype* x);')
|
||||
mut cast_struct := strings.new_builder(100)
|
||||
|
|
|
@ -119,7 +119,7 @@ pub fn gen(files []&ast.File, table &ast.Table, out_name string, pref &pref.Pref
|
|||
}
|
||||
|
||||
pub fn (mut g Gen) typ(a int) &ast.TypeSymbol {
|
||||
return &g.table.type_symbols[a]
|
||||
return g.table.type_symbols[a]
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) generate_header() {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
type MyByte = byte
|
||||
|
||||
type MyInt = int
|
||||
|
||||
type MyString = string
|
||||
|
||||
fn ok() {
|
||||
assert true
|
||||
}
|
||||
|
||||
// bytes
|
||||
fn test_byte_aliasing() {
|
||||
dump(byte(123))
|
||||
dump(MyByte(byte(123)))
|
||||
dump(byte(MyByte(byte(123))))
|
||||
ok()
|
||||
}
|
||||
|
||||
fn test_pbyte_aliasing() {
|
||||
unsafe {
|
||||
dump(voidptr(&byte(123)))
|
||||
dump(voidptr(&MyByte(&byte(123))))
|
||||
dump(voidptr(&byte(&MyByte(&byte(123)))))
|
||||
}
|
||||
ok()
|
||||
}
|
||||
|
||||
// ints
|
||||
fn test_int_aliasing() {
|
||||
dump(int(123))
|
||||
dump(int(MyInt(123)))
|
||||
dump(MyInt(int(MyInt(123))))
|
||||
ok()
|
||||
}
|
||||
|
||||
fn test_pint_aliasing() {
|
||||
unsafe {
|
||||
dump(voidptr(&int(123456)))
|
||||
dump(voidptr(&MyInt(&int(123456))))
|
||||
dump(voidptr(&int(&MyInt(&int(123456)))))
|
||||
}
|
||||
ok()
|
||||
}
|
||||
|
||||
// strings
|
||||
fn test_string_aliasing() {
|
||||
$if msvc {
|
||||
eprintln('> TODO: msvc errors out for casting a `string` to a `string`')
|
||||
}
|
||||
$if !msvc {
|
||||
dump(string('abc'))
|
||||
dump(string(MyString('abc')))
|
||||
dump(MyString(string(MyString('abc'))))
|
||||
}
|
||||
ok()
|
||||
}
|
||||
|
||||
fn test_pstring_aliasing() {
|
||||
s := 'abc'
|
||||
unsafe {
|
||||
dump(voidptr(&string(&s)))
|
||||
dump(voidptr(&string(&MyString(&s))))
|
||||
dump(voidptr(&MyString(&string(&MyString(&s)))))
|
||||
}
|
||||
ok()
|
||||
}
|
|
@ -13,6 +13,10 @@ pub mut:
|
|||
last_line int // the line number where the ast object ends (used by vfmt)
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
pub fn (mut p Position) free() {
|
||||
}
|
||||
|
||||
pub fn (pos Position) extend(end Position) Position {
|
||||
return Position{
|
||||
...pos
|
||||
|
|
Loading…
Reference in New Issue