diff --git a/src/core/c-function.c b/src/core/c-function.c index ae6778681a..552e6d97ea 100644 --- a/src/core/c-function.c +++ b/src/core/c-function.c @@ -148,11 +148,14 @@ if (!return_defined && VAL_WORD_SYM(blk) == SYM_RETURN && IS_BLOCK(blk+1)) { return_defined = TRUE; blk++; // skips the return's specification - continue; + Remove_Series(words, n+1, 1); + break; } // fall thru... default: - Trap1(RE_BAD_FUNC_DEF, blk); + // Report full invalid function spec block in the error. + Set_Block(DS_RETURN, block); + Trap1(RE_BAD_FUNC_DEF, DS_RETURN); } } diff --git a/src/tests/units/func-test.r3 b/src/tests/units/func-test.r3 index bd5a6e5316..8a7dadbd47 100644 --- a/src/tests/units/func-test.r3 +++ b/src/tests/units/func-test.r3 @@ -46,6 +46,57 @@ Rebol [ ===end-group=== +===start-group=== "function construction" + +--test-- "return: keyword" + ;@@ https://github.com/Oldes/Rebol-issues/issues/2602 + ;; because unit tests are guearded by `wrap`, the return value would be unset:/ + return: :lib/return ;; so use the original function + ;; maybe it would be good not to use return as a set-word in this case at all! + + fun: func[a [integer!] return: [integer!]][ return 2 * a 'foo] + --assert 2 == fun 1 + + foreach spec [ + [return: []] + [return: [] "Foo"] + [a return: []] + [return: [] a] + [return: [integer!]] + [a [integer!] return: [integer!]] + [/foo return: [integer!]] + ["test" return: []] + ["test" return: [] "Foo"] + ["test" a return: []] + ["test" return: [] a] + ["test" return: [integer!]] + ["test" a [integer!] return: [integer!]] + ["test" /foo return: [integer!]] + ][ + --assert all [ + function? fun: try [ func :spec [true] ] + spec == spec-of :fun + ] + ] + foreach spec [ + [return:] + [return: ""] + ][ + --assert all [ + error? e: try [ func :spec [] ] + e/id = 'bad-func-def + e/arg1 == spec + ] + ] + --assert all [ + error? e: try [ func [return: [] a return: []][] ] + e/id = 'dup-vars + e/arg1 = 'return + ] + +===end-group=== + + ===start-group=== "Apply" --test-- "apply :do [:func]"