-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add semantic analysis of type aliases and parameters #6109
Conversation
063126f
to
fcd5e14
Compare
If interested, working with examples at https://gist.github.com/zanieb/fe1d6c32db2e9a6cc1bcb3be6feaaf05 |
This is looking good to me! |
PR Check ResultsEcosystem✅ ecosystem check detected no changes. BenchmarkLinux
Windows
|
1636bcc
to
5d3a631
Compare
5d3a631
to
b80a5b5
Compare
Ensures that type parameter names are bound in the value expression
The parent scope of classes and functions is now always a `Type` scope and additional traversal must be done to reach the scope of interest
b80a5b5
to
093d40f
Compare
Huh my latest commit is pushed but missing. Silly GitHub. |
# Types used in aliased assignment must exist | ||
|
||
type Foo = DoesNotExist # F821: Undefined name `DoesNotExist` | ||
type Foo = list[DoesNotExist] # F821: Undefined name `DoesNotExist` |
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.
Were you able to test these against the updated version of Pyflakes?
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.
I haven't! I'll do that and confirm they match. I tested for correctness with Pyright and Python runtime errors.
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.
The results are identical except that pyflakes emits two incorrect warnings
10:21: undefined name 'Ts'
11:21: undefined name 'P'
They appear to handle binding of type var tuples and param specs incorrectly.
} | ||
|
||
/// Returns the first parent of the given scope that is not a [`ScopeKind::Type`] scope, if any. | ||
pub fn scope_parent_skip_types(&self, scope: &Scope) -> Option<&Scope<'a>> { |
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.
Hmm, maybe non_type_scope_parent
, so that it describes the data returned rather than the action taken? But not a strong opinion.
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.
I'm not attached to my name but I don't like that one either haha maybe scope_non_type_parent
? eek. I also wanted to try scope_first_parent_not(kind: ScopeKind)
or something but making it generic felt weird too.
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.
Maybe what you have here is just clearest... Or scope_parent_skip_type_scopes
???
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.
Maybe first_non_type_parent_scope
or non_type_parent_scope
?
Or we name it first_value_scope
. The way I think about it is that variables can either bind a value or a type.
Unrelated: Is this a python thing that types have their own scope? In JS, they all end up in the same scope, but each binding is either a value or a type.
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.
Yeah, surprisingly they added an entirely new lexical scope to support type parameters specifically in PEP 695: https://peps.python.org/pep-0695/#type-parameter-scopes. It's required due to some of the nuances of when these things are evaluated.
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.
(Perhaps we should consider a more specific name for that scope kind though.)
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.
I kind of like TypeParam
scope more than Type
but I didn't want to deviate in this first pass
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.
This looks great! I love the thoroughness of the test suite. I admittedly didn't review the actual test results for semantic correctness but am happy to take a closer look on any of the finer points if useful.
def can_access_inside[T](t: T) -> T: # OK | ||
print(T) # OK | ||
return t # OK | ||
class Forward: ... # OK |
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.
Self: Need to move Forward
definition to end of file or change names so they do not collide across test cases.
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.
Another benefit of isolating fixtures >.<
} | ||
|
||
/// Returns the first parent of the given scope that is not a [`ScopeKind::Type`] scope, if any. | ||
pub fn scope_parent_skip_types(&self, scope: &Scope) -> Option<&Scope<'a>> { |
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.
Maybe first_non_type_parent_scope
or non_type_parent_scope
?
Or we name it first_value_scope
. The way I think about it is that variables can either bind a value or a type.
Unrelated: Is this a python thing that types have their own scope? In JS, they all end up in the same scope, but each binding is either a value or a type.
Requires astral-sh/RustPython-Parser#42
Related PyCQA/pyflakes#778
PEP-695
Part of #5062
Summary
Adds a scope for type parameters, a type parameter binding kind, and checker visitation of type parameters in type alias statements, function definitions, and class definitions.
A few changes were necessary to ensure correctness following the insertion of a new scope between function and class scopes and their parent.
Test Plan
Undefined name snapshots.
Unused type parameter rule will be added as follow-up.