GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — SystemError for pep695 type parameter with the same name as the inner class · Issue #109219 · python/cpython

SystemError for pep695 type parameter with the same name as the inner class #109219

New issue
Copy link
New issue
Copy link
Closed
Closed
SystemError for pep695 type parameter with the same name as the inner class#109219
Copy link
Assignees
JelleZijlstra
Labels
3.12only security fixesonly security fixes3.13only security fixesonly security fixesrelease-blockertopic-typingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@15r10nk
15r10nk
opened on Sep 10, 2023
Issue body actions

Bug report

Bug description:

The following script shows the SystemError:

class name_1[name_4]:

    class name_4[name_2](name_4):
        name_4

output (Python 3.12.0rc2+):

SystemError: compiler_lookup_arg(name='name_4') with reftype=3 failed in <generic parameters of name_4>; freevars of code name_4: ('.type_params', 'name_4')

minimizing it further leads some different crashes:
The propably most interresting one is this, which does not look special at all.

class name_1[name_3]:
    class name_4[name_2](name_5):
        pass

output (Python 3.12.0rc2+):

Traceback (most recent call last):
  File "/home/frank/projects/pysource-codegen/bug3.py", line 1, in <module>
    class name_1[name_3]:
  File "/home/frank/projects/pysource-codegen/bug3.py", line 1, in <generic parameters of name_1>
    class name_1[name_3]:
  File "/home/frank/projects/pysource-codegen/bug3.py", line 2, in name_1
    class name_4[name_2](name_5):
  File "/home/frank/projects/pysource-codegen/bug3.py", line 2, in <generic parameters of name_4>
    class name_4[name_2](name_5):
                         ^^^^^^
NameError: name 'name_5' is not defined. Did you mean: 'name_2'?
Modules/gcmodule.c:113: gc_decref: Assertion "gc_get_refs(g) > 0" failed: refcount is too small
Enable tracemalloc to get the memory block allocation traceback

object address  : 0x7f2c57a12930
object refcount : 1
object type     : 0x557ad9ef1fe0
object type name: dict
object repr     : {'__module__': '__main__', '__qualname__': 'name_1', '__type_params__': (name_3,)}

Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed
Python runtime state: finalizing (tstate=0x0000557ada04eba0)

Current thread 0x00007f2c57f21280 (most recent call first):
  Garbage-collecting
  <no Python frame>

@JelleZijlstra I think this is another one for you. Feel free to create a second issue if you think that they are unrelated.

CPython versions tested on:

3.12

Operating systems tested on:

Linux

Linked PRs

  • gh-109219: propagate free vars through type param scopes #109377
  • gh-109219: propagate used free vars through type param scopes [v2] #109389
  • [3.12] gh-109219: propagate free vars through type param scopes (GH-109377) #109410

Activity

  1. 15r10nk
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Sep 10, 2023
  2. AlexWaygood
    added
    topic-typing
    release-blocker
    3.12only security fixesonly security fixes
    3.13only security fixesonly security fixes
    on Sep 10, 2023
  3. AlexWaygood
    assigned
    JelleZijlstra
    on Sep 10, 2023
  4. ezio-melotti
    added this to Release and Deferred blockers 🚫on Sep 10, 2023
  5. github-project-automation
    moved this to Todo in Release and Deferred blockers 🚫on Sep 10, 2023
  6. JelleZijlstra commented on Sep 10, 2023

    @JelleZijlstra
    JelleZijlstra
    on Sep 10, 2023
    Member
    More actions

    Thanks. The second one should be fixed by #109123. I'll have to look into what is causing the SystemError on your first example.

  7. JelleZijlstra commented on Sep 11, 2023

    @JelleZijlstra
    JelleZijlstra
    on Sep 11, 2023
    Member
    More actions

    I spent some time last night trying to get this to work without success. I'll try more later today, but here are my thoughts so far on this example:

    class name_1[name_4]:
    
        class name_4[name_2](name_4):
            name_4

    The name_4 in the body of the inner class should refer to the type param of the outer class, because the bodies of inner classes can't see names defined in outer classes, but they can see names defined in outer function-like scopes.

    The name_4 in the bases of the inner class should be a NameError. If a name is bound anywhere in a class body, then we look only at the class scope and the global scope, not any intervening scopes. I discuss this in https://jellezijlstra.github.io/pep695 in the section that starts "A few more edge cases came up later." In this case, the name is bound in the class body, but there is no binding yet when the bases of the inner class are evaluated, so next we look at the globals, where there is also no name_4, so we raise a NameError.

    cc @carljm, would appreciate if you could see whether you agree with this diagnosis, and if you can see a simple way to implement the desired behavior in the compiler.

  8. carljm commented on Sep 11, 2023

    @carljm
    carljm
    on Sep 11, 2023
    Member
    More actions

    Your analysis looks correct to me! I'll take a look at implementation...

  9. JelleZijlstra commented on Sep 12, 2023

    @JelleZijlstra
    JelleZijlstra
    on Sep 12, 2023
    Member
    More actions

    I suppose the problem is that inside the annotation scope for the inner class, name_4 needs to be present with two different meanings: a GLOBAL_IMPLICIT for the use in the annotation scope itself, and a free variable, so that it can be put in the cell for the class scope. I'm not sure the compiler has a way to do that in general, though there are some cases involving class scopes that do work like this.

    Reacted by Carl Meyer
  10. carljm commented on Sep 13, 2023

    @carljm
    carljm
    on Sep 13, 2023
    Member
    More actions

    A similar example that still reproduces the bug, but simplifies and perhaps clarifies a few things (replace the outer annotation scope with a regular function scope, and use a normal re-definition of the typevar in the class scope instead of circularly naming the inner class the same as the typevar; this example should run successfully rather than raise a NameError):

    def f():
        T = str
        class C:
            T = int
            class D[U](T):
                T
        assert int in C.D.__bases__
    
  11. carljm commented on Sep 13, 2023

    @carljm
    carljm
    on Sep 13, 2023
    Member
    More actions

    In my latter example, the T = str in the outer f() function (equivalent to the presence of name_4 in outer class type params in the original example) is key to reproducing the bug. It is this definition of T (not the redefinition in the class) which causes the innermost T (in the body of the inner class) to have scope FREE rather than GLOBAL_IMPLICIT (as it does if you remove the line T = str from my example.)

    I haven't quite sorted out yet what should be happening here; I'll come back to it tomorrow.

  12. carljm commented on Sep 13, 2023

    @carljm
    carljm
    on Sep 13, 2023
    Member
    More actions

    I'm using this test case to debug, and focusing on the discrepancy between the behavior with and without the [U] type param on the inner class, since the presence of that type param should not change the behavior of the name T. This test case fails with the SystemError as written, and passes if the [U] is removed:

        def test_complex_nested_classes(self):
            code = """
                def f():
                    T = str
                    class C:
                        T = int
                        class D[U](T):
                            x = T
                    return C
            """
            C = run_code(code)["f"]()
            self.assertIn(int, C.D.__bases__)
            self.assertIs(C.D.x, str)
    
  13. carljm commented on Sep 13, 2023

    @carljm
    carljm
    on Sep 13, 2023
    Member
    More actions

    FWIW, I also wrote this PyST_Dump function to help debug this: https://gist.github.com/carljm/ecf76f8d0b4d77b00a5ae79b93d1418a

    Maybe we should commit this, ifdef-ed out by default, similar to the dump_* functions in flowgraph.c.

    Reacted by Jelle Zijlstra
  14. carljm
    added a commit that references this issue on Sep 13, 2023

    pythongh-109219: propagate used free vars through type param scopes

    8ff3f71
  15. carljm commented on Sep 13, 2023

    @carljm
    carljm
    on Sep 13, 2023
    Member
    More actions

    #109377 fixes this case. I'm still working through some scenarios to see whether it needs more tweaks to avoid breaking any other case.

    The fix is to use the symbol flag DEF_CLASS_FREE, which permits adding names to freevars in a class scope, so as to propagate the free var from an inner scope up to a wrapping function-like scope that defines the name in a cell, while the actual uses of the name in the class body can still have a scope other than FREE. So the fix here is to consider a can_see_class_scope scope within a class (i.e. the type param scope here) to be equivalent to a class body when it comes to applying the DEF_CLASS_FREE tag in this situation.

    I think the PR may still need an adjustment to ensure we only do this if the name is bound in an enclosing scope.

  16. 15r10nk commented on Sep 13, 2023

    @15r10nk
    15r10nk
    on Sep 13, 2023
    ContributorAuthor
    More actions

    hi, I generated some more examples.

    I used cpython from commit 21f4e6d.
    I have no idea if they are all caused by the same bug, but I hope that they are helpful.

    class name_1[**name_0]:
        try:
    
            class name_3[name_3](name_4=name_0):
                name_0
        except {name_0} as name_5:
            from name_4 import name_0
        else:
            pass
        finally:
            pass
    
    # output:
    # Traceback (most recent call last):
    #   File "/home/frank/projects/pysource-playground/test_code.py", line 6, in <module>
    #     compile(source,sys.argv[1],"exec")
    # SystemError: compiler_lookup_arg(name='name_0') with reftype=3 failed in <generic parameters of name_3>; freevars of code name_3: ('.type_params', 'name_0')
    class name_1[*name_1]:
    
        async def name_1[**name_0](name_5: name_1, /): # type: 
            name_1
    
    # output:
    # Traceback (most recent call last):
    #   File "/home/frank/projects/pysource-playground/test_code.py", line 6, in <module>
    #     compile(source,sys.argv[1],"exec")
    # SystemError: compiler_lookup_arg(name='name_1') with reftype=3 failed in <generic parameters of name_1>; freevars of code name_1: ('name_1',)
    class name_0[name_2]:
        (name_2 := name_1)
    
        def name_5[*name_4]() -> name_2: # type: ignoresome text
            name_2
    
    # output:
    # Traceback (most recent call last):
    #   File "/home/frank/projects/pysource-playground/test_code.py", line 6, in <module>
    #     compile(source,sys.argv[1],"exec")
    # SystemError: compiler_lookup_arg(name='name_2') with reftype=3 failed in <generic parameters of name_5>; freevars of code name_5: ('name_2',)
    class name_4[**name_0]:
    
        class name_0[name_4](**name_0):
            name_0
    
    # output:
    # Traceback (most recent call last):
    #   File "/home/frank/projects/pysource-playground/test_code.py", line 6, in <module>
    #     compile(source,sys.argv[1],"exec")
    # SystemError: compiler_lookup_arg(name='name_0') with reftype=3 failed in <generic parameters of name_0>; freevars of code name_0: ('.type_params', 'name_0')
    class name_5[**name_5]:
    
        class name_5[name_1](**name_5):
            {name_4: name_4 for name_1 in name_3 if name_5}
    
    # output:
    # Traceback (most recent call last):
    #   File "/home/frank/projects/pysource-playground/test_code.py", line 6, in <module>
    #     compile(source,sys.argv[1],"exec")
    # SystemError: compiler_lookup_arg(name='name_5') with reftype=3 failed in <generic parameters of name_5>; freevars of code name_5: ('.type_params', 'name_5')
    class name_0[name_5]:
    
        @(name_5 := 0)
        class name_3[*name_4](name_5=name_5):
            {name_0 for name_0 in name_4 if name_5}
    
    # output:
    # Traceback (most recent call last):
    #   File "/home/frank/projects/pysource-playground/test_code.py", line 6, in <module>
    #     compile(source,sys.argv[1],"exec")
    # SystemError: compiler_lookup_arg(name='name_5') with reftype=3 failed in <generic parameters of name_3>; freevars of code name_3: ('.type_params', 'name_4', 'name_5')
    class name_2[*name_0]:
        match something:
            case {**name_4}:
                name_0 = name_3 # type: ignoresome text
        with name_0: # type: ignoresome text
    
            class name_2[name_5](name_0):
                name_0
    
    # output:
    # Traceback (most recent call last):
    #   File "/home/frank/projects/pysource-playground/test_code.py", line 6, in <module>
    #     compile(source,sys.argv[1],"exec")
    # SystemError: compiler_lookup_arg(name='name_0') with reftype=3 failed in <generic parameters of name_2>; freevars of code name_2: ('.type_params', 'name_0')

    Background:

    I'm currently updating pysource-minimize and pysource-codegen to 3.12.
    I created therefor a little test repository https://github.com/15r10nk/pysource-playground, which I used to generate this examples.
    This code is still work in progress and the examples might be not as minimal as they could be.
    I'm not able to continue my work until next week (family ...).
    You can test a new python version with this repository in the meantime if you want. Create an issue in this repository if you have any problems, I will try to help you.

  17. carljm commented on Sep 13, 2023

    @carljm
    carljm
    on Sep 13, 2023
    Member
    More actions

    @15r10nk Thank you! At first glance just based on the error messages, I suspect these are all the same bug, but I will turn them into test cases and verify the fix handles all of them.

  18. carljm commented on Sep 13, 2023

    @carljm
    carljm
    on Sep 13, 2023
    Member
    More actions

    I tested all of the above cases and #109377 fixes them all; they all compile successfully and then fail as expected at runtime with either NameError or TypeError. I don't think they even need to be added to the PR as separate regression tests, since they all test for the same bug.

    Reacted by Frank Hoffmann
  19. carljm
    added 2 commits that reference this issue on Sep 13, 2023

    pythongh-109219: propagate used free vars through type param scopes [v2]

    a56116d

    gh-109219: propagate free vars through type param scopes (#109377)

    909adb5
  20. miss-islington
    added a commit that references this issue on Sep 14, 2023

    pythongh-109219: propagate free vars through type param scopes (pytho…

    956af19
  21. Yhg1s
    added a commit that references this issue on Sep 14, 2023

    [3.12] gh-109219: propagate free vars through type param scopes (GH-1…

    35c633d
  22. JelleZijlstra commented on Sep 18, 2023

    @JelleZijlstra
    JelleZijlstra
    on Sep 18, 2023
    Member
    More actions

    Merged and backported, thanks @15r10nk for the report and @carljm for the fix!

    Reacted by Frank Hoffmann
  23. JelleZijlstra
    closed this as completedon Sep 18, 2023
  24. github-project-automation
    moved this from Todo to Done in Release and Deferred blockers 🚫on Sep 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @JelleZijlstra
    JelleZijlstra

Labels

3.12only security fixesonly security fixes3.13only security fixesonly security fixesrelease-blockertopic-typingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Projects

  • Release and Deferred blockers 🚫
    Status
    Done
    Show more project fields

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.