Extract a generic specialisation using its own type parameters in the same order like an unbound type

This replicates an oddity in the Java extractor that it doesn't differentiate a specialisation Generic<T1, T2, ...> from the unbound type, if T1, T2, ... are Generic's declared type variables occurring in the same order. For example, in `class MyList<T> { void addAll(MyList<T> param) { ... } }`, the type of `param` is an instantiated type, but
gets extracted as an unbound type. This commit can be reverted (except for the improvement to isUnspecialised) if/when that is fixed.
This commit is contained in:
Chris Smowton
2022-04-16 09:13:01 +01:00
committed by Ian Lynagh
parent f3bd89a5cf
commit d63124a761
2 changed files with 19 additions and 3 deletions

View File

@@ -922,7 +922,12 @@ open class KotlinUsesExtractor(
}
}
val reorderedArgs = orderTypeArgsLeftToRight(c, argsIncludingOuterClasses)
// C<T1, T2, ...>, where C is declared (class|interface) C<T1, T2, ...> { ... }, takes the class label C without
// qualification, even in contexts like `class MyList<T> { public void addAll(List<T> otherList) { ... } }`
// where this would normally constitute a constructed type. This replicates a quirk of the Java extractor.
val typeArgsIfSpecialised = argsIncludingOuterClasses?.let { if (isUnspecialised(c, it)) listOf() else it }
val reorderedArgs = orderTypeArgsLeftToRight(c, typeArgsIfSpecialised)
val typeArgLabels = reorderedArgs?.map { getTypeArgumentLabel(it) }
val typeArgsShortName =
if (typeArgLabels == null)

View File

@@ -8,6 +8,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
@@ -20,6 +21,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
@@ -194,14 +196,23 @@ fun IrTypeArgument.withQuestionMark(b: Boolean): IrTypeArgument =
typealias TypeSubstitution = (IrType, KotlinUsesExtractor.TypeContext, IrPluginContext) -> IrType
// Returns true if type is C<T1, T2, ...> where C is declared `class C<T1, T2, ...> { ... }`
fun isUnspecialised(classType: IrClass, args: List<IrTypeArgument>) =
classType.typeParameters.zip(args).all { paramAndArg ->
fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List<IrTypeArgument>): Boolean {
val unspecialisedHere = paramsContainer.typeParameters.zip(args).all { paramAndArg ->
(paramAndArg.second as? IrTypeProjection)?.let {
// Type arg refers to the class' own type parameter?
it.variance == Variance.INVARIANT &&
it.type.classifierOrNull?.owner === paramAndArg.first
} ?: false
}
val remainingArgs = args.drop(paramsContainer.typeParameters.size)
val parent = paramsContainer.parent as? IrTypeParametersContainer
val parentUnspecialised = when {
remainingArgs.isEmpty() -> true
parent == null -> false
else -> isUnspecialised(paramsContainer.parentAsClass, remainingArgs)
}
return unspecialisedHere && parentUnspecialised
}
// Returns true if type is C<T1, T2, ...> where C is declared `class C<T1, T2, ...> { ... }`
fun isUnspecialised(type: IrSimpleType) = (type.classifier.owner as? IrClass)?.let {