Repository: astral-sh/ruff
File: crates/ruff_python_parser/src/semantic_errors.rs (Rust)

Code before:
    names: FxHashSet<&'a ast::name::Name>,
    ctx: &'a Ctx,
}

impl<'a, Ctx: SemanticSyntaxContext> MatchPatternVisitor<'a, Ctx> {
    fn visit_pattern(&mut self, pattern: &'a Pattern) {
        // test_ok class_keyword_in_case_pattern
        // match 2:
        //     case Class(x=x): ...

        // test_err multiple_assignment_in_case_pattern
        // match 2:
        //     case [y, z, y]: ...  # MatchSequence
        //     case [y, z, *y]: ...  # MatchSequence
        //     case [y, y, y]: ...  # MatchSequence multiple
        //     case {1: x, 2: x}: ...  # MatchMapping duplicate pattern
        //     case {1: x, **x}: ...  # MatchMapping duplicate in **rest
        //     case Class(x, x): ...  # MatchClass positional
        //     case Class(y=x, z=x): ...  # MatchClass keyword
        //     case [x] | {1: x} | Class(y=x, z=x): ...  # MatchOr
        //     case x as x: ...  # MatchAs
        match pattern {
            Pattern::MatchValue(_) | Pattern::MatchSingleton(_) => {}
            Pattern::MatchStar(ast::PatternMatchStar { name, .. }) => {
                if let Some(name) = name {
                    self.insert(name);
                }
            }
            Pattern::MatchSequence(ast::PatternMatchSequence { patterns, .. }) => {
                for pattern in patterns {
                    self.visit_pattern(pattern);
                }
            }
            Pattern::MatchMapping(ast::PatternMatchMapping {
                keys,
                patterns,
                rest,
                ..
            }) => {
                for pattern in patterns {
                    self.visit_pattern(pattern);
                }
                if let Some(rest) = rest {
                    self.insert(rest);
                }

                let mut seen = FxHashSet::default();
                for key in keys
                    .iter()
                    // complex numbers (`1 + 2j`) are allowed as keys but are not literals
                    // because they are represented as a `BinOp::Add` between a real number and

Review comment (suggestion):
I think it's probably worth copying the comment from B901:


```suggestion
            // Do not recurse into nested functions; they're evaluated separately.
            Stmt::FunctionDef(_) | Stmt::ClassDef(_) => {}
```

Code after:
        if let Expr::Named(ast::ExprNamed { target, .. }) = expr {
            if let Expr::Name(ast::ExprName { id, range, .. }) = &**target {
                if self.comprehensions.iter().any(|comp| {
                    comp.target
                        .as_name_expr()
                        .is_some_and(|name| name.id == *id)
                }) {
                    self.rebound_variables.push(*range);
                }
            }
        }
        walk_expr(self, expr);
    }
}

#[derive(Default)]
struct ReturnVisitor {
    return_range: Option<TextRange>,
    has_yield: bool,
}

impl Visitor<'_> for ReturnVisitor {
    fn visit_stmt(&mut self, stmt: &Stmt) {
        match stmt {
            // Do not recurse into nested functions; they're evaluated separately.
            Stmt::FunctionDef(_) | Stmt::ClassDef(_) => {}
            Stmt::Return(ast::StmtReturn {
                value: Some(_),
                range,
                ..
            }) => {
                self.return_range = Some(*range);
                walk_stmt(self, stmt);
            }
            _ => walk_stmt(self, stmt),
        }
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match expr {
            Expr::Lambda(_) => {}
            Expr::Yield(_) | Expr::YieldFrom(_) => {
                self.has_yield = true;
            }
            _ => walk_expr(self, expr),
        }
    }
}

struct MatchPatternVisitor<'a, Ctx> {
    names: FxHashSet<&'a ast::name::Name>,