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 {
|
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 {
|
if types in a {
|
||||||
return false
|
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())
|
// c.error('`void` type has no methods', node.left.position())
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
mut has_generic := false // x.foo<T>() instead of x.foo<int>()
|
|
||||||
mut concrete_types := []ast.Type{}
|
mut concrete_types := []ast.Type{}
|
||||||
for concrete_type in node.concrete_types {
|
for concrete_type in node.concrete_types {
|
||||||
if concrete_type.has_flag(.generic) {
|
if concrete_type.has_flag(.generic) {
|
||||||
has_generic = true
|
|
||||||
concrete_types << c.unwrap_generic(concrete_type)
|
concrete_types << c.unwrap_generic(concrete_type)
|
||||||
} else {
|
} else {
|
||||||
concrete_types << concrete_type
|
concrete_types << concrete_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if has_generic {
|
if concrete_types.len > 0 {
|
||||||
if c.table.register_fn_concrete_types(node.name, concrete_types) {
|
if c.table.register_fn_concrete_types(node.name, concrete_types) {
|
||||||
c.need_recheck_generic_fns = true
|
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',
|
c.error('generic fn using generic types cannot be called outside of generic fn',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
if has_generic {
|
if concrete_types.len > 0 {
|
||||||
mut no_exists := true
|
mut no_exists := true
|
||||||
if c.mod != '' && !fn_name.contains('.') {
|
if 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 {
|
|
||||||
no_exists = c.table.register_fn_concrete_types(fn_name, concrete_types)
|
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 {
|
if no_exists {
|
||||||
c.need_recheck_generic_fns = true
|
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 = ''
|
p.expr_mod = ''
|
||||||
concrete_types = p.parse_concrete_types()
|
concrete_types = p.parse_concrete_types()
|
||||||
concrete_list_pos = concrete_list_pos.extend(p.prev_tok.position())
|
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)
|
p.check(.lpar)
|
||||||
args := p.call_args()
|
args := p.call_args()
|
||||||
|
@ -528,6 +520,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
scope: p.scope
|
scope: p.scope
|
||||||
label_names: p.label_names
|
label_names: p.label_names
|
||||||
}
|
}
|
||||||
|
if generic_names.len > 0 {
|
||||||
|
p.table.register_fn_generic_types(name)
|
||||||
|
}
|
||||||
p.label_names = []
|
p.label_names = []
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
return fn_decl
|
return fn_decl
|
||||||
|
|
Loading…
Reference in New Issue