generics: lots of fixes
parent
4608898bcd
commit
67750c91d7
|
@ -10,10 +10,6 @@ import v.checker
|
|||
import v.parser
|
||||
import v.depgraph
|
||||
|
||||
const (
|
||||
max_nr_errors = 100
|
||||
)
|
||||
|
||||
pub struct Builder {
|
||||
pub:
|
||||
table &table.Table
|
||||
|
@ -26,6 +22,7 @@ mut:
|
|||
global_scope &ast.Scope
|
||||
out_name_c string
|
||||
out_name_js string
|
||||
max_nr_errors int = 100
|
||||
pub mut:
|
||||
module_search_paths []string
|
||||
}
|
||||
|
@ -233,7 +230,7 @@ fn (b &Builder) print_warnings_and_errors() {
|
|||
ferror := util.formatted_error(kind, err.message, err.file_path, err.pos)
|
||||
eprintln(ferror)
|
||||
// eprintln('')
|
||||
if i > max_nr_errors {
|
||||
if i > b.max_nr_errors {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +245,7 @@ fn (b &Builder) print_warnings_and_errors() {
|
|||
ferror := util.formatted_error(kind, err.message, err.file_path, err.pos)
|
||||
eprintln(ferror)
|
||||
// eprintln('')
|
||||
if i > max_nr_errors {
|
||||
if i > b.max_nr_errors {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module checker
|
||||
|
||||
import v.table
|
||||
|
||||
pub fn (c &Checker) check_types(got, expected table.Type) bool {
|
||||
t := c.table
|
||||
got_idx := got.idx()
|
||||
exp_idx := expected.idx()
|
||||
// got_is_ptr := got.is_ptr()
|
||||
exp_is_ptr := expected.is_ptr()
|
||||
// println('check: $got_type_sym.name, $exp_type_sym.name')
|
||||
// # NOTE: use idxs here, and symbols below for perf
|
||||
if got_idx == exp_idx {
|
||||
// this is returning true even if one type is a ptr
|
||||
// and the other is not, is this correct behaviour?
|
||||
return true
|
||||
}
|
||||
if got_idx == table.none_type_idx && expected.flag_is(.optional) {
|
||||
return true
|
||||
}
|
||||
// allow pointers to be initialized with 0. TODO: use none instead
|
||||
if exp_is_ptr && got_idx == table.int_type_idx {
|
||||
return true
|
||||
}
|
||||
if exp_idx == table.voidptr_type_idx || got_idx == table.voidptr_type_idx {
|
||||
return true
|
||||
}
|
||||
if exp_idx == table.any_type_idx || got_idx == table.any_type_idx {
|
||||
return true
|
||||
}
|
||||
// TODO i64 as int etc
|
||||
if (exp_idx in table.pointer_type_idxs || exp_idx in table.number_type_idxs) && (got_idx in
|
||||
table.pointer_type_idxs || got_idx in table.number_type_idxs) {
|
||||
return true
|
||||
}
|
||||
// if exp_idx in pointer_type_idxs && got_idx in pointer_type_idxs {
|
||||
// return true
|
||||
// }
|
||||
// see hack in checker IndexExpr line #691
|
||||
if (got_idx == table.byte_type_idx && exp_idx == table.byteptr_type_idx) || (exp_idx ==
|
||||
table.byte_type_idx && got_idx == table.byteptr_type_idx) {
|
||||
return true
|
||||
}
|
||||
if (got_idx == table.char_type_idx && exp_idx == table.charptr_type_idx) || (exp_idx ==
|
||||
table.char_type_idx && got_idx == table.charptr_type_idx) {
|
||||
return true
|
||||
}
|
||||
if expected == table.t_type && got == table.t_type {
|
||||
return true
|
||||
}
|
||||
// # NOTE: use symbols from this point on for perf
|
||||
got_type_sym := t.get_type_symbol(got)
|
||||
exp_type_sym := t.get_type_symbol(expected)
|
||||
//
|
||||
if exp_type_sym.kind == .function && got_type_sym.kind == .int {
|
||||
// TODO temporary
|
||||
// fn == 0
|
||||
return true
|
||||
}
|
||||
// allow enum value to be used as int
|
||||
if (got_type_sym.is_int() && exp_type_sym.kind == .enum_) || (exp_type_sym.is_int() &&
|
||||
got_type_sym.kind == .enum_) {
|
||||
return true
|
||||
}
|
||||
// TODO
|
||||
// if got_type_sym.kind == .array && exp_type_sym.kind == .array {
|
||||
// return true
|
||||
// }
|
||||
if got_type_sym.kind == .array_fixed && exp_type_sym.kind == .byteptr {
|
||||
info := got_type_sym.info as table.ArrayFixed
|
||||
if info.elem_type.idx() == table.byte_type_idx {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
if exp_type_sym.name == 'array' || got_type_sym.name == 'array' {
|
||||
return true
|
||||
}
|
||||
// TODO
|
||||
// accept [] when an expected type is an array
|
||||
if got_type_sym.kind == .array && got_type_sym.name == 'array_void' && exp_type_sym.kind ==
|
||||
.array {
|
||||
return true
|
||||
}
|
||||
// type alias
|
||||
if (got_type_sym.kind == .alias && got_type_sym.parent_idx == exp_idx) || (exp_type_sym.kind ==
|
||||
.alias && exp_type_sym.parent_idx == got_idx) {
|
||||
return true
|
||||
}
|
||||
// sum type
|
||||
if got_type_sym.kind == .sum_type {
|
||||
sum_info := got_type_sym.info as table.SumType
|
||||
// TODO: handle `match SumType { &PtrVariant {} }` currently just checking base
|
||||
if expected.set_nr_muls(0) in sum_info.variants {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if exp_type_sym.kind == .sum_type {
|
||||
sum_info := exp_type_sym.info as table.SumType
|
||||
// TODO: handle `match SumType { &PtrVariant {} }` currently just checking base
|
||||
if got.set_nr_muls(0) in sum_info.variants {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// fn type
|
||||
if got_type_sym.kind == .function && exp_type_sym.kind == .function {
|
||||
got_info := got_type_sym.info as table.FnType
|
||||
exp_info := exp_type_sym.info as table.FnType
|
||||
got_fn := got_info.func
|
||||
exp_fn := exp_info.func
|
||||
// we are using check() to compare return type & args as they might include
|
||||
// functions themselves. TODO: optimize, only use check() when needed
|
||||
if got_fn.args.len == exp_fn.args.len && c.check_types(got_fn.return_type, exp_fn.return_type) {
|
||||
for i, got_arg in got_fn.args {
|
||||
exp_arg := exp_fn.args[i]
|
||||
if !c.check_types(got_arg.typ, exp_arg.typ) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -274,7 +274,7 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
|
|||
if field.has_default_expr {
|
||||
c.expected_type = field.typ
|
||||
field_expr_type := c.expr(field.default_expr)
|
||||
if !c.table.check(field_expr_type, field.typ) {
|
||||
if !c.check_types(field_expr_type, field.typ) {
|
||||
field_expr_type_sym := c.table.get_type_symbol(field_expr_type)
|
||||
field_type_sym := c.table.get_type_symbol(field.typ)
|
||||
c.error('default expression for field `${field.name}` ' + 'has type `${field_expr_type_sym.name}`, but should be `${field_type_sym.name}`',
|
||||
|
@ -363,7 +363,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
|||
expr_type := c.expr(field.expr)
|
||||
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
||||
if !c.table.check(expr_type, info_field.typ) {
|
||||
if !c.check_types(expr_type, info_field.typ) {
|
||||
c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
|
||||
field.pos)
|
||||
}
|
||||
|
@ -467,11 +467,11 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
return table.void_type
|
||||
}
|
||||
// the expressions have different types (array_x and x)
|
||||
if c.table.check(right_type, left_value_type) { // , right_type) {
|
||||
if c.check_types(right_type, left_value_type) { // , right_type) {
|
||||
// []T << T
|
||||
return table.void_type
|
||||
}
|
||||
if right.kind == .array && c.table.check(left_value_type, c.table.value_type(right_type)) {
|
||||
if right.kind == .array && c.check_types(left_value_type, c.table.value_type(right_type)) {
|
||||
// []T << []T
|
||||
return table.void_type
|
||||
}
|
||||
|
@ -534,7 +534,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
infix_expr.pos)
|
||||
}
|
||||
// Dual sides check (compatibility check)
|
||||
if !c.table.check(right_type, left_type) {
|
||||
if !c.check_types(right_type, left_type) {
|
||||
// for type-unresolved consts
|
||||
if left_type == table.void_type || right_type == table.void_type {
|
||||
return table.void_type
|
||||
|
@ -673,7 +673,7 @@ fn (mut c Checker) assign_expr(mut assign_expr ast.AssignExpr) {
|
|||
else {}
|
||||
}
|
||||
// Dual sides check (compatibility check)
|
||||
if !c.table.check(right_type, left_type) {
|
||||
if !c.check_types(right_type, left_type) {
|
||||
left_type_sym := c.table.get_type_symbol(left_type)
|
||||
right_type_sym := c.table.get_type_symbol(right_type)
|
||||
c.error('cannot assign `$right_type_sym.name` to variable `${assign_expr.left.str()}` of type `$left_type_sym.name`',
|
||||
|
@ -775,7 +775,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
c.type_implements(got_arg_typ, exp_arg_typ, arg.expr.position())
|
||||
continue
|
||||
}
|
||||
if !c.table.check(got_arg_typ, exp_arg_typ) {
|
||||
if !c.check_types(got_arg_typ, exp_arg_typ) {
|
||||
got_arg_sym := c.table.get_type_symbol(got_arg_typ)
|
||||
// str method, allow type with str method if fn arg is string
|
||||
if exp_arg_sym.kind == .string && got_arg_sym.has_method('str') {
|
||||
|
@ -968,7 +968,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
|||
return true
|
||||
}
|
||||
*/
|
||||
if !c.table.check(typ, arg.typ) {
|
||||
if !c.check_types(typ, arg.typ) {
|
||||
// str method, allow type with str method if fn arg is string
|
||||
if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
||||
continue
|
||||
|
@ -1064,7 +1064,7 @@ pub fn (mut c Checker) check_or_block(mut call_expr ast.CallExpr, ret_type table
|
|||
match last_stmt {
|
||||
ast.ExprStmt {
|
||||
it.typ = c.expr(it.expr)
|
||||
type_fits := c.table.check(it.typ, ret_type)
|
||||
type_fits := c.check_types(it.typ, ret_type)
|
||||
is_panic_or_exit := is_expr_panic_or_exit(it.expr)
|
||||
if type_fits || is_panic_or_exit {
|
||||
return
|
||||
|
@ -1163,8 +1163,11 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
|||
}
|
||||
for i, exp_type in expected_types {
|
||||
got_typ := got_types[i]
|
||||
ok := if exp_type == table.t_type { c.table.check(got_typ, c.cur_generic_type) } else { c.table.check(got_typ,
|
||||
/*
|
||||
ok := if exp_type == table.t_type { c.check_types(got_typ, c.cur_generic_type) } else { c.check_types(got_typ,
|
||||
exp_type) }
|
||||
*/
|
||||
ok := c.check_types(got_typ, exp_type)
|
||||
if !ok { // !c.table.check(got_typ, exp_typ) {
|
||||
got_typ_sym := c.table.get_type_symbol(got_typ)
|
||||
exp_typ_sym := c.table.get_type_symbol(exp_type)
|
||||
|
@ -1264,7 +1267,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
c.fail_if_immutable(ident)
|
||||
var_type := c.expr(ident)
|
||||
assign_stmt.left_types << var_type
|
||||
if !c.table.check(val_type, var_type) {
|
||||
if !c.check_types(val_type, var_type) {
|
||||
val_type_sym := c.table.get_type_symbol(val_type)
|
||||
var_type_sym := c.table.get_type_symbol(var_type)
|
||||
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`',
|
||||
|
@ -1366,7 +1369,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
|
|||
c.expected_type = typ
|
||||
continue
|
||||
}
|
||||
if !c.table.check(elem_type, typ) {
|
||||
if !c.check_types(elem_type, typ) {
|
||||
elem_type_sym := c.table.get_type_symbol(elem_type)
|
||||
c.error('expected array element with type `$elem_type_sym.name`', array_init.pos)
|
||||
}
|
||||
|
@ -1845,7 +1848,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
|||
info := ident.info as ast.IdentVar
|
||||
if info.typ == table.t_type {
|
||||
// Got a var with type T, return current generic type
|
||||
return c.cur_generic_type
|
||||
// return c.cur_generic_type
|
||||
}
|
||||
return info.typ
|
||||
} else if ident.kind == .constant {
|
||||
|
@ -1871,9 +1874,12 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
|||
is_optional: is_optional
|
||||
}
|
||||
if typ == table.t_type {
|
||||
sym := c.table.get_type_symbol(c.cur_generic_type)
|
||||
println('IDENT T unresolved $ident.name typ=$sym.name')
|
||||
// Got a var with type T, return current generic type
|
||||
typ = c.cur_generic_type
|
||||
// typ = c.cur_generic_type
|
||||
}
|
||||
// } else {
|
||||
it.typ = typ
|
||||
// unwrap optional (`println(x)`)
|
||||
if is_optional {
|
||||
|
@ -1975,7 +1981,7 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
|
|||
c.expected_type = cond_type
|
||||
typ := c.expr(expr)
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
if !node.is_sum_type && !c.table.check(typ, cond_type) {
|
||||
if !node.is_sum_type && !c.check_types(typ, cond_type) {
|
||||
exp_sym := c.table.get_type_symbol(cond_type)
|
||||
c.error('cannot use `$typ_sym.name` as `$exp_sym.name` in `match`', node.pos)
|
||||
}
|
||||
|
@ -2260,13 +2266,13 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) table.Type {
|
|||
val := node.vals[i]
|
||||
key_type := c.expr(key)
|
||||
val_type := c.expr(val)
|
||||
if !c.table.check(key_type, key0_type) {
|
||||
if !c.check_types(key_type, key0_type) {
|
||||
key0_type_sym := c.table.get_type_symbol(key0_type)
|
||||
key_type_sym := c.table.get_type_symbol(key_type)
|
||||
c.error('map init: cannot use `$key_type_sym.name` as `$key0_type_sym.name` for map key',
|
||||
node.pos)
|
||||
}
|
||||
if !c.table.check(val_type, val0_type) {
|
||||
if !c.check_types(val_type, val0_type) {
|
||||
val0_type_sym := c.table.get_type_symbol(val0_type)
|
||||
val_type_sym := c.table.get_type_symbol(val_type)
|
||||
c.error('map init: cannot use `$val_type_sym.name` as `$val0_type_sym.name` for map value',
|
||||
|
|
|
@ -14,23 +14,24 @@ const (
|
|||
|
||||
pub struct Fmt {
|
||||
pub:
|
||||
out strings.Builder
|
||||
out_imports strings.Builder
|
||||
table &table.Table
|
||||
out strings.Builder
|
||||
out_imports strings.Builder
|
||||
table &table.Table
|
||||
pub mut:
|
||||
indent int
|
||||
empty_line bool
|
||||
line_len int
|
||||
single_line_if bool
|
||||
cur_mod string
|
||||
file ast.File
|
||||
did_imports bool
|
||||
is_assign bool
|
||||
auto_imports []string // automatically inserted imports that the user forgot to specify
|
||||
import_pos int // position of the imports in the resulting string for later autoimports insertion
|
||||
used_imports []string // to remove unused imports
|
||||
is_debug bool
|
||||
mod2alias map[string]string // for `import time as t`, will contain: 'time'=>'t'
|
||||
indent int
|
||||
empty_line bool
|
||||
line_len int
|
||||
single_line_if bool
|
||||
cur_mod string
|
||||
file ast.File
|
||||
did_imports bool
|
||||
is_assign bool
|
||||
auto_imports []string // automatically inserted imports that the user forgot to specify
|
||||
import_pos int // position of the imports in the resulting string for later autoimports insertion
|
||||
used_imports []string // to remove unused imports
|
||||
is_debug bool
|
||||
mod2alias map[string]string // for `import time as t`, will contain: 'time'=>'t'
|
||||
use_short_fn_args bool
|
||||
}
|
||||
|
||||
pub fn fmt(file ast.File, table &table.Table, is_debug bool) string {
|
||||
|
@ -44,7 +45,7 @@ pub fn fmt(file ast.File, table &table.Table, is_debug bool) string {
|
|||
}
|
||||
for imp in file.imports {
|
||||
f.mod2alias[imp.mod.all_after_last('.')] = imp.alias
|
||||
}
|
||||
}
|
||||
f.cur_mod = 'main'
|
||||
for stmt in file.stmts {
|
||||
if stmt is ast.Import {
|
||||
|
@ -838,6 +839,15 @@ pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
|
|||
}
|
||||
|
||||
pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
||||
/*
|
||||
if node.args.len == 1 && node.expected_arg_types.len == 1 && node.args[0].expr is ast.StructInit &&
|
||||
node.args[0].typ == node.expected_arg_types[0] {
|
||||
// struct_init := node.args[0].expr as ast.StructInit
|
||||
// if struct_init.typ == node.args[0].typ {
|
||||
f.use_short_fn_args = true
|
||||
// }
|
||||
}
|
||||
*/
|
||||
if node.is_method {
|
||||
if node.left is ast.Ident {
|
||||
it := node.left as ast.Ident
|
||||
|
@ -876,6 +886,7 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
|||
f.write(')')
|
||||
f.or_expr(node.or_block)
|
||||
}
|
||||
f.use_short_fn_args = false
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
|
||||
|
@ -1101,7 +1112,11 @@ pub fn (mut f Fmt) struct_init(it ast.StructInit) {
|
|||
}
|
||||
f.write('}')
|
||||
} else {
|
||||
f.writeln('$name{')
|
||||
if f.use_short_fn_args {
|
||||
f.writeln('')
|
||||
} else {
|
||||
f.writeln('$name{')
|
||||
}
|
||||
f.indent++
|
||||
for field in it.fields {
|
||||
f.write('$field.name: ')
|
||||
|
@ -1109,7 +1124,9 @@ pub fn (mut f Fmt) struct_init(it ast.StructInit) {
|
|||
f.writeln('')
|
||||
}
|
||||
f.indent--
|
||||
f.write('}')
|
||||
if !f.use_short_fn_args {
|
||||
f.write('}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ pub fn (mut g Gen) write_typeof_functions() {
|
|||
// V type to C type
|
||||
fn (mut g Gen) typ(t table.Type) string {
|
||||
mut styp := g.base_type(t)
|
||||
if styp.len == 1 && g.cur_generic_type != 0 {
|
||||
if styp.len == 1 && t == table.t_type && g.cur_generic_type != 0 {
|
||||
// T => int etc
|
||||
return g.typ(g.cur_generic_type)
|
||||
}
|
||||
|
@ -968,8 +968,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
g.expr(val)
|
||||
} else {
|
||||
if val is ast.ArrayInit {
|
||||
g.gen_default_init_value( val as ast.ArrayInit )
|
||||
}
|
||||
g.gen_default_init_value(val as ast.ArrayInit)
|
||||
}
|
||||
g.write('{$styp _ = ')
|
||||
g.expr(val)
|
||||
g.writeln(';}')
|
||||
|
@ -979,7 +979,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
mut is_fixed_array_init := false
|
||||
mut has_val := false
|
||||
if val is ast.ArrayInit {
|
||||
is_fixed_array_init, has_val = g.gen_default_init_value( val as ast.ArrayInit )
|
||||
is_fixed_array_init, has_val = g.gen_default_init_value(val as ast.ArrayInit)
|
||||
}
|
||||
is_inside_ternary := g.inside_ternary != 0
|
||||
cur_line := if is_inside_ternary {
|
||||
|
@ -1487,7 +1487,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
|
|||
if node.left_type == table.string_type_idx && node.op == .plus_assign {
|
||||
// str += str2 => `str = string_add(str, str2)`
|
||||
g.expr(node.left)
|
||||
g.write(' = string_add(')
|
||||
g.write(' = /*f*/string_add(')
|
||||
str_add = true
|
||||
}
|
||||
right_sym := g.table.get_type_symbol(node.right_type)
|
||||
|
@ -1563,13 +1563,14 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
// }
|
||||
// string + string, string == string etc
|
||||
// g.infix_op = node.op
|
||||
left_sym := g.table.get_type_symbol(node.left_type)
|
||||
left_type := if node.left_type == table.t_type { g.cur_generic_type } else { node.left_type }
|
||||
left_sym := g.table.get_type_symbol(left_type)
|
||||
if node.op == .key_is {
|
||||
g.is_expr(node)
|
||||
return
|
||||
}
|
||||
right_sym := g.table.get_type_symbol(node.right_type)
|
||||
if node.left_type == table.ustring_type_idx && node.op != .key_in && node.op != .not_in {
|
||||
if left_type == table.ustring_type_idx && node.op != .key_in && node.op != .not_in {
|
||||
fn_name := match node.op {
|
||||
.plus { 'ustring_add(' }
|
||||
.eq { 'ustring_eq(' }
|
||||
|
@ -1585,7 +1586,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
g.write(', ')
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else if node.left_type == table.string_type_idx && node.op != .key_in && node.op != .not_in {
|
||||
} else if left_type == table.string_type_idx && node.op != .key_in && node.op != .not_in {
|
||||
fn_name := match node.op {
|
||||
.plus { 'string_add(' }
|
||||
.eq { 'string_eq(' }
|
||||
|
@ -1602,8 +1603,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else if node.op in [.eq, .ne] && left_sym.kind == .array && right_sym.kind == .array {
|
||||
styp := g.table.value_type(node.left_type)
|
||||
ptr_typ := g.typ(node.left_type).split('_')[1]
|
||||
styp := g.table.value_type(left_type)
|
||||
ptr_typ := g.typ(left_type).split('_')[1]
|
||||
if ptr_typ !in g.array_fn_definitions {
|
||||
sym := g.table.get_type_symbol(left_sym.array_info().elem_type)
|
||||
g.generate_array_equality_fn(ptr_typ, styp, sym)
|
||||
|
@ -1634,7 +1635,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
}
|
||||
else {}
|
||||
}
|
||||
styp := g.typ(node.left_type)
|
||||
styp := g.typ(left_type)
|
||||
g.write('_IN($styp, ')
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
|
@ -1653,18 +1654,18 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
g.expr(node.left)
|
||||
g.write(')')
|
||||
}
|
||||
} else if node.op == .left_shift && g.table.get_type_symbol(node.left_type).kind == .array {
|
||||
} else if node.op == .left_shift && g.table.get_type_symbol(left_type).kind == .array {
|
||||
// arr << val
|
||||
tmp := g.new_tmp_var()
|
||||
sym := g.table.get_type_symbol(node.left_type)
|
||||
sym := g.table.get_type_symbol(left_type)
|
||||
info := sym.info as table.Array
|
||||
if right_sym.kind == .array && info.elem_type != node.right_type {
|
||||
// push an array => PUSH_MANY, but not if pushing an array to 2d array (`[][]int << []int`)
|
||||
g.write('_PUSH_MANY(&')
|
||||
g.expr(node.left)
|
||||
g.write(', (')
|
||||
g.expr_with_cast(node.right, node.right_type, node.left_type)
|
||||
styp := g.typ(node.left_type)
|
||||
g.expr_with_cast(node.right, node.right_type, left_type)
|
||||
styp := g.typ(left_type)
|
||||
g.write('), $tmp, $styp)')
|
||||
} else {
|
||||
// push a single element
|
||||
|
@ -1682,10 +1683,9 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
}
|
||||
g.write(' }))')
|
||||
}
|
||||
} else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in
|
||||
[.eq, .ne] {
|
||||
} else if (left_type == node.right_type) && left_type.is_float() && node.op in [.eq, .ne] {
|
||||
// floats should be compared with epsilon
|
||||
if node.left_type == table.f64_type_idx {
|
||||
if left_type == table.f64_type_idx {
|
||||
if node.op == .eq {
|
||||
g.write('f64_eq(')
|
||||
} else {
|
||||
|
@ -1706,7 +1706,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
left_sym.name.contains('.')) && left_sym.kind != .alias || left_sym.kind == .alias && (left_sym.info as table.Alias).language ==
|
||||
.c {
|
||||
// !left_sym.is_number() {
|
||||
g.write(g.typ(node.left_type))
|
||||
g.write(g.typ(left_type))
|
||||
g.write('_')
|
||||
g.write(util.replace_op(node.op.str()))
|
||||
g.write('(')
|
||||
|
@ -2976,7 +2976,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
|
|||
if g.pref.is_debug {
|
||||
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
|
||||
g.writeln('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), ${cvar_name}.v_error );')
|
||||
}else{
|
||||
} else {
|
||||
g.writeln('\tv_panic(${cvar_name}.v_error);')
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -21,6 +21,8 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
|||
if it.is_generic && g.cur_generic_type == 0 { // need the cur_generic_type check to avoid inf. recursion
|
||||
// loop thru each generic type and generate a function
|
||||
for gen_type in g.table.fn_gen_types[it.name] {
|
||||
sym := g.table.get_type_symbol(gen_type)
|
||||
println('gen fn `$it.name` for type `$sym.name`')
|
||||
g.cur_generic_type = gen_type
|
||||
g.gen_fn_decl(it)
|
||||
}
|
||||
|
@ -234,6 +236,9 @@ fn (mut g Gen) fn_args(args []table.Arg, is_variadic bool) ([]string, []string)
|
|||
caname := c_name(arg.name)
|
||||
arg_type_sym := g.table.get_type_symbol(arg.typ)
|
||||
mut arg_type_name := g.typ(arg.typ) // arg_type_sym.name.replace('.', '__')
|
||||
if arg.name == 'xxx' {
|
||||
println('! ' + arg_type_name)
|
||||
}
|
||||
is_varg := i == args.len - 1 && is_variadic
|
||||
if is_varg {
|
||||
varg_type_str := int(arg.typ).str()
|
||||
|
@ -264,7 +269,7 @@ fn (mut g Gen) fn_args(args []table.Arg, is_variadic bool) ([]string, []string)
|
|||
fargtypes << arg_type_name
|
||||
} else {
|
||||
mut nr_muls := arg.typ.nr_muls()
|
||||
s := arg_type_name + ' ' + caname
|
||||
s := arg_type_name + '/*F*/ ' + caname
|
||||
if arg.is_mut {
|
||||
// mut arg needs one *
|
||||
nr_muls = 1
|
||||
|
|
|
@ -109,6 +109,7 @@ pub mut:
|
|||
skip_warnings bool // like C's "-w"
|
||||
use_color ColorOutput // whether the warnings/errors should use ANSI color escapes.
|
||||
is_parallel bool
|
||||
error_limit int
|
||||
}
|
||||
|
||||
pub fn parse_args(args []string) (&Preferences, string) {
|
||||
|
@ -201,6 +202,9 @@ pub fn parse_args(args []string) (&Preferences, string) {
|
|||
'-print_v_files' {
|
||||
res.print_v_files = true
|
||||
}
|
||||
'-error-limit' {
|
||||
res.error_limit =cmdline.option(current_args, '-error-limit', '0').int()
|
||||
}
|
||||
'-os' {
|
||||
target_os := cmdline.option(current_args, '-os', '')
|
||||
i++
|
||||
|
|
|
@ -359,7 +359,7 @@ pub fn (t TypeSymbol) str() string {
|
|||
pub fn (mut t Table) register_builtin_type_symbols() {
|
||||
// reserve index 0 so nothing can go there
|
||||
// save index check, 0 will mean not found
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .placeholder
|
||||
name: 'reserved_0'
|
||||
})
|
||||
|
@ -368,72 +368,72 @@ pub fn (mut t Table) register_builtin_type_symbols() {
|
|||
name: 'void'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .voidptr
|
||||
name: 'voidptr'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .byteptr
|
||||
name: 'byteptr'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .charptr
|
||||
name: 'charptr'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .i8
|
||||
name: 'i8'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .i16
|
||||
name: 'i16'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .int
|
||||
name: 'int'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .i64
|
||||
name: 'i64'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .byte
|
||||
name: 'byte'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .u16
|
||||
name: 'u16'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .u32
|
||||
name: 'u32'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .u64
|
||||
name: 'u64'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .f32
|
||||
name: 'f32'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .f64
|
||||
name: 'f64'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .char
|
||||
name: 'char'
|
||||
mod: 'builtin'
|
||||
|
@ -448,37 +448,37 @@ pub fn (mut t Table) register_builtin_type_symbols() {
|
|||
name: 'none'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .string
|
||||
name: 'string'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .ustring
|
||||
name: 'ustring'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .array
|
||||
name: 'array'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .map
|
||||
name: 'map'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .any
|
||||
name: 'any'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .any
|
||||
name: 'T'
|
||||
mod: 'builtin'
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .size_t
|
||||
name: 'size_t'
|
||||
mod: 'builtin'
|
||||
|
@ -486,13 +486,13 @@ pub fn (mut t Table) register_builtin_type_symbols() {
|
|||
// TODO: remove. for v1 map compatibility
|
||||
map_string_string_idx := t.find_or_register_map(string_type, string_type)
|
||||
map_string_int_idx := t.find_or_register_map(string_type, int_type)
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .alias
|
||||
name: 'map_string'
|
||||
mod: 'builtin'
|
||||
parent_idx: map_string_string_idx
|
||||
})
|
||||
t.register_type_symbol(TypeSymbol{
|
||||
t.register_type_symbol({
|
||||
kind: .alias
|
||||
name: 'map_int'
|
||||
mod: 'builtin'
|
||||
|
|
|
@ -438,123 +438,6 @@ pub fn (t &Table) value_type(typ Type) Type {
|
|||
return void_type
|
||||
}
|
||||
|
||||
pub fn (t &Table) check(got, expected Type) bool {
|
||||
got_idx := got.idx()
|
||||
exp_idx := expected.idx()
|
||||
// got_is_ptr := got.is_ptr()
|
||||
exp_is_ptr := expected.is_ptr()
|
||||
// println('check: $got_type_sym.name, $exp_type_sym.name')
|
||||
// # NOTE: use idxs here, and symbols below for perf
|
||||
if got_idx == exp_idx {
|
||||
// this is returning true even if one type is a ptr
|
||||
// and the other is not, is this correct behaviour?
|
||||
return true
|
||||
}
|
||||
if got_idx == none_type_idx && expected.flag_is(.optional) {
|
||||
return true
|
||||
}
|
||||
// allow pointers to be initialized with 0. TODO: use none instead
|
||||
if exp_is_ptr && got_idx == int_type_idx {
|
||||
return true
|
||||
}
|
||||
if exp_idx == voidptr_type_idx || got_idx == voidptr_type_idx {
|
||||
return true
|
||||
}
|
||||
if exp_idx == any_type_idx || got_idx == any_type_idx {
|
||||
return true
|
||||
}
|
||||
// TODO i64 as int etc
|
||||
if (exp_idx in pointer_type_idxs || exp_idx in number_type_idxs) && (got_idx in pointer_type_idxs ||
|
||||
got_idx in number_type_idxs) {
|
||||
return true
|
||||
}
|
||||
// if exp_idx in pointer_type_idxs && got_idx in pointer_type_idxs {
|
||||
// return true
|
||||
// }
|
||||
// see hack in checker IndexExpr line #691
|
||||
if (got_idx == byte_type_idx && exp_idx == byteptr_type_idx) || (exp_idx == byte_type_idx &&
|
||||
got_idx == byteptr_type_idx) {
|
||||
return true
|
||||
}
|
||||
if (got_idx == char_type_idx && exp_idx == charptr_type_idx) || (exp_idx == char_type_idx &&
|
||||
got_idx == charptr_type_idx) {
|
||||
return true
|
||||
}
|
||||
// # NOTE: use symbols from this point on for perf
|
||||
got_type_sym := t.get_type_symbol(got)
|
||||
exp_type_sym := t.get_type_symbol(expected)
|
||||
//
|
||||
if exp_type_sym.kind == .function && got_type_sym.kind == .int {
|
||||
// TODO temporary
|
||||
// fn == 0
|
||||
return true
|
||||
}
|
||||
// allow enum value to be used as int
|
||||
if (got_type_sym.is_int() && exp_type_sym.kind == .enum_) || (exp_type_sym.is_int() &&
|
||||
got_type_sym.kind == .enum_) {
|
||||
return true
|
||||
}
|
||||
// TODO
|
||||
// if got_type_sym.kind == .array && exp_type_sym.kind == .array {
|
||||
// return true
|
||||
// }
|
||||
if got_type_sym.kind == .array_fixed && exp_type_sym.kind == .byteptr {
|
||||
info := got_type_sym.info as ArrayFixed
|
||||
if info.elem_type.idx() == byte_type_idx {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
if exp_type_sym.name == 'array' || got_type_sym.name == 'array' {
|
||||
return true
|
||||
}
|
||||
// TODO
|
||||
// accept [] when an expected type is an array
|
||||
if got_type_sym.kind == .array && got_type_sym.name == 'array_void' && exp_type_sym.kind ==
|
||||
.array {
|
||||
return true
|
||||
}
|
||||
// type alias
|
||||
if (got_type_sym.kind == .alias && got_type_sym.parent_idx == exp_idx) || (exp_type_sym.kind ==
|
||||
.alias && exp_type_sym.parent_idx == got_idx) {
|
||||
return true
|
||||
}
|
||||
// sum type
|
||||
if got_type_sym.kind == .sum_type {
|
||||
sum_info := got_type_sym.info as SumType
|
||||
// TODO: handle `match SumType { &PtrVariant {} }` currently just checking base
|
||||
if expected.set_nr_muls(0) in sum_info.variants {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if exp_type_sym.kind == .sum_type {
|
||||
sum_info := exp_type_sym.info as SumType
|
||||
// TODO: handle `match SumType { &PtrVariant {} }` currently just checking base
|
||||
if got.set_nr_muls(0) in sum_info.variants {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// fn type
|
||||
if got_type_sym.kind == .function && exp_type_sym.kind == .function {
|
||||
got_info := got_type_sym.info as FnType
|
||||
exp_info := exp_type_sym.info as FnType
|
||||
got_fn := got_info.func
|
||||
exp_fn := exp_info.func
|
||||
// we are using check() to compare return type & args as they might include
|
||||
// functions themselves. TODO: optimize, only use check() when needed
|
||||
if got_fn.args.len == exp_fn.args.len && t.check(got_fn.return_type, exp_fn.return_type) {
|
||||
for i, got_arg in got_fn.args {
|
||||
exp_arg := exp_fn.args[i]
|
||||
if !t.check(got_arg.typ, exp_arg.typ) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Once we have a module format we can read from module file instead
|
||||
// this is not optimal
|
||||
pub fn (table &Table) qualify_module(mod, file_path string) string {
|
||||
|
|
|
@ -5,12 +5,12 @@ fn simple<T>(p T) T {
|
|||
return p
|
||||
}
|
||||
|
||||
fn plus<T>(a, b T) T {
|
||||
fn plus<T>(xxx, b T) T {
|
||||
// x := a
|
||||
// y := b
|
||||
// ww := ww
|
||||
// q := xx + 1
|
||||
return a + b
|
||||
return xxx + b
|
||||
}
|
||||
|
||||
fn test_generic_fn() {
|
||||
|
@ -19,10 +19,10 @@ fn test_generic_fn() {
|
|||
assert simple<string>('g') == 'g'
|
||||
assert simple<string>('g') + 'h' == 'gh'
|
||||
a := plus<int>(2, 3)
|
||||
println(a)
|
||||
assert a == 5
|
||||
assert plus<int>(10, 1) == 11
|
||||
// plus<string>('a', 'b')
|
||||
println(a)
|
||||
assert plus<string>('a', 'b') == 'ab'
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue