Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/generics.rs (Rust)

Code before:
    containing_scope: FileScopeId,
    typevar_binding_context: Option<Definition<'db>>,
    typevar: TypeVarInstance<'db>,
) -> Option<BoundTypeVarInstance<'db>> {
    // typing.Self is treated like a legacy typevar, but doesn't follow the same scoping rules.
    // It is always bound to the outermost method in the nearest enclosing class.
    //
    // The ancestor walk looks for a (function, class) pair in the scope hierarchy. We stop
    // at the first class boundary (when the inner scope is a class) to avoid traversing past
    // a nested class into an outer class. For example, in:
    //
    // ```python
    // class Outer:
    //     def method(self) -> None:
    //         class Inner:
    //             def get(self) -> Self: ...
    // ```
    //
    // When resolving `Self` in `get`'s return annotation, the containing scope is the `Inner`
    // class body. Without the class-boundary break, the walk would skip `Inner` and find
    // `(method, Outer)`, incorrectly binding Self to `Outer` instead of `Inner`.
    if matches!(typevar.kind(db), TypeVarKind::TypingSelf) {
        for ((_, inner), (_, outer)) in index.ancestor_scopes(containing_scope).tuple_windows() {
            if inner.kind().is_class() {
                break;
            }
            if outer.kind().is_class() {
                if let NodeWithScopeKind::Function(function) = inner.node() {
                    let definition = index.expect_single_definition(function);
                    return Some(typevar.with_binding_context(db, definition));
                }
            }
        }
    }
    enclosing_generic_contexts(db, index, containing_scope)
        .find_map(|enclosing_context| enclosing_context.binds_typevar(db, typevar))
        .or_else(|| {
            typevar_binding_context.map(|typevar_binding_context| {
                typevar.with_binding_context(db, typevar_binding_context)
            })
        })
}

/// Create a `typing.Self` type variable for a given class.
pub(crate) fn typing_self<'db>(
    db: &'db dyn Db,
    function_scope_id: ScopeId,
    typevar_binding_context: Option<Definition<'db>>,
    class: ClassLiteral<'db>,
) -> Option<BoundTypeVarInstance<'db>> {
    let index = semantic_index(db, function_scope_id.file(db));

Review comment (bug):
I don't think this is the correct fix, unfortunately. For example, this test fails on your branch:

```py
from typing import Self

class Foo:
    class Bar:
        def method_a(self) -> None:
            def first_param_is_explicit_self(this: Self) -> None:
                reveal_type(this)  # revealed: Self@method_a
                reveal_type(self)  # revealed: Self@method_a
```

Code after:
    index: &SemanticIndex<'db>,
    containing_scope: FileScopeId,
    typevar_binding_context: Option<Definition<'db>>,
    typevar: TypeVarInstance<'db>,
) -> Option<BoundTypeVarInstance<'db>> {
    // typing.Self is treated like a legacy typevar, but doesn't follow the same scoping rules. It
    // is always bound to the outermost method in the nearest enclosing class. The walk looks for a
    // (function, class) pair in the scope hierarchy. The caller (`typing_self`) is responsible for
    // ensuring that `containing_scope` starts from the function body scope rather than the scope
    // where the function is defined, so that the function itself appears in the ancestor chain.
    //
    // We also match `FunctionTypeParameters` as a valid inner scope because for generic methods
    // (e.g., `def foo[T](self) -> Self`), the type-params scope sits between the function body
    // and the class body in the ancestor chain.
    if matches!(typevar.kind(db), TypeVarKind::TypingSelf) {
        for ((_, inner), (_, outer)) in index.ancestor_scopes(containing_scope).tuple_windows() {
            if outer.kind().is_class() {
                match inner.node() {
                    NodeWithScopeKind::Function(function)
                    | NodeWithScopeKind::FunctionTypeParameters(function) => {
                        let definition = index.expect_single_definition(function);
                        return Some(typevar.with_binding_context(db, definition));
                    }
                    _ => {}
                }
            }
        }
    }
    enclosing_generic_contexts(db, index, containing_scope)
        .find_map(|enclosing_context| enclosing_context.binds_typevar(db, typevar))
        .or_else(|| {
            typevar_binding_context.map(|typevar_binding_context| {
                typevar.with_binding_context(db, typevar_binding_context)
            })
        })
}

/// Create a `typing.Self` type variable for a given class.
pub(crate) fn typing_self<'db>(
    db: &'db dyn Db,
    scope_id: ScopeId,
    typevar_binding_context: Option<Definition<'db>>,
    class: ClassLiteral<'db>,
) -> Option<BoundTypeVarInstance<'db>> {
    let file = scope_id.file(db);
    let index = semantic_index(db, file);

    let identity = TypeVarIdentity::new(
        db,
        ast::name::Name::new_static("Self"),
        // `Self` has a different upper bound dependent on the containing class,