generics: lots of fixes

pull/5000/head
Alexander Medvednikov 2020-05-24 04:43:00 +02:00
parent 4608898bcd
commit 67750c91d7
10 changed files with 247 additions and 208 deletions

View File

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

View File

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

View File

@ -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',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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'
}
/*