From 3fa05203d33996069d7a0696156ea49a3b68ca07 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Sun, 15 May 2022 20:50:09 +0200 Subject: [PATCH] :art: Improve return handling --- include/env/func.h | 5 ++- src/emit/emit.c | 12 +++---- src/lib/deep_equal.c | 2 +- src/lib/engine.c | 1 - src/lib/lib_func.c | 2 +- src/lib/object_op.c | 6 ++-- src/lib/union.c | 2 +- src/parse/check.c | 63 +++++++++++------------------------- src/parse/check_traits.c | 2 +- src/parse/operator.c | 2 +- src/parse/scan0.c | 2 +- src/parse/scan1.c | 17 ++++++++-- src/parse/scan2.c | 2 +- src/parse/template.c | 4 +-- tests/error/name_conflict.gw | 2 +- 15 files changed, 54 insertions(+), 70 deletions(-) diff --git a/include/env/func.h b/include/env/func.h index 42230c69..db728f35 100644 --- a/include/env/func.h +++ b/include/env/func.h @@ -8,7 +8,6 @@ enum fflag { fflag_tmpl = 1 << 3, fflag_valid = 1 << 4, fflag_emit = 1 << 5, - fflag_return = 1 << 6, } __attribute__((packed)); struct Func_ { @@ -18,8 +17,8 @@ struct Func_ { Func next; m_str name; float inline_mult; - uint16_t weight; - uint16_t memoize; + uint16_t weight; // used to mark gack use in scan1 + uint16_t memoize; // used to mark return in scan1 uint16_t ref; uint16_t vt_index; ae_flag flag; diff --git a/src/emit/emit.c b/src/emit/emit.c index 50b8fe2c..e77094ff 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -541,7 +541,7 @@ ANN static m_bool _emit_symbol(const Emitter emit, const Symbol *data) { } if (vflag(v, vflag_builtin) || vflag(v, vflag_direct)) return emit_symbol_builtin(emit, data); - if(is_func(emit->gwion, v->type) && !is_fptr(emit->gwion, v->type)) { + if(is_func(emit->gwion, v->type) && !is_fptr(emit->gwion, v->type)) { // is_func const Func f = v->type->info->func; if(f->code) regpushi(emit, (m_uint)f->code); @@ -1220,7 +1220,7 @@ ANN static m_bool emit_func_args(const Emitter emit, const Exp_Call *exp_call) { if (exp_call->args) CHECK_BB(emit_exp(emit, exp_call->args)); const Type t = actual_type(emit->gwion, exp_call->func->type); if (is_func(emit->gwion, t) && - fbflag(t->info->func->def->base, fbflag_variadic)) + fbflag(t->info->func->def->base, fbflag_variadic)) // is_callable emit_func_arg_vararg(emit, exp_call); return GW_OK; } @@ -1266,7 +1266,7 @@ ANN static inline bool member_inlinable(const Emitter emit, const Func f, const ANN static inline Func is_inlinable(const Emitter emit, const Exp_Call *exp_call) { const Type ftype = exp_call->func->type; - if (!is_func(emit->gwion, ftype) || is_fptr(emit->gwion, ftype) || + if (!is_func(emit->gwion, ftype) || is_fptr(emit->gwion, ftype) || // is_fptr !ftype->info->func->code || ftype->info->func->code->builtin) return false; const Func f = ftype->info->func; @@ -1371,7 +1371,7 @@ ANN static m_bool _emit_exp_call(const Emitter emit, const Exp_Call *exp_call) { CHECK_BB(prepare_call(emit, exp_call)); else CHECK_BB(emit_func_args(emit, exp_call)); - if (is_func(emit->gwion, t)) + if (is_func(emit->gwion, t)) // is_callable needs type CHECK_BB(emit_exp_call1(emit, t->info->func, is_static_call(emit, exp_call->func))); else { @@ -1396,7 +1396,7 @@ ANN static m_bool emit_exp_call(const Emitter emit, const Exp_Call *exp_call) { const Instr instr = emit_add_instr(emit, Reg2RegAddr); instr->m_val = -SZ_INT; } else { - if (!is_func(emit->gwion, exp_call->func->type) && + if (!is_func(emit->gwion, exp_call->func->type) && // is_callable tflag(e->type, tflag_struct)) regpop(emit, SZ_INT); } @@ -2564,7 +2564,7 @@ ANN static m_bool emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt) { } ANN static m_bool emit_type_def(const Emitter emit, const Type_Def tdef) { - if (tdef->when) CHECK_BB(emit_func_def(emit, tdef->when_def)); + if (tdef->when_def) CHECK_BB(emit_func_def(emit, tdef->when_def)); if (!is_fptr(emit->gwion, tdef->type) && !tflag(tdef->type, tflag_cdef)) { if(!tflag(tdef->type->info->parent, tflag_emit)) diff --git a/src/lib/deep_equal.c b/src/lib/deep_equal.c index 93713cb7..28d1ccbb 100644 --- a/src/lib/deep_equal.c +++ b/src/lib/deep_equal.c @@ -48,7 +48,7 @@ static void type_get_member(const Gwion gwion, const Type t, const Vector v) { for(m_uint i = 0; i < map_size(m); i++) { const Value value = (Value)map_at(m, i); if(!vflag(value, vflag_member)) continue; - if(is_func(gwion, value->type) && !is_fptr(gwion, value->type)) continue; + if(is_func(gwion, value->type) && !is_fptr(gwion, value->type)) continue; // is_func vector_add(v, (m_uint)value); } } diff --git a/src/lib/engine.c b/src/lib/engine.c index 49c5afa8..fe93fe1b 100644 --- a/src/lib/engine.c +++ b/src/lib/engine.c @@ -43,7 +43,6 @@ OP_CHECK(opck_object_dot); OP_EMIT(opem_object_dot); static ID_CHECK(idck_predicate) { - set_fflag(env->func, fflag_return); return exp_self(prim)->type; } diff --git a/src/lib/lib_func.c b/src/lib/lib_func.c index 5d5cf211..6e4b50e3 100644 --- a/src/lib/lib_func.c +++ b/src/lib/lib_func.c @@ -249,7 +249,7 @@ ANN static Type fptr_type(const Env env, struct FptrInfo *info) { if (!is_class(env->gwion, info->lhs->value_ref->type)) { if (!(info->lhs = nspc_lookup_func1(nspc, sym))) { const Value v = nspc_lookup_value1(nspc, insert_symbol(c)); - if (!is_func(env->gwion, v->type)) return NULL; + if (!is_func(env->gwion, v->type)) return NULL; // is_callable info->lhs = v->type->info->func; } } else { diff --git a/src/lib/object_op.c b/src/lib/object_op.c index 984bf45b..d748b5e4 100644 --- a/src/lib/object_op.c +++ b/src/lib/object_op.c @@ -197,7 +197,7 @@ OP_CHECK(opck_object_dot) { } const Value v = nspc_lookup_value1(env->curr, member->xid); if (v && member->is_call) { - if (is_func(env->gwion, v->type) && (!v->from->owner_class || isa(the_base, v->from->owner_class) > 0)) + if (is_func(env->gwion, v->type) && (!v->from->owner_class || isa(the_base, v->from->owner_class) > 0)) // is_callable needs type return v->type; if (is_class(env->gwion, v->type)) { DECL_OO(const Type, parent, = class_type(env, member, v->type)); @@ -255,12 +255,12 @@ OP_EMIT(opem_object_dot) { } if (!is_class(emit->gwion, member->base->type) && (vflag(value, vflag_member) || - (is_func(emit->gwion, exp_self(member)->type) && + (is_func(emit->gwion, exp_self(member)->type) && // is_func !is_fptr(emit->gwion, exp_self(member)->type)))) { if (!tflag(t_base, tflag_struct) && vflag(value, vflag_member)) CHECK_BB(emit_exp(emit, member->base)); } - if (is_func(emit->gwion, exp_self(member)->type) && + if (is_func(emit->gwion, exp_self(member)->type) && // is_func !is_fptr(emit->gwion, exp_self(member)->type)) emit_member_func(emit, member); else if (vflag(value, vflag_member)) { diff --git a/src/lib/union.c b/src/lib/union.c index 369c331d..a3cf314e 100644 --- a/src/lib/union.c +++ b/src/lib/union.c @@ -32,7 +32,7 @@ static OP_EMIT(opem_union_dot) { const Exp_Dot *member = (Exp_Dot *)data; const Map map = &member->base->type->nspc->info->value->map; CHECK_BB(emit_exp(emit, member->base)); - if (is_func(emit->gwion, exp_self(member)->type)) { + if (is_func(emit->gwion, exp_self(member)->type)) { // is_callable? can only be a func const Instr instr = emit_add_instr(emit, RegPushImm); const Func f = (Func)vector_front(&member->base->type->info->parent->nspc->vtable); diff --git a/src/parse/check.c b/src/parse/check.c index 2366510d..f3cb165f 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -311,7 +311,7 @@ ANN static Value check_non_res_value(const Env env, const Symbol *data) { _("non-global variable '%s' used from global function/class."), s_name(var)) } else if(env->func && fbflag(env->func->def->base, fbflag_locale)) { - if(!is_func(env->gwion, value->type) && value->from->owner && !from_global_nspc(env, value->from->owner)) + if(!is_func(env->gwion, value->type) && value->from->owner && !from_global_nspc(env, value->from->owner)) // is_callable ERR_O(prim_pos(data), _("invalid variable access from locale definition")); } return value; @@ -402,8 +402,6 @@ ANN static Type check_prim_id(const Env env, const Symbol *data) { ANN static Type check_prim_perform(const Env env, const Symbol *data) { env_add_effect(env, *data, prim_pos(data)); env_weight(env, 1); - if (env->func && env->scope->depth == 1) // so ops no dot set scope->depth ? - set_fflag(env->func, fflag_return); return env->gwion->type[et_void]; } @@ -481,7 +479,7 @@ ANN static inline Type type_list_base_func(const Type type) { } ANN static inline Type type_list_base(const Gwion gwion, const Type type) { - return !(is_func(gwion, type) && !is_fptr(gwion, type)) ? + return !(is_func(gwion, type) && !is_fptr(gwion, type)) ? // is_func type : type_list_base_func(type); } @@ -549,7 +547,7 @@ ANN static Func call2ufcs(const Env env, Exp_Call *call, const Value v) { ANN Func ufcs(const Env env, const Func up, Exp_Call *const call) { const Value v = nspc_lookup_value1(env->curr, up->def->base->xid); - if (v && is_func(env->gwion, v->type) && !v->from->owner_class) + if (v && is_func(env->gwion, v->type) && !v->from->owner_class) // is_callable return call2ufcs(env, call, v); return NULL; } @@ -813,7 +811,7 @@ ANN m_bool func_check(const Env env, Exp_Call *const exp) { "site. did you meant to use `@=>`?")) const Type t = actual_type(env->gwion, exp->func->type); if(!is_fptr(env->gwion, t)) { - if (is_func(env->gwion, t) && exp->func->exp_type == ae_exp_dot && + if (is_func(env->gwion, t) && exp->func->exp_type == ae_exp_dot && // is_callable !t->info->value->from->owner_class) { if (exp->args) CHECK_OB(check_exp(env, exp->args)); return call2ufcs(env, exp, t->info->func->value_ref) ? GW_OK : GW_ERROR; @@ -1081,22 +1079,25 @@ ANN m_bool check_type_def(const Env env, const Type_Def tdef) { set_fbflag(fb, fbflag_op); const Exp helper = new_prim_id(env->gwion->mp, insert_symbol("@predicate"), tdef->when->pos); - const Exp when = cpy_exp(env->gwion->mp, tdef->when); + const Exp when = tdef->when; + tdef->when = NULL; when->next = helper; - Stmt_List body = new_mp_vector(env->gwion->mp, sizeof(struct Stmt_), 1); + Stmt_List body = new_mp_vector(env->gwion->mp, sizeof(struct Stmt_), 2); mp_vector_set(body, struct Stmt_, 0, ((struct Stmt_) { .stmt_type = ae_stmt_exp, .d = { .stmt_exp = { .val = when }}, .pos = when->pos })); + mp_vector_set(body, struct Stmt_, 1, + ((struct Stmt_) { + .stmt_type = ae_stmt_exp, + .pos = when->pos + })); const Stmt code = new_stmt_code(env->gwion->mp, body, when->pos); const Func_Def fdef = new_func_def(env->gwion->mp, fb, code); - if(traverse_func_def(env, fdef) < 0) { - free_mp_vector(env->gwion->mp, sizeof(struct Stmt_), body); - return GW_ERROR; - } + tdef->when_def = fdef; + CHECK_BB(traverse_func_def(env, fdef)); if (isa(when->type, env->gwion->type[et_bool]) < 0) { - free_mp_vector(env->gwion->mp, sizeof(struct Stmt_), body); char explain[strlen(when->type->name) + 20]; sprintf(explain, "found `{/+}%s{0}`", when->type->name); gwerr_basic("Invalid `{/+}when{0}` predicate expression type", explain, @@ -1107,35 +1108,18 @@ ANN m_bool check_type_def(const Env env, const Type_Def tdef) { env_set_error(env); return GW_ERROR; } - /* - // enable static checking - const Func f = fdef->base->func; - const struct Op_Func opfunc = { .ck=opck_predicate }; - const struct Op_Import opi = { .rhs=f->value_ref->type, - .func=&opfunc, .data=(uintptr_t)f, .pos=tdef->pos, - .op=insert_symbol("@func_check") }; CHECK_BB(add_op(env->gwion, &opi)); - */ // we handle the return after, so that we don't get *cant' use implicit // casting while defining it* - const Exp ret_id = - new_prim_id(env->gwion->mp, insert_symbol("self"), when->pos); + const Exp ret_id = new_prim_id(env->gwion->mp, insert_symbol("self"), when->pos); ret_id->d.prim.value = new_value(env, tdef->type, "self", tdef->pos); struct Stmt_ ret = { .stmt_type = ae_stmt_return, .d = { .stmt_exp = { .val = ret_id }}, .pos = when->pos }; - mp_vector_add(env->gwion->mp, &fdef->d.code->d.stmt_code.stmt_list, struct Stmt_, ret); - ret_id->type = tdef->type; - tdef->when_def = fdef; - } - if (!is_fptr(env->gwion, tdef->type) && !tflag(tdef->type, tflag_cdef)) { - if(!tflag(tdef->type->info->parent, tflag_check)) - return check_class_def(env, tdef->type->info->parent->info->cdef); + mp_vector_set(fdef->d.code->d.stmt_code.stmt_list, struct Stmt_, 1, ret); + ret_id->type = tdef->type; } - - return (!is_fptr(env->gwion, tdef->type) && tdef->type->info->cdef) - ? check_class_def(env, tdef->type->info->cdef) - : GW_OK; + return GW_OK; } ANN static Type check_exp_lambda(const Env env, const Exp_If *exp_if NUSED) { return env->gwion->type[et_lambda]; @@ -1303,11 +1287,6 @@ stmt_func_xxx(loop, Stmt_Loop, env_inline_mult(env, 1.5); check_idx(env, stmt->i stmt_func_xxx(each, Stmt_Each, env_inline_mult(env, 1.5), do_stmt_each(env, stmt)) ANN static m_bool check_stmt_return(const Env env, const Stmt_Exp stmt) { - if (!env->func) - ERR_B(stmt_self(stmt)->pos, - _("'return' statement found outside function definition")) - if (env->scope->depth == 1) // so ops no dot set scope->depth ? - set_fflag(env->func, fflag_return); if (!strcmp(s_name(env->func->def->base->xid), "new")) { if(stmt->val) ERR_B(stmt_self(stmt)->pos, @@ -1686,12 +1665,6 @@ ANN m_bool check_fdef(const Env env, const Func_Def fdef) { CHECK_BB(check_stmt_code(env, &fdef->d.code->d.stmt_code)); env->scope->depth++; } - // check fdef->base->td for `new` - if (fdef->base->td && fdef->base->ret_type && - fdef->base->ret_type != env->gwion->type[et_void] && fdef->d.code && - !fflag(fdef->base->func, fflag_return)) - ERR_B(fdef->base->td->pos, - _("missing return statement in a non void function")); return GW_OK; } diff --git a/src/parse/check_traits.c b/src/parse/check_traits.c index aba6c009..2c0dad3a 100644 --- a/src/parse/check_traits.c +++ b/src/parse/check_traits.c @@ -61,7 +61,7 @@ ANN static bool request_fun(const Env env, const Type t, const Func_Def request) { const Value v = nspc_lookup_value0(t->nspc, request->base->xid); if (v) { - if (!is_func(env->gwion, v->type) || is_fptr(env->gwion, v->type)) { + if (!is_func(env->gwion, v->type) || is_fptr(env->gwion, v->type)) { // is_fptr gwerr_basic("is not a function", NULL, NULL, v->from->filename, v->from->loc, 0); return false; diff --git a/src/parse/operator.c b/src/parse/operator.c index 5179dd44..8f94d9fc 100644 --- a/src/parse/operator.c +++ b/src/parse/operator.c @@ -356,7 +356,7 @@ ANN Type op_check(const Env env, struct Op_Import *opi) { gwerr_basic(_("no match found for operator"), "expected duration", "did you try converting to `dur`?", env->name, opi->pos, 0); env->context->error = true; } else if (strcmp(op, "@implicit")) { - if (opi->rhs && opi->lhs && is_func(env->gwion, opi->rhs)) { + if (opi->rhs && opi->lhs && is_func(env->gwion, opi->rhs)) { // is_callable const size_t len = strlen(op); if (len > 2 && !strcmp(op + len - 2, "=>")) return chuck_rewrite(env, opi, op, len); diff --git a/src/parse/scan0.c b/src/parse/scan0.c index c237c607..275966ca 100644 --- a/src/parse/scan0.c +++ b/src/parse/scan0.c @@ -187,7 +187,7 @@ ANN m_bool scan0_type_def(const Env env, const Type_Def tdef) { context_global(env); env_push_global(env); } - if (!is_func(env->gwion, base)) { + if (!is_func(env->gwion, base)) { // is_callable if (!tdef->ext->types && (!tdef->ext->array || !tdef->ext->array->exp)) { typedef_simple(env, tdef, base); } else diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 4f5faf19..8438427f 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -536,9 +536,17 @@ ANN m_bool scan1_union_def(const Env env, const Union_Def udef) { #define scan1_stmt_until scan1_stmt_flow #define scan1_stmt_continue dummy_func #define scan1_stmt_break dummy_func -#define scan1_stmt_return scan1_stmt_exp #define scan1_stmt_retry dummy_func +ANN static m_bool scan1_stmt_return(const Env env, const Stmt_Exp stmt) { + if (!env->func) + ERR_B(stmt_self(stmt)->pos, + _("'return' statement found outside function definition")) + if (env->scope->depth <= 2) env->func->memoize = 1; + if(stmt->val) scan1_exp(env, stmt->val); + return GW_OK; +} + ANN static m_bool scan1_stmt_pp(const Env env, const Stmt_PP stmt) { if (stmt->pp_type == ae_pp_include) env->name = stmt->data; return GW_OK; @@ -658,7 +666,7 @@ ANN static inline m_bool scan1_fdef_defined(const Env env, const Func_Def fdef) { const Value v = nspc_lookup_value1(env->curr, fdef->base->xid); if (!v) return GW_OK; - if (is_func(env->gwion, actual_type(env->gwion, v->type))) return GW_OK; + if (is_func(env->gwion, actual_type(env->gwion, v->type))) return GW_OK; // is_callable if ((!env->class_def || !GET_FLAG(env->class_def, final)) && !nspc_lookup_value0(env->curr, fdef->base->xid)) ERR_B(fdef->base->pos, @@ -684,6 +692,11 @@ ANN static m_bool _scan1_func_def(const Env env, const Func_Def fdef) { --env->scope->depth; env->func = former; if (global) env_pop(env, scope); + if ((strcmp(s_name(fdef->base->xid), "@implicit") || fbflag(fdef->base, fbflag_internal)) && !fdef->builtin && fdef->base->ret_type && + fdef->base->ret_type != env->gwion->type[et_void] && fdef->d.code && + !fake.memoize) + ERR_B(fdef->base->td->pos, + _("missing return statement in a non void function %u"), fake.memoize); if (fdef->base->xid == insert_symbol("@gack") && !fake.weight) { gwerr_basic(_("`@gack` operator does not print anything"), NULL, _("use `<<<` `>>>` in the function"), env->name, fdef->base->pos, 0); diff --git a/src/parse/scan2.c b/src/parse/scan2.c index e45c28a2..a68f0131 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -301,7 +301,7 @@ ANN static m_bool scan2_stmt_list(const Env env, Stmt_List l) { ANN static m_bool scan2_func_def_overload(const Env env, const Func_Def f, const Value overload) { const m_bool fptr = is_fptr(env->gwion, overload->type); - if (!is_func(env->gwion, overload->type) || + if (!is_func(env->gwion, overload->type) || // is_fptr is_fptr(env->gwion, overload->type)) { if (!fbflag(f->base, fbflag_internal)) ERR_B(f->base->pos, diff --git a/src/parse/template.c b/src/parse/template.c index 1a9121f1..c3f25aaf 100644 --- a/src/parse/template.c +++ b/src/parse/template.c @@ -114,7 +114,7 @@ static ANN Type scan_func(const Env env, const Type t, const Type_Decl *td) { } static ANN Type maybe_func(const Env env, const Type t, const Type_Decl *td) { - if (is_func(env->gwion, t) && t->info->func->def->base->tmpl) + if (is_func(env->gwion, t) && t->info->func->def->base->tmpl) // is_callable needs type return scan_func(env, t, td); ERR_O(td->pos, _("type '%s' is not template. You should not provide template types"), @@ -122,7 +122,7 @@ static ANN Type maybe_func(const Env env, const Type t, const Type_Decl *td) { } ANN static Type _scan_type(const Env env, const Type t, Type_Decl *td) { - if (tflag(t, tflag_tmpl) && !is_func(env->gwion, t)) { + if (tflag(t, tflag_tmpl) && !is_func(env->gwion, t)) { // is_callable if (tflag(t, tflag_ntmpl) && !td->types) return t; if(!td->types) { const Type new_type = nspc_lookup_type1(env->curr, td->xid); diff --git a/tests/error/name_conflict.gw b/tests/error/name_conflict.gw index ea409add..b2c29453 100644 --- a/tests/error/name_conflict.gw +++ b/tests/error/name_conflict.gw @@ -4,5 +4,5 @@ class C { } class D extends C { - fun int test() {} + fun int test() { return 42;} } -- 2.43.0