lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi All,

please see the following example script.

Kind regards

  Lars Dölle


---8<--- snip -----8<---- snap -----


--[[

Summary:

  Lua version 5.1, 5.2beta and perhaps earlier contains what could
  be called a glitch in the compiler. It is very unlikely to cause
  troubles, thought, and can be worked around.


Diagnostic:

  Compiling assingment statements of the form

    var1[exp1],var2[exp2] = exp3,exp4

  should be translated to code executing serially

    |var1| |exp1| |var2| |exp2| |exp3| |exp4|
    SetTable @var1 @exp1 @exp3
    SetTable @var2 @exp2 @exp4

  but the assignment sequence in the end is inverted, meaning
  an execution sequence like

    |var1| |exp1| |var2| |exp2| |exp3| |exp4|
    SetTable @var2 @exp2 @exp4
    SetTable @var1 @exp1 @exp3

  is produced instead. The same holds for non-indexed variables,
  including locals, globals and upvalues.


Impact:

  All types of variables are effected by wrongly implemented
  semantics in rare, perhaps mechanically produced cases.

  While for globals, upvalues and locals the glitch could only
  be triggered by using the same variable twice in an assignment,
  a potential side effect on tables with __newindex might be
  provoked even using different variables.

  The semantics of the composite assignment is inconsistent.


Workaround:

  Decompose the assignment. The case of a vararg might be
  handled by first assigning to different locals.


Examples:

  follow

--]]

local function check(v,typ,name) -- utility
  io.write(string.format("%s '%s' is %d ",typ,name,v))
  if v == 1 then io.write(string.format("but should be 2")) end
  if v == 2 then io.write(string.format("as it should be")) end
  print()
end


-- demonstrating the glitch on locals --

local a

a,a = 1,2 -- 'a' is assigned 1 and not 2

check(a,"local ","a")

-- This behaviour is at least unexpected, since the assignment
-- intuitively should have the same meaning as

a = 1
a = 2

check(a,"local ","a")

-- identically, a local declaration properly yields 2

local a,a = 1,2

check(a,"local ","a")

-- likely, a functioncall yields 2
-- (needing ';()' since <function> is not a <prefixexp>)

;(function (a,a) check(a,"parm  ","a") end)(1,2)


-- demonstrating the glitch on globals --

b,b = 1,2

check(b,"global","b")


-- demonstrating the glitch on closed upvalues --

;
(function ()
   local x
   return function ()
            x,x = 1,2
            check(x,"upval ","x")
          end
 end)()()


-- demonstrating the glitch on tables --

local x = {}

x.a,x.a = 1,2

check(x.a,"field ","a")


-- demonstrating the glitch on different variables --

local side_effect = 1
local function new(name,note)
  local instance = { name = name, note=note }
  setmetatable(instance,{ __newindex =
    function (_,idx,val)
      print("tbl",name, "idx",idx, "val",val, note,side_effect)
      side_effect = side_effect+1
    end })
  return instance
end

local A = new("A","side_effect should be 1st but is")
local B = new("B","side_effect should be 2nd but is")

A.a,B.b = 1,2