]> Nishi Git Mirror - gwion.git/commitdiff
:art: Improve return handling
authorJérémie Astor <fennecdjay@gmail.com>
Sun, 15 May 2022 18:50:09 +0000 (20:50 +0200)
committerJérémie Astor <fennecdjay@gmail.com>
Sun, 15 May 2022 18:50:09 +0000 (20:50 +0200)
15 files changed:
include/env/func.h
src/emit/emit.c
src/lib/deep_equal.c
src/lib/engine.c
src/lib/lib_func.c
src/lib/object_op.c
src/lib/union.c
src/parse/check.c
src/parse/check_traits.c
src/parse/operator.c
src/parse/scan0.c
src/parse/scan1.c
src/parse/scan2.c
src/parse/template.c
tests/error/name_conflict.gw

index 42230c69bf5fd085d69a3adadb321dab83f72adc..db728f35f65c5f857c55b66b2b332ff25a16b2a2 100644 (file)
@@ -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;
index 50b8fe2c68afee7662bb9cd97e85304e6fc51cc4..e77094ff0f4f0040b8e9d3e65e4ee2af342bc569 100644 (file)
@@ -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))
index 93713cb792aba2dbebc4d44e04f18f2db50e0f67..28d1ccbb7166fdd4edc326cb8be26f7cc5e9c613 100644 (file)
@@ -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);
   }
 }
index 49c5afa8b2ac5d308f4ae9d734fd8d83ae8bc0b3..fe93fe1b96e440f5320e124d702db0b4f9ade554 100644 (file)
@@ -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;
 }
 
index 5d5cf21134232e806413439e29f2ff0f8b0ebfa6..6e4b50e3666d981b4119e840b3c65a66455c9761 100644 (file)
@@ -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 {
index 984bf45beb52453ee3a19377f22dc688f608de5c..d748b5e472668cd4c48ccdf91564edae93508e34 100644 (file)
@@ -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)) {
index 369c331d38e9d535a20a9a508381c15587c99d8f..a3cf314ef1dc1587e72c40c95e19e60e1fe19653 100644 (file)
@@ -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);
index 2366510dc8a2ebf3933f9429d60a85d75d8a9635..f3cb165f0b5dbc395fc50dadf3deea562ecd8c6a 100644 (file)
@@ -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;
 }
 
index aba6c009a847a69521c440736be8017bc98680f5..2c0dad3ae5f98ae7ad364c3b279672b4233de1d3 100644 (file)
@@ -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;
index 5179dd4488f4e3c9075193952dc1c37089548b3c..8f94d9fc4c999309f6aae9a542f5b4fb3f05fb75 100644 (file)
@@ -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);
index c237c60783dd111e58816fe8cfacc307d9d472df..275966ca989dd086dfe6fa7fe2c9886584e07872 100644 (file)
@@ -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
index 4f5faf19ed8a91c3c192bd1c3e455865ab49f350..8438427f1fc5732c06748272d1dffdccc0f868a7 100644 (file)
@@ -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);
index e45c28a26048308349c19b427d98e4b000fc0278..a68f0131d4e65e4d95d0b3e709802447ce5d9ae2 100644 (file)
@@ -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,
index 1a9121f1e0f705edc150beff33347736cc7eb785..c3f25aafc9ec026c9c13ccab5ddfdd69d44bc54a 100644 (file)
@@ -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);
index ea409add8c7ac6832747206965dfd9a68be916be..b2c2945381a8b4443a6f2658e36bc934cb47a1ce 100644 (file)
@@ -4,5 +4,5 @@ class C {
 }
 
 class D extends C {
-  fun int test() {}
+  fun int test() { return 42;}
 }