Merge pull request #13919 from igfoo/igfoo/useFunction

Kotlin: useFunction might return null
This commit is contained in:
Ian Lynagh
2023-08-10 12:17:20 +01:00
committed by GitHub
2 changed files with 138 additions and 63 deletions

View File

@@ -552,9 +552,13 @@ open class KotlinFileExtractor(
logger.warnElement("Expected annotation property to define a getter", prop)
} else {
val getterId = useFunction<DbMethod>(getter)
val exprId = extractAnnotationValueExpression(v, id, i, "{$getterId}", getter.returnType, extractEnumTypeAccesses)
if (exprId != null) {
tw.writeAnnotValue(id, getterId, exprId)
if (getterId == null) {
logger.errorElement("Couldn't get ID for getter", getter)
} else {
val exprId = extractAnnotationValueExpression(v, id, i, "{$getterId}", getter.returnType, extractEnumTypeAccesses)
if (exprId != null) {
tw.writeAnnotValue(id, getterId, exprId)
}
}
}
}
@@ -979,6 +983,10 @@ open class KotlinFileExtractor(
private fun extractInstanceInitializerBlock(parent: StmtParent, enclosingConstructor: IrConstructor) {
with("object initializer block", enclosingConstructor) {
val constructorId = useFunction<DbConstructor>(enclosingConstructor)
if (constructorId == null) {
logger.errorElement("Cannot get ID for constructor", enclosingConstructor)
return
}
val enclosingClass = enclosingConstructor.parentClassOrNull
if (enclosingClass == null) {
logger.errorElement("Constructor's parent is not a class", enclosingConstructor)
@@ -1410,10 +1418,17 @@ open class KotlinFileExtractor(
val sourceDeclaration =
overriddenAttributes?.sourceDeclarationId ?:
if (typeSubstitution != null && overriddenAttributes?.id == null)
useFunction(f)
else
if (typeSubstitution != null && overriddenAttributes?.id == null) {
val sourceFunId = useFunction<DbCallable>(f)
if (sourceFunId == null) {
logger.errorElement("Cannot get source ID for function", f)
id // TODO: This is wrong; we ought to just fail in this case
} else {
sourceFunId
}
} else {
id
}
val extReceiver = f.extensionReceiverParameter
// The following parameter order is correct, because member $default methods (where the order would be [dispatchParam], [extensionParam], normalParams) are not extracted here
@@ -2926,7 +2941,11 @@ open class KotlinFileExtractor(
tw.writeStmts_throwstmt(throwId, stmtParent.parent, stmtParent.idx, callable)
tw.writeHasLocation(throwId, locId)
val newExprId = extractNewExpr(it, null, thrownType, locId, throwId, 0, callable, throwId)
extractTypeAccess(thrownType, locId, newExprId, -3, callable, throwId)
if (newExprId == null) {
logger.errorElement("No ID for newExpr in noWhenBranchMatchedException", c)
} else {
extractTypeAccess(thrownType, locId, newExprId, -3, callable, throwId)
}
}
}
isBuiltinCallInternal(c, "illegalArgumentException") -> {
@@ -3270,7 +3289,14 @@ open class KotlinFileExtractor(
idx: Int,
callable: Label<out DbCallable>,
enclosingStmt: Label<out DbStmt>
): Label<DbNewexpr> = extractNewExpr(useFunction<DbConstructor>(calledConstructor, constructorTypeArgs), constructedType, locId, parent, idx, callable, enclosingStmt)
): Label<DbNewexpr>? {
val funId = useFunction<DbConstructor>(calledConstructor, constructorTypeArgs)
if (funId == null) {
logger.error("Cannot get ID for newExpr function")
return null
}
return extractNewExpr(funId, constructedType, locId, parent, idx, callable, enclosingStmt)
}
private fun needsObinitFunction(c: IrClass) = c.primaryConstructor == null && c.constructors.count() > 1
@@ -3310,26 +3336,31 @@ open class KotlinFileExtractor(
extractDefaultsCallArguments(it, e.symbol.owner, callable, enclosingStmt, valueArgs, null, null)
}
} else {
extractNewExpr(e.symbol.owner, eType.arguments, type, locId, parent, idx, callable, enclosingStmt).also {
val realCallTarget = e.symbol.owner.realOverrideTarget
// Generated constructor calls to kotlin.Enum have no arguments in IR, but the constructor takes two parameters.
if (e is IrEnumConstructorCall &&
realCallTarget is IrConstructor &&
realCallTarget.parentClassOrNull?.fqNameWhenAvailable?.asString() == "kotlin.Enum" &&
realCallTarget.valueParameters.size == 2 &&
realCallTarget.valueParameters[0].type == pluginContext.irBuiltIns.stringType &&
realCallTarget.valueParameters[1].type == pluginContext.irBuiltIns.intType) {
val id0 = extractNull(pluginContext.irBuiltIns.stringType, locId, it, 0, callable, enclosingStmt)
tw.writeCompiler_generated(id0, CompilerGeneratedKinds.ENUM_CONSTRUCTOR_ARGUMENT.kind)
val id1 = extractConstantInteger(0, locId, it, 1, callable, enclosingStmt)
tw.writeCompiler_generated(id1, CompilerGeneratedKinds.ENUM_CONSTRUCTOR_ARGUMENT.kind)
} else {
extractCallValueArguments(it, e, enclosingStmt, callable, 0)
}
val newExprId = extractNewExpr(e.symbol.owner, eType.arguments, type, locId, parent, idx, callable, enclosingStmt)
if (newExprId == null) {
logger.errorElement("Cannot get newExpr ID", e)
return
}
val realCallTarget = e.symbol.owner.realOverrideTarget
// Generated constructor calls to kotlin.Enum have no arguments in IR, but the constructor takes two parameters.
if (e is IrEnumConstructorCall &&
realCallTarget is IrConstructor &&
realCallTarget.parentClassOrNull?.fqNameWhenAvailable?.asString() == "kotlin.Enum" &&
realCallTarget.valueParameters.size == 2 &&
realCallTarget.valueParameters[0].type == pluginContext.irBuiltIns.stringType &&
realCallTarget.valueParameters[1].type == pluginContext.irBuiltIns.intType) {
val id0 = extractNull(pluginContext.irBuiltIns.stringType, locId, newExprId, 0, callable, enclosingStmt)
tw.writeCompiler_generated(id0, CompilerGeneratedKinds.ENUM_CONSTRUCTOR_ARGUMENT.kind)
val id1 = extractConstantInteger(0, locId, newExprId, 1, callable, enclosingStmt)
tw.writeCompiler_generated(id1, CompilerGeneratedKinds.ENUM_CONSTRUCTOR_ARGUMENT.kind)
} else {
extractCallValueArguments(newExprId, e, enclosingStmt, callable, 0)
}
newExprId
}
if (isAnonymous) {
@@ -3698,9 +3729,13 @@ open class KotlinFileExtractor(
val locId = tw.getLocation(e)
val methodId = useFunction<DbConstructor>(e.symbol.owner)
if (methodId == null) {
logger.errorElement("Cannot get ID for delegating constructor", e)
} else {
tw.writeCallableBinding(id.cast<DbCaller>(), methodId)
}
tw.writeHasLocation(id, locId)
tw.writeCallableBinding(id.cast<DbCaller>(), methodId)
extractCallValueArguments(id, e, id, callable, 0)
val dr = e.dispatchReceiver
if (dr != null) {
@@ -4636,7 +4671,11 @@ open class KotlinFileExtractor(
extractExprContext(callId, locId, labels.methodId, retId)
val callableId = useFunction<DbCallable>(target.owner.realOverrideTarget, classTypeArgsIncludingOuterClasses)
tw.writeCallableBinding(callId.cast<DbCaller>(), callableId)
if (callableId == null) {
logger.error("Cannot get ID for reflection target")
} else {
tw.writeCallableBinding(callId.cast<DbCaller>(), callableId)
}
val useFirstArgAsDispatch: Boolean
if (dispatchReceiverInfo != null) {
@@ -4818,20 +4857,24 @@ open class KotlinFileExtractor(
val getterReturnType = parameterTypes.last()
if (getter != null) {
val getLabels = addFunctionManual(tw.getFreshIdLabel(), OperatorNameConventions.GET.asString(), getterParameterTypes, getterReturnType, classId, locId)
val getterCallableId = useFunction<DbCallable>(getter.owner.realOverrideTarget, classTypeArguments)
if (getterCallableId == null) {
logger.errorElement("Cannot get ID for getter", propertyReferenceExpr)
} else {
val getLabels = addFunctionManual(tw.getFreshIdLabel(), OperatorNameConventions.GET.asString(), getterParameterTypes, getterReturnType, classId, locId)
helper.extractCallToReflectionTarget(
getLabels,
getter,
getterReturnType,
expressionTypeArguments,
classTypeArguments
)
helper.extractCallToReflectionTarget(
getLabels,
getter,
getterReturnType,
expressionTypeArguments,
classTypeArguments
)
tw.writePropertyRefGetBinding(idPropertyRef, getterCallableId)
tw.writePropertyRefGetBinding(idPropertyRef, getterCallableId)
helper.extractPropertyReferenceInvoke(getLabels.methodId, getterParameterTypes, getterReturnType)
helper.extractPropertyReferenceInvoke(getLabels.methodId, getterParameterTypes, getterReturnType)
}
} else {
// Property without a getter.
if (backingField == null) {
@@ -4852,19 +4895,22 @@ open class KotlinFileExtractor(
}
if (setter != null) {
val setLabels = addFunctionManual(tw.getFreshIdLabel(), OperatorNameConventions.SET.asString(), parameterTypes, pluginContext.irBuiltIns.unitType, classId, locId)
val setterCallableId = useFunction<DbCallable>(setter.owner.realOverrideTarget, classTypeArguments)
if (setterCallableId == null) {
logger.errorElement("Cannot get ID for setter", propertyReferenceExpr)
} else {
val setLabels = addFunctionManual(tw.getFreshIdLabel(), OperatorNameConventions.SET.asString(), parameterTypes, pluginContext.irBuiltIns.unitType, classId, locId)
helper.extractCallToReflectionTarget(
setLabels,
setter,
pluginContext.irBuiltIns.unitType,
expressionTypeArguments,
classTypeArguments
)
helper.extractCallToReflectionTarget(
setLabels,
setter,
pluginContext.irBuiltIns.unitType,
expressionTypeArguments,
classTypeArguments
)
tw.writePropertyRefSetBinding(idPropertyRef, setterCallableId)
tw.writePropertyRefSetBinding(idPropertyRef, setterCallableId)
}
} else {
if (backingField != null && !backingField.owner.isFinal) {
val setLabels = addFunctionManual(tw.getFreshIdLabel(), OperatorNameConventions.SET.asString(), parameterTypes, pluginContext.irBuiltIns.unitType, classId, locId)
@@ -4999,7 +5045,11 @@ open class KotlinFileExtractor(
tw.writeCallableBinding(idMemberRef, ids.constructor)
val targetCallableId = useFunction<DbCallable>(target.owner.realOverrideTarget, classTypeArguments)
tw.writeMemberRefBinding(idMemberRef, targetCallableId)
if (targetCallableId == null) {
logger.errorElement("Cannot get ID for function reference callable", functionReferenceExpr)
} else {
tw.writeMemberRefBinding(idMemberRef, targetCallableId)
}
val helper = CallableReferenceHelper(functionReferenceExpr, locId, ids)
@@ -5145,7 +5195,11 @@ open class KotlinFileExtractor(
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
extractExprContext(callId, locId, funLabels.methodId, retId)
val calledMethodId = useFunction<DbMethod>(lambda)
tw.writeCallableBinding(callId, calledMethodId)
if (calledMethodId == null) {
logger.errorElement("Cannot get ID for called lambda", lambda)
} else {
tw.writeCallableBinding(callId, calledMethodId)
}
// this access
extractThisAccess(ids.type, funLabels.methodId, callId, -1, retId, locId)
@@ -5614,7 +5668,11 @@ open class KotlinFileExtractor(
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
extractExprContext(callId, locId, ids.function, returnId)
val calledMethodId = useFunction<DbMethod>(invokeMethod, functionType.arguments)
tw.writeCallableBinding(callId, calledMethodId)
if (calledMethodId == null) {
logger.errorElement("Cannot get ID for called method", invokeMethod)
} else {
tw.writeCallableBinding(callId, calledMethodId)
}
// <fn> access
val lhsId = tw.getFreshIdLabel<DbVaraccess>()
@@ -5737,14 +5795,17 @@ open class KotlinFileExtractor(
if (baseConstructor == null) {
logger.warnElement("Cannot find base constructor", elementToReportOn)
} else {
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt>()
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.constructor)
val baseConstructorId = useFunction<DbConstructor>(baseConstructor)
if (baseConstructorId == null) {
logger.errorElement("Cannot find base constructor ID", elementToReportOn)
} else {
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt>()
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.constructor)
tw.writeHasLocation(superCallId, locId)
tw.writeCallableBinding(superCallId.cast<DbCaller>(), baseConstructorId)
extractSuperconstructorArgs(superCallId)
tw.writeHasLocation(superCallId, locId)
tw.writeCallableBinding(superCallId.cast<DbCaller>(), baseConstructorId)
extractSuperconstructorArgs(superCallId)
}
}
}

View File

@@ -1322,16 +1322,30 @@ open class KotlinUsesExtractor(
else -> false
}
fun <T: DbCallable> useFunction(f: IrFunction, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>? = null, noReplace: Boolean = false): Label<out T> {
return useFunction(f, null, classTypeArgsIncludingOuterClasses, noReplace)
}
fun <T: DbCallable> useFunction(f: IrFunction, parentId: Label<out DbElement>?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, noReplace: Boolean = false): Label<out T> {
fun <T: DbCallable> useFunction(f: IrFunction, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>? = null, noReplace: Boolean = false): Label<out T>? {
if (f.isLocalFunction()) {
val ids = getLocallyVisibleFunctionLabels(f)
return ids.function.cast<T>()
}
val javaFun = kotlinFunctionToJavaEquivalent(f, noReplace)
val parentId = useDeclarationParent(javaFun.parent, false, classTypeArgsIncludingOuterClasses, true)
if (parentId == null) {
logger.error("Couldn't find parent ID for function ${f.name.asString()}")
return null
}
return useFunction(f, javaFun, parentId, classTypeArgsIncludingOuterClasses)
}
fun <T: DbCallable> useFunction(f: IrFunction, parentId: Label<out DbElement>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, noReplace: Boolean = false): Label<out T> {
if (f.isLocalFunction()) {
val ids = getLocallyVisibleFunctionLabels(f)
return ids.function.cast<T>()
}
val javaFun = kotlinFunctionToJavaEquivalent(f, noReplace)
return useFunction(f, javaFun, parentId, classTypeArgsIncludingOuterClasses)
}
private fun <T: DbCallable> useFunction(f: IrFunction, javaFun: IrFunction, parentId: Label<out DbElement>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?): Label<out T> {
val label = getFunctionLabel(javaFun, parentId, classTypeArgsIncludingOuterClasses)
val id: Label<T> = tw.getLabelFor(label) {
extractPrivateSpecialisedDeclaration(f, classTypeArgsIncludingOuterClasses)