[Cython] cython-devel-tests-pyregr regression

Vitja Makarov vitja.makarov at gmail.com
Thu Aug 23 07:39:34 CEST 2012


2012/8/23 Vitja Makarov <vitja.makarov at gmail.com>:
> 2012/8/23 Stefan Behnel <stefan_ml at behnel.de>:
>> Vitja Makarov, 23.08.2012 07:03:
>>> 2012/8/23 Stefan Behnel <stefan_ml at behnel.de>:
>>>> Vitja Makarov, 22.08.2012 22:34:
>>>>> 2012/8/23 Stefan Behnel:
>>>>>> Vitja Makarov, 22.08.2012 22:11:
>>>>>>> I've found regression:
>>>>>>>
>>>>>>> https://sage.math.washington.edu:8091/hudson/job/cython-devel-tests-pyregr/
>>>>>>
>>>>>> Interesting. It's a Py2 list comprehension in a class body that's failing here:
>>>>>>
>>>>>> """
>>>>>>  class TestHelpSubparsersOrdering(HelpTestCase):
>>>>>>      subparsers_signatures = [Sig(name=name)
>>>>>>                               for name in ('a', 'b', 'c', 'd', 'e')]
>>>>>>  """
>>>>>>
>>>>>> I wonder why "name" isn't declared as a variable yet at the point where it
>>>>>> is being looked up in the function call.
>>>>>
>>>>>     def lookup_relative(self, name, pos):
>>>>>         if name == "name":
>>>>>             print name
>>>>>             from ipdb import set_trace; set_trace()
>>>>>         entry = self.lookup_here(name)
>>>>>         if entry is not None and entry.pos[1:] <= pos[1:]: # Lookup fails here
>>>>>             return entry
>>>>>         if self.outer_scope:
>>>>>             return self.outer_scope.lookup_relative(name, pos)
>>>>>         return None
>>>>>
>>>>>
>>>>> What is that comparison for?
>>>>
>>>> Ah, yes, it is wrong in this context. It was meant to prevent names defined
>>>> further down in the class body from being considered assignments to the
>>>> name being looked up. Class bodies are not function bodies, assignments in
>>>> them do not make a name "local". As long as it's not assigned, it's not
>>>> defined and must be looked up in the outer scope.
>>>
>>> Do you remember this ticket #671
>>>
>>> If there is assignment in the class body we first lookup in the class
>>> dict and then in globals.
>>>
>>> B = 0
>>> def foo():
>>>     B = 1
>>>     class Foo():
>>>         A = B
>>>         B = B
>>>     class Bar():
>>>         A = B
>>>     print Foo.A, Foo.B, Bar.A
>>> foo()
>>>
>>> prints "0 0 1"
>>
>> In the case at hand, it's not an assignment but a method declaration. Maybe
>> that makes a difference.
>>
>> In any case, this needs some more investigation than I did for my change. I
>> think it can be rolled back completely.
>>
>>
>>>> I think comprehensions are actually the only case where a name is used in
>>>> the source before its declaration. It should work in all other cases.
>>>>
>>>> I had considered solving this problem with the flow control analysis
>>>> information, but I can't see how that helps me to figure out if an entry is
>>>> already assigned (i.e. declared) at a given point in the class body.
>>>>
>>>> Any idea?
>>>
>>> What would you do with maybe assigned case?
>>
>> Hmm, yes - I guess we can't solve the general case at compile time. That's
>> unfortunate, though, because it prevents proper compile time optimisation
>> of builtins in class bodies when their names are assigned at some point,
>> e.g. with a ".type()" method or ".set()", as was the case here.
>>
>> Stefan
>>
>
>
>
> This is NameNode related problem
>
> The following code would fail as well:
> XXX = 123
> class Foo(object):
>     t1 = XXX  # XXX   cf_is_null = True
>     t2 = XXX  # XXX   cf_is_null = False
>     XXX = 123
>
> CF assumes that after first apperence of NULL name it must be then set
> otherwise exception must be raised.
> NameNode code relays on CF here, so I think it mustn't. We must
> allways check result of PyObject_GetItem() and if's NULL look at the
> globals then.
>
> I'll try to fix it soon.
>
>

I've reverted your commit and here is my fix:
https://github.com/vitek/cython/commit/198f254f62360b61c895ba68be0f4dbe07444449

Cause of different class scope lookup rules I think we can't fully
trust CF here.


-- 
vitja.


More information about the cython-devel mailing list