Intrinsics for 'reversed': infrastructure & primitive range support
#KT-21323 In Progress
This commit is contained in:
@@ -188,6 +188,14 @@ fun isPrimitiveNumberRangeExtensionContainsPrimitiveNumber(descriptor: CallableD
|
||||
return true
|
||||
}
|
||||
|
||||
fun isPrimitiveProgressionReverse(descriptor: CallableDescriptor): Boolean {
|
||||
if (!isTopLevelInPackage(descriptor, "reversed", "kotlin.ranges")) return false
|
||||
if (descriptor.valueParameters.isNotEmpty()) return false
|
||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return false
|
||||
if (!isPrimitiveProgression(extensionReceiverType)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isPrimitiveNumberType(type: KotlinType) =
|
||||
KotlinBuiltIns.isByte(type) ||
|
||||
KotlinBuiltIns.isShort(type) ||
|
||||
|
||||
+6
-1
@@ -33,7 +33,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class PrimitiveNumberRangeLiteralRangeValue(
|
||||
rangeCall: ResolvedCall<out CallableDescriptor>
|
||||
): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
|
||||
) : PrimitiveNumberRangeIntrinsicRangeValue(rangeCall),
|
||||
ReversableRangeValue {
|
||||
|
||||
override fun getBoundedValue(codegen: ExpressionCodegen) =
|
||||
SimpleBoundedValue(codegen, rangeCall)
|
||||
@@ -42,6 +43,10 @@ class PrimitiveNumberRangeLiteralRangeValue(
|
||||
getConstRangeForInRangeLiteralGenerator(codegen, forExpression) ?:
|
||||
ForInSimpleProgressionLoopGenerator.fromBoundedValueWithStep1(codegen, forExpression, getBoundedValue(codegen))
|
||||
|
||||
override fun createForInReversedLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator =
|
||||
// TODO const-bounded version
|
||||
ForInSimpleProgressionLoopGenerator.fromBoundedValueWithStepMinus1(codegen, forExpression, getBoundedValue(codegen))
|
||||
|
||||
private fun getConstRangeForInRangeLiteralGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator? {
|
||||
val rhsExpression = rangeCall.valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() } ?: return null
|
||||
val constValue = codegen.getCompileTimeConstant(rhsExpression).safeAs<IntegerValueConstant<*>>() ?: return null
|
||||
|
||||
@@ -32,6 +32,11 @@ interface RangeValue {
|
||||
}
|
||||
|
||||
|
||||
interface ReversableRangeValue : RangeValue {
|
||||
fun createForInReversedLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator
|
||||
}
|
||||
|
||||
|
||||
interface BoundedValue {
|
||||
val instanceType: Type
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -127,7 +128,15 @@ private fun ExpressionCodegen.createIntrinsifiedRangeValueOrNull(rangeCall: Reso
|
||||
CharSequenceIndicesRangeValue(rangeCall)
|
||||
isComparableRangeTo(rangeCallee) ->
|
||||
ComparableRangeLiteralRangeValue(this, rangeCall)
|
||||
isPrimitiveProgressionReverse(rangeCallee) ->
|
||||
createReversedRangeValueOrNull(rangeCall)
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExpressionCodegen.createReversedRangeValueOrNull(rangeCall: ResolvedCall<out CallableDescriptor>): RangeValue? {
|
||||
val receiver = rangeCall.extensionReceiver as? ExpressionReceiver ?: return null
|
||||
val receiverRangeValue = createRangeValueForExpression(receiver.expression) as? ReversableRangeValue ?: return null
|
||||
return ReversedRangeValue(receiverRangeValue)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
|
||||
class ReversedRangeValue(private val original: ReversableRangeValue) : RangeValue, ReversableRangeValue {
|
||||
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
||||
original.createInExpressionGenerator(codegen, operatorReference)
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator =
|
||||
original.createForInReversedLoopGenerator(codegen, forExpression)
|
||||
|
||||
override fun createForInReversedLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator =
|
||||
original.createForLoopGenerator(codegen, forExpression)
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun box(): String {
|
||||
for (i in (4 .. 1).reversed()) {
|
||||
throw AssertionError("Loop should not be executed")
|
||||
}
|
||||
for (i in (4L .. 1L).reversed()) {
|
||||
throw AssertionError("Loop should not be executed")
|
||||
}
|
||||
for (i in ('D' .. 'A').reversed()) {
|
||||
throw AssertionError("Loop should not be executed")
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// WITH_RUNTIME
|
||||
import kotlin.test.*
|
||||
|
||||
fun box(): String {
|
||||
var sum = 0
|
||||
for (i in (1 .. 4).reversed()) {
|
||||
sum = sum * 10 + i
|
||||
}
|
||||
assertEquals(4321, sum)
|
||||
|
||||
var sumL = 0L
|
||||
for (i in (1L .. 4L).reversed()) {
|
||||
sumL = sumL * 10 + i
|
||||
}
|
||||
assertEquals(4321L, sumL)
|
||||
|
||||
var sumC = 0
|
||||
for (i in ('1' .. '4').reversed()) {
|
||||
sumC = sumC * 10 + i.toInt() - '0'.toInt()
|
||||
}
|
||||
assertEquals(4321, sumC)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun box(): String {
|
||||
for (i in (4 .. 1).reversed()) {
|
||||
throw AssertionError("Loop should not be executed")
|
||||
}
|
||||
for (i in (4L .. 1L).reversed()) {
|
||||
throw AssertionError("Loop should not be executed")
|
||||
}
|
||||
for (i in ('D' .. 'A').reversed()) {
|
||||
throw AssertionError("Loop should not be executed")
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 0 reversed
|
||||
// 0 getFirst
|
||||
// 0 getLast
|
||||
// 0 getStep
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// WITH_RUNTIME
|
||||
import kotlin.test.*
|
||||
|
||||
fun box(): String {
|
||||
var sum = 0
|
||||
for (i in (1 .. 4).reversed()) {
|
||||
sum = sum * 10 + i
|
||||
}
|
||||
assertEquals(4321, sum)
|
||||
|
||||
var sumL = 0L
|
||||
for (i in (1L .. 4L).reversed()) {
|
||||
sumL = sumL * 10 + i
|
||||
}
|
||||
assertEquals(4321L, sumL)
|
||||
|
||||
var sumC = 0
|
||||
for (i in ('1' .. '4').reversed()) {
|
||||
sumC = sumC * 10 + i.toInt() - '0'.toInt()
|
||||
}
|
||||
assertEquals(4321, sumC)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 0 reversed
|
||||
// 0 getFirst
|
||||
// 0 getLast
|
||||
// 0 getStep
|
||||
+21
@@ -15233,6 +15233,27 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInReversed")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ForInReversed extends AbstractIrBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInForInReversed() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRangeLiteral.kt")
|
||||
public void testForInReversedEmptyRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||
public void testForInReversedRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -15233,6 +15233,27 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInReversed")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ForInReversed extends AbstractBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInForInReversed() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRangeLiteral.kt")
|
||||
public void testForInReversedEmptyRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||
public void testForInReversedRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -1399,6 +1399,27 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInReversed")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ForInReversed extends AbstractBytecodeTextTest {
|
||||
public void testAllFilesPresentInForInReversed() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRangeLiteral.kt")
|
||||
public void testForInReversedEmptyRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInReversed/forInReversedEmptyRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||
public void testForInReversedRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInReversed/forInReversedRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/hashCode")
|
||||
|
||||
@@ -15233,6 +15233,27 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInReversed")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ForInReversed extends AbstractLightAnalysisModeTest {
|
||||
public void testAllFilesPresentInForInReversed() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRangeLiteral.kt")
|
||||
public void testForInReversedEmptyRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||
public void testForInReversedRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+21
@@ -16649,6 +16649,27 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInReversed")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ForInReversed extends AbstractJsCodegenBoxTest {
|
||||
public void testAllFilesPresentInForInReversed() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRangeLiteral.kt")
|
||||
public void testForInReversedEmptyRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||
public void testForInReversedRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user