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) {
for r in runes {
res := string(r)
res := r.str()
#res.str = String.fromCharCode(r.val)
b << res.bytes()
}

View File

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

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

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

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() {
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' {
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() {
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)

View File

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

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 {
return &g.table.type_symbols[a]
return g.table.type_symbols[a]
}
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)
}
[unsafe]
pub fn (mut p Position) free() {
}
pub fn (pos Position) extend(end Position) Position {
return Position{
...pos