all: fix casting of `string(MyString('abc'))` and `byte(MyByte(123))`; improve TypeSymbol handling (#12617)

pull/12641/head
Delyan Angelov 2021-12-01 09:50:53 +02:00 committed by GitHub
parent 519ca90cfa
commit 47aa2b1f93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 348 additions and 278 deletions

View File

@ -92,7 +92,7 @@ pub fn (mut b Builder) cut_to(pos int) string {
pub fn (mut b Builder) write_runes(runes []rune) { pub fn (mut b Builder) write_runes(runes []rune) {
for r in runes { for r in runes {
res := string(r) res := r.str()
#res.str = String.fromCharCode(r.val) #res.str = String.fromCharCode(r.val)
b << res.bytes() b << res.bytes()
} }

View File

@ -10,7 +10,7 @@ import v.util
[heap] [heap]
pub struct Table { pub struct Table {
pub mut: pub mut:
type_symbols []TypeSymbol type_symbols []&TypeSymbol
type_idxs map[string]int type_idxs map[string]int
fns map[string]Fn fns map[string]Fn
iface_types map[string][]Type iface_types map[string][]Type
@ -42,8 +42,11 @@ pub mut:
// used by vls to avoid leaks // used by vls to avoid leaks
// TODO remove manual memory management // TODO remove manual memory management
[unsafe] [unsafe]
pub fn (t &Table) free() { pub fn (mut t Table) free() {
unsafe { unsafe {
for s in t.type_symbols {
s.free()
}
t.type_symbols.free() t.type_symbols.free()
t.type_idxs.free() t.type_idxs.free()
t.fns.free() t.fns.free()
@ -169,7 +172,6 @@ fn (p []Param) equals(o []Param) bool {
pub fn new_table() &Table { pub fn new_table() &Table {
mut t := &Table{ mut t := &Table{
type_symbols: []TypeSymbol{cap: 64000}
global_scope: &Scope{ global_scope: &Scope{
parent: 0 parent: 0
} }
@ -348,7 +350,7 @@ pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn {
if ts.parent_idx == 0 { if ts.parent_idx == 0 {
break break
} }
ts = unsafe { &t.type_symbols[ts.parent_idx] } ts = t.type_symbols[ts.parent_idx]
} }
return none return none
} }
@ -490,7 +492,7 @@ pub fn (t &Table) find_field(s &TypeSymbol, name string) ?StructField {
if ts.parent_idx == 0 { if ts.parent_idx == 0 {
break break
} }
ts = unsafe { &t.type_symbols[ts.parent_idx] } ts = t.type_symbols[ts.parent_idx]
} }
return none return none
} }
@ -625,7 +627,7 @@ pub fn (t &Table) find_type_idx(name string) int {
} }
[inline] [inline]
pub fn (t &Table) find_type(name string) ?TypeSymbol { pub fn (t &Table) find_type(name string) ?&TypeSymbol {
idx := t.type_idxs[name] idx := t.type_idxs[name]
if idx > 0 { if idx > 0 {
return t.type_symbols[idx] return t.type_symbols[idx]
@ -634,6 +636,7 @@ pub fn (t &Table) find_type(name string) ?TypeSymbol {
} }
pub const invalid_type_symbol = &TypeSymbol{ pub const invalid_type_symbol = &TypeSymbol{
idx: -1
parent_idx: -1 parent_idx: -1
language: .v language: .v
mod: 'builtin' mod: 'builtin'
@ -643,10 +646,14 @@ pub const invalid_type_symbol = &TypeSymbol{
} }
[inline] [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 { pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
idx := typ.idx() idx := typ.idx()
if idx > 0 { if idx > 0 {
return unsafe { &t.type_symbols[idx] } return t.type_symbols[idx]
} }
// this should never happen // 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`. 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 { pub fn (t &Table) get_final_type_symbol(typ Type) &TypeSymbol {
mut idx := typ.idx() mut idx := typ.idx()
if idx > 0 { if idx > 0 {
current_type := t.type_symbols[idx] current_symbol := t.type_symbols[idx]
if current_type.kind == .alias { if current_symbol.kind == .alias {
idx = (current_type.info as Alias).parent_type.idx() idx = (current_symbol.info as Alias).parent_type.idx()
} }
return unsafe { &t.type_symbols[idx] } return t.type_symbols[idx]
} }
// this should never happen // 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`.') 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] [inline]
pub fn (t &Table) get_type_name(typ Type) string { pub fn (t &Table) get_type_name(typ Type) string {
typ_sym := t.get_type_symbol(typ) sym := t.get_type_symbol(typ)
return typ_sym.name return sym.name
} }
[inline] [inline]
@ -688,38 +695,36 @@ pub fn (t &Table) unalias_num_type(typ Type) Type {
return typ return typ
} }
fn (mut t Table) check_for_already_registered_symbol(typ TypeSymbol, existing_idx int) int { fn (mut t Table) rewrite_already_registered_symbol(typ TypeSymbol, existing_idx int) int {
ex_type := t.type_symbols[existing_idx] existing_symbol := t.type_symbols[existing_idx]
match ex_type.kind { if existing_symbol.kind == .placeholder {
.placeholder { // override placeholder
// override placeholder t.type_symbols[existing_idx] = &TypeSymbol{
t.type_symbols[existing_idx] = TypeSymbol{ ...typ
...typ methods: existing_symbol.methods
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
} }
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] [inline]
@ -727,7 +732,7 @@ pub fn (mut t Table) register_type_symbol(sym TypeSymbol) int {
mut idx := -2 mut idx := -2
mut existing_idx := t.type_idxs[sym.name] mut existing_idx := t.type_idxs[sym.name]
if existing_idx > 0 { 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 { if idx != -2 {
return idx return idx
} }
@ -735,14 +740,16 @@ pub fn (mut t Table) register_type_symbol(sym TypeSymbol) int {
if sym.mod == 'main' { if sym.mod == 'main' {
existing_idx = t.type_idxs[sym.name.trim_prefix('main.')] existing_idx = t.type_idxs[sym.name.trim_prefix('main.')]
if existing_idx > 0 { 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 { if idx != -2 {
return idx return idx
} }
} }
} }
idx = t.type_symbols.len idx = t.type_symbols.len
t.type_symbols << sym t.type_symbols << &TypeSymbol{
...sym
}
t.type_symbols[idx].idx = idx t.type_symbols[idx].idx = idx
t.type_idxs[sym.name] = idx t.type_idxs[sym.name] = idx
return idx return idx
@ -1088,31 +1095,31 @@ pub fn (mut t Table) add_placeholder_type(name string, language Language) int {
[inline] [inline]
pub fn (t &Table) value_type(typ Type) Type { 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) { if typ.has_flag(.variadic) {
// ...string => string // ...string => string
// return typ.clear_flag(.variadic) // return typ.clear_flag(.variadic)
array_info := typ_sym.info as Array array_info := sym.info as Array
return array_info.elem_type return array_info.elem_type
} }
if typ_sym.kind == .array { if sym.kind == .array {
// Check index type // Check index type
info := typ_sym.info as Array info := sym.info as Array
return info.elem_type return info.elem_type
} }
if typ_sym.kind == .array_fixed { if sym.kind == .array_fixed {
info := typ_sym.info as ArrayFixed info := sym.info as ArrayFixed
return info.elem_type return info.elem_type
} }
if typ_sym.kind == .map { if sym.kind == .map {
info := typ_sym.info as Map info := sym.info as Map
return info.value_type return info.value_type
} }
if typ_sym.kind == .string && typ.is_ptr() { if sym.kind == .string && typ.is_ptr() {
// (&string)[i] => string // (&string)[i] => string
return string_type return string_type
} }
if typ_sym.kind in [.byteptr, .string] { if sym.kind in [.byteptr, .string] {
return byte_type return byte_type
} }
if typ.is_ptr() { 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 // `none` "implements" the Error interface
return true return true
} }
typ_sym := t.get_type_symbol(typ) sym := t.get_type_symbol(typ)
if typ_sym.language != .v { if sym.language != .v {
return false return false
} }
// generic struct don't generate cast interface fn // generic struct don't generate cast interface fn
if typ_sym.info is Struct { if sym.info is Struct {
if typ_sym.info.is_generic { if sym.info.is_generic {
return false return false
} }
} }
mut inter_sym := t.get_type_symbol(inter_typ) 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 return false
} }
if mut inter_sym.info is Interface { 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 // verify methods
for imethod in inter_sym.info.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) msg := t.is_same_method(imethod, method)
if msg.len > 0 { if msg.len > 0 {
return false 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 { if ifield.typ == voidptr_type {
// Allow `voidptr` fields in interfaces for now. (for example // Allow `voidptr` fields in interfaces for now. (for example
// to enable .db check in vweb) // to enable .db check in vweb)
if t.struct_has_field(typ_sym, ifield.name) { if t.struct_has_field(sym, ifield.name) {
continue continue
} else { } else {
return false 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 { if ifield.typ != field.typ {
return false return false
} else if ifield.is_mut && !(field.is_mut || field.is_global) { } else if ifield.is_mut && !(field.is_mut || field.is_global) {

View File

@ -664,7 +664,7 @@ pub fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
if node.language == .v && !c.is_builtin_mod { if node.language == .v && !c.is_builtin_mod {
c.check_valid_pascal_case(node.name, 'struct name', node.pos) 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 mut has_generic_types := false
if mut struct_sym.info is ast.Struct { if mut struct_sym.info is ast.Struct {
for embed in node.embeds { 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 { 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 node.expr_type = c.expr(node.expr) // type to be casted
from_type_sym := c.table.get_type_symbol(node.expr_type) mut from_type := node.expr_type
to_type_sym := c.table.get_type_symbol(node.typ) // type to be used as cast 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') 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_number() && from_type_sym.name == 'JS.BigInt')
|| (to_type_sym.is_string() && from_type_sym.name == 'JS.String') || (to_type_sym.is_string() && from_type_sym.name == 'JS.String')
|| (node.typ.is_bool() && from_type_sym.name == 'JS.Boolean') || (to_type.is_bool() && from_type_sym.name == 'JS.Boolean')
|| (node.expr_type.is_bool() && to_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.Number')
|| (from_type_sym.is_number() && to_type_sym.name == 'JS.BigInt') || (from_type_sym.is_number() && to_type_sym.name == 'JS.BigInt')
|| (from_type_sym.is_string() && to_type_sym.name == 'JS.String') { || (from_type_sym.is_string() && to_type_sym.name == 'JS.String') {
return node.typ return to_type
} }
if to_type_sym.language != .c { 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 if from_type_sym.kind == .byte && from_type.is_ptr() && to_type_sym.kind == .string
&& !node.typ.is_ptr() { && !to_type.is_ptr() {
c.error('to convert a C string buffer pointer to a V string, use x.vstring() instead of string(x)', c.error('to convert a C string buffer pointer to a V string, use x.vstring() instead of string(x)',
node.pos) 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()) 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.', if to_type == ast.string_type {
node.pos) 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.',
if to_type_sym.kind == .sum_type { node.pos)
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 !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) 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 { } else if mut to_type_sym.info is ast.Alias {
if !c.check_types(node.expr_type, to_type_sym.info.parent_type) { if !c.check_types(from_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 `$to_type_sym_final.name`)',
c.error('cannot convert type `$from_type_sym.name` to `$to_type_sym.name` (alias to `$parent_type_sym.name`)',
node.pos) node.pos)
} }
} else if node.typ == ast.string_type } else if to_type != ast.string_type && from_type == ast.string_type
&& (from_type_sym.kind in [.int_literal, .int, .byte, .byteptr, .bool] && (!(to_type_sym.kind == .alias && to_type_sym_final.name == 'string')) {
|| (from_type_sym.kind == .array && from_type_sym.name == 'array_byte')) { mut error_msg := 'cannot cast a string to a type `$to_type_sym_final.name`, that is not an alias of string'
type_name := c.table.type_to_str(node.expr_type) if mut node.expr is ast.StringLiteral {
c.error('cannot cast type `$type_name` to string, use `x.str()` instead', node.pos) if node.expr.val.len == 1 {
} else if node.expr_type == ast.string_type { error_msg += ", for denoting characters use `$node.expr.val` instead of '$node.expr.val'"
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'"
}
} }
c.error(error_msg, node.pos)
} }
} else if to_type_sym.kind == .byte && node.expr_type != ast.voidptr_type c.error(error_msg, node.pos)
&& from_type_sym.kind != .enum_ && !node.expr_type.is_int() && !node.expr_type.is_float() } else if to_type_sym.kind == .byte && from_type != ast.voidptr_type
&& node.expr_type != ast.bool_type && !node.expr_type.is_ptr() { && from_type_sym.kind != .enum_ && !from_type.is_int() && !from_type.is_float()
type_name := c.table.type_to_str(node.expr_type) && 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) 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 { && !(to_type_sym.info as ast.Struct).is_typedef {
// For now we ignore C typedef because of `C.Window(C.None)` in vlib/clipboard // 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', c.warn('casting to struct is deprecated, use e.g. `Struct{...expr}` instead',
node.pos) node.pos)
from_type_info := from_type_sym.info as ast.Struct 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) node.pos)
} }
} else { } else {
type_name := c.table.type_to_str(node.expr_type) type_name := c.table.type_to_str(from_type)
// dump(node.typ)
// dump(node.expr_type)
// dump(type_name)
// dump(to_type_sym.debug())
c.error('cannot cast `$type_name` to struct', node.pos) c.error('cannot cast `$type_name` to struct', node.pos)
} }
} else if to_type_sym.kind == .interface_ { } else if to_type_sym.kind == .interface_ {
if c.type_implements(node.expr_type, node.typ, node.pos) { if c.type_implements(from_type, to_type, node.pos) {
if !node.expr_type.is_ptr() && !node.expr_type.is_pointer() if !from_type.is_ptr() && !from_type.is_pointer() && from_type_sym.kind != .interface_
&& from_type_sym.kind != .interface_ && !c.inside_unsafe { && !c.inside_unsafe {
c.mark_as_referenced(mut &node.expr, true) 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) 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) { } else if from_type == ast.none_type && !to_type.has_flag(.optional) {
type_name := c.table.type_to_str(node.typ) type_name := c.table.type_to_str(to_type)
c.error('cannot cast `none` to `$type_name`', node.pos) c.error('cannot cast `none` to `$type_name`', node.pos)
} else if from_type_sym.kind == .struct_ && !node.expr_type.is_ptr() { } else if from_type_sym.kind == .struct_ && !from_type.is_ptr() {
if (node.typ.is_ptr() || to_type_sym.kind !in [.sum_type, .interface_]) && !c.is_builtin_mod { if (to_type.is_ptr() || to_type_sym.kind !in [.sum_type, .interface_]) && !c.is_builtin_mod {
type_name := c.table.type_to_str(node.typ) from_type_name := c.table.type_to_str(from_type)
c.error('cannot cast struct to `$type_name`', node.pos) 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 // 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) c.error('cannot type cast $msg', node.pos)
} else if !c.inside_unsafe && node.typ.is_ptr() && node.expr_type.is_ptr() } else if !c.inside_unsafe && to_type.is_ptr() && from_type.is_ptr()
&& node.typ.deref() != ast.char_type && node.expr_type.deref() != ast.char_type { && to_type.deref() != ast.char_type && from_type.deref() != ast.char_type {
ft := c.table.type_to_str(node.expr_type) ft := c.table.type_to_str(from_type)
tt := c.table.type_to_str(node.typ) tt := c.table.type_to_str(to_type)
c.warn('casting `$ft` to `$tt` is only allowed in `unsafe` code', node.pos) 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) c.warn('cannot cast a fixed array (use e.g. `&arr[0]` instead)', node.pos)
} }
if node.has_arg { 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 // checks on int literal to enum cast if the value represents a value on the enum
if to_type_sym.kind == .enum_ { if to_type_sym.kind == .enum_ {
if node.expr is ast.IntegerLiteral { 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() node_val := (node.expr as ast.IntegerLiteral).val.int()
if enum_decl := c.table.enum_decls[to_type_sym.name] { 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 { fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {

View File

@ -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() { 1 | fn main() {
2 | println(string(true)) 2 | println(string(true))
| ~~~~~~~~~~~~ | ~~~~~~~~~~~~
3 | println(string(false)) 3 | println(string(false))
4 | } 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() { 1 | fn main() {
2 | println(string(true)) 2 | println(string(true))
3 | println(string(false)) 3 | println(string(false))

View File

@ -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() { 1 | fn main() {
2 | a := string(1) 2 | a := string(1)
| ~~~~~~~~~ | ~~~~~~~~~

View File

@ -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' { 1 | for by in 'abc' {
2 | println(string(by)) 2 | println(string(by))
| ~~~~~~~~~~ | ~~~~~~~~~~

View File

@ -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() { 3 | fn main() {
4 | foo := Foo{} 4 | foo := Foo{}
5 | _ := string(foo) 5 | _ := string(foo)
| ~~~~~~~~~~~ | ~~~~~~~~~~~
6 | _ := int(foo) 6 | _ := int(foo)
7 | _ := u64(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{} 4 | foo := Foo{}
5 | _ := string(foo) 5 | _ := string(foo)
6 | _ := int(foo) 6 | _ := int(foo)
| ~~~~~~~~ | ~~~~~~~~
7 | _ := u64(foo) 7 | _ := u64(foo)
8 | _ := u32(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) 5 | _ := string(foo)
6 | _ := int(foo) 6 | _ := int(foo)
7 | _ := u64(foo) 7 | _ := u64(foo)
| ~~~~~~~~ | ~~~~~~~~
8 | _ := u32(foo) 8 | _ := u32(foo)
9 | _ := rune(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) 6 | _ := int(foo)
7 | _ := u64(foo) 7 | _ := u64(foo)
8 | _ := u32(foo) 8 | _ := u32(foo)
| ~~~~~~~~ | ~~~~~~~~
9 | _ := rune(foo) 9 | _ := rune(foo)
10 | _ := byte(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) 7 | _ := u64(foo)
8 | _ := u32(foo) 8 | _ := u32(foo)
9 | _ := rune(foo) 9 | _ := rune(foo)
| ~~~~~~~~~ | ~~~~~~~~~
10 | _ := byte(foo) 10 | _ := byte(foo)
11 | _ := i8(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) 8 | _ := u32(foo)
9 | _ := rune(foo) 9 | _ := rune(foo)
10 | _ := byte(foo) 10 | _ := byte(foo)
| ~~~~~~~~~ | ~~~~~~~~~
11 | _ := i8(foo) 11 | _ := i8(foo)
12 | _ := i64(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) 9 | _ := rune(foo)
10 | _ := byte(foo) 10 | _ := byte(foo)
11 | _ := i8(foo) 11 | _ := i8(foo)
| ~~~~~~~ | ~~~~~~~
12 | _ := i64(foo) 12 | _ := i64(foo)
13 | _ := int(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) 10 | _ := byte(foo)
11 | _ := i8(foo) 11 | _ := i8(foo)
12 | _ := i64(foo) 12 | _ := i64(foo)
| ~~~~~~~~ | ~~~~~~~~
13 | _ := int(foo) 13 | _ := int(foo)
14 | _ = &I1(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) 11 | _ := i8(foo)
12 | _ := i64(foo) 12 | _ := i64(foo)
13 | _ := int(foo) 13 | _ := int(foo)

View File

@ -378,18 +378,18 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
g.timers.start('cgen common') g.timers.start('cgen common')
// to make sure type idx's are the same in cached mods // to make sure type idx's are the same in cached mods
if g.pref.build_mode == .build_module { 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 { if idx == 0 {
continue 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 { } 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 { if idx == 0 {
continue 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() { pub fn (mut g Gen) write_typeof_functions() {
g.writeln('') g.writeln('')
g.writeln('// >> typeof() support for sum types / interfaces') g.writeln('// >> typeof() support for sum types / interfaces')
for ityp, typ in g.table.type_symbols { for ityp, sym in g.table.type_symbols {
if typ.kind == .sum_type { if sym.kind == .sum_type {
sum_info := typ.info as ast.SumType sum_info := sym.info as ast.SumType
if sum_info.is_generic { if sum_info.is_generic {
continue 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 { 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 { for v in sum_info.variants {
subtype := g.table.get_type_symbol(v) 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('\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 { } else {
tidx := g.table.find_type_idx(typ.name) tidx := g.table.find_type_idx(sym.name)
g.writeln('\tswitch(sidx) {') 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 { for v in sum_info.variants {
subtype := g.table.get_type_symbol(v) subtype := g.table.get_type_symbol(v)
g.writeln('\t\tcase $v: return "${util.strip_main_name(subtype.name)}";') 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('\t}')
} }
g.writeln('}') g.writeln('}')
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 { 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 { for v in sum_info.variants {
subtype := g.table.get_type_symbol(v) subtype := g.table.get_type_symbol(v)
g.writeln('\tif( sidx == _v_type_idx_${subtype.cname}() ) return ${int(v)};') g.writeln('\tif( sidx == _v_type_idx_${subtype.cname}() ) return ${int(v)};')
} }
g.writeln('\treturn ${int(ityp)};') g.writeln('\treturn ${int(ityp)};')
} else { } else {
tidx := g.table.find_type_idx(typ.name) tidx := g.table.find_type_idx(sym.name)
g.writeln('\tswitch(sidx) {') g.writeln('\tswitch(sidx) {')
g.writeln('\t\tcase $tidx: return ${int(ityp)};') g.writeln('\t\tcase $tidx: return ${int(ityp)};')
for v in sum_info.variants { for v in sum_info.variants {
@ -791,27 +791,27 @@ pub fn (mut g Gen) write_typeof_functions() {
g.writeln('\t}') g.writeln('\t}')
} }
g.writeln('}') g.writeln('}')
} else if typ.kind == .interface_ { } else if sym.kind == .interface_ {
if typ.info !is ast.Interface { if sym.info !is ast.Interface {
continue continue
} }
inter_info := typ.info as ast.Interface inter_info := sym.info as ast.Interface
if inter_info.is_generic { if inter_info.is_generic {
continue continue
} }
g.definitions.writeln('static char * v_typeof_interface_${typ.cname}(int sidx);') g.definitions.writeln('static char * v_typeof_interface_${sym.cname}(int sidx);')
g.writeln('static char * v_typeof_interface_${typ.cname}(int sidx) { /* $typ.name */ ') g.writeln('static char * v_typeof_interface_${sym.cname}(int sidx) { /* $sym.name */ ')
for t in inter_info.types { for t in inter_info.types {
subtype := g.table.get_type_symbol(t) 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('') 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 { for t in inter_info.types {
subtype := g.table.get_type_symbol(t) 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('\treturn ${int(ityp)};')
g.writeln('}') g.writeln('}')
@ -1097,24 +1097,24 @@ fn (g &Gen) type_sidx(t ast.Type) string {
// //
pub fn (mut g Gen) write_typedef_types() { pub fn (mut g Gen) write_typedef_types() {
for typ in g.table.type_symbols { for sym in g.table.type_symbols {
if typ.name in c.builtins { if sym.name in c.builtins {
continue continue
} }
match typ.kind { match sym.kind {
.array { .array {
info := typ.info as ast.Array info := sym.info as ast.Array
elem_sym := g.table.get_type_symbol(info.elem_type) elem_sym := g.table.get_type_symbol(info.elem_type)
if elem_sym.kind != .placeholder && !info.elem_type.has_flag(.generic) { 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 { .array_fixed {
info := typ.info as ast.ArrayFixed info := sym.info as ast.ArrayFixed
elem_sym := g.table.get_type_symbol(info.elem_type) elem_sym := g.table.get_type_symbol(info.elem_type)
if elem_sym.is_builtin() { if elem_sym.is_builtin() {
// .array_fixed { // .array_fixed {
styp := typ.cname styp := sym.cname
// array_fixed_char_300 => char x[300] // array_fixed_char_300 => char x[300]
mut fixed := styp[12..] mut fixed := styp[12..]
len := styp.after('_') len := styp.after('_')
@ -1135,59 +1135,59 @@ pub fn (mut g Gen) write_typedef_types() {
} }
} }
.chan { .chan {
if typ.name != 'chan' { if sym.name != 'chan' {
g.type_definitions.writeln('typedef chan $typ.cname;') g.type_definitions.writeln('typedef chan $sym.cname;')
chan_inf := typ.chan_info() chan_inf := sym.chan_info()
chan_elem_type := chan_inf.elem_type chan_elem_type := chan_inf.elem_type
if !chan_elem_type.has_flag(.generic) { if !chan_elem_type.has_flag(.generic) {
el_stype := g.typ(chan_elem_type) el_stype := g.typ(chan_elem_type)
g.channel_definitions.writeln(' 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; $el_stype val;
sync__Channel_try_pop_priv(ch, &val, false); sync__Channel_try_pop_priv(ch, &val, false);
return val; return val;
}') }')
g.channel_definitions.writeln(' 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); sync__Channel_try_push_priv(ch, &val, false);
}') }')
} }
} }
} }
.map { .map {
g.type_definitions.writeln('typedef map $typ.cname;') g.type_definitions.writeln('typedef map $sym.cname;')
} }
else { else {
continue continue
} }
} }
} }
for typ in g.table.type_symbols { for sym in g.table.type_symbols {
if typ.kind == .alias && typ.name !in c.builtins { if sym.kind == .alias && sym.name !in c.builtins {
g.write_alias_typesymbol_declaration(typ) g.write_alias_typesymbol_declaration(sym)
} }
} }
for typ in g.table.type_symbols { for sym in g.table.type_symbols {
if typ.kind == .function && typ.name !in c.builtins { if sym.kind == .function && sym.name !in c.builtins {
g.write_fn_typesymbol_declaration(typ) g.write_fn_typesymbol_declaration(sym)
} }
} }
// Generating interfaces after all the common types have been defined // Generating interfaces after all the common types have been defined
// to prevent generating interface struct before definition of field types // to prevent generating interface struct before definition of field types
for typ in g.table.type_symbols { for sym in g.table.type_symbols {
if typ.kind == .interface_ && typ.name !in c.builtins { if sym.kind == .interface_ && sym.name !in c.builtins {
g.write_interface_typedef(typ) g.write_interface_typedef(sym)
} }
} }
for typ in g.table.type_symbols { for sym in g.table.type_symbols {
if typ.kind == .interface_ && typ.name !in c.builtins { if sym.kind == .interface_ && sym.name !in c.builtins {
g.write_interface_typesymbol_declaration(typ) g.write_interface_typesymbol_declaration(sym)
} }
} }
} }
pub fn (mut g Gen) write_alias_typesymbol_declaration(sym ast.TypeSymbol) { 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] == `.` is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.`
mut is_typedef := false mut is_typedef := false
if parent.info is ast.Struct { 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 { .voidptr {
ts := if g.pref.m64 { 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 { } 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) return g.map_fn_ptrs(ts)
} }
@ -5102,27 +5102,7 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) {
} }
g.is_amp = false g.is_amp = false
sym := g.table.get_type_symbol(node.typ) sym := g.table.get_type_symbol(node.typ)
if sym.kind == .string && !node.typ.is_ptr() { if sym.kind in [.sum_type, .interface_] {
// `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_] {
g.expr_with_cast(node.expr, node.expr_type, node.typ) 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 { } else if sym.kind == .struct_ && !node.typ.is_ptr() && !(sym.info as ast.Struct).is_typedef {
// deprecated, replaced by Struct{...exr} // deprecated, replaced by Struct{...exr}
@ -6328,11 +6308,11 @@ fn (mut g Gen) write_builtin_types() {
if g.pref.no_builtin { if g.pref.no_builtin {
return return
} }
mut builtin_types := []ast.TypeSymbol{} // builtin types mut builtin_types := []&ast.TypeSymbol{} // builtin types
// builtin types need to be on top // builtin types need to be on top
// everything except builtin will get sorted // everything except builtin will get sorted
for builtin_name in c.builtins { 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_ { if sym.kind == .interface_ {
g.write_interface_typedef(sym) g.write_interface_typedef(sym)
g.write_interface_typesymbol_declaration(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 // Sort the types, make sure types that are referenced by other types
// are added before them. // are added before them.
fn (mut g Gen) write_sorted_types() { fn (mut g Gen) write_sorted_types() {
mut types := []ast.TypeSymbol{cap: g.table.type_symbols.len} // structs that need to be sorted mut symbols := []&ast.TypeSymbol{cap: g.table.type_symbols.len} // structs that need to be sorted
for typ in g.table.type_symbols { for sym in g.table.type_symbols {
if typ.name !in c.builtins { if sym.name !in c.builtins {
types << typ symbols << sym
} }
} }
// sort structs // sort structs
types_sorted := g.sort_structs(types) sorted_symbols := g.sort_structs(symbols)
// Generate C code // Generate C code
g.type_definitions.writeln('// builtin types:') g.type_definitions.writeln('// builtin types:')
g.type_definitions.writeln('//------------------ #endbuiltin') g.type_definitions.writeln('//------------------ #endbuiltin')
g.write_types(types_sorted) g.write_types(sorted_symbols)
} }
fn (mut g Gen) write_types(types []ast.TypeSymbol) { fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
for typ in types { for sym in symbols {
if typ.name.starts_with('C.') { if sym.name.starts_with('C.') {
continue continue
} }
if typ.kind == .none_ { if sym.kind == .none_ {
g.type_definitions.writeln('struct none {') g.type_definitions.writeln('struct none {')
g.type_definitions.writeln('\tEMPTY_STRUCT_DECLARATION;') g.type_definitions.writeln('\tEMPTY_STRUCT_DECLARATION;')
g.type_definitions.writeln('};') g.type_definitions.writeln('};')
g.typedefs2.writeln('typedef struct none none;') g.typedefs2.writeln('typedef struct none none;')
} }
// sym := g.table.get_type_symbol(typ) // sym := g.table.get_type_symbol(typ)
mut name := typ.cname mut name := sym.cname
match mut typ.info { match mut sym.info {
ast.Struct { ast.Struct {
if typ.info.is_generic { if sym.info.is_generic {
continue continue
} }
if name.contains('_T_') { if name.contains('_T_') {
@ -6388,7 +6368,7 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
mut pre_pragma := '' mut pre_pragma := ''
mut post_pragma := '' mut post_pragma := ''
for attr in typ.info.attrs { for attr in sym.info.attrs {
match attr.name { match attr.name {
'_pack' { '_pack' {
pre_pragma += '#pragma pack(push, $attr.arg)\n' 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) g.type_definitions.writeln(pre_pragma)
if typ.info.is_union { if sym.info.is_union {
g.type_definitions.writeln('union $name {') g.type_definitions.writeln('union $name {')
} else { } else {
g.type_definitions.writeln('struct $name {') g.type_definitions.writeln('struct $name {')
} }
if typ.info.fields.len > 0 || typ.info.embeds.len > 0 { if sym.info.fields.len > 0 || sym.info.embeds.len > 0 {
for field in typ.info.fields { for field in sym.info.fields {
// Some of these structs may want to contain // Some of these structs may want to contain
// optionals that may not be defined at this point // optionals that may not be defined at this point
// if this is the case then we are going to // 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') // g.type_definitions.writeln('} $name;\n')
// //
ti_attrs := if typ.info.attrs.contains('packed') { ti_attrs := if sym.info.attrs.contains('packed') {
'__attribute__((__packed__))' '__attribute__((__packed__))'
} else { } else {
'' ''
@ -6469,26 +6449,26 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
} }
} }
ast.SumType { ast.SumType {
if typ.info.is_generic { if sym.info.is_generic {
continue continue
} }
g.typedefs.writeln('typedef struct $name $name;') g.typedefs.writeln('typedef struct $name $name;')
g.type_definitions.writeln('') g.type_definitions.writeln('')
g.type_definitions.writeln('// Union sum type $name = ') 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('// | ${variant:4d} = ${g.typ(variant.idx()):-20s}')
} }
g.type_definitions.writeln('struct $name {') g.type_definitions.writeln('struct $name {')
g.type_definitions.writeln('\tunion {') 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) 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\t${g.typ(variant.ref())} _$variant_sym.cname;')
} }
g.type_definitions.writeln('\t};') g.type_definitions.writeln('\t};')
g.type_definitions.writeln('\tint _typ;') 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') 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;') 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('') g.type_definitions.writeln('')
} }
ast.ArrayFixed { ast.ArrayFixed {
elem_sym := g.table.get_type_symbol(typ.info.elem_type) elem_sym := g.table.get_type_symbol(sym.info.elem_type)
if !elem_sym.is_builtin() && !typ.info.elem_type.has_flag(.generic) { if !elem_sym.is_builtin() && !sym.info.elem_type.has_flag(.generic) {
// .array_fixed { // .array_fixed {
styp := typ.cname styp := sym.cname
// array_fixed_char_300 => char x[300] // array_fixed_char_300 => char x[300]
// [16]&&&EventListener{} => Array_fixed_main__EventListener_16_ptr3 // [16]&&&EventListener{} => Array_fixed_main__EventListener_16_ptr3
// => typedef main__EventListener*** Array_fixed_main__EventListener_16_ptr3 [16] // => typedef main__EventListener*** Array_fixed_main__EventListener_16_ptr3 [16]
mut fixed_elem_name := g.typ(typ.info.elem_type.set_nr_muls(0)) mut fixed_elem_name := g.typ(sym.info.elem_type.set_nr_muls(0))
if typ.info.elem_type.is_ptr() { if sym.info.elem_type.is_ptr() {
fixed_elem_name += '*'.repeat(typ.info.elem_type.nr_muls()) 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__') { if fixed_elem_name.starts_with('C__') {
fixed_elem_name = fixed_elem_name[3..] 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 // 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) util.timing_start(@METHOD)
defer { defer {
util.timing_measure(@METHOD) 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() mut dep_graph := depgraph.new_dep_graph()
// types name list // types name list
mut type_names := []string{} mut type_names := []string{}
for typ in typesa { for sym in typesa {
type_names << typ.name type_names << sym.name
} }
// loop over types // loop over types
for t in typesa { for sym in typesa {
if t.kind == .interface_ { if sym.kind == .interface_ {
dep_graph.add(t.name, []) dep_graph.add(sym.name, [])
continue continue
} }
// create list of deps // create list of deps
mut field_deps := []string{} mut field_deps := []string{}
match mut t.info { match mut sym.info {
ast.ArrayFixed { 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 { if dep in type_names {
field_deps << dep field_deps << dep
} }
} }
ast.Struct { ast.Struct {
for embed in t.info.embeds { for embed in sym.info.embeds {
dep := g.table.get_type_symbol(embed).name dep := g.table.get_type_symbol(embed).name
// skip if not in types list or already in deps // skip if not in types list or already in deps
if dep !in type_names || dep in field_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 field_deps << dep
} }
for field in t.info.fields { for field in sym.info.fields {
dep := g.table.get_type_symbol(field.typ).name dep := g.table.get_type_symbol(field.typ).name
// skip if not in types list or already in deps // skip if not in types list or already in deps
if dep !in type_names || dep in field_deps || field.typ.is_ptr() { 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 {} else {}
} }
// add type and dependant types to graph // add type and dependant types to graph
dep_graph.add(t.name, field_deps) dep_graph.add(sym.name, field_deps)
} }
// sort graph // sort graph
dep_graph_sorted := dep_graph.resolve() 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') '\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 // 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 { 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] [inline]
@ -7184,19 +7164,19 @@ fn (g Gen) as_cast_name_table() string {
fn (mut g Gen) interface_table() string { fn (mut g Gen) interface_table() string {
mut sb := strings.new_builder(100) mut sb := strings.new_builder(100)
mut conversion_functions := strings.new_builder(100) mut conversion_functions := strings.new_builder(100)
for ityp in g.table.type_symbols { for isym in g.table.type_symbols {
if ityp.kind != .interface_ { if isym.kind != .interface_ {
continue continue
} }
if ityp.info !is ast.Interface { if isym.info !is ast.Interface {
continue continue
} }
inter_info := ityp.info as ast.Interface inter_info := isym.info as ast.Interface
if inter_info.is_generic { if inter_info.is_generic {
continue continue
} }
// interface_name is for example Speaker // interface_name is for example Speaker
interface_name := ityp.cname interface_name := isym.cname
// generate a struct that references interface methods // generate a struct that references interface methods
methods_struct_name := 'struct _${interface_name}_interface_methods' methods_struct_name := 'struct _${interface_name}_interface_methods'
mut methods_struct_def := strings.new_builder(100) 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) cctype := g.cc_type(st, true)
$if debug_interface_table ? { $if debug_interface_table ? {
eprintln( eprintln(
'>> interface name: $ityp.name | concrete type: $st.debug() | st symname: ' + '>> interface name: $isym.name | concrete type: $st.debug() | st symname: ' +
st_sym.name) st_sym.name)
} }
// Speaker_Cat_index = 0 // Speaker_Cat_index = 0
@ -7253,7 +7233,7 @@ fn (mut g Gen) interface_table() string {
} }
already_generated_mwrappers[interface_index_name] = current_iinidx already_generated_mwrappers[interface_index_name] = current_iinidx
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') // 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);') sb.writeln('static $interface_name I_${cctype}_to_Interface_${interface_name}($cctype* x);')
mut cast_struct := strings.new_builder(100) mut cast_struct := strings.new_builder(100)

View File

@ -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 { 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() { pub fn (mut g Gen) generate_header() {

View File

@ -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()
}

View File

@ -13,6 +13,10 @@ pub mut:
last_line int // the line number where the ast object ends (used by vfmt) 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 { pub fn (pos Position) extend(end Position) Position {
return Position{ return Position{
...pos ...pos