Implement $default method synthesis

This adds methods that fill in default parameters whenever a constructor or method uses default parameter values. I use as similar an approach to the real Kotlin compiler as possible both because this produces the desirable dataflow, and because it should merge cleanly with the same class file seen by the Java extractor, which will see and
extract the signatures of the default methods.
This commit is contained in:
Chris Smowton
2022-10-03 14:47:07 +01:00
parent 6f3c9e4403
commit 34a0a0d080
8 changed files with 1460 additions and 95 deletions

View File

@@ -1043,9 +1043,9 @@ open class KotlinUsesExtractor(
f.parent,
maybeParentId,
getFunctionShortName(f).nameInDB,
maybeParameterList ?: f.valueParameters,
(maybeParameterList ?: f.valueParameters).map { it.type },
getAdjustedReturnType(f),
f.extensionReceiverParameter,
f.extensionReceiverParameter?.type,
getFunctionTypeParameters(f),
classTypeArgsIncludingOuterClasses,
overridesCollectionsMethodWithAlteredParameterTypes(f),
@@ -1067,12 +1067,12 @@ open class KotlinUsesExtractor(
maybeParentId: Label<out DbElement>?,
// The name of the function; normally f.name.asString().
name: String,
// The value parameters that the functions takes; normally f.valueParameters.
parameters: List<IrValueParameter>,
// The types of the value parameters that the functions takes; normally f.valueParameters.map { it.type }.
parameterTypes: List<IrType>,
// The return type of the function; normally f.returnType.
returnType: IrType,
// The extension receiver of the function, if any; normally f.extensionReceiverParameter.
extensionReceiverParameter: IrValueParameter?,
// The extension receiver of the function, if any; normally f.extensionReceiverParameter?.type.
extensionParamType: IrType?,
// The type parameters of the function. This does not include type parameters of enclosing classes.
functionTypeParameters: List<IrTypeParameter>,
// The type arguments of enclosing classes of the function.
@@ -1089,11 +1089,7 @@ open class KotlinUsesExtractor(
prefix: String = "callable"
): String {
val parentId = maybeParentId ?: useDeclarationParent(parent, false, classTypeArgsIncludingOuterClasses, true)
val allParams = if (extensionReceiverParameter == null) {
parameters
} else {
listOf(extensionReceiverParameter) + parameters
}
val allParamTypes = if (extensionParamType == null) parameterTypes else listOf(extensionParamType) + parameterTypes
val substitutionMap = classTypeArgsIncludingOuterClasses?.let { notNullArgs ->
if (notNullArgs.isEmpty()) {
@@ -1103,11 +1099,11 @@ open class KotlinUsesExtractor(
enclosingClass?.let { notNullClass -> makeTypeGenericSubstitutionMap(notNullClass, notNullArgs) }
}
}
val getIdForFunctionLabel = { it: IndexedValue<IrValueParameter> ->
val getIdForFunctionLabel = { it: IndexedValue<IrType> ->
// Kotlin rewrites certain Java collections types adding additional generic constraints-- for example,
// Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin universe.
// If this has happened, erase the type again to get the correct Java signature.
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value.type, name, it.index) else it.value.type
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value, name, it.index) else it.value
// Add any wildcard types that the Kotlin compiler would add in the Java lowering of this function:
val withAddedWildcards = addJavaLoweringWildcards(maybeAmendedForCollections, addParameterWildcardsByDefault, javaSignature?.let { sig -> getJavaValueParameterType(sig, it.index) })
// Now substitute any class type parameters in:
@@ -1117,7 +1113,7 @@ open class KotlinUsesExtractor(
val maybeErased = if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
"{${useType(maybeErased).javaResult.id}}"
}
val paramTypeIds = allParams.withIndex().joinToString(separator = ",", transform = getIdForFunctionLabel)
val paramTypeIds = allParamTypes.withIndex().joinToString(separator = ",", transform = getIdForFunctionLabel)
val labelReturnType =
if (name == "<init>")
pluginContext.irBuiltIns.unitType
@@ -1551,7 +1547,7 @@ open class KotlinUsesExtractor(
* Note that `Array<T>` is retained (with `T` itself erased) because these are expected to be lowered to Java
* arrays, which are not generic.
*/
private fun erase (t: IrType): IrType {
fun erase (t: IrType): IrType {
if (t is IrSimpleType) {
val classifier = t.classifier
val owner = classifier.owner
@@ -1578,6 +1574,8 @@ open class KotlinUsesExtractor(
private fun eraseTypeParameter(t: IrTypeParameter) =
erase(t.superTypes[0])
fun getValueParameterLabel(parentId: Label<out DbElement>?, idx: Int) = "@\"params;{$parentId};$idx\""
/**
* Gets the label for `vp` in the context of function instance `parent`, or in that of its declaring function if
* `parent` is null.
@@ -1607,7 +1605,7 @@ open class KotlinUsesExtractor(
logger.error("Unexpected negative index for parameter")
}
return "@\"params;{$parentId};$idx\""
return getValueParameterLabel(parentId, idx)
}
@@ -1669,7 +1667,7 @@ open class KotlinUsesExtractor(
val returnType = getter?.returnType ?: setter?.valueParameters?.singleOrNull()?.type ?: pluginContext.irBuiltIns.unitType
val typeParams = getFunctionTypeParameters(func)
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false, javaSignature = null, addParameterWildcardsByDefault = false, prefix = "property")
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext.type, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false, javaSignature = null, addParameterWildcardsByDefault = false, prefix = "property")
}
}