[Python-Dev] bug in grammar
Guido van Rossum
guido@digicool.com
Thu, 18 Jan 2001 11:55:39 -0500
> As part of the implementation of PEP 227 (and in an attempt to reach
> some low-hanging fruit Guido mentioned on the types-sig long ago), I
> have been working on a compiler pass that generates a module-level
> symbol table. I recently discovered a bug in the handling of list
> comprehensions that was giving me headaches.
>
> I realize now that the problem is with the current grammar and/or
> compiler. Here's a simple demonstration; try it in your friendly
> python 2.0 interpreter.
>
> >>> [i for i in range(10)] = (1, 2, 3)
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> ValueError: unpack list of wrong size
>
> The generated bytecode is:
>
> 0 SET_LINENO 0
>
> 3 SET_LINENO 1
> 6 LOAD_CONST 0 (1)
> 9 LOAD_CONST 1 (2)
> 12 LOAD_CONST 2 (3)
> 15 BUILD_TUPLE 3
> 18 UNPACK_SEQUENCE 1
> 21 STORE_NAME 0 (i)
> 24 LOAD_CONST 3 (None)
> 27 RETURN_VALUE
>
> I assume this isn't intended :-). The compiler is ignoring everything
> after the initial atom in the list comprehension. It's basically
> compiling the code as if it were:
>
> [i] = (1, 2, 3)
>
> I'm not sure how to try and fix this. Should the grammar allow one to
> construct the example statement above? If not, I'm not sure how to
> fix the grammar. If not, I suppose the compiler should detect that
> the list comp is misplaced. This seems fairly messy, since there are
> about 10 nodes between the expr_stmt and the list_for.
>
> Or is this a cool way to use list comprehensions to generate
> ValueErrors?
Good catch! Not everything cool deserves to be preserved.
It looks like this happens because the code that traverses lists on
the left-hand side of an assignment was never told about list
comprehensions. You're right that the grammar can't be fixed; it's
for the same reason that it can't be fixed to disallow "f() = 1".
The solution is to add a test for this to the compiler that flags this
as an error.
--Guido van Rossum (home page: http://www.python.org/~guido/)