diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 0c8aebb2f3f..db4357d1593 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -922,7 +922,12 @@ open class KotlinUsesExtractor( } } - val reorderedArgs = orderTypeArgsLeftToRight(c, argsIncludingOuterClasses) + // C, where C is declared (class|interface) C { ... }, takes the class label C without + // qualification, even in contexts like `class MyList { public void addAll(List 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) diff --git a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt index 0526aa6d05c..872919466c6 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt @@ -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 where C is declared `class C { ... }` -fun isUnspecialised(classType: IrClass, args: List) = - classType.typeParameters.zip(args).all { paramAndArg -> +fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List): 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 where C is declared `class C { ... }` fun isUnspecialised(type: IrSimpleType) = (type.classifier.owner as? IrClass)?.let {