You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Generated classes does not work with forward references #1701
The NamedTuple also plays a role -- if I change a.py to define
classATuple:
a=None# type: Any
then the error disappears.
The problem may not be unique to NamedTuple but it is caused by the late processing of the definition of ATuple when using NamedTuple; with a regular class definition the first pass of the semantic analysis (viz., semanal.FirstPass.visit_class_def()) creates the definition of ATuple, but when ATuple is the result of a NamedTuple() expression is created during the "regular" semantic analysis (viz., semanal.SemanticAnalyzer.process_namedtuple_definition(), called from visit_assignment_stmt() in the same class).
None of the improvements to import cycle processing currently being considered help (neither #2167 nor #2264). I'm guessing some form of deferred processing in the semantic analyzer might have to be devised in order to handle this properly, or we need to move part of the NamedTuple analysis to the FirstPass. (I believe we can't move all of it, since it may contain references to other types; but we may be able to construct a placeholder in the FirstPass that gets populated in the second pass, similar to the way regular class definitions are processed.)
Here are some additional thoughts. I think that this problem probably affects named tuples, type aliases, typed dicts and type variable definitions (e.g. bounds). I've hit this problem myself and I agree that this looks important.
1) Splitting second semantic analysis pass
Another option is to split the main semantic analysis pass into two passes, the first of which would resolve named tuples and type aliases, and the second one would resolve type annotations. However, this could slow things down as both passes would have to keep track of defined names, etc.
2) Deferred processing of AST nodes
Deferred processing, similar to what we have in the type checker, would likely work, but I think that we'd need to take a copy of almost all of the semantic analyzer state to do full deferred processing, and we'd have to ensure that running semantic analysis twice on the same nodes doesn't cause trouble. I'd rather avoid this if possible.
3) Deferred processing of types only
A less general deferred processing seems the most promising approach to me. We'd create a special kind of partially defined type when we encounter a type reference where the target hasn't been processed yet. This type would record the fully qualified name of the target type. In the third pass we'd patch up these partially defined types (or generate errors if they still don't refer to types). The slightly tricky bit with this approach is that we'd need to translate all types that might have these partially defined types as components, but we can skip this step when there's nothing to do. For example, we could collect all deferred types in a list, and if the list is empty for a set of modules, we'd skip the patching-up step.
mypy --fast-parser --python 3.6 foo.py
foo.py:6: error: Incompatible types in assignment (expression has type List[None], variable has type List[GraphEdge])
Also note that If I re-order the definitions so GraphEdge comes first, the error is not raised.
Activity
gvanrossum commentedon Jun 12, 2016
gvanrossum commentedon Oct 17, 2016
The NamedTuple also plays a role -- if I change a.py to define
then the error disappears.
The problem may not be unique to NamedTuple but it is caused by the late processing of the definition of ATuple when using NamedTuple; with a regular class definition the first pass of the semantic analysis (viz., semanal.FirstPass.visit_class_def()) creates the definition of ATuple, but when ATuple is the result of a NamedTuple() expression is created during the "regular" semantic analysis (viz., semanal.SemanticAnalyzer.process_namedtuple_definition(), called from visit_assignment_stmt() in the same class).
None of the improvements to import cycle processing currently being considered help (neither #2167 nor #2264). I'm guessing some form of deferred processing in the semantic analyzer might have to be devised in order to handle this properly, or we need to move part of the NamedTuple analysis to the FirstPass. (I believe we can't move all of it, since it may contain references to other types; but we may be able to construct a placeholder in the FirstPass that gets populated in the second pass, similar to the way regular class definitions are processed.)
gvanrossum commentedon Oct 20, 2016
This feels important but fairly tricky.
JukkaL commentedon Oct 21, 2016
Here are some additional thoughts. I think that this problem probably affects named tuples, type aliases, typed dicts and type variable definitions (e.g. bounds). I've hit this problem myself and I agree that this looks important.
1) Splitting second semantic analysis pass
Another option is to split the main semantic analysis pass into two passes, the first of which would resolve named tuples and type aliases, and the second one would resolve type annotations. However, this could slow things down as both passes would have to keep track of defined names, etc.
2) Deferred processing of AST nodes
Deferred processing, similar to what we have in the type checker, would likely work, but I think that we'd need to take a copy of almost all of the semantic analyzer state to do full deferred processing, and we'd have to ensure that running semantic analysis twice on the same nodes doesn't cause trouble. I'd rather avoid this if possible.
3) Deferred processing of types only
A less general deferred processing seems the most promising approach to me. We'd create a special kind of partially defined type when we encounter a type reference where the target hasn't been processed yet. This type would record the fully qualified name of the target type. In the third pass we'd patch up these partially defined types (or generate errors if they still don't refer to types). The slightly tricky bit with this approach is that we'd need to translate all types that might have these partially defined types as components, but we can skip this step when there's nothing to do. For example, we could collect all deferred types in a list, and if the list is empty for a set of modules, we'd skip the patching-up step.
mikeyhew commentedon Jan 26, 2017
Here is another example that doesn't work with NamedTuple, but does without it:
Error message from MyPy:
Also note that If I re-order the definitions so GraphEdge comes first, the error is not raised.
Fix crashes and fails in forward references (#3952)