1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check each generic function for each type

This commit is contained in:
Alexander Medvednikov 2020-05-21 21:51:49 +02:00
parent b2b0461218
commit d3ce6fd2e7
4 changed files with 57 additions and 33 deletions

View File

@ -15,28 +15,29 @@ const (
)
pub struct Checker {
table &table.Table
table &table.Table
pub mut:
file ast.File
nr_errors int
nr_warnings int
errors []errors.Error
warnings []errors.Warning
error_lines []int // to avoid printing multiple errors for the same line
expected_type table.Type
fn_return_type table.Type // current function's return type
const_decl string
const_deps []string
const_names []string
pref &pref.Preferences // Preferences shared from V struct
in_for_count int // if checker is currently in an for loop
file ast.File
nr_errors int
nr_warnings int
errors []errors.Error
warnings []errors.Warning
error_lines []int // to avoid printing multiple errors for the same line
expected_type table.Type
fn_return_type table.Type // current function's return type
const_decl string
const_deps []string
const_names []string
pref &pref.Preferences // Preferences shared from V struct
in_for_count int // if checker is currently in an for loop
// checked_ident string // to avoid infinit checker loops
var_decl_name string
returns bool
scope_returns bool
mod string // current module name
is_builtin_mod bool // are we in `builtin`?
inside_unsafe bool
var_decl_name string
returns bool
scope_returns bool
mod string // current module name
is_builtin_mod bool // are we in `builtin`?
inside_unsafe bool
cur_generic_type table.Type
}
pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker {
@ -1158,11 +1159,13 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
// c.error('wrong number of return arguments:\n\texpected: $expected_table.str()\n\tgot: $got_types.str()', return_stmt.pos)
c.error('wrong number of return arguments', return_stmt.pos)
}
for i, exp_typ in expected_types {
for i, exp_type in expected_types {
got_typ := got_types[i]
if !c.table.check(got_typ, exp_typ) {
ok := if exp_type == table.t_type { c.table.check(got_typ, c.cur_generic_type) } else { c.table.check(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_typ)
exp_typ_sym := c.table.get_type_symbol(exp_type)
pos := return_stmt.exprs[i].position()
c.error('cannot use `$got_typ_sym.name` as type `$exp_typ_sym.name` in return argument',
pos)
@ -1815,6 +1818,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
if ident.name == c.var_decl_name { // c.checked_ident {
// Do not allow `x := x`
c.error('unresolved: `$ident.name`', ident.pos)
return table.void_type
}
@ -1836,6 +1840,10 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
// second use
if ident.kind == .variable {
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 info.typ
} else if ident.kind == .constant {
info := ident.info as ast.IdentVar
@ -1859,6 +1867,10 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
typ: typ
is_optional: is_optional
}
if typ == table.t_type {
// Got a var with type T, return current generic type
typ = c.cur_generic_type
}
it.typ = typ
// unwrap optional (`println(x)`)
if is_optional {
@ -2315,6 +2327,16 @@ fn (c &Checker) fileis(s string) bool {
}
fn (mut c Checker) fn_decl(it ast.FnDecl) {
if it.is_generic && c.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 c.table.fn_gen_types[it.name] {
c.cur_generic_type = gen_type
// println('\ncalling check for $it.name for type ' + gen_type.str())
c.fn_decl(it)
}
c.cur_generic_type = 0
return
}
if it.language == .v && !c.is_builtin_mod {
c.check_valid_snake_case(it.name, 'function name', it.pos)
}

View File

@ -18,7 +18,6 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
for gen_type in g.table.fn_gen_types[it.name] {
g.cur_generic_type = gen_type
g.gen_fn_decl(it)
println(gen_type)
}
g.cur_generic_type = 0
return

View File

@ -438,12 +438,12 @@ pub fn (mut t Table) register_builtin_type_symbols() {
name: 'char'
mod: 'builtin'
})
t.register_type_symbol(TypeSymbol{
t.register_type_symbol({
kind: .bool
name: 'bool'
mod: 'builtin'
})
t.register_type_symbol(TypeSymbol{
t.register_type_symbol({
kind: .none_
name: 'none'
mod: 'builtin'
@ -473,6 +473,11 @@ pub fn (mut t Table) register_builtin_type_symbols() {
name: 'any'
mod: 'builtin'
})
t.register_type_symbol(TypeSymbol{
kind: .any
name: 'T'
mod: 'builtin'
})
t.register_type_symbol(TypeSymbol{
kind: .size_t
name: 'size_t'
@ -493,11 +498,6 @@ pub fn (mut t Table) register_builtin_type_symbols() {
mod: 'builtin'
parent_idx: map_string_int_idx
})
t.register_type_symbol(TypeSymbol{
kind: .any
name: 'T'
mod: 'builtin'
})
}
[inline]

View File

@ -6,7 +6,8 @@ fn simple<T>(p T) T {
}
fn plus<T>(a, b T) T {
// q := a + 1
// ww := ww
// q := xx + 1
return a + b
}
@ -15,7 +16,9 @@ fn test_generic_fn() {
assert simple<int>(1 + 0) == 1
assert simple<string>('g') == 'g'
assert simple<string>('g') + 'h' == 'gh'
// plus<int>(2, 3)
a := plus<int>(2, 3)
// plus<string>('a', 'b')
println(a)
}
/*