FIR resolve: make substitution also for mapped Java type parameters

This commit is contained in:
Mikhail Glukhikh
2019-11-20 13:12:46 +03:00
parent b3056b8bf5
commit 71b95bd91d
4 changed files with 52 additions and 21 deletions
@@ -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<FirTypeParameter>,
typeArguments: Array<out ConeKotlinTypeProjection>,
session: FirSession
): Map<FirTypeParameterSymbol, ConeKotlinType> {
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)
}
}
}
@@ -2,11 +2,11 @@ FILE: test.kt
public abstract interface UseIterable : R|MyIterable<kotlin/String>| {
public open fun test(): R|kotlin/Unit| {
lval it: R|kotlin/collections/MutableIterator<kotlin/String>| = this@R|kotlin/collections/MutableIterable|.R|FakeOverride<kotlin/collections/MutableIterable.iterator: R|kotlin/collections/MutableIterator<kotlin/String>|>|()
lval split: R|java/util/Spliterator<T!>| = this@R|java/lang/Iterable|.R|FakeOverride<java/lang/Iterable.spliterator: R|java/util/Spliterator<T!>|>|()
lval split: R|java/util/Spliterator<kotlin/String!>| = this@R|java/lang/Iterable|.R|FakeOverride<java/lang/Iterable.spliterator: R|java/util/Spliterator<kotlin/String!>|>|()
}
}
public final fun test(some: R|kotlin/collections/Iterable<kotlin/String>|): R|kotlin/Unit| {
lval it: R|kotlin/collections/Iterator<kotlin/String>| = R|<local>/some|.R|FakeOverride<kotlin/collections/Iterable.iterator: R|kotlin/collections/Iterator<kotlin/String>|>|()
lval split: R|java/util/Spliterator<T!>| = R|<local>/some|.R|FakeOverride<java/lang/Iterable.spliterator: R|java/util/Spliterator<T!>|>|()
lval split: R|java/util/Spliterator<kotlin/String!>| = R|<local>/some|.R|FakeOverride<java/lang/Iterable.spliterator: R|java/util/Spliterator<kotlin/String!>|>|()
}
@@ -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<String, String>) {
// 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
}
}
+10 -2
View File
@@ -6,14 +6,18 @@ FILE: test.kt
)
lval otherResult: R|kotlin/String| = R|<local>/map|.R|FakeOverride<kotlin/collections/Map.getOrDefault: R|kotlin/String|>|(String(key), String(value))
lval anotherResult: <ERROR TYPE REF: Unresolved name: replace> = R|<local>/map|.<Unresolved name: replace>#(String(key), String(value))
R|<local>/map|.R|java/util/Map.forEach|(<L> = forEach@fun <anonymous>(key: R|K!|, value: R|V!|): R|kotlin/Unit| {
R|<local>/map|.R|FakeOverride<java/util/Map.forEach: R|kotlin/Unit|>|(<L> = forEach@fun <anonymous>(key: R|kotlin/String!|, value: R|kotlin/String!|): R|kotlin/Unit| {
R|kotlin/io/println|(<strcat>(R|<local>/key|.R|kotlin/Any.toString|(), String(: ), R|<local>/value|.R|kotlin/Any.toString|()))
R|<local>/key|.R|kotlin/String.length|
R|<local>/value|.R|kotlin/String.length|
}
)
R|<local>/map|.R|kotlin/collections/forEach|<R|kotlin/String|, R|kotlin/String|>(<L> = forEach@fun <anonymous>(<destruct>: R|kotlin/collections/Map.Entry<kotlin/String, kotlin/String>|): R|kotlin/Unit| <kind=UNKNOWN> {
lval key: R|kotlin/String| = R|<local>/<destruct>|.R|kotlin/collections/component1|<R|kotlin/String|, R|kotlin/String|>()
lval value: R|kotlin/String| = R|<local>/<destruct>|.R|kotlin/collections/component2|<R|kotlin/String|, R|kotlin/String|>()
R|kotlin/io/println|(<strcat>(R|<local>/key|.R|kotlin/Any.toString|(), String(: ), R|<local>/value|.R|kotlin/Any.toString|()))
R|<local>/key|.R|kotlin/String.length|
R|<local>/value|.R|kotlin/String.length|
}
)
}
@@ -24,14 +28,18 @@ FILE: test.kt
)
lval otherResult: R|kotlin/String| = R|<local>/map|.R|FakeOverride<kotlin/collections/Map.getOrDefault: R|kotlin/String|>|(String(key), String(value))
lval anotherResult: <ERROR TYPE REF: Unresolved name: replace> = R|<local>/map|.<Unresolved name: replace>#(String(key), String(value))
R|<local>/map|.R|java/util/Map.forEach|(<L> = forEach@fun <anonymous>(key: R|K!|, value: R|V!|): R|kotlin/Unit| {
R|<local>/map|.R|FakeOverride<java/util/Map.forEach: R|kotlin/Unit|>|(<L> = forEach@fun <anonymous>(key: R|kotlin/String!|, value: R|kotlin/String!|): R|kotlin/Unit| {
R|kotlin/io/println|(<strcat>(R|<local>/key|.R|kotlin/Any.toString|(), String(: ), R|<local>/value|.R|kotlin/Any.toString|()))
R|<local>/key|.R|kotlin/String.length|
R|<local>/value|.R|kotlin/String.length|
}
)
R|<local>/map|.R|kotlin/collections/forEach|<R|kotlin/String|, R|kotlin/String|>(<L> = forEach@fun <anonymous>(<destruct>: R|kotlin/collections/Map.Entry<kotlin/String, kotlin/String>|): R|kotlin/Unit| <kind=UNKNOWN> {
lval key: R|kotlin/String| = R|<local>/<destruct>|.R|kotlin/collections/component1|<R|kotlin/String|, R|kotlin/String|>()
lval value: R|kotlin/String| = R|<local>/<destruct>|.R|kotlin/collections/component2|<R|kotlin/String|, R|kotlin/String|>()
R|kotlin/io/println|(<strcat>(R|<local>/key|.R|kotlin/Any.toString|(), String(: ), R|<local>/value|.R|kotlin/Any.toString|()))
R|<local>/key|.R|kotlin/String.length|
R|<local>/value|.R|kotlin/String.length|
}
)
}