From a78df40231bc2d022bf5e0e10ef12ec2c79d4f80 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Tue, 9 Mar 2021 14:08:32 +0100 Subject: [PATCH] :art: Introduce ufcc --- include/tmp_resolve.h | 4 +-- include/traverse.h | 2 +- src/lib/object_op.c | 7 ++-- src/parse/check.c | 61 +++++++++++++++++++++++++++-------- src/parse/func_resolve_tmpl.c | 16 ++++----- tests/ufcc/has_func.gw | 13 ++++++++ tests/ufcc/no_func.gw | 9 ++++++ 7 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 tests/ufcc/has_func.gw create mode 100644 tests/ufcc/no_func.gw diff --git a/include/tmp_resolve.h b/include/tmp_resolve.h index 6577be04..fd0bde35 100644 --- a/include/tmp_resolve.h +++ b/include/tmp_resolve.h @@ -1,5 +1,5 @@ #ifndef __TMPL_RESOLVE #define __TMPL_RESOLVE -ANN Func find_template_match(const Env env, const Value value, const Exp_Call* exp); -ANN2(1, 2) Func find_func_match(const Env env, const Func up, const Exp exp); +ANN Func find_template_match(const Env env, const Value value, Exp_Call *const exp); +ANN Func find_func_match(const Env env, const Func up, Exp_Call *const exp); #endif diff --git a/include/traverse.h b/include/traverse.h index 5ab16b32..7c841d0c 100644 --- a/include/traverse.h +++ b/include/traverse.h @@ -47,5 +47,5 @@ ANN m_bool scan1_class_def(const Env, const Class_Def); ANN m_bool scan2_class_def(const Env, const Class_Def); ANN m_bool check_class_def(const Env, const Class_Def); -ANN Type check_exp_call1(const Env env, const Exp_Call *exp); +ANN Type check_exp_call1(const Env env, Exp_Call *const exp); #endif diff --git a/src/lib/object_op.c b/src/lib/object_op.c index 8b90f6d5..3cbc35b4 100644 --- a/src/lib/object_op.c +++ b/src/lib/object_op.c @@ -111,8 +111,8 @@ ANN static void emit_member_func(const Emitter emit, const Exp_Dot* member) { exp_setvar(member->base, 1); emit_exp(emit, member->base); } - const Instr func_i = emit_add_instr(emit, f->code ? RegPushImm : SetFunc); - func_i->m_val = (m_uint)f->code ?: (m_uint)f; + const Instr func_i = emit_add_instr(emit, f->code ? RegPushImm : SetFunc); + func_i->m_val = (m_uint)f->code ?: (m_uint)f; return; } const Instr instr = emit_add_instr(emit, DotFunc); @@ -168,6 +168,9 @@ OP_CHECK(opck_object_dot) { _("keyword 'this' must be associated with object instance...")) const Value value = get_value(env, member, the_base); if(!value) { + const Value v = nspc_lookup_value1(env->curr, member->xid); + if(v && isa(v->type, env->gwion->type[et_function]) > 0) + return v->type; env_err(env, exp_self(member)->pos, _("class '%s' has no member '%s'"), the_base->name, str); if(member->base->type->nspc) diff --git a/src/parse/check.c b/src/parse/check.c index 24d145d7..ed8a3eb8 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -454,15 +454,40 @@ ANN2(1,2) static Func find_func_match_actual(const Env env, Func func, const Exp return NULL; } -ANN2(1, 2) Func find_func_match(const Env env, const Func up, const Exp exp) { +ANN static Type check_exp_call(const Env env, Exp_Call* exp); + +ANN static Func call2ufcc(const Env env, Exp_Call* call, const Value v) { + const Exp this = call->func->d.exp_dot.base; + this->next = call->args; + call->args = this; + call->func->type = v->type; + call->func->d.prim.value = v; + call->func->d.prim.d.var = call->func->d.exp_dot.xid; + call->func->exp_type = ae_exp_primary; + call->func->d.prim.prim_type = ae_prim_id; + call->args = this; + CHECK_OO(check_exp_call(env, call)) + return call->func->type->info->func; +} + +ANN Func ufcc(const Env env, const Func up, Exp_Call *const call) { + const Value v = nspc_lookup_value1(env->curr, up->def->base->xid); + if(v && isa(v->type, env->gwion->type[et_function]) > 0 && !vflag(v, vflag_member)) + return call2ufcc(env, call, v); + return NULL; +} + +ANN Func find_func_match(const Env env, const Func up, Exp_Call *const call) { Func func; + const Exp exp = call->args; const Exp args = (exp && isa(exp->type, env->gwion->type[et_void]) < 0) ? exp : NULL; if((func = find_func_match_actual(env, up, args, 0, 1)) || (func = find_func_match_actual(env, up, args, 1, 1)) || (func = find_func_match_actual(env, up, args, 0, 0)) || (func = find_func_match_actual(env, up, args, 1, 0))) return func; - return NULL; + return call->func->exp_type == ae_exp_dot && up->value_ref->from->owner_class ? + ufcc(env, up, call) : NULL; } ANN m_bool check_traverse_fdef(const Env env, const Func_Def fdef) { @@ -542,7 +567,7 @@ ANN static m_uint get_type_number(ID_List list) { return type_number; } -ANN static Func get_template_func(const Env env, const Exp_Call* func, const Value v) { +ANN static Func get_template_func(const Env env, Exp_Call *const func, const Value v) { const Func f = find_template_match(env, v, func); if(f) { // copy that tmpl->call? @@ -651,14 +676,22 @@ ANN static Type check_lambda_call(const Env env, const Exp_Call *exp) { return ret > 0 ? l->def->base->ret_type : NULL; } -ANN m_bool func_check(const Env env, const Exp_Call *exp) { +ANN m_bool func_check(const Env env, Exp_Call *const exp) { CHECK_OB(check_exp(env, exp->func)) if(exp->func->exp_type == ae_exp_decl) ERR_B(exp->func->pos, _("Can't call late function pointer at declaration site")) const Type t = actual_type(env->gwion, exp->func->type); + if(isa(t, env->gwion->type[et_function]) > 0 && + exp->func->exp_type == ae_exp_dot && !t->info->owner_class) { + if(exp->args) + CHECK_OB(check_exp(env, exp->args)) + const Func f = call2ufcc(env, exp, t->info->func->value_ref); + if(f) + return GW_OK; + } const Exp e = exp_self(exp); struct Op_Import opi = { .op=insert_symbol("@func_check"), - .rhs=t, .pos=e->pos, .data=(uintptr_t)e }; + .rhs=t, .pos=e->pos, .data=(uintptr_t)e }; CHECK_NB(op_check(env, &opi)) // doesn't really return NULL if(e->exp_type != ae_exp_call) return 0; @@ -666,7 +699,7 @@ ANN m_bool func_check(const Env env, const Exp_Call *exp) { GW_OK : GW_ERROR; } -ANN Type check_exp_call1(const Env env, const Exp_Call *exp) { +ANN Type check_exp_call1(const Env env, Exp_Call *const exp) { DECL_BO(const m_bool, ret, = func_check(env, exp)) if(!ret) return exp_self(exp)->type; @@ -688,7 +721,7 @@ ANN Type check_exp_call1(const Env env, const Exp_Call *exp) { CHECK_OO(check_exp(env, exp->args)) if(tflag(t, tflag_ftmpl)) return check_exp_call_template(env, (Exp_Call*)exp); - const Func func = find_func_match(env, t->info->func, exp->args); + const Func func = find_func_match(env, t->info->func, exp); if(func) { exp->func->type = func->value_ref->type; return func->def->base->ret_type; @@ -838,12 +871,14 @@ DECL_EXP_FUNC(check, Type, Env) ANN Type check_exp(const Env env, const Exp exp) { Exp curr = exp; - do { - CHECK_OO((curr->type = check_exp_func[curr->exp_type](env, &curr->d))) - if(env->func && isa(curr->type, env->gwion->type[et_lambda]) < 0 && isa(curr->type, env->gwion->type[et_function]) > 0 && - !fflag(curr->type->info->func, fflag_pure)) - unset_fflag(env->func, fflag_pure); - } while((curr = curr->next)); + if(!exp->type) { + do { + CHECK_OO((curr->type = check_exp_func[curr->exp_type](env, &curr->d))) + if(env->func && isa(curr->type, env->gwion->type[et_lambda]) < 0 && isa(curr->type, env->gwion->type[et_function]) > 0 && + !fflag(curr->type->info->func, fflag_pure)) + unset_fflag(env->func, fflag_pure); + } while((curr = curr->next)); + } return exp->type; } diff --git a/src/parse/func_resolve_tmpl.c b/src/parse/func_resolve_tmpl.c index e46fd87a..d75db3b1 100644 --- a/src/parse/func_resolve_tmpl.c +++ b/src/parse/func_resolve_tmpl.c @@ -16,7 +16,7 @@ struct ResolverArgs { const Value v; - const Exp_Call *e; + Exp_Call *const e; const m_str tmpl_name; const Type_List types; }; @@ -32,13 +32,13 @@ ANN static inline m_bool tmpl_valid(const Env env, const Func_Def fdef) { check_traverse_fdef(env, fdef) > 0; } -ANN static Func ensure_tmpl(const Env env, const Func_Def fdef, const Exp_Call *exp) { +ANN static Func ensure_tmpl(const Env env, const Func_Def fdef, Exp_Call *const exp) { if(!tmpl_valid(env, fdef)) return NULL; const Func f = fdef->base->func; const Func next = f->next; f->next = NULL; - const Func func = find_func_match(env, f, exp->args); + const Func func = find_func_match(env, f, exp); f->next = next; if(func) set_fflag(func, fflag_tmpl | fflag_valid); @@ -47,7 +47,7 @@ ANN static Func ensure_tmpl(const Env env, const Func_Def fdef, const Exp_Call * ANN static inline Func ensure_fptr(const Env env, struct ResolverArgs* ra, const Fptr_Def fptr) { CHECK_BO(traverse_fptr_def(env, fptr)) - return find_func_match(env, fptr->base->func, ra->e->args); + return find_func_match(env, fptr->base->func, ra->e); } ANN static Func fptr_match(const Env env, struct ResolverArgs* ra) { @@ -76,7 +76,7 @@ ANN static Func fptr_match(const Env env, struct ResolverArgs* ra) { ANN static Func tmpl_exists(const Env env, struct ResolverArgs* ra, const Value exists) { if(env->func == exists->d.func_ref) - return find_func_match(env, env->func, ra->e->args) ? env->func : NULL; + return find_func_match(env, env->func, ra->e) ? env->func : NULL; return ensure_tmpl(env, exists->d.func_ref->def, ra->e); } @@ -106,7 +106,7 @@ ANN static Func func_match(const Env env, struct ResolverArgs* ra) { return NULL; } -ANN static Func find_tmpl(const Env env, const Value v, const Exp_Call* exp, const m_str tmpl_name) { +ANN static Func find_tmpl(const Env env, const Value v, Exp_Call *const exp, const m_str tmpl_name) { const Type_List types = exp->tmpl->call; const Func former = env->func; const m_uint scope = env->scope->depth; @@ -124,7 +124,7 @@ ANN static Func find_tmpl(const Env env, const Value v, const Exp_Call* exp, con return m_func; } -ANN static Func _find_template_match(const Env env, const Value v, const Exp_Call* exp) { +ANN static Func _find_template_match(const Env env, const Value v, Exp_Call *const exp) { DECL_OO(const m_str, tmpl_name, = tl2str(env->gwion, exp->tmpl->call, exp->func->pos)) const Func f = find_tmpl(env, v, exp, tmpl_name); free_mstr(env->gwion->mp, tmpl_name); @@ -138,7 +138,7 @@ ANN static inline m_bool check_call(const Env env, const Exp_Call* exp) { return GW_OK; } -ANN Func find_template_match(const Env env, const Value value, const Exp_Call* exp) { +ANN Func find_template_match(const Env env, const Value value, Exp_Call *const exp) { CHECK_BO(check_call(env, exp)) const Func f = _find_template_match(env, value, exp); if(f) diff --git a/tests/ufcc/has_func.gw b/tests/ufcc/has_func.gw new file mode 100644 index 00000000..3bd7ec20 --- /dev/null +++ b/tests/ufcc/has_func.gw @@ -0,0 +1,13 @@ +class C { + fun void test(int i) { + <<< "member func called test">>>; + } +} + +fun void test(C c) { + <<< "func called test">>>; +} + +const C c; +c.test(); +c.test(2); diff --git a/tests/ufcc/no_func.gw b/tests/ufcc/no_func.gw new file mode 100644 index 00000000..60080d84 --- /dev/null +++ b/tests/ufcc/no_func.gw @@ -0,0 +1,9 @@ +#! [contains] func called test +class C {} + +fun void test(C c) { + <<< "func called test">>>; +} + +const C c; +c.test(); -- 2.43.0