JVM IR: lookup symbols by name in ProgressionHandlers in known classes only

Alternatively, we could improve the lookup utilities and their usages to
always find the exact override of a symbol from
Collection/Iterable/CharSequence/etc, but since we need to load the
original symbol anyway in cases when the loop subject's type is a type
parameter, we might as well simplify everything and always reference the
original symbol.

Also improve exception message and removed unused declarations in
IrBackendUtils.kt.
This commit is contained in:
Alexander Udalov
2019-11-29 13:15:12 +01:00
parent 359e49fa02
commit 025360edc4
16 changed files with 221 additions and 39 deletions
@@ -73,6 +73,7 @@ open class BuiltinSymbolsBase(protected val builtIns: KotlinBuiltIns, private va
val iterator = getClass(Name.identifier("Iterator"), "kotlin", "collections")
val charSequence = getClass(Name.identifier("CharSequence"), "kotlin")
val string = getClass(Name.identifier("String"), "kotlin")
val primitiveIteratorsByType = PrimitiveType.values().associate { type ->
val iteratorClass = getClass(Name.identifier(type.typeName.asString() + "Iterator"), "kotlin", "collections")
@@ -272,6 +272,7 @@ internal abstract class HeaderInfoBuilder(context: CommonBackendContext, private
private val progressionHandlers = listOf(
CollectionIndicesHandler(context),
ArrayIndicesHandler(context),
CharSequenceIndicesHandler(context),
UntilHandler(context, progressionElementTypes),
DownToHandler(context, progressionElementTypes),
@@ -512,16 +512,25 @@ internal abstract class IndicesHandler(protected val context: CommonBackendConte
internal class CollectionIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
override val matcher = SimpleCalleeMatcher {
extensionReceiver { it != null && it.type.run { isArray() || isPrimitiveArray() || isCollection() } }
extensionReceiver { it?.type?.isCollection() == true }
fqName { it == FqName("kotlin.collections.<get-indices>") }
parameterCount { it == 0 }
}
// The lowering operates on subtypes of Collection. Therefore, the IrType could be
// a type parameter bounded by Collection. When that is the case, we cannot get
// the class from the type and instead uses the Collection getter.
override val IrType.sizePropertyGetter
get() = getClass()?.getPropertyGetter("size")?.owner ?: context.ir.symbols.collection.getPropertyGetter("size")!!.owner
override val IrType.sizePropertyGetter: IrSimpleFunction
get() = context.ir.symbols.collection.getPropertyGetter("size")!!.owner
}
internal class ArrayIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
override val matcher = SimpleCalleeMatcher {
extensionReceiver { it != null && it.type.run { isArray() || isPrimitiveArray() } }
fqName { it == FqName("kotlin.collections.<get-indices>") }
parameterCount { it == 0 }
}
override val IrType.sizePropertyGetter: IrSimpleFunction
get() = getClass()!!.getPropertyGetter("size")!!.owner
}
internal class CharSequenceIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
@@ -532,11 +541,8 @@ internal class CharSequenceIndicesHandler(context: CommonBackendContext) : Indic
parameterCount { it == 0 }
}
// The lowering operates on subtypes of CharSequence. Therefore, the IrType could be
// a type parameter bounded by CharSequence. When that is the case, we cannot get
// the class from the type and instead uses the CharSequence getter.
override val IrType.sizePropertyGetter
get() = getClass()?.getPropertyGetter("length")?.owner ?: context.ir.symbols.charSequence.getPropertyGetter("length")!!.owner
override val IrType.sizePropertyGetter: IrSimpleFunction
get() = context.ir.symbols.charSequence.getPropertyGetter("length")!!.owner
}
/** Builds a [HeaderInfo] for calls to reverse an iterable. */
@@ -673,18 +679,11 @@ internal open class CharSequenceIterationHandler(context: CommonBackendContext,
parameterCount { it == 0 }
}
// The lowering operates on subtypes of CharSequence. Therefore, the IrType could be
// a type parameter bounded by CharSequence. When that is the case, we cannot get
// the class from the type and instead uses the CharSequence getter and function.
override val IrType.sizePropertyGetter
get() = getClass()?.getPropertyGetter("length")?.owner ?: context.ir.symbols.charSequence.getPropertyGetter("length")!!.owner
override val IrType.sizePropertyGetter: IrSimpleFunction
get() = context.ir.symbols.charSequence.getPropertyGetter("length")!!.owner
override val IrType.getFunction
get() = getClass()?.functions?.single {
it.name == OperatorNameConventions.GET &&
it.valueParameters.size == 1 &&
it.valueParameters[0].type.isInt()
} ?: context.ir.symbols.charSequence.getSimpleFunction(OperatorNameConventions.GET.asString())!!.owner
override val IrType.getFunction: IrSimpleFunction
get() = context.ir.symbols.charSequence.getSimpleFunction(OperatorNameConventions.GET.asString())!!.owner
}
/**
@@ -694,6 +693,12 @@ internal open class CharSequenceIterationHandler(context: CommonBackendContext,
*/
internal class StringIterationHandler(context: CommonBackendContext) : CharSequenceIterationHandler(context, canCacheLast = true) {
override fun matchIterable(expression: IrExpression) = expression.type.isString()
override val IrType.sizePropertyGetter: IrSimpleFunction
get() = context.ir.symbols.string.getPropertyGetter("length")!!.owner
override val IrType.getFunction: IrSimpleFunction
get() = context.ir.symbols.string.getSimpleFunction(OperatorNameConventions.GET.asString())!!.owner
}
/** Builds a [HeaderInfo] for calls to `withIndex()`. */
@@ -740,13 +745,7 @@ internal open class DefaultIterableHandler(private val context: CommonBackendCon
override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
// The lowering operates on subtypes of Iterable. Therefore, the IrType could be
// a type parameter bounded by Iterable. When that is the case, we cannot get
// the class from the type and instead uses the Iterable.iterator() function.
val iteratorFun = expression.type.getClass()?.functions?.single {
it.name == OperatorNameConventions.ITERATOR &&
it.valueParameters.isEmpty()
} ?: iterableClassSymbol.getSimpleFunction(OperatorNameConventions.ITERATOR.asString())!!.owner
val iteratorFun = iterableClassSymbol.getSimpleFunction(OperatorNameConventions.ITERATOR.asString())!!.owner
IterableHeaderInfo(
scope.createTmpVariable(irCall(iteratorFun).apply { dispatchReceiver = expression }, nameHint = "iterator")
)
@@ -16,18 +16,24 @@
package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
fun IrClass.getPropertyDeclaration(name: String) =
declarations.filterIsInstance<IrProperty>().atMostOne { it.name.asString() == name }
private fun IrClass.getPropertyDeclaration(name: String): IrProperty? {
val properties = declarations.filterIsInstance<IrProperty>().filter { it.name.asString() == name }
if (properties.size > 1) {
error(
"More than one property with name $name in class $fqNameWhenAvailable:\n" +
properties.joinToString("\n", transform = IrProperty::render)
)
}
return properties.firstOrNull()
}
fun IrClass.getSimpleFunction(name: String): IrSimpleFunctionSymbol? =
private fun IrClass.getSimpleFunction(name: String): IrSimpleFunctionSymbol? =
findDeclaration<IrSimpleFunction> { it.name.asString() == name }?.symbol
fun IrClass.getPropertyGetter(name: String): IrSimpleFunctionSymbol? =
@@ -38,11 +44,6 @@ fun IrClass.getPropertySetter(name: String): IrSimpleFunctionSymbol? =
getPropertyDeclaration(name)?.setter?.symbol
?: getSimpleFunction("<set-$name>").also { assert(it?.owner?.correspondingPropertySymbol?.owner?.name?.asString() == name) }
fun IrClass.getPropertyField(name: String): IrFieldSymbol? =
getPropertyDeclaration(name)?.backingField?.symbol
fun IrClassSymbol.getPropertyDeclaration(name: String) = owner.getPropertyDeclaration(name)
fun IrClassSymbol.getSimpleFunction(name: String): IrSimpleFunctionSymbol? = owner.getSimpleFunction(name)
fun IrClassSymbol.getPropertyGetter(name: String): IrSimpleFunctionSymbol? = owner.getPropertyGetter(name)
fun IrClassSymbol.getPropertySetter(name: String): IrSimpleFunctionSymbol? = owner.getPropertySetter(name)
fun IrClassSymbol.getPropertyField(name: String): IrFieldSymbol? = owner.getPropertyField(name)
@@ -0,0 +1,36 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
class C : CharSequence {
// Unused declarations, which are here only to confuse the backend who might lookup symbols by name
private val List<String>.length: Int
get() = size
private operator fun List<String>.get(i: Int) =
this.get(i)
override val length: Int
get() = 2
override fun get(index: Int): Char =
if (index == 0) 'O' else 'K'
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence =
throw AssertionError()
}
fun box(): String {
var result = ""
val c = C()
for (i in c.indices) {
if (i == 0) {
result += c[i]
}
}
for ((i, x) in c.withIndex()) {
if (i == 1) {
result += x
}
}
return result
}
@@ -0,0 +1,20 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
class C : Iterable<String> {
// Unused declaration, which is here only to confuse the backend who might lookup symbols by name
private fun List<Int>.iterator(): Double = size.toDouble()
override fun iterator(): Iterator<String> = listOf("OK").iterator()
}
fun box(): String {
val c = C()
for ((i, x) in c.withIndex()) {
if (i == 0) {
return x
}
}
return "Fail"
}
@@ -0,0 +1,12 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
fun box(): String {
val a = ArrayList<String>()
a.add("OK")
for (i in a.indices) {
return a[i]
}
return "Fail"
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
fun box(): String {
val a = ArrayList<String>()
a.add("OK")
for (i in a.indices) {
return a[i]
}
return "Fail"
}
// 0 iterator
@@ -19531,6 +19531,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/ranges/forInCharSequenceWithMultipleGetFunctions.kt");
}
@TestMetadata("forInCustomCharSequence.kt")
public void testForInCustomCharSequence() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomCharSequence.kt");
}
@TestMetadata("forInCustomIterable.kt")
public void testForInCustomIterable() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomIterable.kt");
}
@TestMetadata("forInRangeLiteralWithMixedTypeBounds.kt")
public void testForInRangeLiteralWithMixedTypeBounds() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInRangeLiteralWithMixedTypeBounds.kt");
@@ -20265,6 +20275,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInIndices"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("forInArrayListIndices.kt")
public void testForInArrayListIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInArrayListIndices.kt");
}
@TestMetadata("forInCharSequenceIndices.kt")
public void testForInCharSequenceIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInCharSequenceIndices.kt");
@@ -1928,6 +1928,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/forInIndices"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("forInArrayListIndices.kt")
public void testForInArrayListIndices() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInArrayListIndices.kt");
}
@TestMetadata("forInCharSequenceIndices.kt")
public void testForInCharSequenceIndices() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInCharSequenceIndices.kt");
@@ -19531,6 +19531,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/ranges/forInCharSequenceWithMultipleGetFunctions.kt");
}
@TestMetadata("forInCustomCharSequence.kt")
public void testForInCustomCharSequence() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomCharSequence.kt");
}
@TestMetadata("forInCustomIterable.kt")
public void testForInCustomIterable() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomIterable.kt");
}
@TestMetadata("forInRangeLiteralWithMixedTypeBounds.kt")
public void testForInRangeLiteralWithMixedTypeBounds() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInRangeLiteralWithMixedTypeBounds.kt");
@@ -20265,6 +20275,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInIndices"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("forInArrayListIndices.kt")
public void testForInArrayListIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInArrayListIndices.kt");
}
@TestMetadata("forInCharSequenceIndices.kt")
public void testForInCharSequenceIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInCharSequenceIndices.kt");
@@ -18015,6 +18015,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/ranges/forInCharSequenceWithMultipleGetFunctions.kt");
}
@TestMetadata("forInCustomCharSequence.kt")
public void testForInCustomCharSequence() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomCharSequence.kt");
}
@TestMetadata("forInCustomIterable.kt")
public void testForInCustomIterable() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomIterable.kt");
}
@TestMetadata("forInRangeLiteralWithMixedTypeBounds.kt")
public void testForInRangeLiteralWithMixedTypeBounds() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInRangeLiteralWithMixedTypeBounds.kt");
@@ -18749,6 +18759,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInIndices"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@TestMetadata("forInArrayListIndices.kt")
public void testForInArrayListIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInArrayListIndices.kt");
}
@TestMetadata("forInCharSequenceIndices.kt")
public void testForInCharSequenceIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInCharSequenceIndices.kt");
@@ -18015,6 +18015,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/ranges/forInCharSequenceWithMultipleGetFunctions.kt");
}
@TestMetadata("forInCustomCharSequence.kt")
public void testForInCustomCharSequence() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomCharSequence.kt");
}
@TestMetadata("forInCustomIterable.kt")
public void testForInCustomIterable() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomIterable.kt");
}
@TestMetadata("forInRangeLiteralWithMixedTypeBounds.kt")
public void testForInRangeLiteralWithMixedTypeBounds() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInRangeLiteralWithMixedTypeBounds.kt");
@@ -18749,6 +18759,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInIndices"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@TestMetadata("forInArrayListIndices.kt")
public void testForInArrayListIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInArrayListIndices.kt");
}
@TestMetadata("forInCharSequenceIndices.kt")
public void testForInCharSequenceIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInCharSequenceIndices.kt");
@@ -1883,6 +1883,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/forInIndices"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@TestMetadata("forInArrayListIndices.kt")
public void testForInArrayListIndices() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInArrayListIndices.kt");
}
@TestMetadata("forInCharSequenceIndices.kt")
public void testForInCharSequenceIndices() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInCharSequenceIndices.kt");
@@ -15196,6 +15196,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/ranges/forInCharSequenceWithMultipleGetFunctions.kt");
}
@TestMetadata("forInCustomCharSequence.kt")
public void testForInCustomCharSequence() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomCharSequence.kt");
}
@TestMetadata("forInCustomIterable.kt")
public void testForInCustomIterable() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomIterable.kt");
}
@TestMetadata("forInRangeLiteralWithMixedTypeBounds.kt")
public void testForInRangeLiteralWithMixedTypeBounds() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInRangeLiteralWithMixedTypeBounds.kt");
@@ -15925,6 +15935,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInIndices"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
}
@TestMetadata("forInArrayListIndices.kt")
public void testForInArrayListIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInArrayListIndices.kt");
}
@TestMetadata("forInCharSequenceIndices.kt")
public void testForInCharSequenceIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInCharSequenceIndices.kt");
@@ -16376,6 +16376,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/ranges/forInCharSequenceWithMultipleGetFunctions.kt");
}
@TestMetadata("forInCustomCharSequence.kt")
public void testForInCustomCharSequence() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomCharSequence.kt");
}
@TestMetadata("forInCustomIterable.kt")
public void testForInCustomIterable() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInCustomIterable.kt");
}
@TestMetadata("forInRangeLiteralWithMixedTypeBounds.kt")
public void testForInRangeLiteralWithMixedTypeBounds() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInRangeLiteralWithMixedTypeBounds.kt");
@@ -17105,6 +17115,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInIndices"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("forInArrayListIndices.kt")
public void testForInArrayListIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInArrayListIndices.kt");
}
@TestMetadata("forInCharSequenceIndices.kt")
public void testForInCharSequenceIndices() throws Exception {
runTest("compiler/testData/codegen/box/ranges/forInIndices/forInCharSequenceIndices.kt");