Details in the implementation of the integer 'for' loop

Changed some implementation details; in particular, it is back using
an internal variable to keep the index, with the control variable
being only a copy of that internal variable. (The direct use of
the control variable demands a check of its type for each access,
which offsets the gains from the use of a single variable.)
diff --git a/lvm.c b/lvm.c
index 75b05f0..31b4dc3 100644
--- a/lvm.c
+++ b/lvm.c
@@ -150,35 +150,36 @@
 ** Try to convert a 'for' limit to an integer, preserving the semantics
 ** of the loop.  (The following explanation assumes a positive step;
 ** it is valid for negative steps mutatis mutandis.)
+** Return true if the loop must not run.
 ** If the limit is an integer or can be converted to an integer,
-** rounding down, that is it.
+** rounding down, that is the limit.
 ** Otherwise, check whether the limit can be converted to a float. If
 ** the float is too large, clip it to LUA_MAXINTEGER.  If the float
 ** is too negative, the loop should not run, because any initial
-** integer value is greater than such limit; so, it sets 'stopnow'.
+** integer value is greater than such limit; so, it returns true to
+** signal that.
 ** (For this latter case, no integer limit would be correct; even a
 ** limit of LUA_MININTEGER would run the loop once for an initial
 ** value equal to LUA_MININTEGER.)
 */
-static int forlimit (const TValue *lim, lua_Integer *p, lua_Integer step,
-                     int *stopnow) {
-  *stopnow = 0;  /* usually, let loops run */
+static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
+                                   lua_Integer *p, lua_Integer step) {
   if (!luaV_tointeger(lim, p, (step < 0 ? 2 : 1))) {
     /* not coercible to in integer */
     lua_Number flim;  /* try to convert to float */
     if (!tonumber(lim, &flim)) /* cannot convert to float? */
-      return 0;  /* not a number */
-    /* 'flim' is a float out of integer bounds */
+      luaG_forerror(L, lim, "limit");
+    /* else 'flim' is a float out of integer bounds */
     if (luai_numlt(0, flim)) {  /* if it is positive, it is too large */
+      if (step < 0) return 1;  /* initial value must be less than it */
       *p = LUA_MAXINTEGER;  /* truncate */
-      if (step < 0) *stopnow = 1;  /* initial value must be less than it */
     }
     else {  /* it is less than min integer */
+      if (step > 0) return 1;  /* initial value must be greater than it */
       *p = LUA_MININTEGER;  /* truncate */
-      if (step > 0) *stopnow = 1;  /* initial value must be greater than it */
     }
   }
-  return 1;
+  return (step > 0 ? init > *p : init < *p);  /* not to run? */
 }
 
 
@@ -1637,24 +1638,26 @@
       }
       vmcase(OP_FORLOOP) {
         if (ttisinteger(s2v(ra + 2))) {  /* integer loop? */
-          lua_Unsigned count = l_castS2U(ivalue(s2v(ra)));
+          lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
           if (count > 0) {  /* still more iterations? */
             lua_Integer step = ivalue(s2v(ra + 2));
-            lua_Integer idx = ivalue(s2v(ra + 3));
+            lua_Integer idx = ivalue(s2v(ra));  /* internal index */
+            chgivalue(s2v(ra + 1), count - 1);  /* update counter */
             idx = intop(+, idx, step);  /* add step to index */
-            chgivalue(s2v(ra), count - 1);  /* update counter... */
-            setivalue(s2v(ra + 3), idx);  /* ...and index */
+            chgivalue(s2v(ra), idx);  /* update internal index */
+            setivalue(s2v(ra + 3), idx);  /* and control variable */
             pc -= GETARG_Bx(i);  /* jump back */
           }
         }
         else {  /* floating loop */
           lua_Number step = fltvalue(s2v(ra + 2));
           lua_Number limit = fltvalue(s2v(ra + 1));
-          lua_Number idx = fltvalue(s2v(ra + 3));
-          idx = luai_numadd(L, idx, step);  /* inc. index */
+          lua_Number idx = fltvalue(s2v(ra));
+          idx = luai_numadd(L, idx, step);  /* increment index */
           if (luai_numlt(0, step) ? luai_numle(idx, limit)
                                   : luai_numle(limit, idx)) {
-            setfltvalue(s2v(ra + 3), idx);  /* update index */
+            chgfltvalue(s2v(ra), idx);  /* update internal index */
+            setfltvalue(s2v(ra + 3), idx);  /* and control variable */
             pc -= GETARG_Bx(i);  /* jump back */
           }
         }
@@ -1665,56 +1668,52 @@
         TValue *pinit = s2v(ra);
         TValue *plimit = s2v(ra + 1);
         TValue *pstep = s2v(ra + 2);
-        lua_Integer ilimit;
-        int stopnow;
         savestate(L, ci);  /* in case of errors */
-        if (ttisinteger(pinit) && ttisinteger(pstep) &&
-            forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) {
-          /* integer loop */
+        if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */
           lua_Integer init = ivalue(pinit);
           lua_Integer step = ivalue(pstep);
-          setivalue(s2v(ra + 3), init);  /* control variable */
+          lua_Integer limit;
           if (step == 0)
             luaG_runerror(L, "'for' step is zero");
-          else if (stopnow)
+          setivalue(s2v(ra + 3), init);  /* control variable */
+          if (forlimit(L, init, plimit, &limit, step))
             pc += GETARG_Bx(i) + 1;  /* skip the loop */
-          else if (step > 0) {  /* ascending loop? */
-            if (init > ilimit)
-              pc += GETARG_Bx(i) + 1;  /* skip the loop */
-            else {
-              lua_Unsigned count = l_castS2U(ilimit) - l_castS2U(init);
+          else {  /* prepare loop counter */
+            lua_Unsigned count;
+            if (step > 0) {  /* ascending loop? */
+              count = l_castS2U(limit) - l_castS2U(init);
               if (step != 1)  /* avoid division in the too common case */
                 count /= l_castS2U(step);
-              setivalue(s2v(ra), count);
             }
-          }
-          else {  /* descending loop */
-            if (init < ilimit)
-              pc += GETARG_Bx(i) + 1;  /* skip the loop */
-            else {
-              lua_Unsigned count = l_castS2U(init) - l_castS2U(ilimit);
+            else {  /* step < 0; descending loop */
+              count = l_castS2U(init) - l_castS2U(limit);
               count /= -l_castS2U(step);
-              setivalue(s2v(ra), count);
             }
+            /* store the counter in place of the limit (which won't be
+               needed anymore */
+            setivalue(plimit, l_castU2S(count));
           }
         }
         else {  /* try making all values floats */
-          lua_Number init; lua_Number flimit; lua_Number step;
-          if (unlikely(!tonumber(plimit, &flimit)))
+          lua_Number init; lua_Number limit; lua_Number step;
+          if (unlikely(!tonumber(plimit, &limit)))
             luaG_forerror(L, plimit, "limit");
-          setfltvalue(plimit, flimit);
           if (unlikely(!tonumber(pstep, &step)))
             luaG_forerror(L, pstep, "step");
-          setfltvalue(pstep, step);
           if (unlikely(!tonumber(pinit, &init)))
             luaG_forerror(L, pinit, "initial value");
           if (step == 0)
             luaG_runerror(L, "'for' step is zero");
-          if (luai_numlt(0, step) ? luai_numlt(flimit, init)
-                                   : luai_numlt(init, flimit))
+          if (luai_numlt(0, step) ? luai_numlt(limit, init)
+                                   : luai_numlt(init, limit))
             pc += GETARG_Bx(i) + 1;  /* skip the loop */
-          else
+          else {
+            /* make sure internal values are all float */
+            setfltvalue(plimit, limit);
+            setfltvalue(pstep, step);
+            setfltvalue(s2v(ra), init);  /* internal index */
             setfltvalue(s2v(ra + 3), init);  /* control variable */
+          }
         }
         vmbreak;
       }
diff --git a/testes/nextvar.lua b/testes/nextvar.lua
index e769ccd..87a6bfa 100644
--- a/testes/nextvar.lua
+++ b/testes/nextvar.lua
@@ -544,6 +544,12 @@
   a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1)
 end
 
+do   -- changing the control variable
+  local a
+  a = 0; for i = 1, 10 do a = a + 1; i = "x" end; assert(a == 10)
+  a = 0; for i = 10.0, 1, -1 do a = a + 1; i = "x" end; assert(a == 10)
+end
+
 -- conversion
 a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5)