diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt index 5490b80026e..03849845b7f 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt @@ -100,7 +100,7 @@ class JavaSymbolProvider( useLazyNestedClassifierScope = regularClass is FirJavaClass, existingNames = (regularClass as? FirJavaClass)?.existingNestedClassifierNames ) - val wrappedDeclaredScope = wrapScopeWithJvmMapped(regularClass.classId, declaredScope, useSiteSession, scopeSession) + val wrappedDeclaredScope = wrapScopeWithJvmMapped(regularClass, declaredScope, useSiteSession, scopeSession) val superTypeEnhancementScopes = lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession) .mapNotNull { useSiteSuperType -> diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt index d204c17ab0f..528f203e124 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt @@ -21,6 +21,8 @@ import org.jetbrains.kotlin.fir.scopes.jvm.JvmMappedScope import org.jetbrains.kotlin.fir.symbols.* import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeClassErrorType +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -57,11 +59,12 @@ abstract class FirSymbolProvider : FirSessionComponent { ): FirScope? protected fun wrapScopeWithJvmMapped( - classId: ClassId, + klass: FirClass<*>, declaredMemberScope: FirScope, useSiteSession: FirSession, scopeSession: ScopeSession ): FirScope { + val classId = klass.classId val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(classId.asSingleFqName().toUnsafe()) ?: return declaredMemberScope val symbolProvider = useSiteSession.firSymbolProvider @@ -69,8 +72,17 @@ abstract class FirSymbolProvider : FirSessionComponent { ?: return declaredMemberScope val preparedSignatures = JvmMappedScope.prepareSignatures(javaClass) return if (preparedSignatures.isNotEmpty()) { - symbolProvider.getClassUseSiteMemberScope(javaClassId, useSiteSession, scopeSession)?.let { - JvmMappedScope(declaredMemberScope, it, preparedSignatures) + symbolProvider.getClassUseSiteMemberScope(javaClassId, useSiteSession, scopeSession)?.let { javaClassUseSiteScope -> + val jvmMappedScope = JvmMappedScope(declaredMemberScope, javaClassUseSiteScope, preparedSignatures) + if (klass !is FirRegularClass) { + jvmMappedScope + } else { + // We should substitute Java type parameters with base Kotlin type parameters to match overrides perfectly + (klass.symbol.constructType( + klass.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(), + false + ) as ConeClassLikeType).wrapSubstitutionScopeIfNeed(useSiteSession, jvmMappedScope, klass, scopeSession) + } } ?: declaredMemberScope } else { declaredMemberScope @@ -82,7 +94,7 @@ abstract class FirSymbolProvider : FirSessionComponent { val declaredScope = declaredMemberScope(klass) val wrappedDeclaredScope = wrapScopeWithJvmMapped( - klass.classId, declaredScope, useSiteSession, scopeSession + klass, declaredScope, useSiteSession, scopeSession ) val scopes = lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession) .mapNotNull { useSiteSuperType -> diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt index c6e070108cf..744bc63d865 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt @@ -15,14 +15,14 @@ import org.jetbrains.kotlin.name.Name class JvmMappedScope( private val declaredMemberScope: FirScope, - private val javaMappedScope: FirScope, + private val javaMappedClassUseSiteScope: FirScope, private val whiteListSignaturesByName: Map> ) : FirScope() { override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction { val whiteListSignatures = whiteListSignaturesByName[name] ?: return declaredMemberScope.processFunctionsByName(name, processor) - if (!javaMappedScope.processFunctionsByName(name) { symbol -> + if (!javaMappedClassUseSiteScope.processFunctionsByName(name) { symbol -> val jvmSignature = symbol.fir.computeJvmDescriptor() if (jvmSignature !in whiteListSignatures) { ProcessorAction.NEXT diff --git a/compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.kt b/compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.kt new file mode 100644 index 00000000000..7c309e823b4 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.kt @@ -0,0 +1,23 @@ +// FULL_JDK +// FILE: Call.java + +import org.jetbrains.annotations.NotNull; +import java.util.*; + +public interface Call { + @NotNull + Map getArguments(); +} + +// FILE: test.kt + +fun Call.testForEach() { + arguments.forEach { key, value -> + key.length + value.length + } + arguments.forEach { + it.key.length + it.value.length + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.txt b/compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.txt new file mode 100644 index 00000000000..5100d37c6e3 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.txt @@ -0,0 +1,13 @@ +FILE: test.kt + public final fun R|Call|.testForEach(): R|kotlin/Unit| { + R|/Call.arguments|.R|FakeOverride|( = forEach@fun (key: R|kotlin/String!|, value: R|kotlin/String!|): R|kotlin/Unit| { + R|/key|.R|kotlin/String.length| + R|/value|.R|kotlin/String.length| + } + ) + R|/Call.arguments|.R|FakeOverride|( = forEach@fun (): R|kotlin/Unit| { + #.#.# + #.#.# + } + ) + } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.kt b/compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.kt new file mode 100644 index 00000000000..01dc87cbff6 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.kt @@ -0,0 +1,19 @@ +interface Diagnostic { + val name: String +} + +fun foo(conflicting: List) { + val filtered = arrayListOf() + conflicting.groupBy { + it.name + }.forEach { + val diagnostics = it.value + filtered.addAll( + diagnostics.filter { me -> + diagnostics.none { other -> + me != other + } + } + ) + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.txt b/compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.txt new file mode 100644 index 00000000000..37687eb78a2 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.txt @@ -0,0 +1,23 @@ +FILE: noneWithForEach.kt + public abstract interface Diagnostic : R|kotlin/Any| { + public abstract val name: R|kotlin/String| + public get(): R|kotlin/String| + + } + public final fun foo(conflicting: R|kotlin/collections/List|): R|kotlin/Unit| { + lval filtered: R|kotlin/collections/ArrayList| = R|kotlin/collections/arrayListOf|() + R|/conflicting|.R|kotlin/collections/groupBy|( = groupBy@fun (it: R|Diagnostic|): R|kotlin/String| { + R|/it|.R|/Diagnostic.name| + } + ).R|FakeOverride|( = forEach@fun (): R|kotlin/Unit| { + lval diagnostics: = #.# + R|/filtered|.R|FakeOverride|(R|/diagnostics|.#( = filter@fun (me: R|class error: No type for parameter|): { + R|/diagnostics|.#( = none@fun (other: R|class error: No type for parameter|): R|kotlin/Boolean| { + !=(R|/me|, R|/other|) + } + ) + } + )) + } + ) + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java index 1409df9aaae..69e96231254 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java @@ -133,6 +133,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic runTest("compiler/fir/resolve/testData/resolve/stdlib/multipleImplicitReceivers.kt"); } + @TestMetadata("noneWithForEach.kt") + public void testNoneWithForEach() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.kt"); + } + @TestMetadata("nullableTypeParameter.kt") public void testNullableTypeParameter() throws Exception { runTest("compiler/fir/resolve/testData/resolve/stdlib/nullableTypeParameter.kt"); @@ -524,6 +529,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/StaticGenericMethod.kt"); } + @TestMetadata("SyntheticWithForEach.kt") + public void testSyntheticWithForEach() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.kt"); + } + @TestMetadata("typeParameterUse.kt") public void testTypeParameterUse() throws Exception { runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/typeParameterUse.kt");