mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-01 04:18:05 +00:00
[syntax-errors] yield, yield from, and await outside functions (#17298)
Summary -- This PR reimplements [yield-outside-function (F704)](https://docs.astral.sh/ruff/rules/yield-outside-function/) as a semantic syntax error. Despite the name, this rule covers `yield from` and `await` in addition to `yield`. Test Plan -- New linter tests, along with the existing F704 test. --------- Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
This commit is contained in:
parent
7e571791c0
commit
ffef71d106
10 changed files with 538 additions and 57 deletions
|
|
@ -464,6 +464,7 @@ enum Scope {
|
|||
Module,
|
||||
Function { is_async: bool },
|
||||
Comprehension { is_async: bool },
|
||||
Class,
|
||||
}
|
||||
|
||||
struct SemanticSyntaxCheckerVisitor<'a> {
|
||||
|
|
@ -546,20 +547,46 @@ impl SemanticSyntaxContext for SemanticSyntaxCheckerVisitor<'_> {
|
|||
}
|
||||
|
||||
fn in_module_scope(&self) -> bool {
|
||||
self.scopes
|
||||
.last()
|
||||
.is_some_and(|scope| matches!(scope, Scope::Module))
|
||||
true
|
||||
}
|
||||
|
||||
fn in_function_scope(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn in_notebook(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn in_await_allowed_context(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'_> for SemanticSyntaxCheckerVisitor<'_> {
|
||||
fn visit_stmt(&mut self, stmt: &ast::Stmt) {
|
||||
self.with_semantic_checker(|semantic, context| semantic.visit_stmt(stmt, context));
|
||||
match stmt {
|
||||
ast::Stmt::ClassDef(ast::StmtClassDef {
|
||||
arguments,
|
||||
body,
|
||||
decorator_list,
|
||||
type_params,
|
||||
..
|
||||
}) => {
|
||||
for decorator in decorator_list {
|
||||
self.visit_decorator(decorator);
|
||||
}
|
||||
if let Some(type_params) = type_params {
|
||||
self.visit_type_params(type_params);
|
||||
}
|
||||
if let Some(arguments) = arguments {
|
||||
self.visit_arguments(arguments);
|
||||
}
|
||||
self.scopes.push(Scope::Class);
|
||||
self.visit_body(body);
|
||||
self.scopes.pop().unwrap();
|
||||
}
|
||||
ast::Stmt::FunctionDef(ast::StmtFunctionDef { is_async, .. }) => {
|
||||
self.scopes.push(Scope::Function {
|
||||
is_async: *is_async,
|
||||
|
|
@ -581,13 +608,38 @@ impl Visitor<'_> for SemanticSyntaxCheckerVisitor<'_> {
|
|||
ast::visitor::walk_expr(self, expr);
|
||||
self.scopes.pop().unwrap();
|
||||
}
|
||||
ast::Expr::ListComp(ast::ExprListComp { generators, .. })
|
||||
| ast::Expr::SetComp(ast::ExprSetComp { generators, .. })
|
||||
| ast::Expr::DictComp(ast::ExprDictComp { generators, .. }) => {
|
||||
ast::Expr::ListComp(ast::ExprListComp {
|
||||
elt, generators, ..
|
||||
})
|
||||
| ast::Expr::SetComp(ast::ExprSetComp {
|
||||
elt, generators, ..
|
||||
})
|
||||
| ast::Expr::Generator(ast::ExprGenerator {
|
||||
elt, generators, ..
|
||||
}) => {
|
||||
for comprehension in generators {
|
||||
self.visit_comprehension(comprehension);
|
||||
}
|
||||
self.scopes.push(Scope::Comprehension {
|
||||
is_async: generators.iter().any(|gen| gen.is_async),
|
||||
});
|
||||
ast::visitor::walk_expr(self, expr);
|
||||
self.visit_expr(elt);
|
||||
self.scopes.pop().unwrap();
|
||||
}
|
||||
ast::Expr::DictComp(ast::ExprDictComp {
|
||||
key,
|
||||
value,
|
||||
generators,
|
||||
..
|
||||
}) => {
|
||||
for comprehension in generators {
|
||||
self.visit_comprehension(comprehension);
|
||||
}
|
||||
self.scopes.push(Scope::Comprehension {
|
||||
is_async: generators.iter().any(|gen| gen.is_async),
|
||||
});
|
||||
self.visit_expr(key);
|
||||
self.visit_expr(value);
|
||||
self.scopes.pop().unwrap();
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue