Skip to main content

ruff_python_parser/
semantic_errors.rs

1//! [`SemanticSyntaxChecker`] for AST-based syntax errors.
2//!
3//! This checker is not responsible for traversing the AST itself. Instead, its
4//! [`SemanticSyntaxChecker::visit_stmt`] and [`SemanticSyntaxChecker::visit_expr`] methods should
5//! be called in a parent `Visitor`'s `visit_stmt` and `visit_expr` methods, respectively.
6
7use ruff_python_ast::{
8    self as ast, Expr, ExprContext, IrrefutablePatternKind, Pattern, PythonVersion, Stmt, StmtExpr,
9    StmtFunctionDef, StmtImportFrom,
10    comparable::HashableExpr,
11    helpers,
12    visitor::{Visitor, walk_expr, walk_stmt},
13};
14use ruff_text_size::{Ranged, TextRange, TextSize};
15use rustc_hash::{FxBuildHasher, FxHashSet};
16use std::fmt::Display;
17
18#[derive(Debug, Default)]
19pub struct SemanticSyntaxChecker {
20    /// The checker has traversed past the `__future__` import boundary.
21    ///
22    /// For example, the checker could be visiting `x` in:
23    ///
24    /// ```python
25    /// from __future__ import annotations
26    ///
27    /// import os
28    ///
29    /// x: int = 1
30    /// ```
31    ///
32    /// Python considers it a syntax error to import from `__future__` after any other
33    /// non-`__future__`-importing statements.
34    seen_futures_boundary: bool,
35
36    /// The checker has traversed past the module docstring boundary (i.e. seen any statement in the
37    /// module).
38    seen_module_docstring_boundary: bool,
39}
40
41impl SemanticSyntaxChecker {
42    pub fn new() -> Self {
43        Self::default()
44    }
45}
46
47impl SemanticSyntaxChecker {
48    fn add_error<Ctx: SemanticSyntaxContext>(
49        context: &Ctx,
50        kind: SemanticSyntaxErrorKind,
51        range: TextRange,
52    ) {
53        context.report_semantic_error(SemanticSyntaxError {
54            kind,
55            range,
56            python_version: context.python_version(),
57        });
58    }
59
60    fn check_lazy_import_context<Ctx: SemanticSyntaxContext>(
61        ctx: &Ctx,
62        range: TextRange,
63        kind: LazyImportKind,
64    ) -> bool {
65        if let Some(context) = ctx.lazy_import_context() {
66            Self::add_error(
67                ctx,
68                SemanticSyntaxErrorKind::LazyImportNotAllowed { context, kind },
69                range,
70            );
71            return true;
72        }
73        false
74    }
75
76    fn check_stmt<Ctx: SemanticSyntaxContext>(&mut self, stmt: &ast::Stmt, ctx: &Ctx) {
77        match stmt {
78            Stmt::ImportFrom(StmtImportFrom {
79                range,
80                module,
81                level,
82                names,
83                is_lazy,
84                ..
85            }) => {
86                let mut handled_lazy_error = false;
87
88                if *is_lazy {
89                    // test_ok lazy_import_semantic_ok_py315
90                    // # parse_options: {"target-version": "3.15"}
91                    // import contextlib
92                    // with contextlib.nullcontext():
93                    //     lazy import os
94                    // with contextlib.nullcontext():
95                    //     lazy from sys import path
96
97                    // test_err lazy_import_invalid_context_py315
98                    // # parse_options: {"target-version": "3.15"}
99                    // try:
100                    //     lazy import os
101                    // except:
102                    //     pass
103                    //
104                    // try:
105                    //     x
106                    // except* Exception:
107                    //     lazy import sys
108                    //
109                    // def func():
110                    //     lazy import math
111                    //
112                    // async def async_func():
113                    //     lazy from json import loads
114                    //
115                    // class MyClass:
116                    //     lazy import typing
117                    //
118                    // def outer():
119                    //     class Inner:
120                    //         lazy import json
121                    if Self::check_lazy_import_context(ctx, *range, LazyImportKind::ImportFrom) {
122                        handled_lazy_error = true;
123                    } else if names.iter().any(|alias| alias.name.as_str() == "*") {
124                        // test_err lazy_import_invalid_from_py315
125                        // # parse_options: {"target-version": "3.15"}
126                        // lazy from os import *
127                        // lazy from __future__ import annotations
128                        //
129                        // def func():
130                        //     lazy from sys import *
131                        Self::add_error(ctx, SemanticSyntaxErrorKind::LazyImportStar, *range);
132                        handled_lazy_error = true;
133                    } else if matches!(module.as_deref(), Some("__future__")) {
134                        Self::add_error(ctx, SemanticSyntaxErrorKind::LazyFutureImport, *range);
135                        handled_lazy_error = true;
136                    }
137                }
138
139                if handled_lazy_error {
140                    // Skip the regular `from`-import validations after reporting the lazy-specific
141                    // syntax error with the highest precedence.
142                } else if matches!(module.as_deref(), Some("__future__")) {
143                    for name in names {
144                        if !is_known_future_feature(&name.name) {
145                            // test_ok valid_future_feature
146                            // from __future__ import annotations
147
148                            // test_err invalid_future_feature
149                            // from __future__ import invalid_feature
150                            // from __future__ import annotations, invalid_feature
151                            // from __future__ import invalid_feature_1, invalid_feature_2
152                            Self::add_error(
153                                ctx,
154                                SemanticSyntaxErrorKind::FutureFeatureNotDefined(
155                                    name.name.to_string(),
156                                ),
157                                name.range,
158                            );
159                        }
160                    }
161                    if self.seen_futures_boundary {
162                        Self::add_error(ctx, SemanticSyntaxErrorKind::LateFutureImport, *range);
163                    }
164                }
165                for alias in names {
166                    if alias.name.as_str() == "*" && !ctx.in_module_scope() {
167                        // test_err import_from_star
168                        // def f1():
169                        //     from module import *
170                        // class C:
171                        //     from module import *
172                        // def f2():
173                        //     from ..module import *
174                        // def f3():
175                        //     from module import *, *
176
177                        // test_ok import_from_star
178                        // from module import *
179                        Self::add_error(
180                            ctx,
181                            SemanticSyntaxErrorKind::NonModuleImportStar(
182                                helpers::format_import_from(*level, module.as_deref()).to_string(),
183                            ),
184                            *range,
185                        );
186                        break;
187                    }
188                }
189            }
190            Stmt::Import(ast::StmtImport {
191                range,
192                is_lazy: true,
193                ..
194            }) => {
195                Self::check_lazy_import_context(ctx, *range, LazyImportKind::Import);
196            }
197            Stmt::Match(match_stmt) => {
198                Self::irrefutable_match_case(match_stmt, ctx);
199                for case in &match_stmt.cases {
200                    let mut visitor = MatchPatternVisitor {
201                        names: FxHashSet::default(),
202                        ctx,
203                    };
204                    visitor.visit_pattern(&case.pattern);
205                }
206            }
207            Stmt::FunctionDef(ast::StmtFunctionDef {
208                type_params,
209                parameters,
210                ..
211            }) => {
212                if let Some(type_params) = type_params {
213                    Self::duplicate_type_parameter_name(type_params, ctx);
214                    Self::type_parameter_default_order(type_params, ctx);
215                }
216                Self::duplicate_parameter_name(parameters, ctx);
217            }
218            Stmt::Global(ast::StmtGlobal { names, .. }) => {
219                for name in names {
220                    if ctx.is_bound_parameter(name) {
221                        Self::add_error(
222                            ctx,
223                            SemanticSyntaxErrorKind::GlobalParameter(name.to_string()),
224                            name.range,
225                        );
226                    }
227                }
228            }
229            Stmt::ClassDef(ast::StmtClassDef {
230                type_params,
231                arguments,
232                ..
233            }) => {
234                if let Some(type_params) = type_params {
235                    Self::duplicate_type_parameter_name(type_params, ctx);
236                    Self::type_parameter_default_order(type_params, ctx);
237                }
238                if let Some(arguments) = arguments {
239                    Self::duplicate_keyword_args(arguments, ctx);
240                }
241            }
242            Stmt::TypeAlias(ast::StmtTypeAlias {
243                type_params: Some(type_params),
244                ..
245            }) => {
246                Self::duplicate_type_parameter_name(type_params, ctx);
247                Self::type_parameter_default_order(type_params, ctx);
248            }
249            Stmt::Assign(ast::StmtAssign { targets, value, .. }) => {
250                if let [Expr::Starred(ast::ExprStarred { range, .. })] = targets.as_slice() {
251                    // test_ok single_starred_assignment_target
252                    // (*a,) = (1,)
253                    // *a, = (1,)
254                    // [*a] = (1,)
255
256                    // test_err single_starred_assignment_target
257                    // *a = (1,)
258                    Self::add_error(
259                        ctx,
260                        SemanticSyntaxErrorKind::SingleStarredAssignment,
261                        *range,
262                    );
263                }
264
265                // test_ok assign_stmt_starred_expr_value
266                // _ = 4
267                // _ = [4]
268                // _ = (*[1],)
269                // _ = *[1],
270
271                // test_err assign_stmt_starred_expr_value
272                // _ = *[42]
273                // _ = *{42}
274                // _ = *list()
275                // _ = *(p + q)
276                Self::invalid_star_expression(value, ctx);
277            }
278            Stmt::Return(ast::StmtReturn {
279                value,
280                range,
281                node_index: _,
282            }) => {
283                if let Some(value) = value {
284                    // test_err single_star_return
285                    // def f(): return *x
286                    Self::invalid_star_expression(value, ctx);
287                }
288                if !ctx.in_function_scope() {
289                    Self::add_error(ctx, SemanticSyntaxErrorKind::ReturnOutsideFunction, *range);
290                }
291            }
292            Stmt::For(ast::StmtFor {
293                target,
294                iter,
295                is_async,
296                ..
297            }) => {
298                // test_err single_star_for
299                // for _ in *x: ...
300                // for *x in xs: ...
301                Self::invalid_star_expression(target, ctx);
302                Self::invalid_star_expression(iter, ctx);
303                if *is_async {
304                    Self::await_outside_async_function(
305                        ctx,
306                        stmt,
307                        AwaitOutsideAsyncFunctionKind::AsyncFor,
308                    );
309                }
310            }
311            Stmt::With(ast::StmtWith { is_async: true, .. }) => {
312                Self::await_outside_async_function(
313                    ctx,
314                    stmt,
315                    AwaitOutsideAsyncFunctionKind::AsyncWith,
316                );
317            }
318            Stmt::Nonlocal(ast::StmtNonlocal { names, range, .. }) => {
319                // test_ok nonlocal_declaration_at_module_level
320                // def _():
321                //     nonlocal x
322
323                // test_err nonlocal_declaration_at_module_level
324                // nonlocal x
325                // nonlocal x, y
326                if ctx.in_module_scope() {
327                    Self::add_error(
328                        ctx,
329                        SemanticSyntaxErrorKind::NonlocalDeclarationAtModuleLevel,
330                        *range,
331                    );
332                }
333
334                if !ctx.in_module_scope() {
335                    for name in names {
336                        if ctx.is_bound_parameter(name) {
337                            Self::add_error(
338                                ctx,
339                                SemanticSyntaxErrorKind::NonlocalParameter(name.to_string()),
340                                name.range,
341                            );
342                        } else if !ctx.has_nonlocal_binding(name) {
343                            Self::add_error(
344                                ctx,
345                                SemanticSyntaxErrorKind::NonlocalWithoutBinding(name.to_string()),
346                                name.range,
347                            );
348                        }
349                    }
350                }
351            }
352            Stmt::Break(ast::StmtBreak { range, .. }) if !ctx.in_loop_context() => {
353                Self::add_error(ctx, SemanticSyntaxErrorKind::BreakOutsideLoop, *range);
354            }
355            Stmt::Continue(ast::StmtContinue { range, .. }) if !ctx.in_loop_context() => {
356                Self::add_error(ctx, SemanticSyntaxErrorKind::ContinueOutsideLoop, *range);
357            }
358            _ => {}
359        }
360
361        Self::debug_shadowing(stmt, ctx);
362        Self::check_annotation(stmt, ctx);
363    }
364
365    fn check_annotation<Ctx: SemanticSyntaxContext>(stmt: &ast::Stmt, ctx: &Ctx) {
366        match stmt {
367            Stmt::AnnAssign(ast::StmtAnnAssign {
368                target, annotation, ..
369            }) => {
370                if ctx.python_version() > PythonVersion::PY313 {
371                    // test_ok valid_annotation_py313
372                    // # parse_options: {"target-version": "3.13"}
373                    // a: (x := 1)
374                    // def outer():
375                    //     b: (yield 1)
376                    //     c: (yield from 1)
377                    // async def outer():
378                    //     d: (await 1)
379
380                    // test_err invalid_annotation_py314
381                    // # parse_options: {"target-version": "3.14"}
382                    // a: (x := 1)
383                    // def outer():
384                    //     b: (yield 1)
385                    //     c: (yield from 1)
386                    // async def outer():
387                    //     d: (await 1)
388                    let mut visitor = InvalidExpressionVisitor {
389                        position: InvalidExpressionPosition::TypeAnnotation,
390                        ctx,
391                    };
392                    visitor.visit_expr(annotation);
393                }
394                if let Expr::Name(ast::ExprName { id, .. }) = target.as_ref() {
395                    if let Some(global_stmt) = ctx.global(id.as_str()) {
396                        let global_start = global_stmt.start();
397                        if !ctx.in_module_scope() || target.start() < global_start {
398                            Self::add_error(
399                                ctx,
400                                SemanticSyntaxErrorKind::AnnotatedGlobal(id.to_string()),
401                                target.range(),
402                            );
403                        }
404                    }
405                }
406            }
407            Stmt::FunctionDef(ast::StmtFunctionDef {
408                type_params,
409                parameters,
410                returns,
411                ..
412            }) => {
413                // test_ok valid_annotation_function_py313
414                // # parse_options: {"target-version": "3.13"}
415                // def f() -> (y := 3): ...
416                // def g(arg: (x := 1)): ...
417                // def outer():
418                //     def i(x: (yield 1)): ...
419                //     def k() -> (yield 1): ...
420                //     def m(x: (yield from 1)): ...
421                //     def o() -> (yield from 1): ...
422                // async def outer():
423                //     def f() -> (await 1): ...
424                //     def g(arg: (await 1)): ...
425
426                // test_err invalid_annotation_function_py314
427                // # parse_options: {"target-version": "3.14"}
428                // def f() -> (y := 3): ...
429                // def g(arg: (x := 1)): ...
430                // def outer():
431                //     def i(x: (yield 1)): ...
432                //     def k() -> (yield 1): ...
433                //     def m(x: (yield from 1)): ...
434                //     def o() -> (yield from 1): ...
435                // async def outer():
436                //     def f() -> (await 1): ...
437                //     def g(arg: (await 1)): ...
438
439                // test_err invalid_annotation_function
440                // def d[T]() -> (await 1): ...
441                // def e[T](arg: (await 1)): ...
442                // def f[T]() -> (y := 3): ...
443                // def g[T](arg: (x := 1)): ...
444                // def h[T](x: (yield 1)): ...
445                // def j[T]() -> (yield 1): ...
446                // def l[T](x: (yield from 1)): ...
447                // def n[T]() -> (yield from 1): ...
448                // def p[T: (yield 1)](): ...      # yield in TypeVar bound
449                // def q[T = (yield 1)](): ...     # yield in TypeVar default
450                // def r[*Ts = (yield 1)](): ...   # yield in TypeVarTuple default
451                // def s[**Ts = (yield 1)](): ...  # yield in ParamSpec default
452                // def t[T: (x := 1)](): ...       # named expr in TypeVar bound
453                // def u[T = (x := 1)](): ...      # named expr in TypeVar default
454                // def v[*Ts = (x := 1)](): ...    # named expr in TypeVarTuple default
455                // def w[**Ts = (x := 1)](): ...   # named expr in ParamSpec default
456                // def t[T: (await 1)](): ...       # await in TypeVar bound
457                // def u[T = (await 1)](): ...      # await in TypeVar default
458                // def v[*Ts = (await 1)](): ...    # await in TypeVarTuple default
459                // def w[**Ts = (await 1)](): ...   # await in ParamSpec default
460                let mut visitor = InvalidExpressionVisitor {
461                    position: InvalidExpressionPosition::TypeAnnotation,
462                    ctx,
463                };
464                if let Some(type_params) = type_params {
465                    visitor.visit_type_params(type_params);
466                }
467                // the __future__ annotation error takes precedence over the generic error
468                if ctx.future_annotations_or_stub() || ctx.python_version() > PythonVersion::PY313 {
469                    visitor.position = InvalidExpressionPosition::TypeAnnotation;
470                } else if type_params.is_some() {
471                    visitor.position = InvalidExpressionPosition::GenericDefinition;
472                } else {
473                    return;
474                }
475                for param in parameters
476                    .iter()
477                    .filter_map(ast::AnyParameterRef::annotation)
478                {
479                    visitor.visit_expr(param);
480                }
481                if let Some(returns) = returns {
482                    visitor.visit_expr(returns);
483                }
484            }
485            Stmt::ClassDef(ast::StmtClassDef {
486                type_params: Some(type_params),
487                arguments,
488                ..
489            }) => {
490                // test_ok valid_annotation_class
491                // class F(y := list): ...
492                // def f():
493                //     class G((yield 1)): ...
494                //     class H((yield from 1)): ...
495                // async def f():
496                //     class G((await 1)): ...
497
498                // test_err invalid_annotation_class
499                // class F[T](y := list): ...
500                // class I[T]((yield 1)): ...
501                // class J[T]((yield from 1)): ...
502                // class K[T: (yield 1)]: ...      # yield in TypeVar
503                // class L[T: (x := 1)]: ...       # named expr in TypeVar
504                // class M[T]((await 1)): ...
505                // class N[T: (await 1)]: ...
506                let mut visitor = InvalidExpressionVisitor {
507                    position: InvalidExpressionPosition::TypeAnnotation,
508                    ctx,
509                };
510                visitor.visit_type_params(type_params);
511                if let Some(arguments) = arguments {
512                    visitor.position = InvalidExpressionPosition::GenericDefinition;
513                    visitor.visit_arguments(arguments);
514                }
515            }
516            Stmt::TypeAlias(ast::StmtTypeAlias {
517                type_params, value, ..
518            }) => {
519                // test_err invalid_annotation_type_alias
520                // type X[T: (yield 1)] = int      # TypeVar bound
521                // type X[T = (yield 1)] = int     # TypeVar default
522                // type X[*Ts = (yield 1)] = int   # TypeVarTuple default
523                // type X[**Ts = (yield 1)] = int  # ParamSpec default
524                // type Y = (yield 1)              # yield in value
525                // type Y = (x := 1)               # named expr in value
526                // type Y[T: (await 1)] = int      # await in bound
527                // type Y = (await 1)              # await in value
528                let mut visitor = InvalidExpressionVisitor {
529                    position: InvalidExpressionPosition::TypeAlias,
530                    ctx,
531                };
532                visitor.visit_expr(value);
533                if let Some(type_params) = type_params {
534                    visitor.visit_type_params(type_params);
535                }
536            }
537            _ => {}
538        }
539    }
540
541    /// Emit a [`SemanticSyntaxErrorKind::InvalidStarExpression`] if `expr` is starred.
542    fn invalid_star_expression<Ctx: SemanticSyntaxContext>(expr: &Expr, ctx: &Ctx) {
543        // test_ok single_star_in_tuple
544        // def f(): yield (*x,)
545        // def f(): return (*x,)
546        // for _ in (*x,): ...
547        // for (*x,) in xs: ...
548        if expr.is_starred_expr() {
549            Self::add_error(
550                ctx,
551                SemanticSyntaxErrorKind::InvalidStarExpression,
552                expr.range(),
553            );
554        }
555    }
556
557    fn multiple_star_expression<Ctx: SemanticSyntaxContext>(
558        ctx: &Ctx,
559        expr_ctx: ExprContext,
560        elts: &[Expr],
561        range: TextRange,
562    ) {
563        if expr_ctx.is_store() {
564            let mut has_starred = false;
565            for elt in elts {
566                if elt.is_starred_expr() {
567                    if has_starred {
568                        // test_err multiple_starred_assignment_target
569                        // (*a, *b) = (1, 2)
570                        // [*a, *b] = (1, 2)
571                        // (*a, *b, c) = (1, 2, 3)
572                        // [*a, *b, c] = (1, 2, 3)
573                        // (*a, *b, (*c, *d)) = (1, 2)
574
575                        // test_ok multiple_starred_assignment_target
576                        // (*a, b) = (1, 2)
577                        // (*_, normed), *_ = [(1,), 2]
578                        Self::add_error(
579                            ctx,
580                            SemanticSyntaxErrorKind::MultipleStarredExpressions,
581                            range,
582                        );
583                        return;
584                    }
585                    has_starred = true;
586                }
587            }
588        }
589    }
590
591    /// Check for [`SemanticSyntaxErrorKind::WriteToDebug`] in `stmt`.
592    fn debug_shadowing<Ctx: SemanticSyntaxContext>(stmt: &ast::Stmt, ctx: &Ctx) {
593        match stmt {
594            Stmt::FunctionDef(ast::StmtFunctionDef {
595                name,
596                type_params,
597                parameters,
598                ..
599            }) => {
600                // test_err debug_shadow_function
601                // def __debug__(): ...  # function name
602                // def f[__debug__](): ...  # type parameter name
603                // def f(__debug__): ...  # parameter name
604                // lambda __debug__: 0  # lambda parameter name
605                Self::check_identifier(name, ctx);
606                if let Some(type_params) = type_params {
607                    for type_param in type_params.iter() {
608                        Self::check_identifier(type_param.name(), ctx);
609                    }
610                }
611                for parameter in parameters {
612                    Self::check_identifier(parameter.name(), ctx);
613                }
614            }
615            Stmt::ClassDef(ast::StmtClassDef {
616                name, type_params, ..
617            }) => {
618                // test_err debug_shadow_class
619                // class __debug__: ...  # class name
620                // class C[__debug__]: ...  # type parameter name
621                Self::check_identifier(name, ctx);
622                if let Some(type_params) = type_params {
623                    for type_param in type_params.iter() {
624                        Self::check_identifier(type_param.name(), ctx);
625                    }
626                }
627            }
628            Stmt::TypeAlias(ast::StmtTypeAlias {
629                type_params: Some(type_params),
630                ..
631            }) => {
632                // test_err debug_shadow_type_alias
633                // type __debug__ = list[int]  # visited as an Expr but still flagged
634                // type Debug[__debug__] = str
635                for type_param in type_params.iter() {
636                    Self::check_identifier(type_param.name(), ctx);
637                }
638            }
639            Stmt::Import(ast::StmtImport { names, .. })
640            | Stmt::ImportFrom(ast::StmtImportFrom { names, .. }) => {
641                // test_err debug_shadow_import
642                // import __debug__
643                // import debug as __debug__
644                // from x import __debug__
645                // from x import debug as __debug__
646
647                // test_ok debug_rename_import
648                // import __debug__ as debug
649                // from __debug__ import Some
650                // from x import __debug__ as debug
651                for name in names {
652                    match &name.asname {
653                        Some(asname) => Self::check_identifier(asname, ctx),
654                        None => Self::check_identifier(&name.name, ctx),
655                    }
656                }
657            }
658            Stmt::Try(ast::StmtTry { handlers, .. }) => {
659                // test_err debug_shadow_try
660                // try: ...
661                // except Exception as __debug__: ...
662                for handler in handlers
663                    .iter()
664                    .filter_map(ast::ExceptHandler::as_except_handler)
665                {
666                    if let Some(name) = &handler.name {
667                        Self::check_identifier(name, ctx);
668                    }
669                }
670            }
671            // test_err debug_shadow_with
672            // with open("foo.txt") as __debug__: ...
673            _ => {}
674        }
675    }
676
677    /// Check if `ident` is equal to `__debug__` and emit a
678    /// [`SemanticSyntaxErrorKind::WriteToDebug`] if so.
679    fn check_identifier<Ctx: SemanticSyntaxContext>(ident: &ast::Identifier, ctx: &Ctx) {
680        if ident.id == "__debug__" {
681            Self::add_error(
682                ctx,
683                SemanticSyntaxErrorKind::WriteToDebug(WriteToDebugKind::Store),
684                ident.range,
685            );
686        }
687    }
688
689    fn duplicate_type_parameter_name<Ctx: SemanticSyntaxContext>(
690        type_params: &ast::TypeParams,
691        ctx: &Ctx,
692    ) {
693        if type_params.len() < 2 {
694            return;
695        }
696
697        for (i, type_param) in type_params.iter().enumerate() {
698            if type_params
699                .iter()
700                .take(i)
701                .any(|t| t.name().id == type_param.name().id)
702            {
703                // test_ok non_duplicate_type_parameter_names
704                // type Alias[T] = list[T]
705                // def f[T](t: T): ...
706                // class C[T]: ...
707                // class C[T, U, V]: ...
708                // type Alias[T, U: str, V: (str, bytes), *Ts, **P, D = default] = ...
709
710                // test_err duplicate_type_parameter_names
711                // type Alias[T, T] = ...
712                // def f[T, T](t: T): ...
713                // class C[T, T]: ...
714                // type Alias[T, U: str, V: (str, bytes), *Ts, **P, T = default] = ...
715                // def f[T, T, T](): ...  # two errors
716                // def f[T, *T](): ...    # star is still duplicate
717                // def f[T, **T](): ...   # as is double star
718                Self::add_error(
719                    ctx,
720                    SemanticSyntaxErrorKind::DuplicateTypeParameter,
721                    type_param.range(),
722                );
723            }
724        }
725    }
726
727    fn type_parameter_default_order<Ctx: SemanticSyntaxContext>(
728        type_params: &ast::TypeParams,
729        ctx: &Ctx,
730    ) {
731        let mut seen_default = false;
732        for type_param in type_params {
733            let has_default = match type_param {
734                ast::TypeParam::TypeVar(ast::TypeParamTypeVar { default, .. })
735                | ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { default, .. })
736                | ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { default, .. }) => {
737                    default.is_some()
738                }
739            };
740
741            if seen_default && !has_default {
742                // test_err type_parameter_default_order
743                // class C[T = int, U]: ...
744                // class C[T1, T2 = int, T3, T4]: ...
745                // def f[T = int, U](): ...
746                // type Alias[T = int, U] = ...
747                Self::add_error(
748                    ctx,
749                    SemanticSyntaxErrorKind::TypeParameterDefaultOrder(
750                        type_param.name().id.to_string(),
751                    ),
752                    type_param.range(),
753                );
754            }
755            if has_default {
756                seen_default = true;
757            }
758        }
759    }
760
761    fn duplicate_parameter_name<Ctx: SemanticSyntaxContext>(
762        parameters: &ast::Parameters,
763        ctx: &Ctx,
764    ) {
765        if parameters.len() < 2 {
766            return;
767        }
768
769        let mut all_arg_names =
770            FxHashSet::with_capacity_and_hasher(parameters.len(), FxBuildHasher);
771
772        for parameter in parameters {
773            let range = parameter.name().range();
774            let param_name = parameter.name().as_str();
775            if !all_arg_names.insert(param_name) {
776                // test_err params_duplicate_names
777                // def foo(a, a=10, *a, a, a: str, **a): ...
778                Self::add_error(
779                    ctx,
780                    SemanticSyntaxErrorKind::DuplicateParameter(param_name.to_string()),
781                    range,
782                );
783            }
784        }
785    }
786
787    fn duplicate_keyword_args<Ctx: SemanticSyntaxContext>(args: &ast::Arguments, ctx: &Ctx) {
788        if args.keywords.len() < 2 {
789            return;
790        }
791
792        let mut all_arg_names =
793            FxHashSet::with_capacity_and_hasher(args.keywords.len(), FxBuildHasher);
794
795        for (ident, range) in args
796            .keywords
797            .iter()
798            .filter_map(|keyword| keyword.arg.as_ref().map(|arg| (arg, keyword.range)))
799        {
800            if !all_arg_names.insert(ident.as_str()) {
801                // test_err duplicate_keyword_args
802                // def foo(x): ...
803                // foo(x=1, x=2)
804                // def baz(x, y, z): ...
805                // baz(x, y=1, z=3, y=4)
806
807                // test_ok non_duplicate_keyword_args
808                // def foo(x): ...
809                // foo(x=1)
810                // def bar(x, y, z): ...
811                // foo(x="a", y=1, z=True)
812                Self::add_error(
813                    ctx,
814                    SemanticSyntaxErrorKind::DuplicateKeywordArgument(ident.to_string()),
815                    range,
816                );
817            }
818        }
819    }
820
821    fn irrefutable_match_case<Ctx: SemanticSyntaxContext>(stmt: &ast::StmtMatch, ctx: &Ctx) {
822        // test_ok irrefutable_case_pattern_at_end
823        // match x:
824        //     case 2: ...
825        //     case var: ...
826        // match x:
827        //     case 2: ...
828        //     case _: ...
829        // match x:
830        //     case var if True: ...  # don't try to refute a guarded pattern
831        //     case 2: ...
832
833        // test_err irrefutable_case_pattern
834        // match x:
835        //     case var: ...  # capture pattern
836        //     case 2: ...
837        // match x:
838        //     case _: ...
839        //     case 2: ...    # wildcard pattern
840        // match x:
841        //     case var1 as var2: ...  # as pattern with irrefutable left-hand side
842        //     case 2: ...
843        // match x:
844        //     case enum.variant | var: ...  # or pattern with irrefutable part
845        //     case 2: ...
846        for case in stmt
847            .cases
848            .iter()
849            .rev()
850            .skip(1)
851            .filter_map(|case| match case.guard {
852                Some(_) => None,
853                None => case.pattern.irrefutable_pattern(),
854            })
855        {
856            Self::add_error(
857                ctx,
858                SemanticSyntaxErrorKind::IrrefutableCasePattern(case.kind),
859                case.range,
860            );
861        }
862    }
863
864    /// Check `stmt` for semantic syntax errors and update the checker's internal state.
865    ///
866    /// Note that this method should only be called when traversing `stmt` *and* its children. For
867    /// example, if traversal of function bodies needs to be deferred, avoid calling `visit_stmt` on
868    /// the function itself until the deferred body is visited too. Failing to defer `visit_stmt` in
869    /// this case will break any internal state that depends on function scopes, such as `async`
870    /// context detection.
871    pub fn visit_stmt<Ctx: SemanticSyntaxContext>(&mut self, stmt: &ast::Stmt, ctx: &Ctx) {
872        // check for errors
873        self.check_stmt(stmt, ctx);
874
875        // update internal state
876        match stmt {
877            Stmt::Expr(StmtExpr { value, .. })
878                if !self.seen_module_docstring_boundary && value.is_string_literal_expr() => {}
879            Stmt::ImportFrom(StmtImportFrom {
880                module, is_lazy, ..
881            }) => {
882                // Allow eager `__future__` imports until we see any other import. Lazy imports,
883                // including `lazy from __future__ import ...`, always close the boundary.
884                if *is_lazy || !matches!(module.as_deref(), Some("__future__")) {
885                    self.seen_futures_boundary = true;
886                }
887            }
888            Stmt::FunctionDef(StmtFunctionDef { is_async, body, .. }) => {
889                if *is_async {
890                    let mut visitor = ReturnVisitor::default();
891                    visitor.visit_body(body);
892
893                    if visitor.has_yield {
894                        if let Some(return_range) = visitor.return_range {
895                            Self::add_error(
896                                ctx,
897                                SemanticSyntaxErrorKind::ReturnInGenerator,
898                                return_range,
899                            );
900                        }
901                    }
902                }
903                self.seen_futures_boundary = true;
904            }
905            _ => {
906                self.seen_futures_boundary = true;
907            }
908        }
909
910        self.seen_module_docstring_boundary = true;
911    }
912
913    /// Check `expr` for semantic syntax errors and update the checker's internal state.
914    pub fn visit_expr<Ctx: SemanticSyntaxContext>(&mut self, expr: &Expr, ctx: &Ctx) {
915        match expr {
916            Expr::ListComp(ast::ExprListComp {
917                elt, generators, ..
918            })
919            | Expr::SetComp(ast::ExprSetComp {
920                elt, generators, ..
921            }) => {
922                Self::check_generator_expr(elt, generators, ctx);
923                Self::check_generator_clauses(generators, ctx);
924                Self::async_comprehension_in_sync_comprehension(ctx, generators);
925                for generator in generators.iter().filter(|g| g.is_async) {
926                    Self::await_outside_async_function(
927                        ctx,
928                        generator,
929                        AwaitOutsideAsyncFunctionKind::AsyncComprehension,
930                    );
931                }
932            }
933            Expr::DictComp(ast::ExprDictComp {
934                key,
935                value,
936                generators,
937                ..
938            }) => {
939                if let Some(key) = key {
940                    Self::check_generator_expr(key, generators, ctx);
941                }
942                Self::check_generator_expr(value, generators, ctx);
943                Self::check_generator_clauses(generators, ctx);
944                Self::async_comprehension_in_sync_comprehension(ctx, generators);
945                for generator in generators.iter().filter(|g| g.is_async) {
946                    Self::await_outside_async_function(
947                        ctx,
948                        generator,
949                        AwaitOutsideAsyncFunctionKind::AsyncComprehension,
950                    );
951                }
952            }
953            Expr::Generator(ast::ExprGenerator {
954                elt, generators, ..
955            }) => {
956                Self::check_generator_expr(elt, generators, ctx);
957                Self::check_generator_clauses(generators, ctx);
958                // Note that `await_outside_async_function` is not called here because generators
959                // are evaluated lazily. See the note in the function for more details.
960            }
961            Expr::Name(ast::ExprName {
962                range,
963                id,
964                ctx: expr_ctx,
965                node_index: _,
966            }) => {
967                // test_err write_to_debug_expr
968                // del __debug__
969                // del x, y, __debug__, z
970                // __debug__ = 1
971                // x, y, __debug__, z = 1, 2, 3, 4
972
973                // test_err del_debug_py39
974                // # parse_options: {"target-version": "3.9"}
975                // del __debug__
976
977                // test_ok del_debug_py38
978                // # parse_options: {"target-version": "3.8"}
979                // del __debug__
980
981                // test_ok read_from_debug
982                // if __debug__: ...
983                // x = __debug__
984                if id == "__debug__" {
985                    match expr_ctx {
986                        ExprContext::Store => Self::add_error(
987                            ctx,
988                            SemanticSyntaxErrorKind::WriteToDebug(WriteToDebugKind::Store),
989                            *range,
990                        ),
991                        ExprContext::Del => {
992                            let version = ctx.python_version();
993                            if version >= PythonVersion::PY39 {
994                                Self::add_error(
995                                    ctx,
996                                    SemanticSyntaxErrorKind::WriteToDebug(
997                                        WriteToDebugKind::Delete(version),
998                                    ),
999                                    *range,
1000                                );
1001                            }
1002                        }
1003                        _ => {}
1004                    }
1005                }
1006
1007                // PLE0118
1008                if let Some(stmt) = ctx.global(id) {
1009                    let start = stmt.start();
1010                    if expr.start() < start {
1011                        Self::add_error(
1012                            ctx,
1013                            SemanticSyntaxErrorKind::LoadBeforeGlobalDeclaration {
1014                                name: id.to_string(),
1015                                start,
1016                            },
1017                            expr.range(),
1018                        );
1019                    }
1020                }
1021            }
1022            Expr::Yield(ast::ExprYield { value, .. }) => {
1023                if let Some(value) = value {
1024                    // test_err single_star_yield
1025                    // def f(): yield *x
1026                    Self::invalid_star_expression(value, ctx);
1027                }
1028                Self::yield_outside_function(ctx, expr, YieldOutsideFunctionKind::Yield);
1029            }
1030            Expr::YieldFrom(_) => {
1031                Self::yield_outside_function(ctx, expr, YieldOutsideFunctionKind::YieldFrom);
1032                if ctx.in_function_scope() && ctx.in_async_context() {
1033                    // test_err yield_from_in_async_function
1034                    // async def f(): yield from x
1035
1036                    Self::add_error(
1037                        ctx,
1038                        SemanticSyntaxErrorKind::YieldFromInAsyncFunction,
1039                        expr.range(),
1040                    );
1041                }
1042            }
1043            Expr::Await(_) => {
1044                Self::yield_outside_function(ctx, expr, YieldOutsideFunctionKind::Await);
1045                Self::await_outside_async_function(ctx, expr, AwaitOutsideAsyncFunctionKind::Await);
1046            }
1047            Expr::Tuple(ast::ExprTuple {
1048                elts,
1049                ctx: expr_ctx,
1050                range,
1051                ..
1052            })
1053            | Expr::List(ast::ExprList {
1054                elts,
1055                ctx: expr_ctx,
1056                range,
1057                ..
1058            }) => {
1059                Self::multiple_star_expression(ctx, *expr_ctx, elts, *range);
1060            }
1061            Expr::Lambda(ast::ExprLambda {
1062                parameters: Some(parameters),
1063                ..
1064            }) => {
1065                for parameter in parameters {
1066                    Self::check_identifier(parameter.name(), ctx);
1067                }
1068                Self::duplicate_parameter_name(parameters, ctx);
1069            }
1070            Expr::Call(ast::ExprCall { arguments, .. }) => {
1071                Self::duplicate_keyword_args(arguments, ctx);
1072            }
1073            _ => {}
1074        }
1075    }
1076
1077    /// PLE1142
1078    fn await_outside_async_function<Ctx: SemanticSyntaxContext, Node: Ranged>(
1079        ctx: &Ctx,
1080        node: Node,
1081        kind: AwaitOutsideAsyncFunctionKind,
1082    ) {
1083        if ctx.in_async_context() {
1084            return;
1085        }
1086        // `await` is allowed at the top level of a Jupyter notebook.
1087        // See: https://ipython.readthedocs.io/en/stable/interactive/autoawait.html.
1088        if ctx.in_module_scope() && ctx.in_notebook() {
1089            return;
1090        }
1091        // Generators are evaluated lazily, so you can use `await` in them. For example:
1092        //
1093        // ```python
1094        // # This is valid
1095        // def f():
1096        //     (await x for x in y)
1097        //     (x async for x in y)
1098        //
1099        // # This is invalid
1100        // def f():
1101        //     (x for x in await y)
1102        //     [await x for x in y]
1103        // ```
1104        //
1105        // This check is required in addition to avoiding calling this function in `visit_expr`
1106        // because the generator scope applies to nested parts of the `Expr::Generator` that are
1107        // visited separately.
1108        if ctx.in_generator_context() {
1109            return;
1110        }
1111        Self::add_error(
1112            ctx,
1113            SemanticSyntaxErrorKind::AwaitOutsideAsyncFunction(kind),
1114            node.range(),
1115        );
1116    }
1117
1118    /// F704
1119    fn yield_outside_function<Ctx: SemanticSyntaxContext>(
1120        ctx: &Ctx,
1121        expr: &Expr,
1122        kind: YieldOutsideFunctionKind,
1123    ) {
1124        // We are intentionally not inspecting the async status of the scope for now to mimic F704.
1125        // await-outside-async is PLE1142 instead, so we'll end up emitting both syntax errors for
1126        // cases that trigger F704
1127
1128        if ctx.in_function_scope() {
1129            return;
1130        }
1131
1132        if kind.is_await() {
1133            // `await` is allowed at the top level of a Jupyter notebook.
1134            // See: https://ipython.readthedocs.io/en/stable/interactive/autoawait.html.
1135            if ctx.in_module_scope() && ctx.in_notebook() {
1136                return;
1137            }
1138            if ctx.in_await_allowed_context() {
1139                return;
1140            }
1141        } else if ctx.in_yield_allowed_context() {
1142            return;
1143        }
1144
1145        Self::add_error(
1146            ctx,
1147            SemanticSyntaxErrorKind::YieldOutsideFunction(kind),
1148            expr.range(),
1149        );
1150    }
1151
1152    /// Add a [`SemanticSyntaxErrorKind::ReboundComprehensionVariable`] if `expr` rebinds an
1153    /// iteration variable in `generators`.
1154    fn check_generator_expr<Ctx: SemanticSyntaxContext>(
1155        expr: &Expr,
1156        comprehensions: &[ast::Comprehension],
1157        ctx: &Ctx,
1158    ) {
1159        Self::check_rebound_variables(
1160            expr,
1161            comprehension_target_names(comprehensions),
1162            FxHashSet::default(),
1163            ctx,
1164        );
1165        Self::check_class_body_expr(expr, ctx);
1166    }
1167
1168    fn check_generator_clauses<Ctx: SemanticSyntaxContext>(
1169        generators: &[ast::Comprehension],
1170        ctx: &Ctx,
1171    ) {
1172        // test_ok starred_comprehension_target
1173        // [item for (*items,) in source]
1174
1175        // test_err starred_comprehension_target
1176        // [item for *items in source]
1177        for (index, generator) in generators.iter().enumerate() {
1178            Self::invalid_star_expression(&generator.target, ctx);
1179
1180            for if_expr in &generator.ifs {
1181                Self::check_rebound_variables(
1182                    if_expr,
1183                    comprehension_target_names(&generators[..=index]),
1184                    comprehension_target_names(&generators[index + 1..]),
1185                    ctx,
1186                );
1187                Self::check_class_body_expr(if_expr, ctx);
1188            }
1189
1190            let mut visitor = ComprehensionIterableNamedExpressionVisitor::default();
1191            visitor.visit_expr(&generator.iter);
1192            for range in visitor.ranges {
1193                Self::add_error(
1194                    ctx,
1195                    SemanticSyntaxErrorKind::NamedExpressionInComprehensionIterable,
1196                    range,
1197                );
1198            }
1199        }
1200    }
1201
1202    fn check_rebound_variables<'a, Ctx: SemanticSyntaxContext>(
1203        expr: &Expr,
1204        targets: FxHashSet<&'a ast::name::Name>,
1205        direct_targets: FxHashSet<&'a ast::name::Name>,
1206        ctx: &Ctx,
1207    ) {
1208        let mut visitor = ReboundComprehensionVisitor {
1209            targets,
1210            direct_targets,
1211            ranges: Vec::new(),
1212        };
1213        visitor.visit_expr(expr);
1214
1215        // TODO(brent): With multiple diagnostic ranges, mark both the named expression target
1216        // (currently reported) and the comprehension target it rebinds.
1217        for range in visitor.ranges {
1218            // test_err rebound_comprehension_variable
1219            // [(a := 0) for a in range(0)]
1220            // {(a := 0) for a in range(0)}
1221            // {(a := 0): val for a in range(0)}
1222            // {key: (a := 0) for a in range(0)}
1223            // ((a := 0) for a in range(0))
1224            // [[(a := 0)] for a in range(0)]
1225            // [(a := 0) for b in range (0) for a in range(0)]
1226            // [(a := 0) for a in range (0) for b in range(0)]
1227            // [((a := 0), (b := 1)) for a in range (0) for b in range(0)]
1228
1229            // test_ok non_rebound_comprehension_variable
1230            // [a := 0 for x in range(0)]
1231            Self::add_error(
1232                ctx,
1233                SemanticSyntaxErrorKind::ReboundComprehensionVariable,
1234                range,
1235            );
1236        }
1237    }
1238
1239    fn check_class_body_expr<Ctx: SemanticSyntaxContext>(expr: &Expr, ctx: &Ctx) {
1240        if !ctx.in_class_body_comprehension() {
1241            return;
1242        }
1243
1244        let mut visitor = ClassBodyNamedExpressionVisitor::default();
1245        visitor.visit_expr(expr);
1246        for range in visitor.ranges {
1247            Self::add_error(
1248                ctx,
1249                SemanticSyntaxErrorKind::NamedExpressionInClassBodyComprehension,
1250                range,
1251            );
1252        }
1253    }
1254
1255    fn async_comprehension_in_sync_comprehension<Ctx: SemanticSyntaxContext>(
1256        ctx: &Ctx,
1257        generators: &[ast::Comprehension],
1258    ) {
1259        let python_version = ctx.python_version();
1260        if python_version >= PythonVersion::PY311 {
1261            return;
1262        }
1263        // async allowed at notebook top-level
1264        if ctx.in_notebook() && ctx.in_module_scope() {
1265            return;
1266        }
1267        if !ctx.in_sync_comprehension() {
1268            return;
1269        }
1270        for generator in generators.iter().filter(|generator| generator.is_async) {
1271            // test_ok nested_async_comprehension_py311
1272            // # parse_options: {"target-version": "3.11"}
1273            // async def f(): return [[x async for x in foo(n)] for n in range(3)]    # list
1274            // async def g(): return [{x: 1 async for x in foo(n)} for n in range(3)] # dict
1275            // async def h(): return [{x async for x in foo(n)} for n in range(3)]    # set
1276
1277            // test_ok nested_async_comprehension_py310
1278            // # parse_options: {"target-version": "3.10"}
1279            // async def f():
1280            //     [_ for n in range(3)]
1281            //     [_ async for n in range(3)]
1282            // async def f():
1283            //     def g(): ...
1284            //     [_ async for n in range(3)]
1285
1286            // test_ok all_async_comprehension_py310
1287            // # parse_options: {"target-version": "3.10"}
1288            // async def test(): return [[x async for x in elements(n)] async for n in range(3)]
1289
1290            // test_err nested_async_comprehension_py310
1291            // # parse_options: {"target-version": "3.10"}
1292            // async def f(): return [[x async for x in foo(n)] for n in range(3)]    # list
1293            // async def g(): return [{x: 1 async for x in foo(n)} for n in range(3)] # dict
1294            // async def h(): return [{x async for x in foo(n)} for n in range(3)]    # set
1295            // async def i(): return [([y async for y in range(1)], [z for z in range(2)]) for x in range(5)]
1296            // async def j(): return [([y for y in range(1)], [z async for z in range(2)]) for x in range(5)]
1297            Self::add_error(
1298                ctx,
1299                SemanticSyntaxErrorKind::AsyncComprehensionInSyncComprehension(python_version),
1300                generator.range,
1301            );
1302        }
1303    }
1304}
1305
1306fn is_known_future_feature(name: &str) -> bool {
1307    matches!(
1308        name,
1309        "nested_scopes"
1310            | "generators"
1311            | "division"
1312            | "absolute_import"
1313            | "with_statement"
1314            | "print_function"
1315            | "unicode_literals"
1316            | "barry_as_FLUFL"
1317            | "generator_stop"
1318            | "annotations"
1319    )
1320}
1321
1322#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
1323pub enum LazyImportKind {
1324    Import,
1325    ImportFrom,
1326}
1327
1328#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
1329pub enum LazyImportContext {
1330    Function,
1331    Class,
1332    TryExceptBlocks,
1333}
1334
1335#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
1336pub struct SemanticSyntaxError {
1337    pub kind: SemanticSyntaxErrorKind,
1338    pub range: TextRange,
1339    pub python_version: PythonVersion,
1340}
1341
1342impl Display for SemanticSyntaxError {
1343    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1344        match &self.kind {
1345            SemanticSyntaxErrorKind::LateFutureImport => {
1346                f.write_str("__future__ imports must be at the top of the file")
1347            }
1348            SemanticSyntaxErrorKind::NamedExpressionInComprehensionIterable => f.write_str(
1349                "assignment expression cannot be used in a comprehension iterable expression",
1350            ),
1351            SemanticSyntaxErrorKind::NamedExpressionInClassBodyComprehension => f.write_str(
1352                "assignment expression within a comprehension cannot be used in a class body",
1353            ),
1354            SemanticSyntaxErrorKind::ReboundComprehensionVariable => {
1355                f.write_str("assignment expression cannot rebind comprehension variable")
1356            }
1357            SemanticSyntaxErrorKind::DuplicateTypeParameter => {
1358                f.write_str("duplicate type parameter")
1359            }
1360            SemanticSyntaxErrorKind::TypeParameterDefaultOrder(name) => {
1361                write!(
1362                    f,
1363                    "non default type parameter `{name}` follows default type parameter"
1364                )
1365            }
1366            SemanticSyntaxErrorKind::MultipleCaseAssignment(name) => {
1367                write!(f, "multiple assignments to name `{name}` in pattern")
1368            }
1369            SemanticSyntaxErrorKind::MultipleStarredNamesInSequencePattern => {
1370                f.write_str("multiple starred names in sequence pattern")
1371            }
1372            SemanticSyntaxErrorKind::IrrefutableCasePattern(kind) => match kind {
1373                // These error messages are taken from CPython's syntax errors
1374                IrrefutablePatternKind::Name(name) => {
1375                    write!(
1376                        f,
1377                        "name capture `{name}` makes remaining patterns unreachable"
1378                    )
1379                }
1380                IrrefutablePatternKind::Wildcard => {
1381                    f.write_str("wildcard makes remaining patterns unreachable")
1382                }
1383            },
1384            SemanticSyntaxErrorKind::SingleStarredAssignment => {
1385                f.write_str("starred assignment target must be in a list or tuple")
1386            }
1387            SemanticSyntaxErrorKind::WriteToDebug(kind) => match kind {
1388                WriteToDebugKind::Store => f.write_str("cannot assign to `__debug__`"),
1389                WriteToDebugKind::Delete(python_version) => {
1390                    write!(
1391                        f,
1392                        "cannot delete `__debug__` on Python {python_version} (syntax was removed in 3.9)"
1393                    )
1394                }
1395            },
1396            SemanticSyntaxErrorKind::InvalidExpression(kind, position) => {
1397                write!(f, "{kind} cannot be used within a {position}")
1398            }
1399            SemanticSyntaxErrorKind::DuplicateMatchKey(key) => {
1400                write!(
1401                    f,
1402                    "mapping pattern checks duplicate key `{}`",
1403                    EscapeDefault(key)
1404                )
1405            }
1406            SemanticSyntaxErrorKind::DuplicateMatchClassAttribute(name) => {
1407                write!(f, "attribute name `{name}` repeated in class pattern")
1408            }
1409            SemanticSyntaxErrorKind::LoadBeforeGlobalDeclaration { name, start: _ } => {
1410                write!(f, "name `{name}` is used prior to global declaration")
1411            }
1412            SemanticSyntaxErrorKind::LoadBeforeNonlocalDeclaration { name, start: _ } => {
1413                write!(f, "name `{name}` is used prior to nonlocal declaration")
1414            }
1415            SemanticSyntaxErrorKind::InvalidStarExpression => {
1416                f.write_str("Starred expression cannot be used here")
1417            }
1418            SemanticSyntaxErrorKind::AsyncComprehensionInSyncComprehension(python_version) => {
1419                write!(
1420                    f,
1421                    "cannot use an asynchronous comprehension inside of a synchronous comprehension \
1422                        on Python {python_version} (syntax was added in 3.11)",
1423                )
1424            }
1425            SemanticSyntaxErrorKind::YieldOutsideFunction(kind) => {
1426                write!(f, "`{kind}` statement outside of a function")
1427            }
1428            SemanticSyntaxErrorKind::ReturnOutsideFunction => {
1429                f.write_str("`return` statement outside of a function")
1430            }
1431            SemanticSyntaxErrorKind::AwaitOutsideAsyncFunction(kind) => {
1432                write!(f, "{kind} outside of an asynchronous function")
1433            }
1434            SemanticSyntaxErrorKind::DuplicateParameter(name) => {
1435                write!(f, r#"Duplicate parameter "{name}""#)
1436            }
1437            SemanticSyntaxErrorKind::NonlocalDeclarationAtModuleLevel => {
1438                write!(f, "nonlocal declaration not allowed at module level")
1439            }
1440            SemanticSyntaxErrorKind::DuplicateKeywordArgument(name) => {
1441                write!(f, "Duplicate keyword argument `{name}`")
1442            }
1443            SemanticSyntaxErrorKind::NonlocalAndGlobal(name) => {
1444                write!(f, "name `{name}` is nonlocal and global")
1445            }
1446            SemanticSyntaxErrorKind::AnnotatedGlobal(name) => {
1447                write!(f, "annotated name `{name}` can't be global")
1448            }
1449            SemanticSyntaxErrorKind::AnnotatedNonlocal(name) => {
1450                write!(f, "annotated name `{name}` can't be nonlocal")
1451            }
1452            SemanticSyntaxErrorKind::YieldFromInAsyncFunction => {
1453                f.write_str("`yield from` statement in async function; use `async for` instead")
1454            }
1455            SemanticSyntaxErrorKind::NonModuleImportStar(name) => {
1456                write!(f, "`from {name} import *` only allowed at module level")
1457            }
1458            SemanticSyntaxErrorKind::MultipleStarredExpressions => {
1459                write!(f, "Two starred expressions in assignment")
1460            }
1461            SemanticSyntaxErrorKind::FutureFeatureNotDefined(name) => {
1462                write!(f, "Future feature `{name}` is not defined")
1463            }
1464            SemanticSyntaxErrorKind::LazyImportNotAllowed { context, kind } => {
1465                let statement = match kind {
1466                    LazyImportKind::Import => "lazy import",
1467                    LazyImportKind::ImportFrom => "lazy from ... import",
1468                };
1469                let location = match context {
1470                    LazyImportContext::Function => "functions",
1471                    LazyImportContext::Class => "classes",
1472                    LazyImportContext::TryExceptBlocks => "try/except blocks",
1473                };
1474                write!(f, "{statement} not allowed inside {location}")
1475            }
1476            SemanticSyntaxErrorKind::LazyImportStar => {
1477                f.write_str("lazy from ... import * is not allowed")
1478            }
1479            SemanticSyntaxErrorKind::LazyFutureImport => {
1480                f.write_str("lazy from __future__ import is not allowed")
1481            }
1482            SemanticSyntaxErrorKind::BreakOutsideLoop => f.write_str("`break` outside loop"),
1483            SemanticSyntaxErrorKind::ContinueOutsideLoop => f.write_str("`continue` outside loop"),
1484            SemanticSyntaxErrorKind::GlobalParameter(name) => {
1485                write!(
1486                    f,
1487                    "name `{name}` cannot refer to a parameter and a global variable"
1488                )
1489            }
1490            SemanticSyntaxErrorKind::NonlocalParameter(name) => {
1491                write!(
1492                    f,
1493                    "name `{name}` cannot refer to a parameter and a nonlocal variable"
1494                )
1495            }
1496            SemanticSyntaxErrorKind::DifferentMatchPatternBindings => {
1497                write!(f, "alternative patterns bind different names")
1498            }
1499            SemanticSyntaxErrorKind::NonlocalWithoutBinding(name) => {
1500                write!(f, "no binding for nonlocal `{name}` found")
1501            }
1502            SemanticSyntaxErrorKind::ReturnInGenerator => {
1503                write!(f, "`return` with value in async generator")
1504            }
1505        }
1506    }
1507}
1508
1509impl Ranged for SemanticSyntaxError {
1510    fn range(&self) -> TextRange {
1511        self.range
1512    }
1513}
1514
1515#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
1516pub enum SemanticSyntaxErrorKind {
1517    /// Represents a `lazy` import statement in an invalid context.
1518    LazyImportNotAllowed {
1519        context: LazyImportContext,
1520        kind: LazyImportKind,
1521    },
1522
1523    /// Represents the use of `lazy from ... import *`.
1524    LazyImportStar,
1525
1526    /// Represents the use of `lazy from __future__ import ...`.
1527    LazyFutureImport,
1528
1529    /// Represents the use of a `__future__` import after the beginning of a file.
1530    ///
1531    /// ## Examples
1532    ///
1533    /// ```python
1534    /// from pathlib import Path
1535    ///
1536    /// from __future__ import annotations
1537    /// ```
1538    ///
1539    /// This corresponds to the [`late-future-import`] (`F404`) rule in ruff.
1540    ///
1541    /// [`late-future-import`]: https://docs.astral.sh/ruff/rules/late-future-import/
1542    LateFutureImport,
1543
1544    /// Represents the use of an assignment expression within a comprehension iterable clause.
1545    ///
1546    /// ## Examples
1547    ///
1548    /// ```python
1549    /// [x for x in (y := range(3))]
1550    /// [x for x in [z for z in range(3) if (y := z)]]
1551    /// ```
1552    NamedExpressionInComprehensionIterable,
1553
1554    /// Represents the use of an assignment expression within a comprehension nested directly or
1555    /// indirectly in a class body.
1556    ///
1557    /// ## Examples
1558    ///
1559    /// ```python
1560    /// class C:
1561    ///     [(x := y) for y in range(3)]
1562    /// ```
1563    NamedExpressionInClassBodyComprehension,
1564
1565    /// Represents the rebinding of the iteration variable of a list, set, or dict comprehension or
1566    /// a generator expression.
1567    ///
1568    /// ## Examples
1569    ///
1570    /// ```python
1571    /// [(a := 0) for a in range(0)]
1572    /// {(a := 0) for a in range(0)}
1573    /// {(a := 0): val for a in range(0)}
1574    /// {key: (a := 0) for a in range(0)}
1575    /// ((a := 0) for a in range(0))
1576    /// ```
1577    ReboundComprehensionVariable,
1578
1579    /// Represents a duplicate type parameter name in a function definition, class definition, or
1580    /// type alias statement.
1581    ///
1582    /// ## Examples
1583    ///
1584    /// ```python
1585    /// type Alias[T, T] = ...
1586    /// def f[T, T](t: T): ...
1587    /// class C[T, T]: ...
1588    /// ```
1589    DuplicateTypeParameter,
1590
1591    /// Represents a duplicate binding in a `case` pattern of a `match` statement.
1592    ///
1593    /// ## Examples
1594    ///
1595    /// ```python
1596    /// match x:
1597    ///     case [x, y, x]: ...
1598    ///     case x as x: ...
1599    ///     case Class(x=1, x=2): ...
1600    /// ```
1601    MultipleCaseAssignment(ast::name::Name),
1602
1603    /// Represents multiple starred names in a sequence pattern.
1604    ///
1605    /// ## Examples
1606    ///
1607    /// ```python
1608    /// match x:
1609    ///     case [*head, middle, *tail]: ...
1610    /// ```
1611    MultipleStarredNamesInSequencePattern,
1612
1613    /// Represents an irrefutable `case` pattern before the last `case` in a `match` statement.
1614    ///
1615    /// According to the [Python reference], "a match statement may have at most one irrefutable
1616    /// case block, and it must be last."
1617    ///
1618    /// ## Examples
1619    ///
1620    /// ```python
1621    /// match x:
1622    ///     case value: ...  # irrefutable capture pattern
1623    ///     case other: ...
1624    ///
1625    /// match x:
1626    ///     case _: ...      # irrefutable wildcard pattern
1627    ///     case other: ...
1628    /// ```
1629    ///
1630    /// [Python reference]: https://docs.python.org/3/reference/compound_stmts.html#irrefutable-case-blocks
1631    IrrefutableCasePattern(IrrefutablePatternKind),
1632
1633    /// Represents a single starred assignment target outside of a tuple or list.
1634    ///
1635    /// ## Examples
1636    ///
1637    /// ```python
1638    /// *a = (1,)  # SyntaxError
1639    /// ```
1640    ///
1641    /// A starred assignment target can only occur within a tuple or list:
1642    ///
1643    /// ```python
1644    /// b, *a = 1, 2, 3
1645    /// (*a,) = 1, 2, 3
1646    /// [*a] = 1, 2, 3
1647    /// ```
1648    SingleStarredAssignment,
1649
1650    /// Represents a write to `__debug__`. This includes simple assignments and deletions as well
1651    /// other kinds of statements that can introduce bindings, such as type parameters in functions,
1652    /// classes, and aliases, `match` arms, and imports, among others.
1653    ///
1654    /// ## Examples
1655    ///
1656    /// ```python
1657    /// del __debug__
1658    /// __debug__ = False
1659    /// def f(__debug__): ...
1660    /// class C[__debug__]: ...
1661    /// ```
1662    ///
1663    /// See [BPO 45000] for more information.
1664    ///
1665    /// [BPO 45000]: https://github.com/python/cpython/issues/89163
1666    WriteToDebug(WriteToDebugKind),
1667
1668    /// Represents the use of an invalid expression kind in one of several locations.
1669    ///
1670    /// The kinds include `yield` and `yield from` expressions and named expressions, and locations
1671    /// include type parameter bounds and defaults, type annotations, type aliases, and base class
1672    /// lists.
1673    ///
1674    /// ## Examples
1675    ///
1676    /// ```python
1677    /// type X[T: (yield 1)] = int
1678    /// type Y = (yield 1)
1679    /// def f[T](x: int) -> (y := 3): return x
1680    /// ```
1681    InvalidExpression(InvalidExpressionKind, InvalidExpressionPosition),
1682
1683    /// Represents a duplicate key in a `match` mapping pattern.
1684    ///
1685    /// The [CPython grammar] allows keys in mapping patterns to be literals or attribute accesses:
1686    ///
1687    /// ```text
1688    /// key_value_pattern:
1689    ///     | (literal_expr | attr) ':' pattern
1690    /// ```
1691    ///
1692    /// But only literals are checked for duplicates:
1693    ///
1694    /// ```pycon
1695    /// >>> match x:
1696    /// ...     case {"x": 1, "x": 2}: ...
1697    /// ...
1698    ///   File "<python-input-160>", line 2
1699    ///     case {"x": 1, "x": 2}: ...
1700    ///          ^^^^^^^^^^^^^^^^
1701    /// SyntaxError: mapping pattern checks duplicate key ('x')
1702    /// >>> match x:
1703    /// ...     case {x.a: 1, x.a: 2}: ...
1704    /// ...
1705    /// >>>
1706    /// ```
1707    ///
1708    /// ## Examples
1709    ///
1710    /// ```python
1711    /// match x:
1712    ///     case {"x": 1, "x": 2}: ...
1713    /// ```
1714    ///
1715    /// [CPython grammar]: https://docs.python.org/3/reference/grammar.html
1716    DuplicateMatchKey(String),
1717
1718    /// Represents a duplicate attribute name in a `match` class pattern.
1719    ///
1720    /// ## Examples
1721    ///
1722    /// ```python
1723    /// match x:
1724    ///     case Class(x=1, x=2): ...
1725    /// ```
1726    DuplicateMatchClassAttribute(ast::name::Name),
1727
1728    /// Represents the use of a `global` variable before its `global` declaration.
1729    ///
1730    /// ## Examples
1731    ///
1732    /// ```python
1733    /// counter = 1
1734    /// def increment():
1735    ///     print(f"Adding 1 to {counter}")
1736    ///     global counter
1737    ///     counter += 1
1738    /// ```
1739    ///
1740    /// ## Known Issues
1741    ///
1742    /// Note that the order in which the parts of a `try` statement are visited was changed in 3.13,
1743    /// as tracked in Python issue [#111123]. For example, this code was valid on Python 3.12:
1744    ///
1745    /// ```python
1746    /// a = 10
1747    /// def g():
1748    ///     try:
1749    ///         1 / 0
1750    ///     except:
1751    ///         a = 1
1752    ///     else:
1753    ///         global a
1754    /// ```
1755    ///
1756    /// While this more intuitive behavior aligned with the textual order was a syntax error:
1757    ///
1758    /// ```python
1759    /// a = 10
1760    /// def f():
1761    ///     try:
1762    ///         pass
1763    ///     except:
1764    ///         global a
1765    ///     else:
1766    ///         a = 1  # SyntaxError: name 'a' is assigned to before global declaration
1767    /// ```
1768    ///
1769    /// This was reversed in version 3.13 to make the second case valid and the first case a syntax
1770    /// error. We intentionally enforce the 3.13 ordering, regardless of the Python version, which
1771    /// will lead to both false positives and false negatives on 3.12 code that takes advantage of
1772    /// the old behavior. However, as mentioned in the Python issue, we expect code relying on this
1773    /// to be very rare and not worth the additional complexity to detect.
1774    ///
1775    /// [#111123]: https://github.com/python/cpython/issues/111123
1776    LoadBeforeGlobalDeclaration { name: String, start: TextSize },
1777
1778    /// Represents the use of a `nonlocal` variable before its `nonlocal` declaration.
1779    ///
1780    /// ## Examples
1781    ///
1782    /// ```python
1783    /// def f():
1784    ///     counter = 0
1785    ///     def increment():
1786    ///         print(f"Adding 1 to {counter}")
1787    ///         nonlocal counter  # SyntaxError: name 'counter' is used prior to nonlocal declaration
1788    ///         counter += 1
1789    /// ```
1790    ///
1791    /// ## Known Issues
1792    ///
1793    /// See [`LoadBeforeGlobalDeclaration`][Self::LoadBeforeGlobalDeclaration].
1794    LoadBeforeNonlocalDeclaration { name: String, start: TextSize },
1795
1796    /// Represents the use of a starred expression in an invalid location, such as a `return` or
1797    /// `yield` statement.
1798    ///
1799    /// ## Examples
1800    ///
1801    /// ```python
1802    /// def f(): return *x
1803    /// def f(): yield *x
1804    /// for _ in *x: ...
1805    /// for *x in xs: ...
1806    /// ```
1807    InvalidStarExpression,
1808
1809    /// Represents the use of an asynchronous comprehension inside of a synchronous comprehension
1810    /// before Python 3.11.
1811    ///
1812    /// ## Examples
1813    ///
1814    /// Before Python 3.11, code like this produces a syntax error because of the implicit function
1815    /// scope introduced by the outer comprehension:
1816    ///
1817    /// ```python
1818    /// async def elements(n): yield n
1819    ///
1820    /// async def test(): return { n: [x async for x in elements(n)] for n in range(3)}
1821    /// ```
1822    ///
1823    /// This was discussed in [BPO 33346] and fixed in Python 3.11.
1824    ///
1825    /// [BPO 33346]: https://github.com/python/cpython/issues/77527
1826    AsyncComprehensionInSyncComprehension(PythonVersion),
1827
1828    /// Represents the use of `yield`, `yield from`, or `await` outside of a function scope.
1829    ///
1830    ///
1831    /// ## Examples
1832    ///
1833    /// `yield` and `yield from` are only allowed if the immediately-enclosing scope is a function
1834    /// or lambda and not allowed otherwise:
1835    ///
1836    /// ```python
1837    /// yield 1  # error
1838    ///
1839    /// def f():
1840    ///     [(yield 1) for x in y]  # error
1841    /// ```
1842    ///
1843    /// `await` is additionally allowed in comprehensions, if the comprehension itself is in a
1844    /// function scope:
1845    ///
1846    /// ```python
1847    /// await 1  # error
1848    ///
1849    /// async def f():
1850    ///     await 1  # okay
1851    ///     [await 1 for x in y]  # also okay
1852    /// ```
1853    ///
1854    /// This last case _is_ an error, but it has to do with the lambda not being an async function.
1855    /// For the sake of this error kind, this is okay.
1856    ///
1857    /// ## References
1858    ///
1859    /// See [PEP 255] for details on `yield`, [PEP 380] for the extension to `yield from`, [PEP 492]
1860    /// for async-await syntax, and [PEP 530] for async comprehensions.
1861    ///
1862    /// [PEP 255]: https://peps.python.org/pep-0255/
1863    /// [PEP 380]: https://peps.python.org/pep-0380/
1864    /// [PEP 492]: https://peps.python.org/pep-0492/
1865    /// [PEP 530]: https://peps.python.org/pep-0530/
1866    YieldOutsideFunction(YieldOutsideFunctionKind),
1867
1868    /// Represents the use of `return` outside of a function scope.
1869    ReturnOutsideFunction,
1870
1871    /// Represents the use of `await`, `async for`, or `async with` outside of an asynchronous
1872    /// function.
1873    ///
1874    /// ## Examples
1875    ///
1876    /// ```python
1877    /// def f():
1878    ///     await 1                # error
1879    ///     async for x in y: ...  # error
1880    ///     async with x: ...      # error
1881    /// ```
1882    AwaitOutsideAsyncFunction(AwaitOutsideAsyncFunctionKind),
1883
1884    /// Represents a duplicate parameter name in a function or lambda expression.
1885    ///
1886    /// ## Examples
1887    ///
1888    /// ```python
1889    /// def f(x, x): ...
1890    /// lambda x, x: ...
1891    /// ```
1892    DuplicateParameter(String),
1893
1894    /// Represents duplicated keyword arguments in a function call or class definition.
1895    ///
1896    /// ## Examples
1897    ///
1898    /// ```python
1899    /// def f(x): ...
1900    /// f(x=1, x=2)
1901    /// class C(metaclass=type, metaclass=type): ...
1902    /// ```
1903    DuplicateKeywordArgument(String),
1904
1905    /// Represents a nonlocal declaration at module level
1906    NonlocalDeclarationAtModuleLevel,
1907
1908    /// Represents the same variable declared as both nonlocal and global
1909    NonlocalAndGlobal(String),
1910
1911    /// Represents a type annotation on a variable that's been declared global
1912    AnnotatedGlobal(String),
1913
1914    /// Represents a type annotation on a variable that's been declared nonlocal
1915    AnnotatedNonlocal(String),
1916
1917    /// Represents the use of `yield from` inside an asynchronous function.
1918    YieldFromInAsyncFunction,
1919
1920    /// Represents the use of `from <module> import *` outside module scope.
1921    NonModuleImportStar(String),
1922
1923    /// Represents the use of more than one starred expression in an assignment.
1924    ///
1925    /// Python only allows a single starred target when unpacking values on the
1926    /// left-hand side of an assignment. Using multiple starred expressions makes
1927    /// the statement invalid and results in a `SyntaxError`.
1928    MultipleStarredExpressions,
1929
1930    /// Represents the use of a `__future__` feature that is not defined.
1931    FutureFeatureNotDefined(String),
1932
1933    /// Represents the use of a `break` statement outside of a loop.
1934    BreakOutsideLoop,
1935
1936    /// Represents the use of a `continue` statement outside of a loop.
1937    ContinueOutsideLoop,
1938
1939    /// Represents a function parameter that is also declared as `global`.
1940    ///
1941    /// Declaring a parameter as `global` is invalid, since parameters are already
1942    /// bound in the local scope of the function. Using `global` on them introduces
1943    /// ambiguity and will result in a `SyntaxError`.
1944    GlobalParameter(String),
1945
1946    /// Represents a function parameter that is also declared as `nonlocal`.
1947    ///
1948    /// Declaring a parameter as `nonlocal` is invalid, since parameters are already
1949    /// bound in a local scope of the function. using `nonlocal` on them introduces
1950    /// ambiguity and will result in a `SyntaxError`.
1951    NonlocalParameter(String),
1952
1953    /// Represents the use of alternative patterns in a `match` statement that bind different names.
1954    ///
1955    /// Python requires all alternatives in an OR pattern (`|`) to bind the same set of names.
1956    /// Using different names results in a `SyntaxError`.
1957    ///
1958    /// ## Example:
1959    ///
1960    /// ```python
1961    /// match 5:
1962    ///     case [x] | [y]:  # error
1963    ///         ...
1964    /// ```
1965    DifferentMatchPatternBindings,
1966
1967    /// Represents a nonlocal statement for a name that has no binding in an enclosing scope.
1968    NonlocalWithoutBinding(String),
1969
1970    /// Represents a default type parameter followed by a non-default type parameter.
1971    TypeParameterDefaultOrder(String),
1972
1973    /// Represents a `return` statement with a value in an asynchronous generator.
1974    ReturnInGenerator,
1975}
1976
1977#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
1978pub enum AwaitOutsideAsyncFunctionKind {
1979    Await,
1980    AsyncFor,
1981    AsyncWith,
1982    AsyncComprehension,
1983}
1984
1985impl Display for AwaitOutsideAsyncFunctionKind {
1986    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1987        f.write_str(match self {
1988            AwaitOutsideAsyncFunctionKind::Await => "`await`",
1989            AwaitOutsideAsyncFunctionKind::AsyncFor => "`async for`",
1990            AwaitOutsideAsyncFunctionKind::AsyncWith => "`async with`",
1991            AwaitOutsideAsyncFunctionKind::AsyncComprehension => "asynchronous comprehension",
1992        })
1993    }
1994}
1995
1996#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
1997pub enum YieldOutsideFunctionKind {
1998    Yield,
1999    YieldFrom,
2000    Await,
2001}
2002
2003impl YieldOutsideFunctionKind {
2004    pub fn is_await(&self) -> bool {
2005        matches!(self, Self::Await)
2006    }
2007}
2008
2009impl Display for YieldOutsideFunctionKind {
2010    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2011        f.write_str(match self {
2012            YieldOutsideFunctionKind::Yield => "yield",
2013            YieldOutsideFunctionKind::YieldFrom => "yield from",
2014            YieldOutsideFunctionKind::Await => "await",
2015        })
2016    }
2017}
2018
2019#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
2020pub enum InvalidExpressionPosition {
2021    TypeVarBound,
2022    TypeVarDefault,
2023    TypeVarTupleDefault,
2024    ParamSpecDefault,
2025    TypeAnnotation,
2026    GenericDefinition,
2027    TypeAlias,
2028}
2029
2030impl Display for InvalidExpressionPosition {
2031    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2032        f.write_str(match self {
2033            InvalidExpressionPosition::TypeVarBound => "TypeVar bound",
2034            InvalidExpressionPosition::TypeVarDefault => "TypeVar default",
2035            InvalidExpressionPosition::TypeVarTupleDefault => "TypeVarTuple default",
2036            InvalidExpressionPosition::ParamSpecDefault => "ParamSpec default",
2037            InvalidExpressionPosition::TypeAnnotation => "type annotation",
2038            InvalidExpressionPosition::GenericDefinition => "generic definition",
2039            InvalidExpressionPosition::TypeAlias => "type alias",
2040        })
2041    }
2042}
2043
2044#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
2045pub enum InvalidExpressionKind {
2046    Yield,
2047    NamedExpr,
2048    Await,
2049}
2050
2051impl Display for InvalidExpressionKind {
2052    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2053        f.write_str(match self {
2054            InvalidExpressionKind::Yield => "yield expression",
2055            InvalidExpressionKind::NamedExpr => "named expression",
2056            InvalidExpressionKind::Await => "await expression",
2057        })
2058    }
2059}
2060
2061#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
2062pub enum WriteToDebugKind {
2063    Store,
2064    Delete(PythonVersion),
2065}
2066
2067fn comprehension_target_names(
2068    comprehensions: &[ast::Comprehension],
2069) -> FxHashSet<&ast::name::Name> {
2070    let mut visitor = helpers::StoredNameFinder::default();
2071    for comprehension in comprehensions {
2072        visitor.visit_expr(&comprehension.target);
2073    }
2074    visitor.names.into_values().map(|name| &name.id).collect()
2075}
2076
2077#[derive(Default)]
2078struct ComprehensionIterableNamedExpressionVisitor {
2079    ranges: Vec<TextRange>,
2080}
2081
2082impl Visitor<'_> for ComprehensionIterableNamedExpressionVisitor {
2083    fn visit_expr(&mut self, expr: &Expr) {
2084        if let Expr::Named(ast::ExprNamed { target, range, .. }) = expr
2085            && target.is_name_expr()
2086        {
2087            self.ranges.push(*range);
2088        }
2089        walk_expr(self, expr);
2090    }
2091}
2092
2093#[derive(Default)]
2094struct ClassBodyNamedExpressionVisitor {
2095    ranges: Vec<TextRange>,
2096}
2097
2098impl Visitor<'_> for ClassBodyNamedExpressionVisitor {
2099    fn visit_expr(&mut self, expr: &Expr) {
2100        match expr {
2101            Expr::Lambda(ast::ExprLambda { parameters, .. }) => {
2102                // Defaults execute in the enclosing comprehension; lambda bodies do not.
2103                if let Some(parameters) = parameters {
2104                    self.visit_parameters(parameters);
2105                }
2106                return;
2107            }
2108            Expr::ListComp(_) | Expr::SetComp(_) | Expr::DictComp(_) | Expr::Generator(_) => {
2109                // Nested comprehensions are checked when normal traversal reaches them.
2110                return;
2111            }
2112            Expr::Named(ast::ExprNamed { target, range, .. }) if target.is_name_expr() => {
2113                self.ranges.push(*range);
2114            }
2115            _ => {}
2116        }
2117        walk_expr(self, expr);
2118    }
2119}
2120
2121/// Searches for named expressions (`x := y`) rebinding a comprehension or generator expression's
2122/// iteration variables.
2123struct ReboundComprehensionVisitor<'a> {
2124    /// Targets that apply inside nested comprehensions.
2125    targets: FxHashSet<&'a ast::name::Name>,
2126    /// Targets from later filter clauses, which do not apply inside nested comprehensions.
2127    direct_targets: FxHashSet<&'a ast::name::Name>,
2128    ranges: Vec<TextRange>,
2129}
2130
2131impl Visitor<'_> for ReboundComprehensionVisitor<'_> {
2132    fn visit_expr(&mut self, expr: &Expr) {
2133        match expr {
2134            Expr::Lambda(ast::ExprLambda { parameters, .. }) => {
2135                if let Some(parameters) = parameters {
2136                    self.visit_parameters(parameters);
2137                }
2138                return;
2139            }
2140            Expr::ListComp(_) | Expr::SetComp(_) | Expr::DictComp(_) | Expr::Generator(_)
2141                if !self.direct_targets.is_empty() =>
2142            {
2143                let direct_targets = std::mem::take(&mut self.direct_targets);
2144                walk_expr(self, expr);
2145                self.direct_targets = direct_targets;
2146                return;
2147            }
2148            Expr::Named(ast::ExprNamed { target, .. }) => {
2149                if let Expr::Name(ast::ExprName { id, range, .. }) = &**target
2150                    && (self.targets.contains(id) || self.direct_targets.contains(id))
2151                {
2152                    self.ranges.push(*range);
2153                }
2154            }
2155            _ => {}
2156        }
2157        walk_expr(self, expr);
2158    }
2159}
2160
2161#[derive(Default)]
2162struct ReturnVisitor {
2163    return_range: Option<TextRange>,
2164    has_yield: bool,
2165}
2166
2167impl Visitor<'_> for ReturnVisitor {
2168    fn visit_stmt(&mut self, stmt: &Stmt) {
2169        match stmt {
2170            // Do not recurse into nested functions; they're evaluated separately.
2171            Stmt::FunctionDef(_) | Stmt::ClassDef(_) => {}
2172            Stmt::Return(ast::StmtReturn {
2173                value: Some(_),
2174                range,
2175                ..
2176            }) => {
2177                self.return_range = Some(*range);
2178                walk_stmt(self, stmt);
2179            }
2180            _ => walk_stmt(self, stmt),
2181        }
2182    }
2183
2184    fn visit_expr(&mut self, expr: &Expr) {
2185        match expr {
2186            Expr::Lambda(_) => {}
2187            Expr::Yield(_) | Expr::YieldFrom(_) => {
2188                self.has_yield = true;
2189            }
2190            _ => walk_expr(self, expr),
2191        }
2192    }
2193}
2194
2195struct MatchPatternVisitor<'a, Ctx> {
2196    names: FxHashSet<&'a ast::name::Name>,
2197    ctx: &'a Ctx,
2198}
2199
2200impl<'a, Ctx: SemanticSyntaxContext> MatchPatternVisitor<'a, Ctx> {
2201    fn visit_pattern(&mut self, pattern: &'a Pattern) {
2202        // test_ok class_keyword_in_case_pattern
2203        // match 2:
2204        //     case Class(x=x): ...
2205
2206        // test_err multiple_assignment_in_case_pattern
2207        // match 2:
2208        //     case [y, z, y]: ...  # MatchSequence
2209        //     case [y, z, *y]: ...  # MatchSequence
2210        //     case [y, y, y]: ...  # MatchSequence multiple
2211        //     case {1: x, 2: x}: ...  # MatchMapping duplicate pattern
2212        //     case {1: x, **x}: ...  # MatchMapping duplicate in **rest
2213        //     case Class(x, x): ...  # MatchClass positional
2214        //     case Class(y=x, z=x): ...  # MatchClass keyword
2215        //     case [x] | {1: x} | Class(y=x, z=x): ...  # MatchOr
2216        //     case x as x: ...  # MatchAs
2217
2218        // test_err multiple_starred_names_in_sequence_pattern
2219        // match subject:
2220        //     case *first, *second, *third: ...
2221        match pattern {
2222            Pattern::MatchValue(_) | Pattern::MatchSingleton(_) => {}
2223            Pattern::MatchStar(ast::PatternMatchStar { name, .. }) => {
2224                if let Some(name) = name {
2225                    self.insert(name);
2226                }
2227            }
2228            Pattern::MatchSequence(ast::PatternMatchSequence { patterns, .. }) => {
2229                let mut seen_star_pattern = false;
2230                for pattern in patterns {
2231                    if pattern.is_match_star() {
2232                        if seen_star_pattern {
2233                            SemanticSyntaxChecker::add_error(
2234                                self.ctx,
2235                                SemanticSyntaxErrorKind::MultipleStarredNamesInSequencePattern,
2236                                pattern.range(),
2237                            );
2238                        }
2239                        seen_star_pattern = true;
2240                    }
2241                    self.visit_pattern(pattern);
2242                }
2243            }
2244            Pattern::MatchMapping(ast::PatternMatchMapping {
2245                keys,
2246                patterns,
2247                rest,
2248                ..
2249            }) => {
2250                for pattern in patterns {
2251                    self.visit_pattern(pattern);
2252                }
2253                if let Some(rest) = rest {
2254                    self.insert(rest);
2255                }
2256
2257                let mut seen = FxHashSet::default();
2258                for key in keys
2259                    .iter()
2260                    // Signed and complex numbers are allowed as keys but are represented as unary
2261                    // or binary expressions rather than literals.
2262                    .filter(|key| {
2263                        key.is_literal_expr() || key.is_unary_op_expr() || key.is_bin_op_expr()
2264                    })
2265                {
2266                    if !seen.insert(HashableExpr::from(key)) {
2267                        let key_range = key.range();
2268                        let duplicate_key = self.ctx.source()[key_range].to_string();
2269                        // test_ok duplicate_match_key_attr
2270                        // match x:
2271                        //     case {x.a: 1, x.a: 2}: ...
2272
2273                        // test_err duplicate_match_key
2274                        // match x:
2275                        //     case {"x": 1, "x": 2}: ...
2276                        //     case {b"x": 1, b"x": 2}: ...
2277                        //     case {0: 1, 0: 2}: ...
2278                        //     case {1.0: 1, 1.0: 2}: ...
2279                        //     case {1.0 + 2j: 1, 1.0 + 2j: 2}: ...
2280                        //     case {True: 1, True: 2}: ...
2281                        //     case {None: 1, None: 2}: ...
2282                        //     case {0: 1, False: 2}: ...
2283                        //     case {1.0: 1, True: 2}: ...
2284                        //     case {-0: 1, False: 2}: ...
2285                        //     case {1 + 0j: 1, True: 2}: ...
2286                        //     case {
2287                        //     """x
2288                        //     y
2289                        //     z
2290                        //     """: 1,
2291                        //     """x
2292                        //     y
2293                        //     z
2294                        //     """: 2}: ...
2295                        //     case {"x": 1, "x": 2, "x": 3}: ...
2296                        //     case {0: 1, "x": 1, 0: 2, "x": 2}: ...
2297                        //     case [{"x": 1, "x": 2}]: ...
2298                        //     case Foo(x=1, y={"x": 1, "x": 2}): ...
2299                        //     case [Foo(x=1), Foo(x=1, y={"x": 1, "x": 2})]: ...
2300                        //     case {2: 1, 2.0: 2}: ...
2301                        //     case {9007199254740993: 1, 9007199254740993 + 0j: 2}: ...
2302                        SemanticSyntaxChecker::add_error(
2303                            self.ctx,
2304                            SemanticSyntaxErrorKind::DuplicateMatchKey(duplicate_key),
2305                            key_range,
2306                        );
2307                    }
2308                }
2309            }
2310            Pattern::MatchClass(ast::PatternMatchClass { arguments, .. }) => {
2311                for pattern in &arguments.patterns {
2312                    self.visit_pattern(pattern);
2313                }
2314                let mut seen = FxHashSet::default();
2315                for keyword in &arguments.keywords {
2316                    if !seen.insert(&keyword.attr.id) {
2317                        // test_err duplicate_match_class_attr
2318                        // match x:
2319                        //     case Class(x=1, x=2): ...
2320                        //     case [Class(x=1, x=2)]: ...
2321                        //     case {"x": x, "y": Foo(x=1, x=2)}: ...
2322                        //     case [{}, {"x": x, "y": Foo(x=1, x=2)}]: ...
2323                        //     case Class(x=1, d={"x": 1, "x": 2}, other=Class(x=1, x=2)): ...
2324                        SemanticSyntaxChecker::add_error(
2325                            self.ctx,
2326                            SemanticSyntaxErrorKind::DuplicateMatchClassAttribute(
2327                                keyword.attr.id.clone(),
2328                            ),
2329                            keyword.attr.range,
2330                        );
2331                    }
2332                    self.visit_pattern(&keyword.pattern);
2333                }
2334            }
2335            Pattern::MatchAs(ast::PatternMatchAs { pattern, name, .. }) => {
2336                if let Some(pattern) = pattern {
2337                    self.visit_pattern(pattern);
2338                }
2339                if let Some(name) = name {
2340                    self.insert(name);
2341                }
2342            }
2343            Pattern::MatchOr(ast::PatternMatchOr {
2344                patterns, range, ..
2345            }) => {
2346                // each of these patterns should be visited separately because patterns can only be
2347                // duplicated within a single arm of the or pattern. For example, the case below is
2348                // a valid pattern.
2349
2350                // test_ok multiple_assignment_in_case_pattern
2351                // match 2:
2352                //     case Class(x) | [x] | x: ...
2353
2354                let mut previous_names: Option<FxHashSet<&ast::name::Name>> = None;
2355                for pattern in patterns {
2356                    let mut visitor = Self {
2357                        names: FxHashSet::default(),
2358                        ctx: self.ctx,
2359                    };
2360                    visitor.visit_pattern(pattern);
2361                    let Some(prev) = &previous_names else {
2362                        previous_names = Some(visitor.names);
2363                        continue;
2364                    };
2365                    if prev.symmetric_difference(&visitor.names).next().is_some() {
2366                        // test_err different_match_pattern_bindings
2367                        // match x:
2368                        //     case [a] | [b]: ...
2369                        //     case [a] | []: ...
2370                        //     case (x, y) | (x,): ...
2371                        //     case [a, _] | [a, b]: ...
2372                        //     case (x, (y | z)): ...
2373                        //     case [a] | [b] | [c]: ...
2374                        //     case [] | [a]: ...
2375                        //     case [a] | [C(x)]: ...
2376                        //     case [[a] | [b]]: ...
2377                        //     case [C(a)] | [C(b)]: ...
2378                        //     case [C(D(a))] | [C(D(b))]: ...
2379                        //     case [(a, b)] | [(c, d)]: ...
2380
2381                        // test_ok different_match_pattern_bindings
2382                        // match x:
2383                        //     case [a] | [a]: ...
2384                        //     case (x, y) | (x, y): ...
2385                        //     case (x, (y | y)): ...
2386                        //     case [a, _] | [a, _]: ...
2387                        //     case [a] | [C(a)]: ...
2388
2389                        // test_ok nested_alternative_patterns
2390                        // match ruff:
2391                        //     case {"lint": {"select": x} | {"extend-select": x}} | {"select": x}:
2392                        //         ...
2393                        // match 42:
2394                        //     case [[x] | [x]] | x: ...
2395                        // match 42:
2396                        //     case [[x | x] | [x]] | x: ...
2397                        // match 42:
2398                        //     case ast.Subscript(n, ast.Constant() | ast.Slice()) | ast.Attribute(n): ...
2399                        SemanticSyntaxChecker::add_error(
2400                            self.ctx,
2401                            SemanticSyntaxErrorKind::DifferentMatchPatternBindings,
2402                            *range,
2403                        );
2404                        break;
2405                    }
2406                    self.names.extend(visitor.names);
2407                }
2408            }
2409        }
2410    }
2411
2412    /// Add an identifier to the set of visited names in `self` and emit a [`SemanticSyntaxError`]
2413    /// if `ident` has already been seen.
2414    fn insert(&mut self, ident: &'a ast::Identifier) {
2415        if !self.names.insert(&ident.id) {
2416            SemanticSyntaxChecker::add_error(
2417                self.ctx,
2418                SemanticSyntaxErrorKind::MultipleCaseAssignment(ident.id.clone()),
2419                ident.range(),
2420            );
2421        }
2422        // test_err debug_shadow_match
2423        // match x:
2424        //     case __debug__: ...
2425        SemanticSyntaxChecker::check_identifier(ident, self.ctx);
2426    }
2427}
2428
2429struct InvalidExpressionVisitor<'a, Ctx> {
2430    /// Context used for emitting errors.
2431    ctx: &'a Ctx,
2432
2433    position: InvalidExpressionPosition,
2434}
2435
2436impl<Ctx> Visitor<'_> for InvalidExpressionVisitor<'_, Ctx>
2437where
2438    Ctx: SemanticSyntaxContext,
2439{
2440    fn visit_expr(&mut self, expr: &Expr) {
2441        match expr {
2442            Expr::Named(ast::ExprNamed { range, .. }) => {
2443                SemanticSyntaxChecker::add_error(
2444                    self.ctx,
2445                    SemanticSyntaxErrorKind::InvalidExpression(
2446                        InvalidExpressionKind::NamedExpr,
2447                        self.position,
2448                    ),
2449                    *range,
2450                );
2451            }
2452            Expr::Yield(ast::ExprYield { range, .. })
2453            | Expr::YieldFrom(ast::ExprYieldFrom { range, .. }) => {
2454                SemanticSyntaxChecker::add_error(
2455                    self.ctx,
2456                    SemanticSyntaxErrorKind::InvalidExpression(
2457                        InvalidExpressionKind::Yield,
2458                        self.position,
2459                    ),
2460                    *range,
2461                );
2462            }
2463            Expr::Await(ast::ExprAwait { range, .. }) => {
2464                SemanticSyntaxChecker::add_error(
2465                    self.ctx,
2466                    SemanticSyntaxErrorKind::InvalidExpression(
2467                        InvalidExpressionKind::Await,
2468                        self.position,
2469                    ),
2470                    *range,
2471                );
2472            }
2473            _ => {}
2474        }
2475        ast::visitor::walk_expr(self, expr);
2476    }
2477
2478    fn visit_type_param(&mut self, type_param: &ast::TypeParam) {
2479        match type_param {
2480            ast::TypeParam::TypeVar(ast::TypeParamTypeVar { bound, default, .. }) => {
2481                if let Some(expr) = bound {
2482                    self.position = InvalidExpressionPosition::TypeVarBound;
2483                    self.visit_expr(expr);
2484                }
2485                if let Some(expr) = default {
2486                    self.position = InvalidExpressionPosition::TypeVarDefault;
2487                    self.visit_expr(expr);
2488                }
2489            }
2490            ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { default, .. }) => {
2491                if let Some(expr) = default {
2492                    self.position = InvalidExpressionPosition::TypeVarTupleDefault;
2493                    self.visit_expr(expr);
2494                }
2495            }
2496            ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { default, .. }) => {
2497                if let Some(expr) = default {
2498                    self.position = InvalidExpressionPosition::ParamSpecDefault;
2499                    self.visit_expr(expr);
2500                }
2501            }
2502        }
2503    }
2504}
2505
2506/// Information needed from a parent visitor to emit semantic syntax errors.
2507///
2508/// Note that the `in_*_scope` methods should refer to the immediately-enclosing scope. For example,
2509/// `in_function_scope` should return true for this case:
2510///
2511/// ```python
2512/// def f():
2513///     x  # here
2514/// ```
2515///
2516/// but not for this case:
2517///
2518/// ```python
2519/// def f():
2520///     class C:
2521///         x  # here
2522/// ```
2523///
2524/// In contrast, the `in_*_context` methods should traverse parent scopes. For example,
2525/// `in_function_context` should return true for this case:
2526///
2527/// ```python
2528/// def f():
2529///     [x  # here
2530///         for x in range(3)]
2531/// ```
2532///
2533/// but not here:
2534///
2535/// ```python
2536/// def f():
2537///     class C:
2538///         x  # here, classes break function scopes
2539/// ```
2540pub trait SemanticSyntaxContext {
2541    /// Returns `true` if `__future__`-style type annotations are enabled.
2542    fn future_annotations_or_stub(&self) -> bool;
2543
2544    /// Returns the nearest invalid context for a `lazy` import statement, if any.
2545    ///
2546    /// This should return the innermost relevant restriction in order of precedence:
2547    /// function, class, then `try`/`except`.
2548    fn lazy_import_context(&self) -> Option<LazyImportContext>;
2549
2550    /// The target Python version for detecting backwards-incompatible syntax changes.
2551    fn python_version(&self) -> PythonVersion;
2552
2553    /// Returns the source text under analysis.
2554    fn source(&self) -> &str;
2555
2556    /// Return the [`TextRange`] at which a name is declared as `global` in the current scope.
2557    fn global(&self, name: &str) -> Option<TextRange>;
2558
2559    /// Returns `true` if `name` has a binding in an enclosing scope.
2560    fn has_nonlocal_binding(&self, name: &str) -> bool;
2561
2562    /// Returns `true` if the visitor is currently in an async context, i.e. an async function.
2563    fn in_async_context(&self) -> bool;
2564
2565    /// Returns `true` if the visitor is currently in a context where the `await` keyword is
2566    /// allowed.
2567    ///
2568    /// Note that this is method is primarily used to report `YieldOutsideFunction` errors for
2569    /// `await` outside function scopes, irrespective of their async status. As such, this differs
2570    /// from `in_async_context` in two ways:
2571    ///
2572    /// 1. `await` is allowed in a lambda, despite it not being async
2573    /// 2. `await` is allowed in any function, regardless of its async status
2574    ///
2575    /// In short, only nested class definitions should cause this method to return `false`, for
2576    /// example:
2577    ///
2578    /// ```python
2579    /// def f():
2580    ///     await 1  # okay, in a function
2581    ///     class C:
2582    ///         await 1  # error
2583    /// ```
2584    ///
2585    /// See the trait-level documentation for more details.
2586    fn in_await_allowed_context(&self) -> bool;
2587
2588    /// Returns `true` if the visitor is currently in a context where `yield` and `yield from`
2589    /// expressions are allowed.
2590    ///
2591    /// Yield expressions are allowed only in:
2592    /// 1. Function definitions
2593    /// 2. Lambda expressions
2594    ///
2595    /// Unlike `await`, yield is not allowed in:
2596    /// - Comprehensions (list, set, dict)
2597    /// - Generator expressions
2598    /// - Class definitions
2599    ///
2600    /// This method should traverse parent scopes to check if the closest relevant scope
2601    /// is a function or lambda, and that no disallowed context (class, comprehension, generator)
2602    /// intervenes. For example:
2603    ///
2604    /// ```python
2605    /// def f():
2606    ///     yield 1  # okay, in a function
2607    ///     lambda: (yield 1)  # okay, in a lambda
2608    ///
2609    ///     [(yield 1) for x in range(3)]  # error, in a comprehension
2610    ///     ((yield 1) for x in range(3))  # error, in a generator expression
2611    ///     class C:
2612    ///         yield 1  # error, in a class within a function
2613    /// ```
2614    ///
2615    fn in_yield_allowed_context(&self) -> bool;
2616
2617    /// Returns `true` if the visitor is currently inside of a synchronous comprehension.
2618    ///
2619    /// This method is necessary because `in_async_context` only checks for the nearest, enclosing
2620    /// function to determine the (a)sync context. Instead, this method will search all enclosing
2621    /// scopes until it finds a sync comprehension. As a result, the two methods will typically be
2622    /// used together.
2623    fn in_sync_comprehension(&self) -> bool;
2624
2625    /// Returns `true` if a comprehension introduced at the current position is nested directly
2626    /// or indirectly in a class body, without crossing a function or lambda boundary.
2627    fn in_class_body_comprehension(&self) -> bool;
2628
2629    /// Returns `true` if the visitor is at the top-level module scope.
2630    fn in_module_scope(&self) -> bool;
2631
2632    /// Returns `true` if the visitor is in a function scope.
2633    fn in_function_scope(&self) -> bool;
2634
2635    /// Returns `true` if the visitor is within a generator scope.
2636    ///
2637    /// Note that this refers to an `Expr::Generator` precisely, not to comprehensions more
2638    /// generally.
2639    fn in_generator_context(&self) -> bool;
2640
2641    /// Returns `true` if the source file is a Jupyter notebook.
2642    fn in_notebook(&self) -> bool;
2643
2644    fn report_semantic_error(&self, error: SemanticSyntaxError);
2645
2646    /// Returns `true` if the visitor is inside a `for` or `while` loop.
2647    fn in_loop_context(&self) -> bool;
2648
2649    /// Returns `true` if `name` is a bound parameter in the current function or lambda scope.
2650    fn is_bound_parameter(&self, name: &str) -> bool;
2651}
2652
2653/// Modified version of [`std::str::EscapeDefault`] that does not escape single or double quotes.
2654struct EscapeDefault<'a>(&'a str);
2655
2656impl Display for EscapeDefault<'_> {
2657    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2658        use std::fmt::Write;
2659
2660        for c in self.0.chars() {
2661            match c {
2662                '\'' | '\"' => f.write_char(c)?,
2663                _ => write!(f, "{}", c.escape_default())?,
2664            }
2665        }
2666        Ok(())
2667    }
2668}