Skip to content

Commit

Permalink
KT-43399 properly erase extension receiver type in property$annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
dnpetrov committed Nov 23, 2020
1 parent 551d0c1 commit 2662679
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ private val lateinitUsageLoweringPhase = makeIrFilePhase(
internal val propertiesPhase = makeIrFilePhase(
::JvmPropertiesLowering,
name = "Properties",
description = "Move fields and accessors for properties to their classes, replace calls to default property accessors " +
"with field accesses, remove unused accessors and create synthetic methods for property annotations",
description = "Move fields and accessors for properties to their classes, " +
"replace calls to default property accessors with field accesses, " +
"remove unused accessors and create synthetic methods for property annotations",
stickyPostconditions = setOf((PropertiesLowering)::checkNoProperties)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.coerceToUnit
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
Expand Down Expand Up @@ -69,7 +68,13 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE
}

private fun IrBuilderWithScope.substituteSetter(irProperty: IrProperty, expression: IrCall): IrExpression =
patchReceiver(irSetField(expression.dispatchReceiver, irProperty.resolveFakeOverride()!!.backingField!!, expression.getValueArgument(0)!!))
patchReceiver(
irSetField(
expression.dispatchReceiver,
irProperty.resolveFakeOverride()!!.backingField!!,
expression.getValueArgument(0)!!
)
)

private fun IrBuilderWithScope.substituteGetter(irProperty: IrProperty, expression: IrCall): IrExpression {
val backingField = irProperty.resolveFakeOverride()!!.backingField!!
Expand Down Expand Up @@ -131,8 +136,10 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE
returnType = backendContext.irBuiltIns.unitType
}.apply {
declaration.getter?.extensionReceiverParameter?.let { extensionReceiver ->
// Use raw type of extension receiver to avoid generic signature, which would be useless for this method.
extensionReceiverParameter = extensionReceiver.copyTo(this, type = extensionReceiver.type.classifierOrFail.typeWith())
extensionReceiverParameter = extensionReceiver.copyTo(
this,
type = extensionReceiver.type.erasePropertyAnnotationsExtensionReceiverType()
)
}

body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
Expand All @@ -142,6 +149,30 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE
metadata = declaration.metadata
}

private fun IrType.erasePropertyAnnotationsExtensionReceiverType(): IrType {
// Use raw type of extension receiver to avoid generic signature,
// which should not be generated for '...$annotations' method.
val classifier = classifierOrFail
return if (this is IrSimpleType && isArray()) {
when (val arg0 = arguments[0]) {
is IrStarProjection -> {
// 'Array<*>' becomes 'Array<*>'
this
}
is IrTypeProjection -> {
// 'Array<VARIANCE TYPE>' becomes 'Array<VARIANCE erase(TYPE)>'
classifier.typeWithArguments(
listOf(makeTypeProjection(arg0.type.erasePropertyAnnotationsExtensionReceiverType(), arg0.variance))
)
}
else ->
throw AssertionError("Unexpected type argument: $arg0")
}
} else {
classifier.typeWith()
}
}

private fun computeSyntheticMethodName(property: IrProperty): String {
val baseName =
if (backendContext.state.languageVersionSettings.supportsFeature(LanguageFeature.UseGetterNameForPropertyAnnotationsMethodOnJvm)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,13 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon

override fun KotlinTypeMarker.getArgument(index: Int): TypeArgumentMarker =
when (this) {
is IrSimpleType -> arguments[index]
else -> error("Type $this has no arguments")
is IrSimpleType ->
if (index >= arguments.size)
error("No argument $index in type '${this.render()}'")
else
arguments[index]
else ->
error("Type $this has no arguments")
}

override fun KotlinTypeMarker.asTypeArgument() = this as IrTypeArgument
Expand Down
21 changes: 21 additions & 0 deletions compiler/testData/codegen/bytecodeListing/annotations/kt43399.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
interface B {
@A
val Array<Int>.a: Int

@A
val Array<Array<Int>>.b: Int

@A
val Array<IntArray>.c: Int

@A
val Array<*>.d: Int

@A
val Array<out String>.e: Int

@A
val Array<in String>.f: Int
}

annotation class A
29 changes: 29 additions & 0 deletions compiler/testData/codegen/bytecodeListing/annotations/kt43399.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class A {
// source: 'kt43399.kt'
}

@kotlin.Metadata
public final class B$DefaultImpls {
// source: 'kt43399.kt'
public synthetic deprecated static @A method getA$annotations(p0: java.lang.Integer[]): void
public synthetic deprecated static @A method getB$annotations(p0: java.lang.Integer[][]): void
public synthetic deprecated static @A method getC$annotations(p0: int[][]): void
public synthetic deprecated static @A method getD$annotations(p0: java.lang.Object[]): void
public synthetic deprecated static @A method getE$annotations(p0: java.lang.String[]): void
public synthetic deprecated static @A method getF$annotations(p0: java.lang.Object[]): void
public final inner class B$DefaultImpls
}

@kotlin.Metadata
public interface B {
// source: 'kt43399.kt'
public abstract method getA(@org.jetbrains.annotations.NotNull p0: java.lang.Integer[]): int
public abstract method getB(@org.jetbrains.annotations.NotNull p0: java.lang.Integer[][]): int
public abstract method getC(@org.jetbrains.annotations.NotNull p0: int[][]): int
public abstract method getD(@org.jetbrains.annotations.NotNull p0: java.lang.Object[]): int
public abstract method getE(@org.jetbrains.annotations.NotNull p0: java.lang.String[]): int
public abstract method getF(@org.jetbrains.annotations.NotNull p0: java.lang.Object[]): int
public final inner class B$DefaultImpls
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2662679

Please sign in to comment.