-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ty] Don't warn yield not in function when yield is in function
#18008
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
[ty] Don't warn yield not in function when yield is in function
#18008
Conversation
and update the integration tests for this behavior.
|
yield not in function when yield is in functionyield not in function when yield is in function
crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md
Show resolved
Hide resolved
| for scope_info in self.scope_stack.iter().rev() { | ||
| let scope = &self.scopes[scope_info.file_scope_id]; | ||
| match scope.kind() { | ||
| ScopeKind::Lambda | ScopeKind::Function => { |
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 think we should also return false if we see a ScopeKind::Class:
>>> def f():
... class C:
... yield 5
...
File "<python-input-1>", line 3
yield 5
^^^^^^^
SyntaxError: 'yield' outside functionI'm also realizing that I gave bad advice in my comment on the issue. The in_*_scope methods are supposed to refer to the directly-enclosing scope:
ruff/crates/ruff_python_parser/src/semantic_errors.rs
Lines 1649 to 1663 in 7a48477
| /// Note that the `in_*_scope` methods should refer to the immediately-enclosing scope. For example, | |
| /// `in_function_scope` should return true for this case: | |
| /// | |
| /// ```python | |
| /// def f(): | |
| /// x # here | |
| /// ``` | |
| /// | |
| /// but not for this case: | |
| /// | |
| /// ```python | |
| /// def f(): | |
| /// class C: | |
| /// x # here | |
| /// ``` |
We may just want to reuse in_await_allowed_context for detecting this syntax error and also possibly rename it to something like in_function_context.
That should fix the ruff implementation of the rule too, which I guess I hadn't seen issues with either.
|
|
All right, this took longer than I thought for a quite small diff.
Questions:
|
|
The notebook in the ecosystem changes gives the same |
| if !ctx.in_sync_comprehension_scope() | ||
| && !ctx.in_generator_scope() | ||
| && ctx.in_await_allowed_context() |
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 seems a bit strange because in_sync_comprehension_scope and in_await_allowed_context both traverse the parent scopes, but in_generator_scope doesn't. Is there a way to break this check by nesting generators somehow?
I think I would probably lean toward a separate context method anyway, just for clarity. Traversing scopes should be pretty cheap since it's just iterating backwards over a vector for both ruff and ty, but I think this whole check would be simplified if we had an in_yield_allowed_context method or similar. And then we can traverse the stack once anyway.
Ah, actually I think that's the reason for the else-if on kind.is_await. If we don't return from there, we'll run all of these checks again, even though we already know we want a diagnostic for await. So I think I would put this whole section back to something like this:
if kind.is_await {
// ...
} else if ctx.in_yield_allowed_context() {
return
}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.
Makes sense. Adressed in 1d0e43b
I was shying away from adding a new method to the trait because then the implementation in crates/ruff_linter/src/checkers/ast/mod.rs isn't used.
But I now agree it's not that bad.
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.
We could also add a test case for ruff (is that what you mean by the Checker version not being used?)
Yeah no worries about this, I've been seeing it on every PR. If the issue persists we can ignore the file from the ecosystem check. Edit: looks like they fixed it 6 hours ago. Next time the ecosystem check runs it should update! |
ntBre
left a comment
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.
Thanks, this looks good to me! The only additional thing would be adding a test in ruff. I think it could have been susceptible to the same, or at least similar, initial issue. But the existing tests should at least exercise the new context method anyway.
It might be good to get a quick review from someone on the ty side too, but this is otherwise good to go.
|
Added tests in 7460049 |
|
Ping @carljm @dhruvmanila @MichaReiser (because Brent said it would be good if someone from the TY side would review and you're code owners and recent ty committers :) ) |
Closes: astral-sh/ty#299
Summary
Don't warn
yieldnot in function whenyieldis in function.This is achieved by iterating through the scope stack to check if it contains a function scope.
The issue was found when creating the semantic syntax
mdintegration tests (#17748 (comment)).Test Plan
Updated integration tests to reflect this behavior.
I don't know if I fully get how issues / PR's work across the boundaries of
ruffandty. Let me know if i'm doing something wrong.