Improve type deduction for cond and x or y

pull/216/head
XmiliaH 3 years ago
parent 8e815bd67a
commit f56509037a

@ -1103,6 +1103,10 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
} }
static int ravi_is_falsish(ravitype_t type) {
return (type & RAVI_TTAG_FALSISH) || (type == RAVI_TANY || type == RAVI_TNIL || type == RAVI_TBOOLEAN || type == RAVI_TFUNCTION || type == RAVI_TSTRING || type == RAVI_TUSERDATA);
}
/* /*
** Emit code to go through if 'e' is true, jump otherwise. ** Emit code to go through if 'e' is true, jump otherwise.
*/ */
@ -1120,7 +1124,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
break; break;
} }
default: { default: {
if (e->ravi_type == RAVI_TNIL || e->ravi_type == RAVI_TANY || e->ravi_type == RAVI_TBOOLEAN) { if (ravi_is_falsish(e->ravi_type)) {
pc = jumponcond(fs, e, 0); /* jump when false */ pc = jumponcond(fs, e, 0); /* jump when false */
} }
else { else {
@ -1279,7 +1283,7 @@ static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
break; break;
} }
e->u.info = luaK_codeABC(fs, OP_BNOT, 0, r, 0); e->u.info = luaK_codeABC(fs, OP_BNOT, 0, r, 0);
e->ravi_type = e->ravi_type == RAVI_TNUMFLT ? RAVI_TNUMINT : RAVI_TANY; e->ravi_type = e->ravi_type == RAVI_TNUMFLT || e->ravi_type == RAVI_TNUMBER ? RAVI_TNUMINT : RAVI_TANY;
break; break;
case OP_LEN: case OP_LEN:
e->u.info = luaK_codeABC(fs, OP_LEN, 0, r, 0); e->u.info = luaK_codeABC(fs, OP_LEN, 0, r, 0);
@ -1302,7 +1306,7 @@ static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
break; break;
case OP_UNM: case OP_UNM:
e->u.info = luaK_codeABC(fs, OP_UNM, 0, r, 0); e->u.info = luaK_codeABC(fs, OP_UNM, 0, r, 0);
if (e->ravi_type != RAVI_TNUMINT && e->ravi_type != RAVI_TNUMFLT) { if (e->ravi_type != RAVI_TNUMINT && e->ravi_type != RAVI_TNUMFLT && e->ravi_type != RAVI_TNUMBER) {
e->ravi_type = RAVI_TANY; e->ravi_type = RAVI_TANY;
} }
break; break;
@ -1334,51 +1338,60 @@ static void codebinexpval (FuncState *fs, OpCode op,
#define RAVI_OPCODE_GENERIC(op, t) OP_##op #define RAVI_OPCODE_GENERIC(op, t) OP_##op
#define RAVI_COMMUTATIVE(op, t) luaK_codeABC(fs, t(op, FI), 0, rk2, rk1) #define RAVI_COMMUTATIVE(op, t) luaK_codeABC(fs, t(op, FI), 0, rk2, rk1)
#define RAVI_NON_COMMUTATIVE(op, t) luaK_codeABC(fs, t(op, IF), 0, rk1, rk2) #define RAVI_NON_COMMUTATIVE(op, t) luaK_codeABC(fs, t(op, IF), 0, rk1, rk2)
#define RAVI_GEN_ARITH(op, co, ii, t) \ #define RAVI_GEN_ARITH(op, co, ii, t) \
case OP_##op: \ case OP_##op: \
if (e1->ravi_type == RAVI_TNUMFLT) { \ if (e1->ravi_type == RAVI_TNUMFLT) { \
if (e2->ravi_type == RAVI_TNUMFLT) { \ if (e2->ravi_type == RAVI_TNUMFLT) { \
e1->u.info = luaK_codeABC(fs, t(op, FF), 0, rk1, rk2); \ e1->u.info = luaK_codeABC(fs, t(op, FF), 0, rk1, rk2); \
e1->ravi_type = RAVI_TNUMFLT; \ e1->ravi_type = RAVI_TNUMFLT; \
break; \ break; \
} \ } \
else if (e2->ravi_type == RAVI_TNUMINT) { \ else if (e2->ravi_type == RAVI_TNUMINT) { \
e1->u.info = luaK_codeABC(fs, t(op, FI), 0, rk1, rk2); \ e1->u.info = luaK_codeABC(fs, t(op, FI), 0, rk1, rk2); \
e1->ravi_type = RAVI_TNUMFLT; \ e1->ravi_type = RAVI_TNUMFLT; \
break; \ break; \
} \ } \
} \ } \
else if (e1->ravi_type == RAVI_TNUMINT) { \ else if (e1->ravi_type == RAVI_TNUMINT) { \
if (e2->ravi_type == RAVI_TNUMFLT) { \ if (e2->ravi_type == RAVI_TNUMFLT) { \
e1->u.info = co(op, t); \ e1->u.info = co(op, t); \
e1->ravi_type = RAVI_TNUMFLT; \ e1->ravi_type = RAVI_TNUMFLT; \
break; \ break; \
} \ } \
else if (e2->ravi_type == RAVI_TNUMINT) { \ else if (e2->ravi_type == RAVI_TNUMINT) { \
e1->u.info = luaK_codeABC(fs, t(op, II), 0, rk1, rk2); \ e1->u.info = luaK_codeABC(fs, t(op, II), 0, rk1, rk2); \
e1->ravi_type = ii; \ e1->ravi_type = ii; \
break; \ break; \
} \ } \
} \ } \
e1->u.info = luaK_codeABC(fs, OP_##op, 0, rk1, rk2); \ e1->u.info = luaK_codeABC(fs, OP_##op, 0, rk1, rk2); \
e1->ravi_type = RAVI_TANY; \ if ((e1->ravi_type == RAVI_TNUMFLT || e1->ravi_type == RAVI_TNUMINT || e1->ravi_type == RAVI_TNUMBER) && \
(e2->ravi_type == RAVI_TNUMFLT || e2->ravi_type == RAVI_TNUMINT || e2->ravi_type == RAVI_TNUMBER)) { \
e1->ravi_type = (ii == RAVI_TNUMINT) && (e1->ravi_type == RAVI_TNUMINT || e1->ravi_type == RAVI_TNUMBER) && \
(e2->ravi_type == RAVI_TNUMINT || e2->ravi_type == RAVI_TNUMBER) \
? RAVI_TNUMBER \
: RAVI_TNUMFLT; \
} \
else { \
e1->ravi_type = RAVI_TANY; \
} \
break break
#define RAVI_GEN_INT_OP(op) \ #define RAVI_GEN_INT_OP(op) \
case OP_##op: \ case OP_##op: \
if (e1->ravi_type == RAVI_TNUMINT && e2->ravi_type == RAVI_TNUMINT) { \ if (e1->ravi_type == RAVI_TNUMINT && e2->ravi_type == RAVI_TNUMINT) { \
e1->u.info = luaK_codeABC(fs, OP_RAVI_##op##_II, 0, rk1, rk2); \ e1->u.info = luaK_codeABC(fs, OP_RAVI_##op##_II, 0, rk1, rk2); \
e1->ravi_type = RAVI_TNUMINT; \ e1->ravi_type = RAVI_TNUMINT; \
} \ } \
else if ((e1->ravi_type == RAVI_TNUMFLT || e1->ravi_type == RAVI_TNUMINT) && \ else if ((e1->ravi_type == RAVI_TNUMFLT || e1->ravi_type == RAVI_TNUMINT || e1->ravi_type == RAVI_TNUMBER) && \
(e2->ravi_type == RAVI_TNUMFLT || e2->ravi_type == RAVI_TNUMINT)) { \ (e2->ravi_type == RAVI_TNUMFLT || e2->ravi_type == RAVI_TNUMINT || e2->ravi_type == RAVI_TNUMBER)) { \
e1->u.info = luaK_codeABC(fs, OP_##op, 0, rk1, rk2); \ e1->u.info = luaK_codeABC(fs, OP_##op, 0, rk1, rk2); \
e1->ravi_type = RAVI_TNUMINT; \ e1->ravi_type = RAVI_TNUMINT; \
} \ } \
else { \ else { \
e1->u.info = luaK_codeABC(fs, OP_##op, 0, rk1, rk2); \ e1->u.info = luaK_codeABC(fs, OP_##op, 0, rk1, rk2); \
e1->ravi_type = RAVI_TANY; \ e1->ravi_type = RAVI_TANY; \
} \ } \
break break
switch (op) { switch (op) {
@ -1654,41 +1667,35 @@ void luaK_posfix (FuncState *fs, BinOpr op,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
switch (op) { switch (op) {
case OPR_AND: { case OPR_AND: {
lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */
luaK_dischargevars(fs, e2); luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->f, e1->f); luaK_concat(fs, &e2->f, e1->f);
if (e1->ravi_type == RAVI_TNIL) { if (ravi_is_falsish(e1->ravi_type)) {
/* nil and something is still nil. */ if (!ravi_is_falsish(e2->ravi_type))
e2->ravi_type = RAVI_TNIL; e2->ravi_type |= RAVI_TTAG_FALSISH;
}
else if (e1->ravi_type == RAVI_TBOOLEAN || e1->ravi_type == RAVI_TANY) {
/* In these cases the 'and' can go both ways. */
if (e2->ravi_type != e1->ravi_type)
e2->ravi_type = RAVI_TANY;
}
else {
/* Nothing to do here, since the first arg is always truish and therefore the second arg will be used every
* time. */
} }
*e1 = *e2; *e1 = *e2;
break; break;
} }
case OPR_OR: { case OPR_OR: {
lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */
luaK_dischargevars(fs, e2); luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->t, e1->t); luaK_concat(fs, &e2->t, e1->t);
if (e1->ravi_type == RAVI_TNIL) { if (!ravi_is_falsish(e1->ravi_type)) {
/* Nothing to do here, since the first arg is always truish and therefore the second arg will be used every e2->ravi_type = e1->ravi_type;
* time. */
}
else if (e1->ravi_type == RAVI_TBOOLEAN || e1->ravi_type == RAVI_TANY) {
/* In these cases the 'or' can go both ways. */
if (e2->ravi_type != e1->ravi_type)
e2->ravi_type = RAVI_TANY;
} }
else { else {
/* In this case the first argument is truish and will be the return from 'or' */ ravitype_t left = e1->ravi_type & ~RAVI_TTAG_FALSISH;
e2->ravi_type = e1->ravi_type; ravitype_t right = e2->ravi_type & ~RAVI_TTAG_FALSISH;
if (left != right) {
if ((left == RAVI_TNUMBER || left == RAVI_TNUMFLT || left == RAVI_TNUMINT) &&
(right == RAVI_TNUMBER || right == RAVI_TNUMFLT || right == RAVI_TNUMINT)) {
e2->ravi_type = RAVI_TNUMBER | (e2->ravi_type & RAVI_TTAG_FALSISH);
}
else {
e2->ravi_type = RAVI_TANY;
}
}
} }
*e1 = *e2; *e1 = *e2;
break; break;

@ -65,7 +65,9 @@ typedef enum {
RAVI_TSTRING, /* string */ RAVI_TSTRING, /* string */
RAVI_TNIL, /* NIL */ RAVI_TNIL, /* NIL */
RAVI_TBOOLEAN, /* boolean */ RAVI_TBOOLEAN, /* boolean */
RAVI_TUSERDATA /* userdata or lightuserdata */ RAVI_TUSERDATA, /* userdata or lightuserdata */
RAVI_TNUMBER, /* either an integer or a number */
RAVI_TTAG_FALSISH = 0x80
} ravitype_t; } ravitype_t;
/* /*

@ -68,6 +68,7 @@ void ravi_set_debuglevel(int level) { ravi_parser_debug = level; }
/* RAVI - return the type name */ /* RAVI - return the type name */
const char *raviY_typename(ravitype_t tt) { const char *raviY_typename(ravitype_t tt) {
tt &= ~RAVI_TTAG_FALSISH;
switch (tt) { switch (tt) {
case RAVI_TNIL: case RAVI_TNIL:
return "nil"; return "nil";
@ -89,6 +90,8 @@ const char *raviY_typename(ravitype_t tt) {
return "userdata"; return "userdata";
case RAVI_TTABLE: case RAVI_TTABLE:
return "table"; return "table";
case RAVI_TNUMBER:
return "number|float";
default: default:
return "?"; return "?";
} }

@ -1205,31 +1205,22 @@ void luaV_finishOp (lua_State *L) {
Protect(luaV_finishset(L,t,k,v,slot)); } Protect(luaV_finishset(L,t,k,v,slot)); }
int raviV_checktype(lua_State *L, TValue *input, ravitype_t type, TString *usertype) { int raviV_checktype(lua_State *L, TValue *input, ravitype_t type, TString *usertype) {
if (type == RAVI_TANY) if ((type & RAVI_TTAG_FALSISH) && (l_isfalse(input))) return 1;
return 1; switch(type & ~RAVI_TTAG_FALSISH) {
if (type == RAVI_TNIL && ttisnil(input)) case RAVI_TANY: return 1;
return 1; case RAVI_TNIL: return ttisnil(input);
if (type == RAVI_TBOOLEAN && ttisboolean(input)) case RAVI_TBOOLEAN: return ttisnil(input) || ttisboolean(input);
return 1; case RAVI_TNUMINT: return ttisinteger(input);
if (type == RAVI_TNUMINT && ttisinteger(input)) case RAVI_TNUMFLT: return ttisfloat(input);
return 1; case RAVI_TARRAYINT: return ttisiarray(input);
if (type == RAVI_TNUMFLT && ttisfloat(input)) case RAVI_TARRAYFLT: return ttisfarray(input);
return 1; case RAVI_TTABLE: return ttisLtable(input);
if (type == RAVI_TARRAYINT && ttisiarray(input)) case RAVI_TSTRING: return ttisnil(input) || ttisstring(input);
return 1; case RAVI_TFUNCTION: return ttisnil(input) || ttisclosure(input);
if (type == RAVI_TARRAYFLT && ttisfarray(input)) case RAVI_TUSERDATA: return raviV_check_usertype(L, usertype, input);
return 1; case RAVI_TNUMBER: return ttisinteger(input) || ttisfloat(input);
if (type == RAVI_TTABLE && ttisLtable(input)) default: lua_assert(0);
return 1;
if (type == RAVI_TSTRING && ttisstring(input))
return 1;
if (type == RAVI_TFUNCTION && ttisclosure(input))
return 1;
if (type == RAVI_TUSERDATA) {
if (raviV_check_usertype(L, usertype, input))
return 1;
} }
return 0;
} }
int raviV_check_usertype(lua_State *L, TString *name, const TValue *o) int raviV_check_usertype(lua_State *L, TString *name, const TValue *o)

Loading…
Cancel
Save