Skip to content

Commit

Permalink
KT-42151 fix type arguments in local class constructor reference types
Browse files Browse the repository at this point in the history
  • Loading branch information
dnpetrov committed Nov 26, 2020
1 parent b2b8562 commit ee1e05f
Show file tree
Hide file tree
Showing 22 changed files with 678 additions and 32 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.*
Expand Down Expand Up @@ -74,7 +74,10 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)

override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid(this)
return if (expression.isIgnored) expression else FunctionReferenceBuilder(expression).build()
return if (expression.isIgnored)
expression
else
FunctionReferenceBuilder(expression).build()
}

// Handle SAM conversions which wrap a function reference:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.builtins.isKFunctionType
import org.jetbrains.kotlin.builtins.isKSuspendFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.DescriptorMetadataSource
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
Expand All @@ -34,7 +33,9 @@ import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.referenceClassifier
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.util.withScope
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
Expand All @@ -46,7 +47,6 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
import org.jetbrains.kotlin.utils.SmartList

class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down Expand Up @@ -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")
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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
}
}
Expand Down
31 changes: 24 additions & 7 deletions compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 })
Expand Down
11 changes: 10 additions & 1 deletion compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: BINDING_RECEIVERS

// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_FIR: JVM_IR
// KT-42025

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: BINDING_RECEIVERS

// IGNORE_BACKEND_FIR: JVM_IR
// KT-42025

open class L<LL>(val ll: LL)

class Rec<T>(val rt: T)

fun <FT> Rec<FT>.fn(): L<FT> {
class FLocal<LT>(lt: LT, val pt: FT): L<LT>(lt)
return foo2(rt, rt, ::FLocal)
}

val <PT> Rec<PT>.p: L<PT>
get() {
class PLocal<LT>(lt: LT, val pt: PT): L<LT>(lt)
return foo2(rt, rt, ::PLocal)
}

fun <T1, T2, R> foo2(t1: T1, t2: T2, bb: (T1, T2) -> R): R = bb(t1, t2)

fun box(): String =
Rec("O").fn().ll + Rec("K").p.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
open class L<LL : Any?> {
constructor(ll: LL) /* primary */ {
super/*Any*/()
/* <init>() */

}

val ll: LL
field = ll
get

}

class Rec<T : Any?> {
constructor(rt: T) /* primary */ {
super/*Any*/()
/* <init>() */

}

val rt: T
field = rt
get

}

val <PT : Any?> Rec<PT>.p: L<PT>
get(): L<PT> {
local class PLocal<LT : Any?> : L<LT> {
constructor(lt: LT, pt: PT) /* primary */ {
super/*L*/<LT>(ll = lt)
/* <init>() */

}

val pt: PT
field = pt
get

}

return foo2<PT, PT, PLocal<PT>>(t1 = <this>.<get-rt>(), t2 = <this>.<get-rt>(), bb = PLocal::<init>/*<PT>()*/)
}

fun <FT : Any?> Rec<FT>.fn(): L<FT> {
local class FLocal<LT : Any?> : L<LT> {
constructor(lt: LT, pt: FT) /* primary */ {
super/*L*/<LT>(ll = lt)
/* <init>() */

}

val pt: FT
field = pt
get

}

return foo2<FT, FT, FLocal<FT>>(t1 = <this>.<get-rt>(), t2 = <this>.<get-rt>(), bb = FLocal::<init>/*<FT>()*/)
}

fun <T1 : Any?, T2 : Any?, R : Any?> foo2(t1: T1, t2: T2, bb: Function2<T1, T2, R>): R {
return bb.invoke(p1 = t1, p2 = t2)
}
Loading

0 comments on commit ee1e05f

Please sign in to comment.