-
-
Notifications
You must be signed in to change notification settings - Fork 3k
[mypyc] Detect always defined attributes #12600
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
Merged
Merged
Changes from all commits
Commits
Show all changes
100 commits
Select commit
Hold shift + click to select a range
7f3c385
[mypyc] Make BaseAnalysisVisitor generic
JukkaL d3e17ba
[WIP] Start work on always defined attributes analysis
JukkaL 7c7db8e
Fix issues caused by rebase
JukkaL 89c65cf
Add missing import
JukkaL 79d2dd4
Fixed to arbitrary execution visitor
JukkaL 9ba9a77
Add missing cases to visitor
JukkaL 05f596b
Remove attr initialization detection from main ir build phase
JukkaL f3d55e0
Revert more changes
JukkaL 41c7c9e
Add attribute defined implementation
JukkaL 31e413c
Remove unused imports
JukkaL 8540685
Partial implementation of always defined attr analysis using IR
JukkaL c329c6f
Fix some special cases
JukkaL 64bab0a
[mypyc] Keep track of functions that won't run arbitrary code
JukkaL 32e4cab
Functions that can't run arbitrary code are fine
JukkaL 70c18a7
Add docstring
JukkaL 129ec0d
Remove original attempt that worked on mypy ATSs
JukkaL 4ee1558
Detect initialization-only setattr ops
JukkaL cd2132a
Fix initialization of always defined attributes
JukkaL 08262f1
Add test cases
JukkaL f9a9741
Add test cases
JukkaL 181a334
Add comment
JukkaL b9b601b
Fix asserts
JukkaL 4b385d4
Refactor + add docstrings and comments
JukkaL d2fe861
Record which attributes have default values in class body
JukkaL ae2568c
Treat attributes initialized in class body as always defined
JukkaL b076a42
Add IR build test case for attribute default
JukkaL 3194d92
Add tests
JukkaL d79baad
Fix issues caused by rebase
JukkaL 37e5508
Update singledispatch test cases
JukkaL ef38388
Analyze always defined attributes across class hierarchy
JukkaL 92e7eb9
Fix multiple inheritance levels in hierarchy
JukkaL 6cf694c
Add tests
JukkaL 789e63f
DEBUG PRINT
JukkaL 7aff66e
Update failing irbuild tests
JukkaL 025fca5
Fix class IR serialization
JukkaL cded5cd
Fix serialization
JukkaL 27482a0
Fix attributes initialized like "x = None # type: str"
JukkaL 6b411c3
Fix dataclass and attrs defaults
JukkaL 1ebf170
Update test case
JukkaL 5cfb7f9
Improve docstrings
JukkaL bf4a664
Unrelated: remove obsolete comment
JukkaL 6b49963
Also consider "dirty" transitions through branches and gotos
JukkaL 1ae5b54
List comprehensions don't run arbitrary code
JukkaL fafec1d
Refactor test case
JukkaL 70395d0
Deletable attributes can't be always defined
JukkaL 4963ca3
Derived class may affect always defined status in base
JukkaL e28dfaa
Avoid generating branches for always defined attribute gets
JukkaL b30e532
Add comment
JukkaL 6b3e98e
Accept undefined values in setter
JukkaL 9a1c679
WIP docstring update (no correnponding implementation change)
JukkaL e58fb36
Fix after rebase
JukkaL 7b1ac7a
Fix lint
JukkaL cc9615e
Use self leaks instead of running arbitrary code in analysis
JukkaL 0bd7926
Always check for uninitialized values in CPython getter
JukkaL 1d50647
Implement Type shallow copy visitor to avoid copy.copy()
JukkaL a7d909b
Fix issues with new __new__ semantics
JukkaL 2f595be
Add del attr test case
JukkaL 4ff3fc0
Add more inheritance tests
JukkaL b4e32dc
Add some simple trait tests
JukkaL fc9c657
Test with allow_interpreted_subclasses
JukkaL a7a66f7
Test additional kinds of expressions
JukkaL 23eacc8
Add test cases
JukkaL d94963a
Fixes to properties
JukkaL 16c59cc
Fix handling of self in assignments
JukkaL c62b486
Docstring updates
JukkaL 4ddfe84
Update try statement test case
JukkaL ac0761d
Add try/finally test case
JukkaL 69d15e0
Add with test case
JukkaL 41efa34
Add test case
JukkaL 093fcf3
Rename defined -> selfleaks
JukkaL 0659f59
Add test case for Python base class
JukkaL 3fcec57
Add incremental mode test case
JukkaL 18534fb
Improve documentation of tests for multi-file and separate modes
JukkaL 1539ad2
Comment out debug print
JukkaL cbb5f37
Fix after rebase
JukkaL 709f29e
Fix after rebase
JukkaL e494eb2
Fix copying of ParamSpecType
JukkaL 42764d1
Update docstring
JukkaL c575d44
Support copying Parameters
JukkaL 3c3ad7a
Clean up
JukkaL 28ba726
Remove another use of copy.copy()
JukkaL 335fc21
Fix crash during compilation
JukkaL 53eb2cc
Fix stubgen test failures
JukkaL 8371b60
Simplify a bit
JukkaL e83cc7c
Improve test case
JukkaL 5aa0fef
Update comments
JukkaL 47d25d3
Drop run arbitrary code flags
JukkaL 8d1dca2
Kepe track of sometimes initialized attributes in __init__
JukkaL 3d96774
Fix lint
JukkaL 20861b9
Fix syntax on older Python versions
JukkaL 2477704
Merge branch 'master' into always-defined-inheritance-5
JukkaL 96e99d6
Support TypeVarTupleType
JukkaL fed8ecd
Address some feedback
JukkaL 53caf2b
Rename init_unknown_code to init_self_leak
JukkaL 8e371a7
Update comments based on feedback
JukkaL dd436fb
Adjust GenAndKill based on feedback
JukkaL e409f5d
Allow supporting pickle/copy by using @mypyc_attr(serialize=True)
JukkaL d3cc68b
Document the serializable flag
JukkaL 49efa36
Fix example
JukkaL 51e23b0
Address feedback
JukkaL File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
from typing import Any, cast | ||
|
||
from mypy.types import ( | ||
ProperType, UnboundType, AnyType, NoneType, UninhabitedType, ErasedType, DeletedType, | ||
Instance, TypeVarType, ParamSpecType, PartialType, CallableType, TupleType, TypedDictType, | ||
LiteralType, UnionType, Overloaded, TypeType, TypeAliasType, UnpackType, Parameters, | ||
TypeVarTupleType | ||
) | ||
from mypy.type_visitor import TypeVisitor | ||
|
||
|
||
def copy_type(t: ProperType) -> ProperType: | ||
"""Create a shallow copy of a type. | ||
|
||
This can be used to mutate the copy with truthiness information. | ||
|
||
Classes compiled with mypyc don't support copy.copy(), so we need | ||
a custom implementation. | ||
""" | ||
return t.accept(TypeShallowCopier()) | ||
|
||
|
||
class TypeShallowCopier(TypeVisitor[ProperType]): | ||
def visit_unbound_type(self, t: UnboundType) -> ProperType: | ||
return t | ||
|
||
def visit_any(self, t: AnyType) -> ProperType: | ||
return self.copy_common(t, AnyType(t.type_of_any, t.source_any, t.missing_import_name)) | ||
|
||
def visit_none_type(self, t: NoneType) -> ProperType: | ||
return self.copy_common(t, NoneType()) | ||
|
||
def visit_uninhabited_type(self, t: UninhabitedType) -> ProperType: | ||
dup = UninhabitedType(t.is_noreturn) | ||
dup.ambiguous = t.ambiguous | ||
return self.copy_common(t, dup) | ||
|
||
def visit_erased_type(self, t: ErasedType) -> ProperType: | ||
return self.copy_common(t, ErasedType()) | ||
|
||
def visit_deleted_type(self, t: DeletedType) -> ProperType: | ||
return self.copy_common(t, DeletedType(t.source)) | ||
|
||
def visit_instance(self, t: Instance) -> ProperType: | ||
dup = Instance(t.type, t.args, last_known_value=t.last_known_value) | ||
dup.invalid = t.invalid | ||
return self.copy_common(t, dup) | ||
|
||
def visit_type_var(self, t: TypeVarType) -> ProperType: | ||
dup = TypeVarType( | ||
t.name, | ||
t.fullname, | ||
t.id, | ||
values=t.values, | ||
upper_bound=t.upper_bound, | ||
variance=t.variance, | ||
) | ||
return self.copy_common(t, dup) | ||
|
||
def visit_param_spec(self, t: ParamSpecType) -> ProperType: | ||
dup = ParamSpecType(t.name, t.fullname, t.id, t.flavor, t.upper_bound, prefix=t.prefix) | ||
return self.copy_common(t, dup) | ||
|
||
def visit_parameters(self, t: Parameters) -> ProperType: | ||
dup = Parameters(t.arg_types, t.arg_kinds, t.arg_names, | ||
variables=t.variables, | ||
is_ellipsis_args=t.is_ellipsis_args) | ||
return self.copy_common(t, dup) | ||
|
||
def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType: | ||
dup = TypeVarTupleType(t.name, t.fullname, t.id, t.upper_bound) | ||
return self.copy_common(t, dup) | ||
|
||
def visit_unpack_type(self, t: UnpackType) -> ProperType: | ||
dup = UnpackType(t.type) | ||
return self.copy_common(t, dup) | ||
|
||
def visit_partial_type(self, t: PartialType) -> ProperType: | ||
return self.copy_common(t, PartialType(t.type, t.var, t.value_type)) | ||
|
||
def visit_callable_type(self, t: CallableType) -> ProperType: | ||
return self.copy_common(t, t.copy_modified()) | ||
|
||
def visit_tuple_type(self, t: TupleType) -> ProperType: | ||
return self.copy_common(t, TupleType(t.items, t.partial_fallback, implicit=t.implicit)) | ||
|
||
def visit_typeddict_type(self, t: TypedDictType) -> ProperType: | ||
return self.copy_common(t, TypedDictType(t.items, t.required_keys, t.fallback)) | ||
|
||
def visit_literal_type(self, t: LiteralType) -> ProperType: | ||
return self.copy_common(t, LiteralType(value=t.value, fallback=t.fallback)) | ||
|
||
def visit_union_type(self, t: UnionType) -> ProperType: | ||
return self.copy_common(t, UnionType(t.items)) | ||
|
||
def visit_overloaded(self, t: Overloaded) -> ProperType: | ||
return self.copy_common(t, Overloaded(items=t.items)) | ||
|
||
def visit_type_type(self, t: TypeType) -> ProperType: | ||
# Use cast since the type annotations in TypeType are imprecise. | ||
return self.copy_common(t, TypeType(cast(Any, t.item))) | ||
|
||
def visit_type_alias_type(self, t: TypeAliasType) -> ProperType: | ||
assert False, "only ProperTypes supported" | ||
|
||
def copy_common(self, t: ProperType, t2: ProperType) -> ProperType: | ||
t2.line = t.line | ||
t2.column = t.column | ||
t2.can_be_false = t.can_be_false | ||
t2.can_be_true = t.can_be_true | ||
return t2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not supporting
copy.copy
is pretty rough. This will also mean that we don't supportpickle
, right?I don't think that we can reasonably break those without providing an opt-opt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point. I was planning to provide a way to do this later, but I can add it to this PR. We could have a per-class flag saying that this class (and any subclasses, probably) is picklable, and no attribute would be treated as always defined in the class, and thus we can always provide a way of creating an uninitialized instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now it's supported by using
@mypyc_attr(serializable=True)
.