New implementation for constants

VLOCAL expressions keep a reference to their corresponding 'Vardesc',
and 'Upvaldesc' (for upvalues) has a field 'ro' (read-only). So, it is
easier to check whether a variable is read-only. The decoupling in
VLOCAL between 'vidx' ('Vardesc' index) and 'sidx' (stack index)
should also help the forthcoming implementation of compile-time
constant propagation.
diff --git a/lcode.c b/lcode.c
index 1005f1b..cb6ea0d 100644
--- a/lcode.c
+++ b/lcode.c
@@ -52,7 +52,7 @@
 ** If expression is a numeric constant, fills 'v' with its value
 ** and returns 1. Otherwise, returns 0.
 */
-int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v) {
+static int tonumeral (const expdesc *e, TValue *v) {
   if (hasjumps(e))
     return 0;  /* not a numeral */
   switch (e->k) {
@@ -62,42 +62,12 @@
     case VKFLT:
       if (v) setfltvalue(v, e->u.nval);
       return 1;
-    case VUPVAL: {  /* may be a constant */
-      Vardesc *vd = luaY_getvardesc(&fs, e);
-      if (v && vd && !ttisnil(&vd->val)) {
-        setobj(fs->ls->L, v, &vd->val);
-        return 1;
-      }  /* else */
-    }  /* FALLTHROUGH */
     default: return 0;
   }
 }
 
 
 /*
-** If expression 'e' is a constant, change 'e' to represent
-** the constant value.
-*/
-static int const2exp (FuncState *fs, expdesc *e) {
-  Vardesc *vd = luaY_getvardesc(&fs, e);
-  if (vd) {
-    TValue *v = &vd->val;
-    switch (ttypetag(v)) {
-      case LUA_TNUMINT:
-        e->k = VKINT;
-        e->u.ival = ivalue(v);
-        return 1;
-      case LUA_TNUMFLT:
-        e->k = VKFLT;
-        e->u.nval = fltvalue(v);
-        return 1;
-    }
-  }
-  return 0;
-}
-
-
-/*
 ** Return the previous instruction of the current code. If there
 ** may be a jump target between the current instruction and the
 ** previous one, return an invalid instruction (to avoid wrong
@@ -708,15 +678,13 @@
 void luaK_dischargevars (FuncState *fs, expdesc *e) {
   switch (e->k) {
     case VLOCAL: {  /* already in a register */
-      e->u.info = e->u.var.idx;
+      e->u.info = e->u.var.sidx;
       e->k = VNONRELOC;  /* becomes a non-relocatable value */
       break;
     }
     case VUPVAL: {  /* move value to some (pending) register */
-      if (!const2exp(fs, e)) {
-        e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.var.idx, 0);
-        e->k = VRELOC;
-      }
+      e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
+      e->k = VRELOC;
       break;
     }
     case VINDEXUP: {
@@ -971,12 +939,12 @@
   switch (var->k) {
     case VLOCAL: {
       freeexp(fs, ex);
-      exp2reg(fs, ex, var->u.var.idx);  /* compute 'ex' into proper place */
+      exp2reg(fs, ex, var->u.var.sidx);  /* compute 'ex' into proper place */
       return;
     }
     case VUPVAL: {
       int e = luaK_exp2anyreg(fs, ex);
-      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.var.idx, 0);
+      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
       break;
     }
     case VINDEXUP: {
@@ -1203,13 +1171,13 @@
   if (t->k == VUPVAL && !isKstr(fs, k))  /* upvalue indexed by non string? */
     luaK_exp2anyreg(fs, t);  /* put it in a register */
   if (t->k == VUPVAL) {
-    t->u.ind.t = t->u.var.idx;  /* upvalue index */
+    t->u.ind.t = t->u.info;  /* upvalue index */
     t->u.ind.idx = k->u.info;  /* literal string */
     t->k = VINDEXUP;
   }
   else {
     /* register index of the table */
-    t->u.ind.t = (t->k == VLOCAL) ? t->u.var.idx: t->u.info;
+    t->u.ind.t = (t->k == VLOCAL) ? t->u.var.sidx: t->u.info;
     if (isKstr(fs, k)) {
       t->u.ind.idx = k->u.info;  /* literal string */
       t->k = VINDEXSTR;
@@ -1252,9 +1220,7 @@
 static int constfolding (FuncState *fs, int op, expdesc *e1,
                                         const expdesc *e2) {
   TValue v1, v2, res;
-  if (!luaK_tonumeral(fs, e1, &v1) ||
-      !luaK_tonumeral(fs, e2, &v2) ||
-      !validop(op, &v1, &v2))
+  if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
     return 0;  /* non-numeric operands or not safe to fold */
   luaO_rawarith(fs->ls->L, op, &v1, &v2, &res);  /* does operation */
   if (ttisinteger(&res)) {
@@ -1341,7 +1307,7 @@
                        expdesc *e1, expdesc *e2, int flip, int line) {
   if (isSCint(e2))  /* immediate operand? */
     codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line);
-  else if (luaK_tonumeral(fs, e2, NULL) && luaK_exp2K(fs, e2)) {  /* K operand? */
+  else if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) {  /* K operand? */
     int v2 = e2->u.info;  /* K index */
     op = cast(OpCode, op - OP_ADD + OP_ADDK);
     finishbinexpval(fs, e1, e2, op, v2, flip, line);
@@ -1362,7 +1328,7 @@
 static void codecommutative (FuncState *fs, OpCode op,
                              expdesc *e1, expdesc *e2, int line) {
   int flip = 0;
-  if (luaK_tonumeral(fs, e1, NULL)) {  /* is first operand a numeric constant? */
+  if (tonumeral(e1, NULL)) {  /* is first operand a numeric constant? */
     swapexps(e1, e2);  /* change order */
     flip = 1;
   }
@@ -1519,13 +1485,13 @@
     case OPR_MOD: case OPR_POW:
     case OPR_BAND: case OPR_BOR: case OPR_BXOR:
     case OPR_SHL: case OPR_SHR: {
-      if (!luaK_tonumeral(fs, v, NULL))
+      if (!tonumeral(v, NULL))
         luaK_exp2anyreg(fs, v);
       /* else keep numeral, which may be folded with 2nd operand */
       break;
     }
     case OPR_EQ: case OPR_NE: {
-      if (!luaK_tonumeral(fs, v, NULL))
+      if (!tonumeral(v, NULL))
         luaK_exp2RK(fs, v);
       /* else keep numeral, which may be an immediate operand */
       break;
diff --git a/lcode.h b/lcode.h
index c495329..0758f88 100644
--- a/lcode.h
+++ b/lcode.h
@@ -51,7 +51,6 @@
 
 #define luaK_jumpto(fs,t)	luaK_patchlist(fs, luaK_jump(fs), t)
 
-LUAI_FUNC int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v);
 LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
 LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
 LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
diff --git a/ldump.c b/ldump.c
index c447557..3d5b7b3 100644
--- a/ldump.c
+++ b/ldump.c
@@ -149,6 +149,7 @@
   for (i = 0; i < n; i++) {
     DumpByte(f->upvalues[i].instack, D);
     DumpByte(f->upvalues[i].idx, D);
+    DumpByte(f->upvalues[i].ro, D);
   }
 }
 
diff --git a/lobject.h b/lobject.h
index 403b604..64366a9 100644
--- a/lobject.h
+++ b/lobject.h
@@ -460,6 +460,7 @@
   TString *name;  /* upvalue name (for debug information) */
   lu_byte instack;  /* whether it is in stack (register) */
   lu_byte idx;  /* index of upvalue (in stack or in outer function's list) */
+  lu_byte ro;  /* true if upvalue is read-only (const) */
 } Upvaldesc;
 
 
diff --git a/lparser.c b/lparser.c
index 52486e0..1551cda 100644
--- a/lparser.c
+++ b/lparser.c
@@ -156,13 +156,6 @@
 }
 
 
-static void init_var (expdesc *e, expkind k, int i) {
-  e->f = e->t = NO_JUMP;
-  e->k = k;
-  e->u.var.idx = i;
-}
-
-
 static void codestring (LexState *ls, expdesc *e, TString *s) {
   init_exp(e, VK, luaK_stringK(ls->fs, s));
 }
@@ -177,16 +170,15 @@
 ** Register a new local variable in the active 'Proto' (for debug
 ** information).
 */
-static int registerlocalvar (LexState *ls, TString *varname) {
-  FuncState *fs = ls->fs;
+static int registerlocalvar (lua_State *L, FuncState *fs, TString *varname) {
   Proto *f = fs->f;
   int oldsize = f->sizelocvars;
-  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
+  luaM_growvector(L, f->locvars, fs->nlocvars, f->sizelocvars,
                   LocVar, SHRT_MAX, "local variables");
   while (oldsize < f->sizelocvars)
     f->locvars[oldsize++].varname = NULL;
   f->locvars[fs->nlocvars].varname = varname;
-  luaC_objbarrier(ls->L, f, varname);
+  luaC_objbarrier(L, f, varname);
   return fs->nlocvars++;
 }
 
@@ -195,18 +187,19 @@
 ** Create a new local variable with the given 'name'.
 */
 static Vardesc *new_localvar (LexState *ls, TString *name) {
+  lua_State *L = ls->L;
   FuncState *fs = ls->fs;
   Dyndata *dyd = ls->dyd;
   Vardesc *var;
-  int reg = registerlocalvar(ls, name);
+  int reg = registerlocalvar(L, fs, name);
   checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
                   MAXVARS, "local variables");
-  luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
-                  dyd->actvar.size, Vardesc, MAX_INT, "local variables");
+  luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
+                  dyd->actvar.size, Vardesc, USHRT_MAX, "local variables");
   var = &dyd->actvar.arr[dyd->actvar.n++];
-  var->idx = cast(short, reg);
+  var->pidx = cast(short, reg);
   var->ro = 0;
-  setnilvalue(&var->val);
+  setnilvalue(var);
   return var;
 }
 
@@ -223,50 +216,47 @@
   return &fs->ls->dyd->actvar.arr[fs->firstlocal + i];
 }
 
+
 /*
 ** Get the debug-information entry for current variable 'i'.
 */
-static LocVar *getlocvar (FuncState *fs, int i) {
-  int idx = getlocalvardesc(fs, i)->idx;
+static LocVar *localdebuginfo (FuncState *fs, int i) {
+  int idx = getlocalvardesc(fs, i)->pidx;
   lua_assert(idx < fs->nlocvars);
   return &fs->f->locvars[idx];
 }
 
 
-/*
-** Return the "variable description" (Vardesc) of a given
-** local variable and update 'fs' to point to the function
-** where that variable was defined. Return NULL if expression
-** is neither a local variable nor an upvalue.
-*/
-Vardesc *luaY_getvardesc (FuncState **fs, const expdesc *e) {
-  if (e->k == VLOCAL)
-    return getlocalvardesc(*fs, e->u.var.idx);
-  else if (e->k != VUPVAL)
-    return NULL;  /* not a local variable */
-  else {  /* upvalue: must go up all levels up to the original local */
-    int idx = e->u.var.idx;
-    for (;;) {
-      Upvaldesc *up = &(*fs)->f->upvalues[idx];
-      *fs = (*fs)->prev;  /* must look at the previous level */
-      idx = up->idx;  /* at this index */
-      if (*fs == NULL)  /* no more levels? (can happen only with _ENV) */
-        return NULL;
-      else if (up->instack)  /* got to the original level? */
-        return getlocalvardesc(*fs, idx);
-      /* else repeat for previous level */
-    }
-  }
+static void init_var (FuncState *fs, expdesc *e, int i) {
+  e->f = e->t = NO_JUMP;
+  e->k = VLOCAL;
+  e->u.var.vidx = i;
+  e->u.var.sidx = getlocalvardesc(fs, i)->sidx;
 }
 
 
 static void check_readonly (LexState *ls, expdesc *e) {
   FuncState *fs = ls->fs;
-  Vardesc *vardesc = luaY_getvardesc(&fs, e);
-  if (vardesc && vardesc->ro) {  /* is variable local and const? */
+  TString *varname = NULL;  /* to be set if variable is const */
+  switch (e->k) {
+    case VLOCAL: {
+      Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
+      if (vardesc->ro)
+        varname = fs->f->locvars[vardesc->pidx].varname;
+      break;
+    }
+    case VUPVAL: {
+      Upvaldesc *up = &fs->f->upvalues[e->u.info];
+      if (up->ro)
+        varname = up->name;
+      break;
+    }
+    default:
+      return;  /* other cases cannot be read-only */
+  }
+  if (varname) {
     const char *msg = luaO_pushfstring(ls->L,
-       "attempt to assign to const variable '%s'",
-       getstr(fs->f->locvars[vardesc->idx].varname));
+       "attempt to assign to const variable '%s'", getstr(varname));
     luaK_semerror(ls, msg);  /* error */
   }
 }
@@ -274,13 +264,15 @@
 
 /*
 ** Start the scope for the last 'nvars' created variables.
-** (debug info.)
 */
 static void adjustlocalvars (LexState *ls, int nvars) {
   FuncState *fs = ls->fs;
-  fs->nactvar = cast_byte(fs->nactvar + nvars);
-  for (; nvars; nvars--) {
-    getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;
+  int i;
+  for (i = 0; i < nvars; i++) {
+    int varidx = fs->nactvar++;
+    Vardesc *var = getlocalvardesc(fs, varidx);
+    var->sidx = varidx;
+    fs->f->locvars[var->pidx].startpc = fs->pc;
   }
 }
 
@@ -292,7 +284,7 @@
 static void removevars (FuncState *fs, int tolevel) {
   fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
   while (fs->nactvar > tolevel)
-    getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
+    localdebuginfo(fs, --fs->nactvar)->endpc = fs->pc;
 }
 
 
@@ -310,7 +302,7 @@
 }
 
 
-static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
+static Upvaldesc *allocupvalue (FuncState *fs) {
   Proto *f = fs->f;
   int oldsize = f->sizeupvalues;
   checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
@@ -318,11 +310,28 @@
                   Upvaldesc, MAXUPVAL, "upvalues");
   while (oldsize < f->sizeupvalues)
     f->upvalues[oldsize++].name = NULL;
-  f->upvalues[fs->nups].instack = (v->k == VLOCAL);
-  f->upvalues[fs->nups].idx = cast_byte(v->u.var.idx);
-  f->upvalues[fs->nups].name = name;
-  luaC_objbarrier(fs->ls->L, f, name);
-  return fs->nups++;
+  return &f->upvalues[fs->nups++];
+}
+
+
+static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
+  Upvaldesc *up = allocupvalue(fs);
+  FuncState *prev = fs->prev;
+  if (v->k == VLOCAL) {
+    up->instack = 1;
+    up->idx = v->u.var.sidx;
+    up->ro = getlocalvardesc(prev, v->u.var.vidx)->ro;
+    lua_assert(eqstr(name, localdebuginfo(prev, v->u.var.vidx)->varname));
+  }
+  else {
+    up->instack = 0;
+    up->idx = cast_byte(v->u.info);
+    up->ro = prev->f->upvalues[v->u.info].ro;
+    lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name));
+  }
+  up->name = name;
+  luaC_objbarrier(fs->ls->L, fs->f, name);
+  return fs->nups - 1;
 }
 
 
@@ -333,7 +342,7 @@
 static int searchvar (FuncState *fs, TString *n) {
   int i;
   for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
-    if (eqstr(n, getlocvar(fs, i)->varname))
+    if (eqstr(n, localdebuginfo(fs, i)->varname))
       return i;
   }
   return -1;  /* not found */
@@ -364,9 +373,9 @@
   else {
     int v = searchvar(fs, n);  /* look up locals at current level */
     if (v >= 0) {  /* found? */
-      init_var(var, VLOCAL, v);  /* variable is local */
+      init_var(fs, var, v);  /* variable is local */
       if (!base)
-        markupval(fs, v);  /* local will be used as an upval */
+        markupval(fs, var->u.var.sidx);  /* local will be used as an upval */
     }
     else {  /* not found as local at current level; try upvalues */
       int idx = searchupvalue(fs, n);  /* try existing upvalues */
@@ -377,7 +386,7 @@
         /* else was LOCAL or UPVAL */
         idx  = newupvalue(fs, n, var);  /* will be a new upvalue */
       }
-      init_var(var, VUPVAL, idx);  /* new or old upvalue */
+      init_exp(var, VUPVAL, idx);  /* new or old upvalue */
     }
   }
 }
@@ -440,7 +449,7 @@
 ** local variable.
 */
 static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
-  const char *varname = getstr(getlocvar(ls->fs, gt->nactvar)->varname);
+  const char *varname = getstr(localdebuginfo(ls->fs, gt->nactvar)->varname);
   const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'";
   msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname);
   luaK_semerror(ls, msg);  /* raise the error */
@@ -1259,20 +1268,20 @@
   for (; lh; lh = lh->prev) {  /* check all previous assignments */
     if (vkisindexed(lh->v.k)) {  /* assignment to table field? */
       if (lh->v.k == VINDEXUP) {  /* is table an upvalue? */
-        if (v->k == VUPVAL && lh->v.u.ind.t == v->u.var.idx) {
+        if (v->k == VUPVAL && lh->v.u.ind.t == v->u.info) {
           conflict = 1;  /* table is the upvalue being assigned now */
           lh->v.k = VINDEXSTR;
           lh->v.u.ind.t = extra;  /* assignment will use safe copy */
         }
       }
       else {  /* table is a register */
-        if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.idx) {
+        if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.sidx) {
           conflict = 1;  /* table is the local being assigned now */
           lh->v.u.ind.t = extra;  /* assignment will use safe copy */
         }
         /* is index the local being assigned? */
         if (lh->v.k == VINDEXED && v->k == VLOCAL &&
-            lh->v.u.ind.idx == v->u.var.idx) {
+            lh->v.u.ind.idx == v->u.var.sidx) {
           conflict = 1;
           lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */
         }
@@ -1281,14 +1290,16 @@
   }
   if (conflict) {
     /* copy upvalue/local value to a temporary (in position 'extra') */
-    OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
-    luaK_codeABC(fs, op, extra, v->u.var.idx, 0);
+    if (v->k == VLOCAL)
+      luaK_codeABC(fs, OP_MOVE, extra, v->u.var.sidx, 0);
+    else
+      luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0);
     luaK_reserveregs(fs, 1);
   }
 }
 
 /*
-** Parse and compile a mulitple assignment. The first "variable"
+** Parse and compile a multiple assignment. The first "variable"
 ** (a 'suffixedexp') was already read by the caller.
 **
 ** assignment -> suffixedexp restassign
@@ -1652,7 +1663,7 @@
   adjustlocalvars(ls, 1);  /* enter its scope */
   body(ls, &b, 0, ls->linenumber);  /* function created in next register */
   /* debug information will only see the variable after this point! */
-  getlocvar(fs, b.u.info)->startpc = fs->pc;
+  localdebuginfo(fs, b.u.info)->startpc = fs->pc;
 }
 
 
@@ -1870,11 +1881,14 @@
 */
 static void mainfunc (LexState *ls, FuncState *fs) {
   BlockCnt bl;
-  expdesc v;
+  Upvaldesc *env;
   open_func(ls, fs, &bl);
   setvararg(fs, 0);  /* main function is always declared vararg */
-  init_var(&v, VLOCAL, 0);  /* create and... */
-  newupvalue(fs, ls->envn, &v);  /* ...set environment upvalue */
+  env = allocupvalue(fs);  /* ...set environment upvalue */
+  env->instack = 1;
+  env->idx = 0;
+  env->ro = 0;
+  env->name = ls->envn;
   luaX_next(ls);  /* read first token */
   statlist(ls);  /* parse main body */
   check(ls, TK_EOS);
diff --git a/lparser.h b/lparser.h
index b708de2..cc2ec14 100644
--- a/lparser.h
+++ b/lparser.h
@@ -33,8 +33,9 @@
   VKINT,  /* integer constant; nval = numerical integer value */
   VNONRELOC,  /* expression has its value in a fixed register;
                  info = result register */
-  VLOCAL,  /* local variable; var.idx = local register */
-  VUPVAL,  /* upvalue variable; var.idx = index of upvalue in 'upvalues' */
+  VLOCAL,  /* local variable; var.ridx = local register;
+              var.vidx = index in 'actvar.arr'  */
+  VUPVAL,  /* upvalue variable; info = index of upvalue in 'upvalues' */
   VINDEXED,  /* indexed variable;
                 ind.t = table register;
                 ind.idx = key's R index */
@@ -70,8 +71,9 @@
       short idx;  /* index (R or "long" K) */
       lu_byte t;  /* table (register or upvalue) */
     } ind;
-    struct {  /* for local variables and upvalues */
-      lu_byte idx;  /* index of the variable */
+    struct {  /* for local variables */
+      lu_byte sidx;  /* index in the stack */
+      unsigned short vidx;  /* index in 'actvar.arr'  */
     } var;
   } u;
   int t;  /* patch list of 'exit when true' */
@@ -81,9 +83,10 @@
 
 /* description of an active local variable */
 typedef struct Vardesc {
-  TValue val;  /* constant value (if variable is 'const') */
-  short idx;  /* index of the variable in the Proto's 'locvars' array */
+  TValuefields;  /* constant value (if variable is 'const') */
   lu_byte ro;  /* true if variable is 'const' */
+  lu_byte sidx;  /* index of the variable in the stack */
+  short pidx;  /* index of the variable in the Proto's 'locvars' array */
 } Vardesc;
 
 
@@ -144,7 +147,6 @@
 } FuncState;
 
 
-LUAI_FUNC Vardesc *luaY_getvardesc (FuncState **fs, const expdesc *e);
 LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
                                  Dyndata *dyd, const char *name, int firstchar);
 
diff --git a/lundump.c b/lundump.c
index c1cff9e..5c0e94d 100644
--- a/lundump.c
+++ b/lundump.c
@@ -203,6 +203,7 @@
   for (i = 0; i < n; i++) {
     f->upvalues[i].instack = LoadByte(S);
     f->upvalues[i].idx = LoadByte(S);
+    f->upvalues[i].ro = LoadByte(S);
   }
 }
 
diff --git a/testes/locals.lua b/testes/locals.lua
index 50230a2..0de00a9 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -177,14 +177,24 @@
   local <const> a, b, <const> c = 10, 20, 30
   b = a + c + b    -- 'b' is not constant
   assert(a == 10 and b == 60 and c == 30)
-  local function checkro (code, name)
+  local function checkro (name, code)
     local st, msg = load(code)
     local gab = string.format("attempt to assign to const variable '%s'", name)
     assert(not st and string.find(msg, gab))
   end
-  checkro("local x, <const> y, z = 10, 20, 30; x = 11; y = 12", "y")
-  checkro("local <const> x, y, <const> z = 10, 20, 30; x = 11", "x")
-  checkro("local <const> x, y, <const> z = 10, 20, 30; y = 10; z = 11", "z")
+  checkro("y", "local x, <const> y, z = 10, 20, 30; x = 11; y = 12")
+  checkro("x", "local <const> x, y, <const> z = 10, 20, 30; x = 11")
+  checkro("z", "local <const> x, y, <const> z = 10, 20, 30; y = 10; z = 11")
+
+  checkro("z", [[
+    local a, <const> z, b = 10;
+    function foo() a = 20; z = 32; end
+  ]])
+
+  checkro("var1", [[
+    local a, <const> var1 = 10;
+    function foo() a = 20; z = function () var1 = 12; end  end
+  ]])
 end