ast, parser, checker: fix generic fn in builtin module (#12769)

pull/13335/head^2
yuyi 2021-12-10 03:37:43 +08:00 committed by GitHub
parent dbe67c688f
commit 7fc9e614a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 17 deletions

View File

@ -1153,8 +1153,12 @@ pub fn (t &Table) mktyp(typ Type) Type {
}
}
pub fn (mut t Table) register_fn_generic_types(fn_name string) {
t.fn_generic_types[fn_name] = [][]Type{}
}
pub fn (mut t Table) register_fn_concrete_types(fn_name string, types []Type) bool {
mut a := t.fn_generic_types[fn_name]
mut a := t.fn_generic_types[fn_name] or { return false }
if types in a {
return false
}

View File

@ -1986,17 +1986,15 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
// c.error('`void` type has no methods', node.left.position())
return ast.void_type
}
mut has_generic := false // x.foo<T>() instead of x.foo<int>()
mut concrete_types := []ast.Type{}
for concrete_type in node.concrete_types {
if concrete_type.has_flag(.generic) {
has_generic = true
concrete_types << c.unwrap_generic(concrete_type)
} else {
concrete_types << concrete_type
}
}
if has_generic {
if concrete_types.len > 0 {
if c.table.register_fn_concrete_types(node.name, concrete_types) {
c.need_recheck_generic_fns = true
}
@ -2539,13 +2537,17 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
c.error('generic fn using generic types cannot be called outside of generic fn',
node.pos)
}
if has_generic {
if concrete_types.len > 0 {
mut no_exists := true
if c.mod != '' && !fn_name.contains('.') {
// Need to prepend the module when adding a generic type to a function
no_exists = c.table.register_fn_concrete_types(c.mod + '.' + fn_name, concrete_types)
} else {
if fn_name.contains('.') {
no_exists = c.table.register_fn_concrete_types(fn_name, concrete_types)
} else {
no_exists = c.table.register_fn_concrete_types(c.mod + '.' + fn_name, concrete_types)
// if the generic fn does not exist in the current fn calling module, continue
// to look in builtin module
if !no_exists {
no_exists = c.table.register_fn_concrete_types(fn_name, concrete_types)
}
}
if no_exists {
c.need_recheck_generic_fns = true

View File

@ -40,14 +40,6 @@ pub fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr
p.expr_mod = ''
concrete_types = p.parse_concrete_types()
concrete_list_pos = concrete_list_pos.extend(p.prev_tok.position())
// In case of `foo<T>()`
// T is unwrapped and registered in the checker.
full_generic_fn_name := if fn_name.contains('.') { fn_name } else { p.prepend_mod(fn_name) }
has_generic := concrete_types.any(it.has_flag(.generic))
if !has_generic {
// will be added in checker
p.table.register_fn_concrete_types(full_generic_fn_name, concrete_types)
}
}
p.check(.lpar)
args := p.call_args()
@ -528,6 +520,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
scope: p.scope
label_names: p.label_names
}
if generic_names.len > 0 {
p.table.register_fn_generic_types(name)
}
p.label_names = []
p.close_scope()
return fn_decl