[ty] Don't warn yield not in function when yield is in function (#18008)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run

This commit is contained in:
Max Mynter 2025-05-21 18:16:25 +02:00 committed by GitHub
parent d37592175f
commit 02fd48132c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 87 additions and 17 deletions

View file

@ -769,16 +769,21 @@ impl SemanticSyntaxChecker {
// We are intentionally not inspecting the async status of the scope for now to mimic F704.
// await-outside-async is PLE1142 instead, so we'll end up emitting both syntax errors for
// cases that trigger F704
if ctx.in_function_scope() {
return;
}
if kind.is_await() {
if ctx.in_await_allowed_context() {
return;
}
// `await` is allowed at the top level of a Jupyter notebook.
// See: https://ipython.readthedocs.io/en/stable/interactive/autoawait.html.
if ctx.in_module_scope() && ctx.in_notebook() {
return;
}
} else if ctx.in_function_scope() {
if ctx.in_await_allowed_context() {
return;
}
} else if ctx.in_yield_allowed_context() {
return;
}
@ -1719,6 +1724,35 @@ pub trait SemanticSyntaxContext {
/// See the trait-level documentation for more details.
fn in_await_allowed_context(&self) -> bool;
/// Returns `true` if the visitor is currently in a context where `yield` and `yield from`
/// expressions are allowed.
///
/// Yield expressions are allowed only in:
/// 1. Function definitions
/// 2. Lambda expressions
///
/// Unlike `await`, yield is not allowed in:
/// - Comprehensions (list, set, dict)
/// - Generator expressions
/// - Class definitions
///
/// This method should traverse parent scopes to check if the closest relevant scope
/// is a function or lambda, and that no disallowed context (class, comprehension, generator)
/// intervenes. For example:
///
/// ```python
/// def f():
/// yield 1 # okay, in a function
/// lambda: (yield 1) # okay, in a lambda
///
/// [(yield 1) for x in range(3)] # error, in a comprehension
/// ((yield 1) for x in range(3)) # error, in a generator expression
/// class C:
/// yield 1 # error, in a class within a function
/// ```
///
fn in_yield_allowed_context(&self) -> bool;
/// Returns `true` if the visitor is currently inside of a synchronous comprehension.
///
/// This method is necessary because `in_async_context` only checks for the nearest, enclosing