]> Nishi Git Mirror - gwion.git/commitdiff
:art: Union as abstract types
authorJérémie Astor <fennecdjay@gmail.com>
Mon, 21 Dec 2020 22:04:55 +0000 (23:04 +0100)
committerJérémie Astor <fennecdjay@gmail.com>
Mon, 21 Dec 2020 22:04:55 +0000 (23:04 +0100)
include/env/data.h [new file with mode: 0644]
include/opcode.h
opcode.txt
src/emit/emit.c
src/lib/engine.c
src/lib/union.c
src/parse/check.c
src/parse/operator.c
src/parse/scan0.c
src/parse/scan1.c
src/vm/vm.c

diff --git a/include/env/data.h b/include/env/data.h
new file mode 100644 (file)
index 0000000..51281f5
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __AST_DATA
+#define __AST_DATA
+
+typedef struct DataTable_* DataTable;
+ANN DataTable new_datatable(MemPool p, size_t sz);
+ANN void datatable_reset(DataTable);
+ANN void free_datatable(DataTable);
+
+ANN struct Type_*   dataget_type  (DataTable, void*);
+//ANN Type   dataget_cast  (Data, void*);
+//ANN Value  dataget_val   (Data, void*);
+//ANN Func   dataget_func  (Data, void*);
+//ANN Nspc   dataget_nspc  (Data, void*);
+//ANN Vector dataget_vec   (Data, void*);
+//ANN Instr  dataget_instr (Data, void*);
+
+ANN void   dataset_type  (DataTable, void*, struct Type_*);
+//ANN void   dataset_cast  (Data, void*);
+//ANN void   dataset_val   (Data, void*);
+//ANN void   dataset_func  (Data, void*);
+//ANN void   dataset_nspc  (Data, void*);
+//ANN void   dataset_vec   (Data, void*);
+//ANN void   dataset_instr (Data, void*);
+#endif
index 84550cfb912dc5aa0587bd11d64b120da51a6286..a94876d0509fd513a9bdcd1d821499077dea5f3a 100644 (file)
@@ -163,6 +163,7 @@ enum {
   eDotMember2,
   eDotMember3,
   eDotMember4,
+  eUnionCheck,
   eUnionMember,
   eUnionMember2,
   eUnionMember3,
@@ -350,6 +351,7 @@ enum {
 #define  DotMember2          (f_instr)eDotMember2
 #define  DotMember3          (f_instr)eDotMember3
 #define  DotMember4          (f_instr)eDotMember4
+#define  UnionCheck          (f_instr)eUnionCheck
 #define  UnionMember         (f_instr)eUnionMember
 #define  UnionMember2        (f_instr)eUnionMember2
 #define  UnionMember3        (f_instr)eUnionMember3
index 58eae8de6d87100117c44488d6e16a5103dc13b7..840be081f0f68bbcd0910018d70cd44c53ac7134 100644 (file)
@@ -160,6 +160,7 @@ DotMember
 DotMember2
 DotMember3
 DotMember4
+UnionCheck
 UnionMember
 UnionMember2
 UnionMember3
index 724cd07587d1ea56976556200e6798b10513dba7..a0969d8e37a0f05f765c83237798136f1d0e1974 100644 (file)
@@ -1736,13 +1736,20 @@ ANN static m_bool emit_stmt_exp(const Emitter emit, const struct Stmt_Exp_* exp)
   return exp->val ? emit_exp(emit, exp->val) : GW_OK;
 }
 
+ANN static inline m_bool emit_exp1(const Emitter emit, const Exp e) {
+  const Exp next = e->next;
+  e->next = NULL;
+  const m_bool ret = emit_exp(emit, e);
+  e->next = next;
+  return ret;
+}
+
 ANN static m_bool emit_case_head(const Emitter emit, const Exp base,
     const Exp e, const Symbol op, const Vector v) {
-  CHECK_BB(emit_exp(emit, base))
-  CHECK_BB(emit_exp_pop_next(emit, e))
-  const m_int size = -exp_size(e);
-  emit_exp_addref(emit, base, -exp_totalsize(base) + size);
-  emit_exp_addref1(emit, e, size);
+  CHECK_BB(emit_exp1(emit, base))
+  emit_exp_addref1(emit, base, -exp_size(base));
+  CHECK_BB(emit_exp1(emit, e))
+  emit_exp_addref1(emit, e, -exp_size(e));
   const Exp_Binary bin = { .lhs=base, .rhs=e, .op=op };
   struct Exp_ ebin = { .d={.exp_binary=bin}, };
   struct Op_Import opi = { .op=op, .lhs=base->type, .rhs=e->type,
@@ -1767,51 +1774,92 @@ ANN static m_bool emit_case_body(const Emitter emit, const struct Stmt_Match_* s
 
 ANN static m_bool case_value(const Emitter emit, const Exp base, const Exp e) {
   const Value v = e->d.prim.value;
+printf("base->type %s\n", base->type->name);
   v->from->offset = emit_local(emit, base->type);
-  CHECK_BB(emit_exp(emit, base))
-  emit_exp_addref(emit, base, -exp_totalsize(base));
-  regpop(emit, base->type->size);
   const Instr instr = emit_add_instr(emit, Reg2Mem4);
   instr->m_val = v->from->offset;
   instr->m_val2 = base->type->size;
   return GW_OK;
 }
 
+// should be in src/lib/union.c
+static const f_instr unionmember[]  = { UnionMember, UnionMember2, UnionMember3, UnionMember4 };
 
 #define CASE_PASS (Symbol)1
-ANN static Symbol case_op(const Emitter emit, const Exp base, const Exp e) {
+ANN static Symbol case_op(const Emitter emit, const Exp base, const Exp e, const Vector vec, const uint n) {
   if(e->exp_type == ae_exp_primary) {
     if(e->d.prim.prim_type == ae_prim_id) {
       if(e->d.prim.d.var == insert_symbol("_"))
         return CASE_PASS;
       if(!nspc_lookup_value1(emit->env->curr, e->d.prim.d.var)) {
+        if(!n) {
+          CHECK_BO(emit_exp(emit, base))
+          emit_exp_addref(emit, base, -exp_totalsize(base));
+          regpop(emit, base->type->size);
+        }
         CHECK_BO(case_value(emit, base, e))
         return CASE_PASS;
       }
     }
+  } else if(isa(actual_type(emit->gwion, base->type), emit->gwion->type[et_union]) > 0 && e->exp_type == ae_exp_call) {
+    const Exp func = e->d.exp_call.func;
+    if(func->d.prim.prim_type == ae_prim_id) {
+      const Map map = &actual_type(emit->gwion, base->type)->nspc->info->value->map;
+      for(m_uint i = 0; i < map_size(map); ++i) {
+         if(VKEY(map, i) == (m_uint)func->d.prim.d.var) {
+          const Value v = (Value)VVAL(map, i);
+          if(v) {
+            if(!n)
+              CHECK_BO(emit_exp(emit, base))
+            else
+              regpush(emit, SZ_INT);
+            const Instr check = emit_add_instr(emit, UnionCheck);
+            check->m_val2 = i;
+            vector_add(vec, (m_uint)check);
+            const Instr instr = emit_kind(emit, v->type->size, 0 /*emit_addr*/, unionmember);
+            instr->m_val = i;
+            regpop(emit, v->type->size);
+            case_op(emit, e->d.exp_call.args, e->d.exp_call.args, vec, i + 1);
+            return CASE_PASS;
+          }
+        }
+      }
+    }
   }
-  return insert_symbol("==");
+  if(!n)
+    return insert_symbol("==");
+  regpush(emit, SZ_INT);
+  CHECK_BO(emit_exp(emit, e))
+  const Exp_Binary bin = { .lhs=base, .rhs=e, .op=insert_symbol("==") };
+  struct Exp_ ebin = { .d={.exp_binary=bin}, };
+  struct Op_Import opi = { .op=insert_symbol("=="), .lhs=base->type, .rhs=e->type,
+    .data=(uintptr_t)&ebin.d.exp_binary, .pos=e->pos, .op_type=op_binary };
+  CHECK_BO(op_emit(emit, &opi))
+  const Instr instr = emit_add_instr(emit, BranchEqInt);
+  vector_add(vec, (vtype)instr);
 }
 
 ANN static m_bool _emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt,
-    const Vector v) {
+    const Vector v, struct Match_ *const match) {
   Exp e = stmt->cond;
   const Map map = &emit->env->scope->match->map;
   for(m_uint i = 0; i < map_size(map) && e; e = e->next, ++i) {
     const Exp base = (Exp)VKEY(map, i);
-    const Symbol op = case_op(emit, base, e);
+    const Symbol op = case_op(emit, base, e, v, 0);
     if(op != CASE_PASS)
       CHECK_BB(emit_case_head(emit, base, e, op, v))
+else puts("pass");
   }
   CHECK_BB(emit_case_body(emit, stmt))
   return GW_OK;
 }
 
-ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt) {
+ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt,
+      struct Match_ *match) {
   emit_push_scope(emit);
   struct Vector_ v;
   vector_init(&v);
-  const m_bool ret = _emit_stmt_match_case(emit, stmt, &v);
+  const m_bool ret = _emit_stmt_match_case(emit, stmt, &v, match);
   emit_pop_scope(emit);
   for(m_uint i = 0; i < vector_size(&v); ++i) {
     const Instr instr = (Instr)vector_at(&v, i);
@@ -1821,7 +1869,7 @@ ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Mat
   return ret;
 }
 
-ANN static inline void match_unvec(struct Match_ *const match , const m_uint pc) {
+ANN static inline void match_unvec(struct Match_ *const match, const m_uint pc) {
   const Vector vec = &match->vec;
   for(m_uint i = 0; i < vector_size(vec); ++i) {
     const Instr instr = (Instr)VPTR(vec, i);
@@ -1830,8 +1878,8 @@ ANN static inline void match_unvec(struct Match_ *const match , const m_uint pc)
   vector_release(vec);
 }
 
-ANN static m_bool emit_stmt_cases(const Emitter emit, Stmt_List list) {
-  do CHECK_BB(emit_stmt_match_case(emit, &list->stmt->d.stmt_match))
+ANN static m_bool emit_stmt_cases(const Emitter emit, Stmt_List list, struct Match_ *match) {
+  do CHECK_BB(emit_stmt_match_case(emit, &list->stmt->d.stmt_match, match))
   while((list = list->next));
   return GW_OK;
 }
@@ -1841,7 +1889,7 @@ ANN static m_bool emit_match(const Emitter emit, const struct Stmt_Match_* stmt)
     CHECK_BB(emit_stmt(emit, stmt->where, 1))
   MATCH_INI(emit->env->scope)
   vector_init(&m.vec);
-  const m_bool ret = emit_stmt_cases(emit, stmt->list);
+  const m_bool ret = emit_stmt_cases(emit, stmt->list, &m);
   match_unvec(&m, emit_code_size(emit));
   MATCH_END(emit->env->scope)
   return ret;
index 9dc2eaf6f503549db2288e55824731288fff21a4..69a526b5e83b0e5a7ad5cc3a680e0e8e2c10db72 100644 (file)
@@ -146,7 +146,6 @@ ANN static m_bool import_core_libs(const Gwi gwi) {
   GWI_BB(import_string(gwi))
   GWI_BB(import_shred(gwi))
   GWI_BB(import_modules(gwi))
-  GWI_BB(import_union(gwi))
   GWI_BB(import_foreach(gwi))
 
   GWI_BB(gwi_oper_ini(gwi, "@Class", "@Class", "int"))
@@ -156,11 +155,11 @@ ANN static m_bool import_core_libs(const Gwi gwi) {
   GWI_BB(gwi_oper_end(gwi, ">",  instr_class_gt))
   GWI_BB(gwi_oper_end(gwi, "<=", instr_class_le))
   GWI_BB(gwi_oper_end(gwi, "<",  instr_class_lt))
-
+/*
   GWI_BB(gwi_oper_ini(gwi, NULL, (m_str)OP_ANY_TYPE, NULL))
   GWI_BB(gwi_oper_add(gwi, opck_basic_ctor))
   GWI_BB(gwi_oper_end(gwi, "@ctor", NULL))
-
+*/
   GWI_BB(gwi_oper_ini(gwi, "@Compound", (m_str)OP_ANY_TYPE, NULL))
   GWI_BB(gwi_oper_add(gwi, opck_object_dot))
   GWI_BB(gwi_oper_emi(gwi, opem_object_dot))
@@ -171,6 +170,7 @@ ANN static m_bool import_core_libs(const Gwi gwi) {
   GWI_BB(gwi_oper_emi(gwi, opem_object_dot))
   GWI_BB(gwi_oper_end(gwi, "@dot", NULL))
 
+  GWI_BB(import_union(gwi))
   return GW_OK;
 }
 
index 6308bb60ff4a41a1ccfc1b6acaf632687c284058..fff775c1458a6539b47c9bfd8c66b46c26ee2e50 100644 (file)
@@ -52,7 +52,7 @@ static OP_EMIT(opem_union_dot) {
       const Value v = (Value)VVAL(map, i);
       const uint emit_addr = exp_getvar(exp_self(member));
       const Instr instr = emit_kind(emit, v->type->size, emit_addr, unionmember);
-      instr->m_val = i + 1;
+      instr->m_val = i;// + 1;
       instr->m_val2 = v->type->size;
       return GW_OK;
     }
@@ -89,7 +89,8 @@ static OP_CHECK(opck_union_is) {
       e->exp_type = ae_exp_binary;
       e->d.exp_binary.lhs = cpy_exp(env->gwion->mp, exp_func);
       e->d.exp_binary.lhs->d.exp_dot.xid = insert_symbol(env->gwion->st, "@index");
-      e->d.exp_binary.rhs = new_prim_int(env->gwion->mp, i+1, e->pos);
+//      e->d.exp_binary.rhs = new_prim_int(env->gwion->mp, i+1, e->pos);
+      e->d.exp_binary.rhs = new_prim_int(env->gwion->mp, i, e->pos);
       free_exp(env->gwion->mp, exp_func);
       free_exp(env->gwion->mp, exp_args);
       e->d.exp_binary.op = insert_symbol(env->gwion->st, "==");
@@ -104,6 +105,54 @@ static MFUN(union_is) {
   *(m_uint*)RETURN = *(m_uint*)MEM(SZ_INT) == *(m_uint*)o->data;
 }
 
+static OP_CHECK(opck_union_ctor) {
+  Exp_Call *call = (Exp_Call*)data;
+  const Exp name = call->args;
+  if(!name || !name->next || name->next->next)
+    ERR_N(name->pos, "Union constructor takes two arguments, "
+         "'id' and 'value'")
+  if(name->exp_type != ae_exp_primary ||
+        name->d.prim.prim_type != ae_prim_id)
+    return NULL;
+    const Exp val = name->next;
+    const Type base = actual_type(env->gwion, call->func->type);
+    const Map map = &base->nspc->info->value->map;
+    for(m_uint i = 0; i < map_size(map); ++i) {
+    if(VKEY(map, i) == (m_uint)name->d.prim.d.var) {
+      const Value v = (Value)VVAL(map, i);
+      name->d.prim.prim_type = ae_prim_num;
+      name->d.prim.d.num = i;
+      name->type = env->gwion->type[et_int];
+      DECL_ON(const Type, t, = check_exp(env, val))
+      if(isa(t, v->type) < 0) {
+        ERR_N(val->pos, "Invalid type '%s' for '%s', should be '%s'",
+           t->name, v->name, v->type->name)
+      }
+      return base;
+    }
+  }
+  return NULL;
+}
+
+static INSTR(UnionCtor) {
+  POP_REG(shred, instr->m_val2);
+  POP_REG(shred, SZ_INT);
+  const Type t = *(Type*)REG(-SZ_INT*2);
+  const m_uint index = *(m_uint*)REG(-SZ_INT);
+  const M_Object o = *(M_Object*)REG(-SZ_INT) = new_object(shred->info->vm->gwion->mp, NULL, (Type)instr->m_val);
+  *(m_uint*)o->data = index;// + 1;
+  memcpy(o->data + SZ_INT, REG(0), instr->m_val2);
+}
+
+static OP_EMIT(opem_union_ctor) {
+  Exp_Call *call = (Exp_Call*)data;
+  const Type base = actual_type(emit->gwion, call->func->type);
+  const Instr instr = emit_add_instr(emit, UnionCtor);
+  instr->m_val = base;
+  instr->m_val2 = call->args->next->type->size;
+  return GW_OK;
+}
+
 ANN GWION_IMPORT(union) {
   const Type t_none = gwi_mk_type(gwi, "None", 0, NULL);
   GWI_BB(gwi_set_global_type(gwi, t_none, et_none))
@@ -125,6 +174,12 @@ ANN GWION_IMPORT(union) {
   GWI_BB(gwi_func_arg(gwi, "int", "member"))
   GWI_BB(gwi_func_end(gwi, union_is, ae_flag_none))
   GWI_BB(gwi_class_end(gwi))
+
+  GWI_BB(gwi_oper_ini(gwi, NULL, "@Union", NULL))
+  GWI_BB(gwi_oper_add(gwi, opck_union_ctor))
+  GWI_BB(gwi_oper_emi(gwi, opem_union_ctor))
+  GWI_BB(gwi_oper_end(gwi, "@ctor", NULL))
+
   const Func f = (Func)vector_front(&t_union->nspc->info->vtable);
   const struct Op_Func opfunc = { .ck=opck_union_is };
   const struct Op_Import opi = { .rhs=f->value_ref->type,
index 6c936de78678e818b8122bef61d43d1ba1356bf7..0562f8bfcf085e78ade228e86fb87e1d3d8c454d 100644 (file)
@@ -710,12 +710,10 @@ ANN Type check_exp_call1(const Env env, const Exp_Call *exp) {
   if(!ret)
     return exp_self(exp)->type;
   const Type t = actual_type(env->gwion, exp->func->type);
-  if(isa(t, env->gwion->type[et_function]) < 0) {
-    // use func flag?
+  if(isa(t, env->gwion->type[et_function]) < 0) { // use func flag?
     struct Op_Import opi = { .op=insert_symbol("@ctor"), .rhs=actual_type(env->gwion, exp->func->type),
       .data=(uintptr_t)exp, .pos=exp_self(exp)->pos, .op_type=op_exp };
     const Type t = op_check(env, &opi);
-//    exp_self(exp)->info->nspc = t ? t->info->owner : NULL;
     return t;
   }
   if(t == env->gwion->type[et_lambda])
@@ -1028,23 +1026,34 @@ ANN static m_bool check_stmt_exp(const Env env, const Stmt_Exp stmt) {
   return stmt->val ? check_exp(env, stmt->val) ? 1 : -1 : 1;
 }
 
-ANN static Value match_value(const Env env, const Exp_Primary* prim, const m_uint i) {
+ANN static Value match_value(const Env env, const Type base, const Exp_Primary* prim, const m_uint i) {
   const Symbol sym = prim->d.var;
-  const Value v = new_value(env->gwion->mp,
-     ((Exp)VKEY(&env->scope->match->map, i))->type, s_name(sym));
+  const Value v = new_value(env->gwion->mp, base, s_name(sym));
   set_vflag(v, vflag_valid);
   nspc_add_value(env->curr, sym, v);
   VVAL(&env->scope->match->map, i) = (vtype)v;
   return v;
 }
 
-ANN static Symbol case_op(const Env env, const Exp e, const m_uint i) {
+ANN static Symbol case_op(const Env env, const Type base, const Exp e, const m_uint i) {
   if(e->exp_type == ae_exp_primary) {
     if(e->d.prim.prim_type == ae_prim_id) {
       if(e->d.prim.d.var == insert_symbol("_"))
         return NULL;
       if(!nspc_lookup_value1(env->curr, e->d.prim.d.var)) {
-        e->d.prim.value = match_value(env, &e->d.prim, i);
+        e->d.prim.value = match_value(env, base, &e->d.prim, i);
+        return NULL;
+      }
+    }
+  } else if(isa(actual_type(env->gwion, base), env->gwion->type[et_union]) > 0 && e->exp_type == ae_exp_call) {
+    const Exp func = e->d.exp_call.func;
+    if(func->d.prim.prim_type == ae_prim_id) {
+      const Value v= find_value(actual_type(env->gwion, base), func->d.prim.d.var);
+      if(v) {
+        if(!i)
+          e->type = v->type;
+        case_op(env, v->type, e->d.exp_call.args, i);
+        e->d.exp_call.args->type = v->type;
         return NULL;
       }
     }
@@ -1058,17 +1067,19 @@ ANN static m_bool match_case_exp(const Env env, Exp e) {
     if(!e)
       ERR_B(last->pos, _("no enough to match"))
     last = e;
-    const Symbol op = case_op(env, e, i);
+    const Exp base = (Exp)VKEY(&env->scope->match->map, i);
+    const Symbol op = case_op(env, base->type, e, i);
     if(op) {
-      const Exp base = (Exp)VKEY(&env->scope->match->map, i);
-      CHECK_OB(check_exp(env, e))
+      const Exp next = e->next;
+      e->next = NULL;
+      const Type t = check_exp(env, e);
+      e->next = next;
+      CHECK_OB(t)
       Exp_Binary bin = { .lhs=base, .rhs=e, .op=op };
       struct Exp_ ebin = { .d={.exp_binary=bin} };
       struct Op_Import opi = { .op=op, .lhs=base->type, .rhs=e->type,
         .data=(uintptr_t)&ebin.d.exp_binary, .pos=e->pos, .op_type=op_binary };
       CHECK_OB(op_check(env, &opi))
-//      e->info->nspc= info.nspc;
-      return GW_OK;
     }
   }
   if(e)
index 0beaf43b06f0211bd1a20322bb016a8291b2d580..479dc5bb879e9c9899fc74155d9cc1480f99511c 100644 (file)
@@ -34,6 +34,10 @@ ANN void free_op_map(Map map, struct Gwion_ *gwion) {
   map_release(map);
 }
 
+static m_str type_name(const Type t) {
+  return t ? t == OP_ANY_TYPE ? "any" : t->name : "";
+}
+
 static m_bool op_match(const restrict Type t, const restrict Type mo) {
   if(t == OP_ANY_TYPE || mo == OP_ANY_TYPE)
     return GW_OK;
@@ -102,10 +106,6 @@ ANN static Vector op_vector(MemPool p, const struct OpChecker *ock) {
   return create;
 }
 
-static m_str type_name(const Type t) {
-  return t ? t == OP_ANY_TYPE ? "any" : t->name : "";
-}
-
 ANN static m_bool _op_exist(const struct OpChecker* ock, const Nspc n) {
   const Vector v = (Vector)map_get(&n->info->op_map, (vtype)ock->opi->op);
   if(!v || !operator_find2(v, ock->opi->lhs, ock->opi->rhs))
index 0077367ad80a8c38a0d7ca066c312cb55c7ce779..291dc8fef50c9fcb014bfea5d96685cfde37d7a3 100644 (file)
@@ -218,7 +218,7 @@ ANN static Type union_type(const Env env, const Symbol s) {
   t->info->tuple = new_tupleform(env->gwion->mp, NULL); // ???
   add_type(env, env->curr, t);
   mk_class(env, t);
-  SET_FLAG(t, final);
+  SET_FLAG(t, final | ae_flag_abstract);
   return t;
 }
 
index 7c75c0f266f16c72e2dd6626493c009d7d18ec27..0835087a0d82c6c2a2322933c3433ad27284159f 100644 (file)
@@ -414,7 +414,7 @@ ANN static inline m_bool scan1_union_def_inner_loop(const Env env, Union_Def ude
     if(t->size > sz)
       sz = t->size;
   } while((l = l->next));
-udef->type->nspc->info->offset = SZ_INT +sz;
+  udef->type->nspc->info->offset = SZ_INT +sz;
   return GW_OK;
 }
 
index 311cc85b5a6fd21e90faeb67cca8c353c1763f0a..3dd682e7d299ee0d1cfcf60db2e894ff68661b75 100644 (file)
@@ -324,7 +324,7 @@ ANN void vm_run(const VM* vm) { // lgtm [cpp/use-of-goto]
     &&arrayappend, &&autoloop, &&autoloopptr, &&autoloopcount, &&arraytop, &&arrayaccess, &&arrayget, &&arrayaddr, &&arrayvalid,
     &&newobj, &&addref, &&addrefaddr, &&objassign, &&assign, &&remref,
     &&except, &&allocmemberaddr, &&dotmember, &&dotfloat, &&dotother, &&dotaddr,
-    &&unionint, &&unionfloat, &&unionother, &&unionaddr,
+    &&unioncheck, &&unionint, &&unionfloat, &&unionother, &&unionaddr,
     &&staticint, &&staticfloat, &&staticother,
     &&upvalueint, &&upvaluefloat, &&upvalueother, &&upvalueaddr,
     &&dotfunc, &&dotstaticfunc,
@@ -833,6 +833,14 @@ dotaddr:
     continue;\
   }
 
+unioncheck:
+{
+  if(*(m_uint*)(*(M_Object*)(reg-SZ_INT))->data != VAL2) {
+    reg -= SZ_INT;
+    PC_DISPATCH(VAL);
+  }
+  DISPATCH()
+}
 unionint:
 {
   UNION_CHECK