diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-08-24 10:17:54 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-08-24 10:17:54 -0300 |
| commit | 8c8a91f2ef7acccb99e3737913faad8d48b39571 (patch) | |
| tree | 0807151944b7f7fd00eedfcfe94b4ee26fe25b21 | |
| parent | f99509581ee73c1c2dbddb3398e87c098771d31f (diff) | |
| download | lua-8c8a91f2ef7acccb99e3737913faad8d48b39571.tar.gz lua-8c8a91f2ef7acccb99e3737913faad8d48b39571.tar.bz2 lua-8c8a91f2ef7acccb99e3737913faad8d48b39571.zip | |
Deprecated the emulation of '__le' using '__lt'
As hinted in the manual for Lua 5.3, the emulation of the metamethod
for '__le' using '__le' has been deprecated. It is slow, complicates
the logic, and it is easy to avoid this emulation by defining a proper
'__le' function.
Moreover, often this emulation was used wrongly, with a programmer
assuming that an order is total when it is not (e.g., NaN in
floating-point numbers).
| -rw-r--r-- | lstate.h | 8 | ||||
| -rw-r--r-- | ltests.h | 1 | ||||
| -rw-r--r-- | ltm.c | 2 | ||||
| -rw-r--r-- | luaconf.h | 8 | ||||
| -rw-r--r-- | lvm.c | 2 | ||||
| -rw-r--r-- | manual/manual.of | 21 | ||||
| -rw-r--r-- | testes/coroutine.lua | 8 | ||||
| -rw-r--r-- | testes/events.lua | 34 |
8 files changed, 44 insertions, 40 deletions
| @@ -138,9 +138,11 @@ typedef struct CallInfo { | |||
| 138 | #define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ | 138 | #define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ |
| 139 | #define CIST_TAIL (1<<4) /* call was tail called */ | 139 | #define CIST_TAIL (1<<4) /* call was tail called */ |
| 140 | #define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ | 140 | #define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ |
| 141 | #define CIST_LEQ (1<<6) /* using __lt for __le */ | 141 | #define CIST_FIN (1<<6) /* call is running a finalizer */ |
| 142 | #define CIST_FIN (1<<7) /* call is running a finalizer */ | 142 | #define CIST_TRAN (1<<7) /* 'ci' has transfer information */ |
| 143 | #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ | 143 | #if defined(LUA_COMPAT_LT_LE) |
| 144 | #define CIST_LEQ (1<<8) /* using __lt for __le */ | ||
| 145 | #endif | ||
| 144 | 146 | ||
| 145 | /* active function is a Lua function */ | 147 | /* active function is a Lua function */ |
| 146 | #define isLua(ci) (!((ci)->callstatus & CIST_C)) | 148 | #define isLua(ci) (!((ci)->callstatus & CIST_C)) |
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | /* test Lua with compatibility code */ | 14 | /* test Lua with compatibility code */ |
| 15 | #define LUA_COMPAT_MATHLIB | 15 | #define LUA_COMPAT_MATHLIB |
| 16 | #define LUA_COMPAT_LT_LE | ||
| 16 | 17 | ||
| 17 | 18 | ||
| 18 | #define LUA_DEBUG | 19 | #define LUA_DEBUG |
| @@ -188,6 +188,7 @@ int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
| 188 | TMS event) { | 188 | TMS event) { |
| 189 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ | 189 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ |
| 190 | return !l_isfalse(s2v(L->top)); | 190 | return !l_isfalse(s2v(L->top)); |
| 191 | #if defined(LUA_COMPAT_LT_LE) | ||
| 191 | else if (event == TM_LE) { | 192 | else if (event == TM_LE) { |
| 192 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ | 193 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ |
| 193 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ | 194 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ |
| @@ -197,6 +198,7 @@ int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
| 197 | } | 198 | } |
| 198 | /* else error will remove this 'ci'; no need to clear mark */ | 199 | /* else error will remove this 'ci'; no need to clear mark */ |
| 199 | } | 200 | } |
| 201 | #endif | ||
| 200 | luaG_ordererror(L, p1, p2); /* no metamethod found */ | 202 | luaG_ordererror(L, p1, p2); /* no metamethod found */ |
| 201 | return 0; /* to avoid warnings */ | 203 | return 0; /* to avoid warnings */ |
| 202 | } | 204 | } |
| @@ -295,7 +295,7 @@ | |||
| 295 | */ | 295 | */ |
| 296 | 296 | ||
| 297 | /* | 297 | /* |
| 298 | @@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.2. | 298 | @@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. |
| 299 | ** You can define it to get all options, or change specific options | 299 | ** You can define it to get all options, or change specific options |
| 300 | ** to fit your specific needs. | 300 | ** to fit your specific needs. |
| 301 | */ | 301 | */ |
| @@ -316,6 +316,12 @@ | |||
| 316 | */ | 316 | */ |
| 317 | #define LUA_COMPAT_APIINTCASTS | 317 | #define LUA_COMPAT_APIINTCASTS |
| 318 | 318 | ||
| 319 | /* | ||
| 320 | @@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod | ||
| 321 | ** using '__lt'. | ||
| 322 | */ | ||
| 323 | #define LUA_COMPAT_LT_LE | ||
| 324 | |||
| 319 | #endif /* } */ | 325 | #endif /* } */ |
| 320 | 326 | ||
| 321 | 327 | ||
| @@ -754,10 +754,12 @@ void luaV_finishOp (lua_State *L) { | |||
| 754 | case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ | 754 | case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ |
| 755 | int res = !l_isfalse(s2v(L->top - 1)); | 755 | int res = !l_isfalse(s2v(L->top - 1)); |
| 756 | L->top--; | 756 | L->top--; |
| 757 | #if defined(LUA_COMPAT_LT_LE) | ||
| 757 | if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ | 758 | if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ |
| 758 | ci->callstatus ^= CIST_LEQ; /* clear mark */ | 759 | ci->callstatus ^= CIST_LEQ; /* clear mark */ |
| 759 | res = !res; /* negate result */ | 760 | res = !res; /* negate result */ |
| 760 | } | 761 | } |
| 762 | #endif | ||
| 761 | lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); | 763 | lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); |
| 762 | if (res != GETARG_k(inst)) /* condition failed? */ | 764 | if (res != GETARG_k(inst)) /* condition failed? */ |
| 763 | ci->u.l.savedpc++; /* skip jump instruction */ | 765 | ci->u.l.savedpc++; /* skip jump instruction */ |
diff --git a/manual/manual.of b/manual/manual.of index 5a8b1b2c..47a551bf 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
| @@ -474,17 +474,7 @@ The result of the call is always converted to a boolean. | |||
| 474 | 474 | ||
| 475 | @item{@idx{__le}| | 475 | @item{@idx{__le}| |
| 476 | the less equal (@T{<=}) operation. | 476 | the less equal (@T{<=}) operation. |
| 477 | Unlike other operations, | 477 | Behavior similar to the less than operation. |
| 478 | the less-equal operation can use two different events. | ||
| 479 | First, Lua looks for the @idx{__le} metamethod in both operands, | ||
| 480 | like in the less than operation. | ||
| 481 | If it cannot find such a metamethod, | ||
| 482 | then it will try the @idx{__lt} metamethod, | ||
| 483 | assuming that @T{a <= b} is equivalent to @T{not (b < a)}. | ||
| 484 | As with the other comparison operators, | ||
| 485 | the result is always a boolean. | ||
| 486 | (This use of the @idx{__lt} event can be removed in future versions; | ||
| 487 | it is also slower than a real @idx{__le} metamethod.) | ||
| 488 | } | 478 | } |
| 489 | 479 | ||
| 490 | @item{@idx{__index}| | 480 | @item{@idx{__index}| |
| @@ -1643,7 +1633,8 @@ all operations @emphx{wrap around}, | |||
| 1643 | according to the usual rules of two-complement arithmetic. | 1633 | according to the usual rules of two-complement arithmetic. |
| 1644 | (In other words, | 1634 | (In other words, |
| 1645 | they return the unique representable integer | 1635 | they return the unique representable integer |
| 1646 | that is equal modulo @M{2@sp{64}} to the mathematical result.) | 1636 | that is equal modulo @M{2@sp{n}} to the mathematical result, |
| 1637 | where @M{n} is the number of bits of the integer type.) | ||
| 1647 | } | 1638 | } |
| 1648 | 1639 | ||
| 1649 | @sect3{bitwise| @title{Bitwise Operators} | 1640 | @sect3{bitwise| @title{Bitwise Operators} |
| @@ -8537,6 +8528,12 @@ For instance, the result of @T{"1" + "2"} now is an integer, | |||
| 8537 | not a float. | 8528 | not a float. |
| 8538 | } | 8529 | } |
| 8539 | 8530 | ||
| 8531 | @item{ | ||
| 8532 | The use of the @idx{__lt} metamethod to emulate @id{__le} | ||
| 8533 | has been removed. | ||
| 8534 | When needed, this metamethod must be explicitly defined. | ||
| 8535 | } | ||
| 8536 | |||
| 8540 | } | 8537 | } |
| 8541 | 8538 | ||
| 8542 | } | 8539 | } |
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 182c1e18..36eae44a 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | -- $Id: testes/coroutine.lua $ | 1 | -- $Id: testes/coroutine.lua 2018-07-25 15:31:04 -0300 $ |
| 2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file all.lua |
| 3 | 3 | ||
| 4 | print "testing coroutines" | 4 | print "testing coroutines" |
| @@ -619,10 +619,8 @@ end | |||
| 619 | 619 | ||
| 620 | assert(run(function () if (a>=b) then return '>=' else return '<' end end, | 620 | assert(run(function () if (a>=b) then return '>=' else return '<' end end, |
| 621 | {"le", "sub"}) == "<") | 621 | {"le", "sub"}) == "<") |
| 622 | -- '<=' using '<' | ||
| 623 | mt.__le = nil | ||
| 624 | assert(run(function () if (a<=b) then return '<=' else return '>' end end, | 622 | assert(run(function () if (a<=b) then return '<=' else return '>' end end, |
| 625 | {"lt"}) == "<=") | 623 | {"le", "sub"}) == "<=") |
| 626 | assert(run(function () if (a==b) then return '==' else return '~=' end end, | 624 | assert(run(function () if (a==b) then return '==' else return '~=' end end, |
| 627 | {"eq"}) == "~=") | 625 | {"eq"}) == "~=") |
| 628 | 626 | ||
| @@ -677,7 +675,7 @@ do -- a few more tests for comparsion operators | |||
| 677 | return val(a) < val(b) | 675 | return val(a) < val(b) |
| 678 | end, | 676 | end, |
| 679 | } | 677 | } |
| 680 | local mt2 = { __lt = mt1.__lt } -- no __le | 678 | local mt2 = { __lt = mt1.__lt, __le = mt1.__le } |
| 681 | 679 | ||
| 682 | local function run (f) | 680 | local function run (f) |
| 683 | local co = coroutine.wrap(f) | 681 | local co = coroutine.wrap(f) |
diff --git a/testes/events.lua b/testes/events.lua index 21a822a7..c4d43d51 100644 --- a/testes/events.lua +++ b/testes/events.lua | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | -- $Id: testes/events.lua $ | 1 | -- $Id: testes/events.lua 2018-07-25 15:31:04 -0300 $ |
| 2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file all.lua |
| 3 | 3 | ||
| 4 | print('testing metatables') | 4 | print('testing metatables') |
| @@ -217,6 +217,13 @@ t.__lt = function (a,b,c) | |||
| 217 | return a<b, "dummy" | 217 | return a<b, "dummy" |
| 218 | end | 218 | end |
| 219 | 219 | ||
| 220 | t.__le = function (a,b,c) | ||
| 221 | assert(c == nil) | ||
| 222 | if type(a) == 'table' then a = a.x end | ||
| 223 | if type(b) == 'table' then b = b.x end | ||
| 224 | return a<=b, "dummy" | ||
| 225 | end | ||
| 226 | |||
| 220 | function Op(x) return setmetatable({x=x}, t) end | 227 | function Op(x) return setmetatable({x=x}, t) end |
| 221 | 228 | ||
| 222 | local function test () | 229 | local function test () |
| @@ -236,15 +243,6 @@ end | |||
| 236 | 243 | ||
| 237 | test() | 244 | test() |
| 238 | 245 | ||
| 239 | t.__le = function (a,b,c) | ||
| 240 | assert(c == nil) | ||
| 241 | if type(a) == 'table' then a = a.x end | ||
| 242 | if type(b) == 'table' then b = b.x end | ||
| 243 | return a<=b, "dummy" | ||
| 244 | end | ||
| 245 | |||
| 246 | test() -- retest comparisons, now using both `lt' and `le' | ||
| 247 | |||
| 248 | 246 | ||
| 249 | -- test `partial order' | 247 | -- test `partial order' |
| 250 | 248 | ||
| @@ -266,14 +264,6 @@ t.__lt = function (a,b) | |||
| 266 | return next(b) ~= nil | 264 | return next(b) ~= nil |
| 267 | end | 265 | end |
| 268 | 266 | ||
| 269 | t.__le = nil | ||
| 270 | |||
| 271 | assert(Set{1,2,3} < Set{1,2,3,4}) | ||
| 272 | assert(not(Set{1,2,3,4} < Set{1,2,3,4})) | ||
| 273 | assert((Set{1,2,3,4} <= Set{1,2,3,4})) | ||
| 274 | assert((Set{1,2,3,4} >= Set{1,2,3,4})) | ||
| 275 | assert((Set{1,3} <= Set{3,5})) -- wrong!! model needs a `le' method ;-) | ||
| 276 | |||
| 277 | t.__le = function (a,b) | 267 | t.__le = function (a,b) |
| 278 | for k in pairs(a) do | 268 | for k in pairs(a) do |
| 279 | if not b[k] then return false end | 269 | if not b[k] then return false end |
| @@ -281,10 +271,15 @@ t.__le = function (a,b) | |||
| 281 | return true | 271 | return true |
| 282 | end | 272 | end |
| 283 | 273 | ||
| 284 | assert(not (Set{1,3} <= Set{3,5})) -- now its OK! | 274 | assert(Set{1,2,3} < Set{1,2,3,4}) |
| 275 | assert(not(Set{1,2,3,4} < Set{1,2,3,4})) | ||
| 276 | assert((Set{1,2,3,4} <= Set{1,2,3,4})) | ||
| 277 | assert((Set{1,2,3,4} >= Set{1,2,3,4})) | ||
| 278 | assert(not (Set{1,3} <= Set{3,5})) | ||
| 285 | assert(not(Set{1,3} <= Set{3,5})) | 279 | assert(not(Set{1,3} <= Set{3,5})) |
| 286 | assert(not(Set{1,3} >= Set{3,5})) | 280 | assert(not(Set{1,3} >= Set{3,5})) |
| 287 | 281 | ||
| 282 | |||
| 288 | t.__eq = function (a,b) | 283 | t.__eq = function (a,b) |
| 289 | for k in pairs(a) do | 284 | for k in pairs(a) do |
| 290 | if not b[k] then return false end | 285 | if not b[k] then return false end |
| @@ -376,6 +371,7 @@ t1 = {}; c = {}; setmetatable(c, t1) | |||
| 376 | d = {} | 371 | d = {} |
| 377 | t1.__eq = function () return true end | 372 | t1.__eq = function () return true end |
| 378 | t1.__lt = function () return true end | 373 | t1.__lt = function () return true end |
| 374 | t1.__le = function () return false end | ||
| 379 | setmetatable(d, t1) | 375 | setmetatable(d, t1) |
| 380 | assert(c == d and c < d and not(d <= c)) | 376 | assert(c == d and c < d and not(d <= c)) |
| 381 | t2 = {} | 377 | t2 = {} |
