Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mypyc] Don't load forward ref targets while setting up non-ext __annotations__ #14401

Conversation

ichard26
Copy link
Collaborator

@ichard26 ichard26 commented Jan 6, 2023

Take this example:

from typing import NamedTuple

class VTableMethod(NamedTuple):
    cls: "ClassIR"

class ClassIR: pass

In irbuild::classdef::add_non_ext_class_attr_ann(), mypyc tries to assign the ClassIR type object to VTableMethod's __annotations__. This causes a segfault as ClassIR won't be initialized and allocated until after the NamedTuple is set up.

Fortunately, AssignmentStmt preserves the unanalyzed type (UnboundType). If stmt.unanalyzed_type.orginal_str_expr is not None, then we know we're dealing with a forward ref and should just load the string instead.

Unfortunately, it seems difficult (or impossible?) to infer whether an annotation is a forward reference when the annotations future is enabled and the annotation isn't a string.

I guess this fixes mypyc/mypyc#938?


Dataclasses are still broken as strings in __annotations__ cause dataclass's internals to lookup the module in sys.modules which fails (as the module hasn't been fully initialized and added to sys.modules yet!)

@ichard26 ichard26 force-pushed the fix-fwdref-in-class-based-namedtuple-annotations-no-future branch from 5282a98 to a492135 Compare January 6, 2023 03:24
Take this example:

    from typing import NamedTuple

    class VTableMethod(NamedTuple):
        cls: "ClassIR"

    class ClassIR: pass

In irbuild::classdef::add_non_ext_class_attr_ann(), mypyc tries to
assign the ClassIR type object to VTableMethod's __annotations__. This
causes a segfault as ClassIR won't be initialized and allocated until
*after* the NamedTuple is set up.

Fortunately, AssignmentStmt preserves the unanalyzed type (UnboundType).
If `stmt.unanalyzed_type.orginal_str_expr` is not None, then we know
we're dealing with a forward ref and should just load the string
instead.

Unfortunately, it seems difficult (or impossible?) to infer whether
an annotation is a forward reference when the annotations future is
enabled and the annotation isn't a string.
@ichard26 ichard26 force-pushed the fix-fwdref-in-class-based-namedtuple-annotations-no-future branch from a492135 to b867e24 Compare January 6, 2023 03:25
@ichard26 ichard26 marked this pull request as ready for review January 6, 2023 03:47
Copy link
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

# type and load the string instead.
#
# TODO: is it possible to determine whether a non-string annotation is
# actually a forward reference due to the __annotations__ future?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If from __future__ import annotations is used, I think that we can always use string annotations, or whenever there is any doubt that type might contain forward references.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah you're right. I'll open an issue about hardening our __annotations__ handling overall when I have time.

@JukkaL JukkaL merged commit 4ec6ea5 into python:master Jan 9, 2023
@ichard26
Copy link
Collaborator Author

ichard26 commented Jan 9, 2023

@hauntsaninja you can try using class-based NamedTuples again now :)

@ichard26 ichard26 deleted the fix-fwdref-in-class-based-namedtuple-annotations-no-future branch January 9, 2023 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

mypyc doesn't like class-like NamedTuples with forward refs
2 participants