diff --git a/NEWS b/NEWS index 7140361..cc19a6b 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,7 @@ Changes from 0.13.0 instead of silently ignoring them * Multiple expressions are now allowed in the else clause of a for loop + * Argument destructuring no longer interferes with function docstrings. [ Misc. Improvements ] * `read`, `read_str`, and `eval` are exposed and documented as top-level diff --git a/hy/compiler.py b/hy/compiler.py index 29f3f51..953d5d8 100755 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1881,6 +1881,10 @@ class HyASTCompiler(object): force_functiondef = expression.pop(0) == "fn*" arglist = expression.pop(0) + docstring = None + if len(expression) > 1 and isinstance(expression[0], str_type): + docstring = expression.pop(0) + if not isinstance(arglist, HyList): raise HyTypeError(expression, "First argument to `fn' must be a list") @@ -1901,6 +1905,11 @@ class HyASTCompiler(object): ) + expression expression = expression.replace(arg[0]) + # Docstrings must come at the start, so ensure that happens even if we + # generate anonymous variables. + if docstring is not None: + expression.insert(0, docstring) + if PY3: # Python 3.4+ requires that args are an ast.arg object, rather # than an ast.Name or bare string. diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index a77858c..f0ce60b 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -1660,3 +1660,24 @@ [_42 6]) (setv x (XYZ)) (assert (= (. x _42) 6))) + +(defn test-docstrings [] + "Make sure docstrings in functions work and don't clash with return values" + (defn f [] "docstring" 5) + (assert (= (. f __doc__) "docstring")) + + ; destructuring and the implicit variables it creates + ; shouldn't interfere with docstrings + ; (https://github.com/hylang/hy/issues/1409) + (defn f2 [[a b]] "docstring" 5) + (assert (= (. f2 __doc__) "docstring")) + + ; a single string is the return value, not a docstring + ; (https://github.com/hylang/hy/issues/1402) + (defn f3 [] "not a docstring") + (assert (none? (. f3 __doc__))) + (assert (= (f3) "not a docstring")) + + (defn f4 [[a b]] "not a docstring") + (assert (none? (. f4 __doc__))) + (assert (= (f4 [1 2]) "not a docstring")))