From 658f04c3d8702945b9d106e40ab71d16a8fbd7a3 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 23:56:38 +0000 Subject: [PATCH] issue #215 adapt fix by XmiliaH from pull request --- src/lparser.c | 168 +++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 85 deletions(-) diff --git a/src/lparser.c b/src/lparser.c index a73a7a2..b282f8f 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1367,96 +1367,94 @@ static int explist (LexState *ls, expdesc *v) { * 'v' may be a function call returning multiple values, in which case * we need to check all returned values against the expected types. */ -static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types, - TString **usertypes, int nvars, int n) { - /* NOTE that 'v' may not have register assigned yet */ +static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types, TString **usertypes, int nvars, int n) { + /* NOTE that 'v' may not have register assigned yet */ + if (n >= nvars) + return; ravitype_t vartype = var_types[n]; - if (n < nvars && vartype != RAVI_TANY) { - if (v->ravi_type != vartype && - (vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT) && - v->k == VNONRELOC) { - /* as the bytecode for generating a table is already emitted by this stage - * we have to amend the generated byte code - not sure if there is a - * better approach. The location of the OP_NEWTABLE instruction is in - * v->pc and we check that this has the same destination register as - * v->u.info which is our variable */ - // local a:int[] = { 1 } - // ^ We are just past this - // and about to assign to a - int ok = 0; - if (v->pc >= 0) { - Instruction *pc = - &ls->fs->f->code[v->pc]; /* Get the OP_NEWTABLE instruction */ - OpCode op = GET_OPCODE(*pc); - if (op == OP_NEWTABLE) { /* check before making changes */ - int reg = GETARG_A(*pc); - if (reg == - v->u.info) { /* double check that register is as expected */ - op = (vartype == RAVI_TARRAYINT) ? OP_RAVI_NEW_IARRAY - : OP_RAVI_NEW_FARRAY; - SET_OPCODE(*pc, op); /* modify opcode */ - DEBUG_CODEGEN( - raviY_printf(ls->fs, "[%d]* %o ; modify opcode\n", v->pc, *pc)); - ok = 1; - } - } - } - if (!ok) - luaX_syntaxerror(ls, "expecting array initializer"); + if (vartype == RAVI_TANY) + return; + ravitype_t v_type = v->ravi_type; + if (v->k == VINDEXED) { + if (v_type == RAVI_TARRAYINT) { + v_type = RAVI_TNUMINT; } - /* if we are calling a function then convert return types */ - else if (v->ravi_type != vartype && - (vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT || - vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT || - vartype == RAVI_TTABLE || vartype == RAVI_TSTRING || - vartype == RAVI_TFUNCTION || vartype == RAVI_TUSERDATA) && - v->k == VCALL) { - /* For local variable declarations that call functions e.g. - * local i = func() - * Lua ensures that the function returns values to register assigned to - * variable i and above so that no separate OP_MOVE instruction is - * necessary. So that means that we need to coerce the return values - * in situ. - */ - Instruction *pc = - &getinstruction(ls->fs, v); /* Obtain the instruction for OP_CALL */ - lua_assert(GET_OPCODE(*pc) == OP_CALL); - int a = GETARG_A(*pc); /* function return values will be placed from - register pointed by A and upwards */ - int nrets = GETARG_C(*pc) - 1; - /* operand C contains number of return values expected */ - /* Note that at this stage nrets is always 1 - as Lua patches in the this - * value for the last function call in a - * variable declaration statement in adjust_assign and - * localvar_adjust_assign */ - /* all return values that are going to be assigned to typed local vars - * must be converted to the correct type */ - int i; - for (i = n; i < (n + nrets); i++) - /* do we need to convert ? */ - ravi_code_typecoersion(ls, a + (i - n), var_types[i], NULL); + else if (v_type == RAVI_TARRAYFLT) { + v_type = RAVI_TNUMFLT; } - else if ((vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT) && - v->k == VINDEXED) { - if ((vartype == RAVI_TNUMFLT && v->ravi_type != RAVI_TARRAYFLT) || - (vartype == RAVI_TNUMINT && v->ravi_type != RAVI_TARRAYINT)) - luaX_syntaxerror(ls, "Invalid local assignment"); - } - else if ((vartype == RAVI_TSTRING && v->ravi_type != RAVI_TSTRING) || - (vartype == RAVI_TFUNCTION && v->ravi_type != RAVI_TFUNCTION) || - vartype == RAVI_TUSERDATA) { - TString *usertype = usertypes[n]; // NULL if var_types[n] is not userdata - /* we need to make sure that a register is assigned to 'v' - so that we can emit type assertion instructions. This would have - normally happened in the calling function but we do it early here - - possibly missing some optimization opportunity (i.e. avoiding register - assignment) */ - luaK_exp2nextreg(ls->fs, v); - ravi_code_typecoersion(ls, v->u.info, vartype, usertype); + else { + v_type = RAVI_TANY; } - else if (vartype != v->ravi_type){ - luaX_syntaxerror(ls, "Invalid local assignment"); + } + if (v_type == vartype) + return; + if ((vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT) && v->k == VNONRELOC) { + /* as the bytecode for generating a table is already emitted by this stage + * we have to amend the generated byte code - not sure if there is a + * better approach. The location of the OP_NEWTABLE instruction is in + * v->pc and we check that this has the same destination register as + * v->u.info which is our variable */ + // local a:int[] = { 1 } + // ^ We are just past this + // and about to assign to a + int ok = 0; + if (v->pc >= 0) { + Instruction *pc = &ls->fs->f->code[v->pc]; /* Get the OP_NEWTABLE instruction */ + OpCode op = GET_OPCODE(*pc); + if (op == OP_NEWTABLE) { /* check before making changes */ + int reg = GETARG_A(*pc); + if (reg == v->u.info) { /* double check that register is as expected */ + op = (vartype == RAVI_TARRAYINT) ? OP_RAVI_NEW_IARRAY : OP_RAVI_NEW_FARRAY; + SET_OPCODE(*pc, op); /* modify opcode */ + DEBUG_CODEGEN(raviY_printf(ls->fs, "[%d]* %o ; modify opcode\n", v->pc, *pc)); + ok = 1; + } + } } + if (!ok) + luaX_syntaxerror(ls, "expecting array initializer"); + } + /* if we are calling a function then convert return types */ + else if ((vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT || vartype == RAVI_TARRAYFLT || + vartype == RAVI_TARRAYINT || vartype == RAVI_TTABLE || vartype == RAVI_TSTRING || + vartype == RAVI_TFUNCTION || vartype == RAVI_TUSERDATA) && + v->k == VCALL) { + /* For local variable declarations that call functions e.g. + * local i = func() + * Lua ensures that the function returns values to register assigned to + * variable i and above so that no separate OP_MOVE instruction is + * necessary. So that means that we need to coerce the return values + * in situ. + */ + Instruction *pc = &getinstruction(ls->fs, v); /* Obtain the instruction for OP_CALL */ + lua_assert(GET_OPCODE(*pc) == OP_CALL); + int a = GETARG_A(*pc); /* function return values will be placed from + register pointed by A and upwards */ + int nrets = GETARG_C(*pc) - 1; + /* operand C contains number of return values expected */ + /* Note that at this stage nrets is always 1 - as Lua patches in the this + * value for the last function call in a + * variable declaration statement in adjust_assign and + * localvar_adjust_assign */ + /* all return values that are going to be assigned to typed local vars + * must be converted to the correct type */ + int i; + for (i = n; i < (n + nrets); i++) + /* do we need to convert ? */ + ravi_code_typecoersion(ls, a + (i - n), var_types[i], NULL); + } + else if (vartype == RAVI_TSTRING || vartype == RAVI_TFUNCTION || vartype == RAVI_TUSERDATA) { + TString *usertype = usertypes[n]; // NULL if var_types[n] is not userdata + /* we need to make sure that a register is assigned to 'v' + so that we can emit type assertion instructions. This would have + normally happened in the calling function but we do it early here - + possibly missing some optimization opportunity (i.e. avoiding register + assignment) */ + luaK_exp2nextreg(ls->fs, v); + ravi_code_typecoersion(ls, v->u.info, vartype, usertype); + } + else { + luaX_syntaxerror(ls, "Invalid local assignment"); } }