diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt index ba72b16e10b..c0923265df8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* @@ -99,6 +100,27 @@ fun FirClass<*>.buildDefaultUseSiteMemberScope(useSiteSession: FirSession, scope } } +private fun createSubstitution( + typeParameters: List, + typeArguments: Array, + session: FirSession +): Map { + return typeParameters.zip(typeArguments) { typeParameter, typeArgument -> + val typeParameterSymbol = typeParameter.symbol + typeParameterSymbol to when (typeArgument) { + is ConeTypedProjection -> { + typeArgument.type + } + else /* StarProjection */ -> { + ConeTypeIntersector.intersectTypes( + session.inferenceContext(), + typeParameterSymbol.fir.bounds.map { it.coneTypeUnsafe() } + ) + } + } + }.toMap() +} + fun ConeClassLikeType.wrapSubstitutionScopeIfNeed( session: FirSession, useSiteMemberScope: FirScope, @@ -108,23 +130,16 @@ fun ConeClassLikeType.wrapSubstitutionScopeIfNeed( if (this.typeArguments.isEmpty()) return useSiteMemberScope return builder.getOrBuild(declaration.symbol, SubstitutionScopeKey(this)) { val typeParameters = (declaration as? FirTypeParametersOwner)?.typeParameters.orEmpty() - @Suppress("UNCHECKED_CAST") - val substitution = typeParameters.zip(this.typeArguments) { typeParameter, typeArgument -> - val typeParameterSymbol = typeParameter.symbol - typeParameterSymbol to when (typeArgument) { - is ConeTypedProjection -> { - typeArgument.type - } - else /* StarProjection */ -> { - ConeTypeIntersector.intersectTypes( - session.inferenceContext(), - typeParameterSymbol.fir.bounds.map { it.coneTypeUnsafe() } - ) - } - } - }.toMap() - - FirClassSubstitutionScope(session, useSiteMemberScope, builder, substitution) + val originalSubstitution = createSubstitution(typeParameters, typeArguments, session) + val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(declaration.symbol.classId.asSingleFqName().toUnsafe()) + val javaClass = javaClassId?.let { session.firSymbolProvider.getClassLikeSymbolByFqName(it)?.fir } as? FirRegularClass + if (javaClass != null) { + val javaTypeParameters = javaClass.typeParameters + val javaSubstitution = createSubstitution(javaTypeParameters, typeArguments, session) + FirClassSubstitutionScope(session, useSiteMemberScope, builder, originalSubstitution + javaSubstitution) + } else { + FirClassSubstitutionScope(session, useSiteMemberScope, builder, originalSubstitution) + } } } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyIterable.txt b/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyIterable.txt index 5c57df8dcd9..8b94d9d8b95 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyIterable.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyIterable.txt @@ -2,11 +2,11 @@ FILE: test.kt public abstract interface UseIterable : R|MyIterable| { public open fun test(): R|kotlin/Unit| { lval it: R|kotlin/collections/MutableIterator| = this@R|kotlin/collections/MutableIterable|.R|FakeOverride|>|() - lval split: R|java/util/Spliterator| = this@R|java/lang/Iterable|.R|FakeOverride|>|() + lval split: R|java/util/Spliterator| = this@R|java/lang/Iterable|.R|FakeOverride|>|() } } public final fun test(some: R|kotlin/collections/Iterable|): R|kotlin/Unit| { lval it: R|kotlin/collections/Iterator| = R|/some|.R|FakeOverride|>|() - lval split: R|java/util/Spliterator| = R|/some|.R|FakeOverride|>|() + lval split: R|java/util/Spliterator| = R|/some|.R|FakeOverride|>|() } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyMap.kt b/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyMap.kt index f7e178a36fc..ee8804673bd 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyMap.kt +++ b/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyMap.kt @@ -12,10 +12,14 @@ fun test(map: MyMap) { // Java forEach map.forEach { key, value -> println("$key: $value") + key.length + value.length } // Kotlin forEach map.forEach { (key, value) -> println("$key: $value") + key.length + value.length } } @@ -27,9 +31,13 @@ fun test(map: MutableMap) { // Java forEach map.forEach { key, value -> println("$key: $value") + key.length + value.length } // Kotlin forEach map.forEach { (key, value) -> println("$key: $value") + key.length + value.length } } \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyMap.txt b/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyMap.txt index c68e14fd8e2..be1c6675bb5 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyMap.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/j+k/MyMap.txt @@ -6,14 +6,18 @@ FILE: test.kt ) lval otherResult: R|kotlin/String| = R|/map|.R|FakeOverride|(String(key), String(value)) lval anotherResult: = R|/map|.#(String(key), String(value)) - R|/map|.R|java/util/Map.forEach|( = forEach@fun (key: R|K!|, value: R|V!|): R|kotlin/Unit| { + R|/map|.R|FakeOverride|( = forEach@fun (key: R|kotlin/String!|, value: R|kotlin/String!|): R|kotlin/Unit| { R|kotlin/io/println|((R|/key|.R|kotlin/Any.toString|(), String(: ), R|/value|.R|kotlin/Any.toString|())) + R|/key|.R|kotlin/String.length| + R|/value|.R|kotlin/String.length| } ) R|/map|.R|kotlin/collections/forEach|( = forEach@fun (: R|kotlin/collections/Map.Entry|): R|kotlin/Unit| { lval key: R|kotlin/String| = R|/|.R|kotlin/collections/component1|() lval value: R|kotlin/String| = R|/|.R|kotlin/collections/component2|() R|kotlin/io/println|((R|/key|.R|kotlin/Any.toString|(), String(: ), R|/value|.R|kotlin/Any.toString|())) + R|/key|.R|kotlin/String.length| + R|/value|.R|kotlin/String.length| } ) } @@ -24,14 +28,18 @@ FILE: test.kt ) lval otherResult: R|kotlin/String| = R|/map|.R|FakeOverride|(String(key), String(value)) lval anotherResult: = R|/map|.#(String(key), String(value)) - R|/map|.R|java/util/Map.forEach|( = forEach@fun (key: R|K!|, value: R|V!|): R|kotlin/Unit| { + R|/map|.R|FakeOverride|( = forEach@fun (key: R|kotlin/String!|, value: R|kotlin/String!|): R|kotlin/Unit| { R|kotlin/io/println|((R|/key|.R|kotlin/Any.toString|(), String(: ), R|/value|.R|kotlin/Any.toString|())) + R|/key|.R|kotlin/String.length| + R|/value|.R|kotlin/String.length| } ) R|/map|.R|kotlin/collections/forEach|( = forEach@fun (: R|kotlin/collections/Map.Entry|): R|kotlin/Unit| { lval key: R|kotlin/String| = R|/|.R|kotlin/collections/component1|() lval value: R|kotlin/String| = R|/|.R|kotlin/collections/component2|() R|kotlin/io/println|((R|/key|.R|kotlin/Any.toString|(), String(: ), R|/value|.R|kotlin/Any.toString|())) + R|/key|.R|kotlin/String.length| + R|/value|.R|kotlin/String.length| } ) }