~ to fixup
diff --git a/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt b/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt
index 915e450..22307cb 100644
--- a/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt
+++ b/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt
@@ -57,7 +57,7 @@
     private lateinit var singleJavaFileRootsIndex: SingleJavaFileRootsIndex
     private lateinit var packagePartProviders: List<PackagePartProvider>
 
-    private lateinit var javaModuleFinder: JavaModuleFinder
+    lateinit var javaModuleFinder: JavaModuleFinder
         private set
 
     /**
diff --git a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/JavaClassFinderOverBinaryIndex.kt b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/JavaClassFinderOverBinaryIndex.kt
index 032028c..ec84b12 100644
--- a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/JavaClassFinderOverBinaryIndex.kt
+++ b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/JavaClassFinderOverBinaryIndex.kt
@@ -12,6 +12,7 @@
 import org.jetbrains.kotlin.cli.jvm.index.JavaFileExtensions
 import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
 import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
+import org.jetbrains.kotlin.K1Deprecation
 import org.jetbrains.kotlin.load.java.JavaClassFinder
 import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
 import org.jetbrains.kotlin.load.java.structure.JavaClass
diff --git a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaTypeOverAst.kt b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaTypeOverAst.kt
index e97c992..93ceee0 100644
--- a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaTypeOverAst.kt
+++ b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaTypeOverAst.kt
@@ -238,17 +238,31 @@
             return explicitArgs
         }
 
+        // Each parameter is kept together with the class that declares it: the implicit outer
+        // argument is a parameter *of that class*, so the only correct answer is that class's own
+        // instance — FIR matches `JavaTypeParameter`s to `FirTypeParameterSymbol`s by identity
+        // through the per-class `JavaTypeParameterStack`, which is keyed by exactly these objects.
         val outerTypeParams = mutableListOf<JavaTypeParameter>()
+        val outerTypeParamOwners = mutableListOf<JavaClass>()
         var outer = javaClass.outerClass
         while (outer != null && !outer.isStatic) {
-            outerTypeParams.addAll(outer.typeParameters)
+            for (typeParam in outer.typeParameters) {
+                outerTypeParams.add(typeParam)
+                outerTypeParamOwners.add(outer)
+            }
             outer = outer.outerClass
         }
 
-        // Resolve each outer type param through the current context so we get the caller's H
-        // (e.g., Outer.H) rather than the abstract H from the outer class declaration.
-        val lexicalArgs = outerTypeParams.map { typeParam ->
-            with(resolutionContext) { findTypeParameter(typeParam.name.asString()) }
+        // A declared parameter is available at this reference only if the reference is written
+        // inside the declaring class. This is an *identity* test on the enclosing chain, not a
+        // lexical lookup by name: a same-named parameter of a nested class or of the enclosing
+        // generic method shadows the outer one for name resolution, but it is not the parameter
+        // this implicit argument denotes (`class A<T> { class Inner<T> { Inner<String> foo(); } }`
+        // means `A<A.T>.Inner<String>`). Mirrors PSI, whose `JavaClassifierTypeImpl` substitutes an
+        // unmapped `PsiTypeParameter` to itself and never looks names up in the lexical scope.
+        // `null` means "not available here" and routes to the inherited recovery below.
+        val lexicalArgs = outerTypeParams.mapIndexed { index, typeParam ->
+            typeParam.takeIf { isInScopeOfDeclaringClass(outerTypeParamOwners[index]) }
         }
 
         // Inherited case: the inner class is non-static but its outer arguments are neither written
@@ -277,6 +291,30 @@
     }
 
     /**
+     * Whether this type reference is written inside [declaringClass], i.e. whether
+     * [declaringClass]'s own type parameters denote the enclosing instance's ones here.
+     *
+     * Walks the classes lexically enclosing the reference, innermost first. Per JLS a `static`
+     * class has no enclosing instance, which severs the chain of implicit outer type arguments —
+     * the same break the collection walk above and PSI's `PsiUtil.typeParametersIterable` make.
+     *
+     * Classes are compared by [JavaClass.classId] when both have one, so that a reference resolved
+     * through the class finder (a distinct instance for the same class) is still recognised; the
+     * identity comparison covers local/anonymous classes, which have no `ClassId`.
+     */
+    private fun isInScopeOfDeclaringClass(declaringClass: JavaClass): Boolean {
+        val declaringClassId = declaringClass.classId
+        var enclosing: JavaClass? = resolutionContext.scopeContext.containingClass
+        while (enclosing != null) {
+            if (enclosing === declaringClass) return true
+            if (declaringClassId != null && enclosing.classId == declaringClassId) return true
+            if (enclosing.isStatic) return false
+            enclosing = enclosing.outerClass
+        }
+        return false
+    }
+
+    /**
      * Recursively collects all REFERENCE_PARAMETER_LIST nodes in source order,
      * traversing into child JAVA_CODE_REFERENCE nodes (for nested qualified types).
      * For "A<T>.B<U>" → [paramList(<T>), paramList(<U>)] regardless of AST structure.
diff --git a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaTypeResolver.kt b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaTypeResolver.kt
index 308ce0f..081aa03 100644
--- a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaTypeResolver.kt
+++ b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaTypeResolver.kt
@@ -430,16 +430,17 @@
     // of that supertype list sees an empty answer and the walk simply moves outward.
     var current: JavaClass? = containingClass
     while (current != null) {
-        val currentId = current.classId
+        val inheritingClass = current
+        val currentId = inheritingClass.classId
         if (currentId != null) {
             for (supertype in FirBackedJavaClassAdapter(currentId, session).supertypes) {
                 val coneSupertype = (supertype as? FirBackedJavaClassifierType)?.coneType ?: continue
                 val recovered = findTypeArgsForClassInHierarchy(coneSupertype, outerClassId, session, mutableSetOf())
-                if (recovered != null) return recovered.map { recoveredOuterTypeArgument(it, session) }
+                if (recovered != null) return recovered.map { recoveredOuterTypeArgument(it, inheritingClass, session) }
             }
         }
-        if (current.isStatic) break
-        current = current.outerClass
+        if (inheritingClass.isStatic) break
+        current = inheritingClass.outerClass
     }
     return null
 }
@@ -449,27 +450,52 @@
  *
  * A recovered argument is often a type parameter of the containing class itself
  * (`class Outer<E1, E2> extends BaseOuter<Integer, E1>` recovers `Integer, E1`). Such an argument
- * must be handed back as the model's *own* [JavaTypeParameter]: FIR matches `JavaTypeParameter`s to
- * `FirTypeParameterSymbol`s by identity through the per-class `JavaTypeParameterStack`, which does
- * not know resolution-time cone-backed wrappers, so the cone route
- * ([firBackedJavaType]) would degrade the reference to an unbounded wildcard. The name is
- * necessarily in scope — the parameter is declared by a class of the containing chain the recovery
- * walked.
+ * must be handed back as the model's *own* [JavaTypeParameter], the one declared by [inheritingClass]
+ * or by one of its outer classes:
+ * `JavaTypeConversion.toConeKotlinTypeForFlexibleBound` resolves a [JavaTypeParameter] solely by
+ * looking it up in the class's `MutableJavaTypeParameterStack`, a map keyed by the very instances
+ * `FirJavaFacade.createFirJavaClass` took from `JavaClass.typeParameters`. A cone-backed wrapper is
+ * not a key there, so routing a type parameter through [firBackedJavaType] could not produce one:
+ * today that route has no type-parameter branch at all and degrades the reference to an unbounded
+ * wildcard; teaching it one would yield `ConeErrorType(ConeUnresolvedNameError)` instead, unless the
+ * identity protocol in shared FIR code were changed.
+ *
+ * The parameter is looked up in [inheritingClass]'s own declaration chain — the class whose
+ * supertype the argument was read off, then its outer classes — and not in the lexical scope: a
+ * same-named parameter of the enclosing generic method or of a nested class would shadow it there,
+ * and handing that one back would silently substitute a different symbol. Names within a single
+ * parameter list are unique per JLS, and the innermost-first walk mirrors Java shadowing, so the
+ * lookup is unambiguous.
  */
 context(c: JavaResolutionContext)
-private fun recoveredOuterTypeArgument(projection: ConeTypeProjection, session: FirSession): JavaType {
+private fun recoveredOuterTypeArgument(projection: ConeTypeProjection, inheritingClass: JavaClass, session: FirSession): JavaType {
     // Arguments read off a resolved FIR supertype are flexible (`kotlin/Int!`, `E1!`), while the
     // Java model is nullability-agnostic and FIR re-derives flexibility when converting back — so
     // the lower bound is what has to be handed over. Without unwrapping, neither branch below
     // matches and everything degrades to an unbounded wildcard.
     val type = (projection as? ConeKotlinType)?.lowerBoundIfFlexible() ?: return firBackedJavaType(projection, session)
     if (type is ConeTypeParameterType) {
-        findTypeParameter(type.lookupTag.name.asString())?.let { return JavaTypeParameterTypeOverAst(it) }
+        findTypeParameterInDeclarationChain(inheritingClass, type.lookupTag.name)?.let { return JavaTypeParameterTypeOverAst(it) }
     }
     return firBackedJavaType(type, session)
 }
 
 /**
+ * Finds the [JavaTypeParameter] named [name] declared by [startClass] or, failing that, by one of
+ * its outer classes, innermost first. A `static` class has no enclosing instance and severs the
+ * chain, so its outer classes' parameters are not visible in its declarations.
+ */
+private fun findTypeParameterInDeclarationChain(startClass: JavaClass, name: Name): JavaTypeParameter? {
+    var current: JavaClass? = startClass
+    while (current != null) {
+        current.typeParameters.firstOrNull { it.name == name }?.let { return it }
+        if (current.isStatic) return null
+        current = current.outerClass
+    }
+    return null
+}
+
+/**
  * Recursively searches [type]'s supertype hierarchy (via [FirBackedJavaClassAdapter.supertypes])
  * for [targetClassId], substituting type arguments down each intermediate class so that, e.g.,
  * `A<X> : Super<X>` instantiated as `A<String>` yields `Super<String>`. Returns the matched
diff --git a/compiler/java-direct/test/org/jetbrains/kotlin/java/direct/JavaParsingImplicitOuterTypeArgumentsTest.kt b/compiler/java-direct/test/org/jetbrains/kotlin/java/direct/JavaParsingImplicitOuterTypeArgumentsTest.kt
new file mode 100644
index 0000000..3d48c1b6
--- /dev/null
+++ b/compiler/java-direct/test/org/jetbrains/kotlin/java/direct/JavaParsingImplicitOuterTypeArgumentsTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2010-2026 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package org.jetbrains.kotlin.java.direct
+
+import org.jetbrains.kotlin.load.java.structure.JavaClass
+import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
+import org.jetbrains.kotlin.load.java.structure.JavaType
+import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
+import org.jetbrains.kotlin.name.Name
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertSame
+import org.junit.jupiter.api.Test
+
+/**
+ * The JLS-implicit type arguments of the enclosing instance, added for a bare reference to a
+ * non-static inner class (`Inner` inside `Outer<T>` denotes `Outer<T>.Inner`).
+ *
+ * Such an argument must be the *declaring* class's own [org.jetbrains.kotlin.load.java.structure.JavaTypeParameter]
+ * instance: FIR maps `JavaTypeParameter`s to `FirTypeParameterSymbol`s by object identity through
+ * the per-class `JavaTypeParameterStack`, so a same-named parameter of a different declaration is
+ * not merely a cosmetic difference — it substitutes a different symbol, silently.
+ */
+class JavaParsingImplicitOuterTypeArgumentsTest : JavaParsingTestBase() {
+
+    @Test
+    fun testImplicitOuterArgumentIsOuterClassParameter() {
+        val source = """
+            public class A<T> {
+                class Inner {
+                    Inner foo() { return null; }
+                }
+            }
+        """.trimIndent()
+        val a = parseFirstClass(source)
+        val inner = a.findInnerClass(Name.identifier("Inner"))!!
+
+        val args = inner.implicitOuterArgumentsOfReturnTypeOf("foo")
+        assertEquals(1, args.size, "`Inner` denotes `A<T>.Inner`, so it has one implicit outer argument")
+        assertSame(a.typeParameters[0], args[0], "The implicit outer argument must be A's own T")
+    }
+
+    @Test
+    fun testImplicitOuterArgumentIsNotShadowedByInnerClassParameter() {
+        // `Inner<String>` inside `Inner` denotes `A<A.T>.Inner<String>`: the nested `T` shadows the
+        // outer one for name resolution, but the enclosing instance is still parameterized by A's T.
+        val source = """
+            public class A<T> {
+                class Inner<T> {
+                    Inner<String> foo() { return null; }
+                }
+            }
+        """.trimIndent()
+        val a = parseFirstClass(source)
+        val inner = a.findInnerClass(Name.identifier("Inner"))!!
+
+        val returnType = inner.returnTypeOf("foo")
+        assertEquals(
+            listOf("String", "T"),
+            returnType.typeArguments.map { (it as JavaClassifierType).classifierQualifiedName },
+            "Explicit argument first, then the implicit outer one",
+        )
+
+        val outerArgument = returnType.typeArguments[1]!!.classifierOfTypeParameter()
+        assertSame(a.typeParameters[0], outerArgument, "The implicit outer argument must be A's T, not Inner's T")
+    }
+
+    @Test
+    fun testImplicitOuterArgumentIsNotShadowedByMethodTypeParameter() {
+        // A generic method whose parameter happens to be named like the outer class's one must not
+        // hijack the implicit outer argument of inner-class types written in its signature.
+        val source = """
+            public class A<T> {
+                class Inner { }
+                <T> Inner foo() { return null; }
+            }
+        """.trimIndent()
+        val a = parseFirstClass(source)
+
+        val args = a.implicitOuterArgumentsOfReturnTypeOf("foo")
+        assertEquals(1, args.size)
+        assertSame(a.typeParameters[0], args[0], "The implicit outer argument must be A's T, not foo's T")
+    }
+
+    @Test
+    fun testImplicitOuterArgumentsOfNestedOuterChain() {
+        // Both enclosing levels contribute, innermost first, and neither is shadowed by `Inner`'s own `U`.
+        val source = """
+            public class A<T> {
+                class Mid<U> {
+                    class Inner<U> {
+                        Inner<String> foo() { return null; }
+                    }
+                }
+            }
+        """.trimIndent()
+        val a = parseFirstClass(source)
+        val mid = a.findInnerClass(Name.identifier("Mid"))!!
+        val inner = mid.findInnerClass(Name.identifier("Inner"))!!
+
+        val args = inner.implicitOuterArgumentsOfReturnTypeOf("foo")
+        assertEquals(2, args.size, "`Inner` denotes `A<T>.Mid<U>.Inner`, so both outer levels contribute")
+        assertSame(mid.typeParameters[0], args[0], "First implicit outer argument must be Mid's own U")
+        assertSame(a.typeParameters[0], args[1], "Second implicit outer argument must be A's T")
+    }
+}
+
+private fun JavaClass.returnTypeOf(methodName: String): JavaClassifierType =
+    methods.first { it.name.asString() == methodName }.returnType as JavaClassifierType
+
+/**
+ * The type-parameter arguments of the method's return type, in order. Explicitly written arguments
+ * are class-like (and, in these tests, unresolved), so filtering on the classifier isolates the
+ * implicit outer ones the model appends.
+ */
+private fun JavaClass.implicitOuterArgumentsOfReturnTypeOf(methodName: String): List<JavaTypeParameter> =
+    returnTypeOf(methodName).typeArguments.mapNotNull { (it as? JavaClassifierType)?.classifier as? JavaTypeParameter }
+
+private fun JavaType.classifierOfTypeParameter(): JavaTypeParameter =
+    (this as JavaClassifierType).classifier as JavaTypeParameter