ast, parser, checker: fix generic fn in builtin module (#12769)
parent
dbe67c688f
commit
7fc9e614a3
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue