diff --git a/hy/compiler.py b/hy/compiler.py index 5d15cf4..fc00a2b 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1893,6 +1893,9 @@ class HyASTCompiler(object): called_as = expression.pop(0) arglist = expression.pop(0) + if not isinstance(arglist, HyList): + raise HyTypeError(expression, + "First argument to (fn) must be a list") ret, args, defaults, stararg, kwargs = self._parse_lambda_list(arglist) if PY34: diff --git a/hy/core/bootstrap.hy b/hy/core/bootstrap.hy index 3afd2c5..1363477 100644 --- a/hy/core/bootstrap.hy +++ b/hy/core/bootstrap.hy @@ -44,6 +44,8 @@ "define a function `name` with signature `lambda-list` and body `body`" (if (not (= (type name) HySymbol)) (macro-error name "defn/defun takes a name as first argument")) + (if (not (isinstance lambda-list HyList)) + (macro-error name "defn/defun takes a parameter list as second argument")) `(setv ~name (fn ~lambda-list ~@body))) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index d615643..a2e8b62 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -52,6 +52,15 @@ (try (eval '(defn lambda [] (print "hello"))) (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))) +(defn test-fn-corner-cases [] + "NATIVE: tests that fn/defn handles corner cases gracefully" + (try (eval '(fn "foo")) + (catch [e [Exception]] (assert (in "to (fn) must be a list" + (str e))))) + (try (eval '(defn foo "foo")) + (catch [e [Exception]] + (assert (in "takes a parameter list as second" (str e)))))) + (defn test-for-loop [] "NATIVE: test for loops" (setv count 0)