KT-42151 fix type arguments in local class constructor reference types

This commit is contained in:
Dmitry Petrov
2020-11-26 15:05:41 +03:00
parent b2b8562f92
commit ee1e05fedd
22 changed files with 678 additions and 32 deletions
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyProperty
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
@@ -1078,18 +1077,37 @@ private fun makeKotlinType(
classifier: IrClassifierSymbol,
arguments: List<IrTypeArgument>,
hasQuestionMark: Boolean
): SimpleType = when (classifier) {
is IrTypeParameterSymbol -> classifier.owner.toIrBasedDescriptor().defaultType
is IrClassSymbol -> {
val classDescriptor = classifier.owner.toIrBasedDescriptor()
val kotlinTypeArguments = arguments.mapIndexed { index, it ->
when (it) {
is IrTypeProjection -> TypeProjectionImpl(it.variance, it.type.toIrBasedKotlinType())
is IrStarProjection -> StarProjectionImpl(classDescriptor.typeConstructor.parameters[index])
else -> error(it)
): SimpleType =
when (classifier) {
is IrTypeParameterSymbol -> classifier.owner.toIrBasedDescriptor().defaultType
is IrClassSymbol -> {
val classDescriptor = classifier.owner.toIrBasedDescriptor()
val kotlinTypeArguments = arguments.mapIndexed { index, it ->
when (it) {
is IrTypeProjection -> TypeProjectionImpl(it.variance, it.type.toIrBasedKotlinType())
is IrStarProjection -> StarProjectionImpl(classDescriptor.typeConstructor.parameters[index])
else -> error(it)
}
}
try {
classDescriptor.defaultType.replace(newArguments = kotlinTypeArguments).makeNullableAsSpecified(hasQuestionMark)
} catch (e: Throwable) {
throw RuntimeException(
"Classifier: $classDescriptor\n" +
"Type parameters:\n" +
classDescriptor.defaultType.constructor.parameters.withIndex()
.joinToString(separator = "\n") {
"${it.index}: ${(it.value as IrBasedTypeParameterDescriptor).owner.render()}"
} +
"\nType arguments:\n" +
arguments.withIndex()
.joinToString(separator = "\n") {
"${it.index}: ${it.value.render()}"
},
e
)
}
}
classDescriptor.defaultType.replace(newArguments = kotlinTypeArguments).makeNullableAsSpecified(hasQuestionMark)
else -> error("unknown classifier kind $classifier")
}
else -> error("unknown classifier kind $classifier")
}
@@ -390,9 +390,9 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
}
}
fun extractTypeParameters(klass: IrDeclarationParent): List<IrTypeParameter> {
fun extractTypeParameters(parent: IrDeclarationParent): List<IrTypeParameter> {
val result = mutableListOf<IrTypeParameter>()
var current: IrDeclarationParent? = klass
var current: IrDeclarationParent? = parent
while (current != null) {
(current as? IrTypeParametersContainer)?.let { result += it.typeParameters }
current =
@@ -404,9 +404,11 @@ fun extractTypeParameters(klass: IrDeclarationParent): List<IrTypeParameter> {
else -> null
}
is IrConstructor -> current.parent as IrClass
is IrFunction -> if (current.visibility == DescriptorVisibilities.LOCAL || current.dispatchReceiverParameter != null) {
current.parent
} else null
is IrFunction ->
if (current.visibility == DescriptorVisibilities.LOCAL || current.dispatchReceiverParameter != null)
current.parent
else
null
else -> null
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.types
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.isPropertyAccessor
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
@@ -155,13 +157,28 @@ val IrClassSymbol.starProjectedType: IrSimpleType
)
val IrClass.typeConstructorParameters: Sequence<IrTypeParameter>
get() = generateSequence(this as IrTypeParametersContainer,
{ current ->
val parent = current.parent as? IrTypeParametersContainer
if (parent is IrClass && current is IrClass && !current.isInner) null
else parent
})
.flatMap { it.typeParameters }
get() =
generateSequence(
this as IrTypeParametersContainer,
{ current ->
val parent = current.parent as? IrTypeParametersContainer
when {
parent is IrSimpleFunction && parent.isPropertyAccessor -> {
// KT-42151
// Property type parameters for local classes declared inside property accessors are not captured in FE descriptors.
// In order to match type parameters against type arguments in IR types translated from KotlinTypes,
// we should stop on property accessor here.
// NB this can potentially cause problems with inline properties with reified type parameters.
// Ideally this should be fixed in FE.
null
}
parent is IrClass && current is IrClass && !current.isInner ->
null
else ->
parent
}
}
).flatMap { it.typeParameters }
fun IrClassifierSymbol.typeWithParameters(parameters: List<IrTypeParameter>): IrSimpleType =
typeWith(parameters.map { it.defaultType })
@@ -526,7 +526,16 @@ fun IrMemberAccessExpression<*>.getTypeSubstitutionMap(irFunction: IrFunction):
val result = mutableMapOf<IrTypeParameterSymbol, IrType>()
if (dispatchReceiverTypeArguments.isNotEmpty()) {
val parentTypeParameters = extractTypeParameters(irFunction.parentClassOrNull!!)
val parentTypeParameters =
if (irFunction is IrConstructor) {
val constructedClass = irFunction.parentAsClass
if (!constructedClass.isInner && dispatchReceiver != null) {
throw AssertionError("Non-inner class constructor reference with dispatch receiver:\n${this.dump()}")
}
extractTypeParameters(constructedClass.parent as IrClass)
} else {
extractTypeParameters(irFunction.parentClassOrNull!!)
}
parentTypeParameters.withIndex().forEach { (index, typeParam) ->
dispatchReceiverTypeArguments[index].typeOrNull?.let {
result[typeParam.symbol] = it