Repository: hylang/hy

Issue:
`setv` in `defclass` with odd number of arguments crashes the compiler
  The following code crashes the compiler:
```lisp
(import csv)
(defclass my-dialect [csv.Dialect]
  (setv lineterminator "\n")
  (setv delimiter = ";")
  (setv quotechar = "\"")
  (setv quoting csv.QUOTE-MINIMAL))
```

And result:

```lisp
% hy
hy 0.19.0 using CPython(default) 3.8.5 on Linux
=> (import csv)
=> (defclass my-dialect [csv.Dialect]
...   (setv lineterminator "\n")
...   (setv delimiter = ";")
...   (setv quotechar = "\"")
...   (setv quoting csv.QUOTE-MINIMAL))
Traceback (most recent call last):
  File "/usr/bin/hy", line 12, in <module>
    sys.exit(hy_main())
  File "/usr/lib/python3.8/code.py", line 232, in interact
    more = self.push(line)
  File "/usr/lib/python3.8/code.py", line 258, in push
    more = self.runsource(source, self.filename)
  File "/usr/lib/python3.8/code.py", line 63, in runsource
    code = self.compile(source, filename, symbol)
  File "/usr/lib/python3.8/codeop.py", line 176, in __call__
    return _maybe_compile(self.compiler, source, filename, symbol)
hy.errors.HyCompileError: Internal Compiler Bug 😱
⤷ Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/hy/compiler.py", line 438, in compile
    ret = self.compile_atom(tree)
  File "/usr/lib/python3.8/site-packages/hy/compiler.py", line 432, in compile_atom
    return Result() + _model_compilers[type(atom)](self, atom)
  File "/usr/lib/python3.8/site-packages/hy/compiler.py", line 1782, in compile_expression
    return Result() + build_method(
  File "/usr/lib/python3.8/site-packages/hy/compiler.py", line 1642, in compile_class_expression
    e = self.compile(self._rewire_init(
  File "/usr/lib/python3.8/site-packages/hy/compiler.py", line 1674, in _rewire_init
    k, v = (decls.pop(0), decls.pop(0))
IndexError: pop from empty list
```




Discussion:
I suppose that happened because I've accidentally inserted `=` character there.
Yep. A minimal version is `(defclass C [] (setv a))`.

Resolving patch:
diff --git a/hy/compiler.py b/hy/compiler.py
--- a/hy/compiler.py
+++ b/hy/compiler.py
@@ -1671,6 +1671,8 @@ def _rewire_init(self, expr):
             else:
                 ann = None
 
+            if len(decls) < 2:
+                break
             k, v = (decls.pop(0), decls.pop(0))
             if ast_str(k) == "__init__" and isinstance(v, HyExpression):
                 v += HyExpression([HySymbol("None")])
@@ -1679,7 +1681,8 @@ def _rewire_init(self, expr):
                 new_args.append(ann)
 
             new_args.extend((k, v))
-        return HyExpression([HySymbol("setv")] + new_args).replace(expr)
+        return (HyExpression([HySymbol("setv")] + new_args + decls)
+            .replace(expr))
 
     @special("dispatch-tag-macro", [STR, FORM])
     def compile_dispatch_tag_macro(self, expr, root, tag, arg):


Test patch:
diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py
--- a/tests/compilers/test_ast.py
+++ b/tests/compilers/test_ast.py
@@ -234,6 +234,10 @@ def test_ast_bad_defclass():
     cant_compile("(defclass a None)")
     cant_compile("(defclass a None None)")
 
+    # https://github.com/hylang/hy/issues/1920
+    cant_compile("(defclass a [] (setv x))")
+    cant_compile("(defclass a [] (setv x 1  y))")
+
 
 def test_ast_good_lambda():
     "Make sure AST can compile valid lambda"