diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-29 13:15:54 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-29 13:15:54 -0300 |
| commit | 4bd10b6fe81c0a56eb9e01e24fba10e655966870 (patch) | |
| tree | ff21703d9f06a0dd4ca4f3317dd0cb7b048c9b8d | |
| parent | 59e565d9555c07e82808d8c1db8f4f4d159b5e5c (diff) | |
| download | lua-4bd10b6fe81c0a56eb9e01e24fba10e655966870.tar.gz lua-4bd10b6fe81c0a56eb9e01e24fba10e655966870.tar.bz2 lua-4bd10b6fe81c0a56eb9e01e24fba10e655966870.zip | |
Better error messages for calling non-callable objects
When available, use the calling code to find a suitable name for what
was being called; this is particularly useful for errors of non-callable
metamethods. This commit also improved the debug information for
order metamethods.
| -rw-r--r-- | ldebug.c | 23 | ||||
| -rw-r--r-- | ldebug.h | 1 | ||||
| -rw-r--r-- | ldo.c | 2 | ||||
| -rw-r--r-- | testes/db.lua | 6 | ||||
| -rw-r--r-- | testes/errors.lua | 14 | ||||
| -rw-r--r-- | testes/locals.lua | 17 |
6 files changed, 52 insertions, 11 deletions
| @@ -629,12 +629,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, | |||
| 629 | case OP_LEN: tm = TM_LEN; break; | 629 | case OP_LEN: tm = TM_LEN; break; |
| 630 | case OP_CONCAT: tm = TM_CONCAT; break; | 630 | case OP_CONCAT: tm = TM_CONCAT; break; |
| 631 | case OP_EQ: tm = TM_EQ; break; | 631 | case OP_EQ: tm = TM_EQ; break; |
| 632 | case OP_LT: case OP_LE: case OP_LTI: case OP_LEI: | 632 | /* no cases for OP_EQI and OP_EQK, as they don't call metamethods */ |
| 633 | *name = "order"; /* '<=' can call '__lt', etc. */ | 633 | case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break; |
| 634 | return "metamethod"; | 634 | case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break; |
| 635 | case OP_CLOSE: case OP_RETURN: | 635 | case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break; |
| 636 | *name = "close"; | ||
| 637 | return "metamethod"; | ||
| 638 | default: | 636 | default: |
| 639 | return NULL; /* cannot find a reasonable name */ | 637 | return NULL; /* cannot find a reasonable name */ |
| 640 | } | 638 | } |
| @@ -697,6 +695,19 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { | |||
| 697 | } | 695 | } |
| 698 | 696 | ||
| 699 | 697 | ||
| 698 | l_noret luaG_callerror (lua_State *L, const TValue *o) { | ||
| 699 | CallInfo *ci = L->ci; | ||
| 700 | const char *name = NULL; /* to avoid warnings */ | ||
| 701 | const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL; | ||
| 702 | if (what != NULL) { | ||
| 703 | const char *t = luaT_objtypename(L, o); | ||
| 704 | luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t); | ||
| 705 | } | ||
| 706 | else | ||
| 707 | luaG_typeerror(L, o, "call"); | ||
| 708 | } | ||
| 709 | |||
| 710 | |||
| 700 | l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) { | 711 | l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) { |
| 701 | luaG_runerror(L, "bad 'for' %s (number expected, got %s)", | 712 | luaG_runerror(L, "bad 'for' %s (number expected, got %s)", |
| 702 | what, luaT_objtypename(L, o)); | 713 | what, luaT_objtypename(L, o)); |
| @@ -31,6 +31,7 @@ LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, | |||
| 31 | StkId *pos); | 31 | StkId *pos); |
| 32 | LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, | 32 | LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, |
| 33 | const char *opname); | 33 | const char *opname); |
| 34 | LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o); | ||
| 34 | LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o, | 35 | LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o, |
| 35 | const char *what); | 36 | const char *what); |
| 36 | LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, | 37 | LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, |
| @@ -372,7 +372,7 @@ void luaD_tryfuncTM (lua_State *L, StkId func) { | |||
| 372 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); | 372 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); |
| 373 | StkId p; | 373 | StkId p; |
| 374 | if (unlikely(ttisnil(tm))) | 374 | if (unlikely(ttisnil(tm))) |
| 375 | luaG_typeerror(L, s2v(func), "call"); /* nothing to call */ | 375 | luaG_callerror(L, s2v(func)); /* nothing to call */ |
| 376 | for (p = L->top; p > func; p--) /* open space for metamethod */ | 376 | for (p = L->top; p > func; p--) /* open space for metamethod */ |
| 377 | setobjs2s(L, p, p-1); | 377 | setobjs2s(L, p, p-1); |
| 378 | L->top++; /* stack space pre-allocated by the caller */ | 378 | L->top++; /* stack space pre-allocated by the caller */ |
diff --git a/testes/db.lua b/testes/db.lua index fdb0da4a..ce559ad9 100644 --- a/testes/db.lua +++ b/testes/db.lua | |||
| @@ -823,8 +823,10 @@ assert(a + 30000 == "add" and a - 3.0 == "sub" and a * 3.0 == "mul" and | |||
| 823 | -a == "unm" and #a == "len" and a & 3 == "band") | 823 | -a == "unm" and #a == "len" and a & 3 == "band") |
| 824 | assert(a|3 == "bor" and 3~a == "bxor" and a<<3 == "shl" and a>>1 == "shr") | 824 | assert(a|3 == "bor" and 3~a == "bxor" and a<<3 == "shl" and a>>1 == "shr") |
| 825 | assert (a==b and a.op == "eq") | 825 | assert (a==b and a.op == "eq") |
| 826 | assert (a>=b and a.op == "order") | 826 | assert (a>=b and a.op == "le") |
| 827 | assert (a>b and a.op == "order") | 827 | assert ("x">=a and a.op == "le") |
| 828 | assert (a>b and a.op == "lt") | ||
| 829 | assert (a>10 and a.op == "lt") | ||
| 828 | assert(~a == "bnot") | 830 | assert(~a == "bnot") |
| 829 | 831 | ||
| 830 | do -- testing for-iterator name | 832 | do -- testing for-iterator name |
diff --git a/testes/errors.lua b/testes/errors.lua index a3f07021..4249f570 100644 --- a/testes/errors.lua +++ b/testes/errors.lua | |||
| @@ -24,8 +24,9 @@ local function doit (s) | |||
| 24 | end | 24 | end |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | local function checkmessage (prog, msg) | 27 | local function checkmessage (prog, msg, debug) |
| 28 | local m = doit(prog) | 28 | local m = doit(prog) |
| 29 | if debug then print(m) end | ||
| 29 | assert(string.find(m, msg, 1, true)) | 30 | assert(string.find(m, msg, 1, true)) |
| 30 | end | 31 | end |
| 31 | 32 | ||
| @@ -120,6 +121,17 @@ assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'")) | |||
| 120 | checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number") | 121 | checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number") |
| 121 | checkmessage("a=(1)..{}", "a table value") | 122 | checkmessage("a=(1)..{}", "a table value") |
| 122 | 123 | ||
| 124 | -- calls | ||
| 125 | checkmessage("local a; a(13)", "local 'a'") | ||
| 126 | checkmessage([[ | ||
| 127 | local a = setmetatable({}, {__add = 34}) | ||
| 128 | a = a + 1 | ||
| 129 | ]], "metamethod 'add'") | ||
| 130 | checkmessage([[ | ||
| 131 | local a = setmetatable({}, {__lt = {}}) | ||
| 132 | a = a > a | ||
| 133 | ]], "metamethod 'lt'") | ||
| 134 | |||
| 123 | -- tail calls | 135 | -- tail calls |
| 124 | checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'") | 136 | checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'") |
| 125 | checkmessage("a={}; do local a=1 end; return a:bbbb(3)", "method 'bbbb'") | 137 | checkmessage("a={}; do local a=1 end; return a:bbbb(3)", "method 'bbbb'") |
diff --git a/testes/locals.lua b/testes/locals.lua index 1b43609b..add023ca 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
| @@ -459,7 +459,22 @@ do -- errors due to non-closable values | |||
| 459 | getmetatable(xyz).__close = nil -- remove metamethod | 459 | getmetatable(xyz).__close = nil -- remove metamethod |
| 460 | end | 460 | end |
| 461 | local stat, msg = pcall(foo) | 461 | local stat, msg = pcall(foo) |
| 462 | assert(not stat and string.find(msg, "attempt to call a nil value")) | 462 | assert(not stat and string.find(msg, "metamethod 'close'")) |
| 463 | |||
| 464 | local function foo () | ||
| 465 | local a1 <close> = func2close(function (_, msg) | ||
| 466 | assert(string.find(msg, "number value")) | ||
| 467 | error(12) | ||
| 468 | end) | ||
| 469 | local a2 <close> = setmetatable({}, {__close = print}) | ||
| 470 | local a3 <close> = func2close(function (_, msg) | ||
| 471 | assert(msg == nil) | ||
| 472 | error(123) | ||
| 473 | end) | ||
| 474 | getmetatable(a2).__close = 4 -- invalidate metamethod | ||
| 475 | end | ||
| 476 | local stat, msg = pcall(foo) | ||
| 477 | assert(not stat and msg == 12) | ||
| 463 | end | 478 | end |
| 464 | 479 | ||
| 465 | 480 | ||
