Skip to main content

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