Skip to content

Commit 102cdcd

Browse files
committed
Fix type substitution and source locations in SAM-converted generic interface implementations
For example, in implementing Producer<T> by an actual lambda of type () -> Int, the return type should be Int, not T. This produced type-variable-out-of-scope consistency check failures.
1 parent 048a530 commit 102cdcd

File tree

2 files changed

+29
-23
lines changed

2 files changed

+29
-23
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -322,17 +322,7 @@ open class KotlinFileExtractor(
322322
val typeParamSubstitution =
323323
when (argsIncludingOuterClasses) {
324324
null -> { x: IrType, _: TypeContext, _: IrPluginContext -> x.toRawType() }
325-
else -> {
326-
makeTypeGenericSubstitutionMap(c, argsIncludingOuterClasses).let {
327-
{ x: IrType, useContext: TypeContext, pluginContext: IrPluginContext ->
328-
x.substituteTypeAndArguments(
329-
it,
330-
useContext,
331-
pluginContext
332-
)
333-
}
334-
}
335-
}
325+
else -> makeGenericSubstitutionFunction(c, argsIncludingOuterClasses)
336326
}
337327

338328
c.declarations.map {
@@ -499,12 +489,12 @@ open class KotlinFileExtractor(
499489
return FieldResult(instanceId, instanceName)
500490
}
501491

502-
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean): TypeResults {
492+
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean, locOverride: Label<DbLocation>? = null): TypeResults {
503493
with("value parameter", vp) {
504-
val location = getLocation(vp, classTypeArgsIncludingOuterClasses)
494+
val location = locOverride ?: getLocation(vp, classTypeArgsIncludingOuterClasses)
505495
val id = useValueParameter(vp, parent)
506496
if (extractTypeAccess) {
507-
extractTypeAccessRecursive(vp.type, location, id, -1)
497+
extractTypeAccessRecursive(typeSubstitution?.let { it(vp.type, TypeContext.OTHER, pluginContext) } ?: vp.type, location, id, -1)
508498
}
509499
return extractValueParameter(id, vp.type, vp.name.asString(), location, parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
510500
}
@@ -664,7 +654,7 @@ open class KotlinFileExtractor(
664654
}
665655
}
666656

667-
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, idOverride: Label<DbMethod>? = null): Label<out DbCallable>? {
657+
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, idOverride: Label<DbMethod>? = null, locOverride: Label<DbLocation>? = null): Label<out DbCallable>? {
668658
if (isFake(f)) return null
669659

670660
with("function", f) {
@@ -682,21 +672,21 @@ open class KotlinFileExtractor(
682672
useFunction<DbCallable>(f, parentId, classTypeArgsIncludingOuterClasses, noReplace = true)
683673

684674
val sourceDeclaration =
685-
if (typeSubstitution != null)
675+
if (typeSubstitution != null && idOverride == null)
686676
useFunction(f)
687677
else
688678
id
689679

690680
val extReceiver = f.extensionReceiverParameter
691681
val idxOffset = if (extReceiver != null) 1 else 0
692682
val paramTypes = f.valueParameters.mapIndexed { i, vp ->
693-
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses)
683+
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, locOverride)
694684
}
695685
val allParamTypes = if (extReceiver != null) {
696686
val extendedType = useType(extReceiver.type)
697687
tw.writeKtExtensionFunctions(id.cast<DbMethod>(), extendedType.javaResult.id, extendedType.kotlinResult.id)
698688

699-
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses)
689+
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, locOverride)
700690
listOf(t) + paramTypes
701691
} else {
702692
paramTypes
@@ -706,7 +696,7 @@ open class KotlinFileExtractor(
706696

707697
val substReturnType = typeSubstitution?.let { it(f.returnType, TypeContext.RETURN, pluginContext) } ?: f.returnType
708698

709-
val locId = getLocation(f, classTypeArgsIncludingOuterClasses)
699+
val locId = locOverride ?: getLocation(f, classTypeArgsIncludingOuterClasses)
710700

711701
if (f.symbol is IrConstructorSymbol) {
712702
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
@@ -726,7 +716,7 @@ open class KotlinFileExtractor(
726716
tw.writeMethodsKotlinType(methodId, returnType.kotlinResult.id)
727717

728718
if (extractMethodAndParameterTypeAccesses) {
729-
extractTypeAccessRecursive(f.returnType, locId, id, -1)
719+
extractTypeAccessRecursive(substReturnType, locId, id, -1)
730720
}
731721

732722
if (shortName.nameInDB != shortName.kotlinName) {
@@ -4002,7 +3992,12 @@ open class KotlinFileExtractor(
40023992
helper.extractParameterToFieldAssignmentInConstructor("<fn>", functionType, fieldId, 0, 1)
40033993

40043994
// add implementation function
4005-
extractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, null, null, ids.function)
3995+
val classTypeArgs = (e.type as? IrSimpleType)?.arguments
3996+
val typeSub = classTypeArgs?.let { makeGenericSubstitutionFunction(typeOwner, it) }
3997+
3998+
fun trySub(t: IrType, context: TypeContext) = if (typeSub == null) t else typeSub(t, context, pluginContext)
3999+
4000+
extractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, typeSub, classTypeArgs, idOverride = ids.function, locOverride = tw.getLocation(e))
40064001

40074002
//body
40084003
val blockId = tw.getFreshIdLabel<DbBlock>()
@@ -4025,7 +4020,7 @@ open class KotlinFileExtractor(
40254020

40264021
// Call to original `invoke`:
40274022
val callId = tw.getFreshIdLabel<DbMethodaccess>()
4028-
val callType = useType(samMember.returnType)
4023+
val callType = useType(trySub(samMember.returnType, TypeContext.RETURN))
40294024
tw.writeExprs_methodaccess(callId, callType.javaResult.id, returnId, 0)
40304025
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
40314026
extractCommonExpr(callId)
@@ -4049,7 +4044,7 @@ open class KotlinFileExtractor(
40494044

40504045
fun extractArgument(p: IrValueParameter, idx: Int, parent: Label<out DbExprparent>) {
40514046
val argsAccessId = tw.getFreshIdLabel<DbVaraccess>()
4052-
val paramType = useType(p.type)
4047+
val paramType = useType(trySub(p.type, TypeContext.OTHER))
40534048
tw.writeExprs_varaccess(argsAccessId, paramType.javaResult.id, parent, idx)
40544049
tw.writeExprsKotlinType(argsAccessId, paramType.kotlinResult.id)
40554050
extractCommonExpr(argsAccessId)

java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,17 @@ open class KotlinUsesExtractor(
215215
fun makeTypeGenericSubstitutionMap(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>) =
216216
getTypeParametersInScope(c).map({ it.symbol }).zip(argsIncludingOuterClasses.map { it.withQuestionMark(true) }).toMap()
217217

218+
fun makeGenericSubstitutionFunction(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>) =
219+
makeTypeGenericSubstitutionMap(c, argsIncludingOuterClasses).let {
220+
{ x: IrType, useContext: TypeContext, pluginContext: IrPluginContext ->
221+
x.substituteTypeAndArguments(
222+
it,
223+
useContext,
224+
pluginContext
225+
)
226+
}
227+
}
228+
218229
// The Kotlin compiler internal representation of Outer<A, B>.Inner<C, D>.InnerInner<E, F>.someFunction<G, H>.LocalClass<I, J> is LocalClass<I, J, G, H, E, F, C, D, A, B>. This function returns [A, B, C, D, E, F, G, H, I, J].
219230
fun orderTypeArgsLeftToRight(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?): List<IrTypeArgument>? {
220231
if(argsIncludingOuterClasses.isNullOrEmpty())

0 commit comments

Comments
 (0)