Provide intrinsic generators for in/!in expression

TODO some tests should fail because range of comparables
(e.g., '"Alpha" .. "Omega"') is currently not implemented
This commit is contained in:
Dmitry Petrov
2017-06-29 18:09:38 +03:00
parent e3320c53f5
commit a7071ae7af
24 changed files with 744 additions and 29 deletions
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenForLambda;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
import org.jetbrains.kotlin.codegen.forLoop.AbstractForLoopGenerator;
import org.jetbrains.kotlin.codegen.forLoop.ForLoopGenerator;
import org.jetbrains.kotlin.codegen.inline.*;
import org.jetbrains.kotlin.codegen.intrinsics.*;
@@ -2871,25 +2870,27 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
private StackValue generateIn(StackValue leftValue, KtExpression rangeExpression, KtSimpleNameExpression operationReference) {
KtExpression deparenthesized = KtPsiUtil.deparenthesize(rangeExpression);
assert deparenthesized != null : "For with empty range expression";
boolean isInverted = operationReference.getReferencedNameElementType() == KtTokens.NOT_IN;
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
if (RangeCodegenUtilKt.isPrimitiveRangeSpecializationOfType(leftValue.type, deparenthesized, bindingContext) ||
RangeCodegenUtilKt.isPrimitiveRangeToExtension(operationReference, bindingContext)) {
generateInPrimitiveRange(leftValue, (KtBinaryExpression) deparenthesized, isInverted);
}
else {
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt
.getResolvedCallWithAssert(operationReference, bindingContext);
StackValue result = invokeFunction(resolvedCall.getCall(), resolvedCall, StackValue.none());
result.put(result.type, v);
if (isInverted) {
genInvertBoolean(v);
}
}
return null;
});
RangeValue rangeValue = RangeValuesKt.createRangeValueForExpression(this, deparenthesized);
return rangeValue.createInExpressionGenerator(this, operationReference).generate(leftValue);
//boolean isInverted = operationReference.getReferencedNameElementType() == KtTokens.NOT_IN;
//return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
// if (RangeCodegenUtilKt.isPrimitiveRangeSpecializationOfType(leftValue.type, deparenthesized, bindingContext) ||
// RangeCodegenUtilKt.isPrimitiveRangeToExtension(operationReference, bindingContext)) {
// generateInPrimitiveRange(leftValue, (KtBinaryExpression) deparenthesized, isInverted);
// }
// else {
// ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt
// .getResolvedCallWithAssert(operationReference, bindingContext);
// StackValue result = invokeFunction(resolvedCall.getCall(), resolvedCall, StackValue.none());
// result.put(result.type, v);
// if (isInverted) {
// genInvertBoolean(v);
// }
// }
// return null;
//});
}
/*
@@ -55,7 +55,7 @@ fun isRange(rangeType: KotlinType) =
fun isProgression(rangeType: KotlinType) =
!rangeType.isMarkedNullable && getPrimitiveProgressionElementType(rangeType) != null
private fun getPrimitiveRangeElementType(rangeType: KotlinType) =
fun getPrimitiveRangeElementType(rangeType: KotlinType) =
getPrimitiveRangeOrProgressionElementType(rangeType, RANGE_TO_ELEMENT_TYPE)
private fun getPrimitiveProgressionElementType(rangeType: KotlinType) =
@@ -0,0 +1,175 @@
/*
* 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.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
abstract class AbstractInPrimitiveNumberRangeExpressionGenerator(
val codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<*>,
private val isInclusiveHighBound: Boolean
) : InExpressionGenerator {
protected val asmElementType =
AsmTypes.valueTypeForPrimitive(
getPrimitiveRangeElementType(rangeCall.resultingDescriptor.returnType!!)
)
private val isInverted =
operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
protected abstract fun genLowBound(): StackValue
protected abstract fun genHighBound(): StackValue
override fun generate(argument: StackValue): BranchedValue =
gen(argument).let { if (isInverted) Invert(it) else it }
private fun gen(argument: StackValue): BranchedValue =
object : BranchedValue(argument, null, asmElementType, Opcodes.IFEQ) {
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
if (jumpIfFalse) {
// arg1 in low .. high
// arg1 >= low && arg1 <[=] high
val cmpHighLabel = Label()
arg1.put(operandType, v)
AsmUtil.dup(v, operandType)
genLowBound().put(operandType, v)
v.jumpIfGe(cmpHighLabel)
AsmUtil.pop(v, operandType)
v.goTo(jumpLabel)
v.mark(cmpHighLabel)
genHighBound().put(operandType, v)
if (isInclusiveHighBound) {
v.jumpIfGt(jumpLabel)
}
else {
v.jumpIfGe(jumpLabel)
}
}
else {
// arg1 !in low .. high
// arg1 < low || arg1 >[=] high
val trueLabel1 = Label()
val trueLabel2 = Label()
arg1.put(operandType, v)
AsmUtil.dup(v, operandType)
genLowBound().put(operandType, v)
v.jumpIfLt(trueLabel1)
genLowBound().put(operandType, v)
if (isInclusiveHighBound) {
v.jumpIfLe(jumpLabel)
}
else {
v.jumpIfLt(jumpLabel)
}
v.goTo(trueLabel2)
v.mark(trueLabel1)
AsmUtil.pop(v, operandType)
v.mark(trueLabel2)
}
}
private fun InstructionAdapter.jumpIfGe(label: Label) {
when {
AsmUtil.isIntPrimitive(operandType) -> ificmpge(label)
operandType === Type.LONG_TYPE -> {
lcmp()
ifge(label)
}
operandType === Type.FLOAT_TYPE || operandType === Type.DOUBLE_TYPE -> {
cmpg(operandType)
ifge(label)
}
else -> throw UnsupportedOperationException("Unexpected type: " + operandType)
}
}
private fun InstructionAdapter.jumpIfLe(label: Label) {
when {
AsmUtil.isIntPrimitive(operandType) -> ificmple(label)
operandType === Type.LONG_TYPE -> {
lcmp()
ifle(label)
}
operandType === Type.FLOAT_TYPE || operandType === Type.DOUBLE_TYPE -> {
cmpg(operandType)
ifle(label)
}
else -> throw UnsupportedOperationException("Unexpected type: " + operandType)
}
}
private fun InstructionAdapter.jumpIfGt(label: Label) {
when {
AsmUtil.isIntPrimitive(operandType) -> ificmpgt(label)
operandType === Type.LONG_TYPE -> {
lcmp()
ifgt(label)
}
operandType === Type.FLOAT_TYPE || operandType === Type.DOUBLE_TYPE -> {
cmpg(operandType)
ifgt(label)
}
else -> throw UnsupportedOperationException("Unexpected type: " + operandType)
}
}
private fun InstructionAdapter.jumpIfLt(label: Label) {
when {
AsmUtil.isIntPrimitive(operandType) -> ificmplt(label)
operandType === Type.LONG_TYPE -> {
lcmp()
iflt(label)
}
operandType === Type.FLOAT_TYPE || operandType === Type.DOUBLE_TYPE -> {
cmpg(operandType)
iflt(label)
}
else -> throw UnsupportedOperationException("Unexpected type: " + operandType)
}
}
}
}
@@ -0,0 +1,56 @@
/*
* 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.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class CallBasedInExpressionGenerator(
val codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression
) : InExpressionGenerator {
private val resolvedCall = operatorReference.getResolvedCallWithAssert(codegen.bindingContext)
private val isInverted = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
override fun generate(argument: StackValue): BranchedValue =
gen(argument).let { if (isInverted) Invert(it) else it }
private fun gen(argument: StackValue): BranchedValue =
object : BranchedValue(argument, null, argument.type, Opcodes.IFEQ) {
override fun putSelector(type: Type, v: InstructionAdapter) {
invokeFunction(v)
}
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
invokeFunction(v)
v.visitJumpInsn(if (jumpIfFalse) Opcodes.IFEQ else Opcodes.IFNE, jumpLabel)
}
private fun invokeFunction(v: InstructionAdapter) {
val result = codegen.invokeFunction(resolvedCall.call, resolvedCall, none())
result.put(result.type, v)
}
}
}
@@ -0,0 +1,42 @@
/*
* 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.StackValue
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
class InArrayIndicesGenerator(
codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<*>
) : AbstractInPrimitiveNumberRangeExpressionGenerator(codegen, operatorReference, rangeCall, isInclusiveHighBound = false) {
private val receiverValue: ReceiverValue = rangeCall.extensionReceiver!!
private val expectedReceiverType: KotlinType = ExpressionCodegen.getExpectedReceiverType(rangeCall)
override fun genLowBound(): StackValue = StackValue.constant(0, asmElementType)
override fun genHighBound(): StackValue =
StackValue.operation(Type.INT_TYPE) { v ->
codegen.generateReceiverValue(receiverValue, false).put(codegen.asmType(expectedReceiverType), v)
v.arraylength()
}
}
@@ -0,0 +1,42 @@
/*
* 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.StackValue
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
class InCharSequenceIndicesGenerator(
codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<*>
) : AbstractInPrimitiveNumberRangeExpressionGenerator(codegen, operatorReference, rangeCall, isInclusiveHighBound = false) {
private val receiverValue: ReceiverValue = rangeCall.extensionReceiver!!
private val expectedReceiverType: KotlinType = ExpressionCodegen.getExpectedReceiverType(rangeCall)
override fun genLowBound(): StackValue = StackValue.constant(0, asmElementType)
override fun genHighBound(): StackValue =
StackValue.operation(Type.INT_TYPE) { v ->
codegen.generateReceiverValue(receiverValue, false).put(codegen.asmType(expectedReceiverType), v)
v.invokeinterface("java/lang/CharSequence", "length", "()I")
}
}
@@ -0,0 +1,42 @@
/*
* 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.StackValue
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
class InCollectionIndicesGenerator(
codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<*>
) : AbstractInPrimitiveNumberRangeExpressionGenerator(codegen, operatorReference, rangeCall, isInclusiveHighBound = false) {
private val receiverValue: ReceiverValue = rangeCall.extensionReceiver!!
private val expectedReceiverType: KotlinType = ExpressionCodegen.getExpectedReceiverType(rangeCall)
override fun genLowBound(): StackValue = StackValue.constant(0, asmElementType)
override fun genHighBound(): StackValue =
StackValue.operation(Type.INT_TYPE) { v ->
codegen.generateReceiverValue(receiverValue, false).put(codegen.asmType(expectedReceiverType), v)
v.invokeinterface("java/util/Collection", "size", "()I")
}
}
@@ -0,0 +1,24 @@
/*
* 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.BranchedValue
import org.jetbrains.kotlin.codegen.StackValue
interface InExpressionGenerator {
fun generate(argument: StackValue): BranchedValue
}
@@ -0,0 +1,37 @@
/*
* 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.StackValue
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
class InPrimitiveNumberDownToGenerator(
codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<*>
) : AbstractInPrimitiveNumberRangeExpressionGenerator(codegen, operatorReference, rangeCall, isInclusiveHighBound = true) {
private val from: ReceiverValue = rangeCall.dispatchReceiver!!
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!
override fun genLowBound(): StackValue = codegen.gen(to)
override fun genHighBound(): StackValue = codegen.generateReceiverValue(from, false)
}
@@ -0,0 +1,38 @@
/*
* 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.StackValue
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
class InPrimitiveNumberRangeLiteralGenerator(
codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<*>
) : AbstractInPrimitiveNumberRangeExpressionGenerator(codegen, operatorReference, rangeCall, isInclusiveHighBound = true) {
private val from: ReceiverValue = rangeCall.dispatchReceiver!!
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!
override fun genLowBound(): StackValue = codegen.generateReceiverValue(from, false)
override fun genHighBound(): StackValue = codegen.gen(to)
}
@@ -0,0 +1,37 @@
/*
* 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.StackValue
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
class InPrimitiveNumberUntilGenerator(
codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<*>
) : AbstractInPrimitiveNumberRangeExpressionGenerator(codegen, operatorReference, rangeCall, isInclusiveHighBound = false) {
private val from: ReceiverValue = rangeCall.dispatchReceiver!!
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!
override fun genLowBound(): StackValue = codegen.generateReceiverValue(from, false)
override fun genHighBound(): StackValue = codegen.gen(to)
}
@@ -20,66 +20,102 @@ import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.forLoop.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
interface RangeValue {
fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator
fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator
}
class ArrayRangeValue : RangeValue {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInArrayLoopGenerator(codegen, forExpression)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
CallBasedInExpressionGenerator(codegen, operatorReference)
}
class PrimitiveRangeRangeValue : RangeValue {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInRangeInstanceLoopGenerator(codegen, forExpression)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
CallBasedInExpressionGenerator(codegen, operatorReference)
}
class PrimitiveProgressionRangeValue : RangeValue {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInProgressionExpressionLoopGenerator(codegen, forExpression)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
CallBasedInExpressionGenerator(codegen, operatorReference)
}
class CharSequenceRangeValue : RangeValue {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInCharSequenceLoopGenerator(codegen, forExpression)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
CallBasedInExpressionGenerator(codegen, operatorReference)
}
class IterableRangeValue : RangeValue {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
IteratorForLoopGenerator(codegen, forExpression)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
CallBasedInExpressionGenerator(codegen, operatorReference)
}
abstract class CallIntrinsicRangeValue(protected val loopRangeCall: ResolvedCall<out CallableDescriptor>): RangeValue
abstract class CallIntrinsicRangeValue(protected val rangeCall: ResolvedCall<out CallableDescriptor>): RangeValue
class PrimitiveNumberRangeToRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
class PrimitiveNumberRangeLiteralRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInRangeLiteralLoopGenerator(codegen, forExpression, loopRangeCall)
ForInRangeLiteralLoopGenerator(codegen, forExpression, rangeCall)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
InPrimitiveNumberRangeLiteralGenerator(codegen, operatorReference, rangeCall)
}
class DownToProgressionRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInDownToProgressionLoopGenerator(codegen, forExpression, loopRangeCall)
ForInDownToProgressionLoopGenerator(codegen, forExpression, rangeCall)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
InPrimitiveNumberDownToGenerator(codegen, operatorReference, rangeCall)
}
class PrimitiveNumberUntilRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInUntilRangeLoopGenerator(codegen, forExpression, loopRangeCall)
ForInUntilRangeLoopGenerator(codegen, forExpression, rangeCall)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
InPrimitiveNumberUntilGenerator(codegen, operatorReference, rangeCall)
}
class ArrayIndicesRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInArrayIndicesRangeLoopGenerator(codegen, forExpression, loopRangeCall)
ForInArrayIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
InArrayIndicesGenerator(codegen, operatorReference, rangeCall)
}
class CollectionIndicesRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInCollectionIndicesRangeLoopGenerator(codegen, forExpression, loopRangeCall)
ForInCollectionIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
InCollectionIndicesGenerator(codegen, operatorReference, rangeCall)
}
class CharSequenceIndicesRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInCharSequenceIndicesRangeLoopGenerator(codegen, forExpression, loopRangeCall)
ForInCharSequenceIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
InCharSequenceIndicesGenerator(codegen, operatorReference, rangeCall)
}
@@ -84,7 +84,7 @@ private fun createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall<out Calla
return when {
isPrimitiveNumberRangeTo(rangeCallee) ->
PrimitiveNumberRangeToRangeValue(rangeCall)
PrimitiveNumberRangeLiteralRangeValue(rangeCall)
isPrimitiveNumberDownTo(rangeCallee) ->
DownToProgressionRangeValue(rangeCall)
isPrimitiveNumberUntil(rangeCallee) ->
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun box(): String = when {
0 in intArrayOf(1, 2, 3) -> "fail 1"
1 !in intArrayOf(1, 2, 3) -> "fail 2"
else -> "OK"
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
val charSeq: String = "123"
fun box(): String = when {
'0' in charSeq -> "fail 1"
'1' !in charSeq -> "fail 2"
else -> "OK"
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
val iterable: Iterable<Int> = listOf(1, 2, 3)
fun box(): String = when {
0 in iterable -> "fail 1"
1 !in iterable -> "fail 2"
else -> "OK"
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
val progression = 1 .. 3 step 2
fun box(): String = when {
0 in progression -> "fail 1"
1 !in progression -> "fail 2"
else -> "OK"
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
val range = 1 .. 3
fun box(): String = when {
0 in range -> "fail 1"
1 !in range -> "fail 2"
else -> "OK"
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
// FILE: Ints.kt
val ints = listOf(1, 2, 3)
// FILE: Test.kt
fun test1(i: Int) =
if (i in ints) "Yes" else "No"
fun test2(i: Int) =
if (i !in ints) "Yes" else "No"
// @TestKt.class:
// 0 ICONST_0
// 0 ICONST_1
// 0 IXOR
@@ -13177,6 +13177,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/contains"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("inArray.kt")
public void testInArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inArray.kt");
doTest(fileName);
}
@TestMetadata("inCharSequence.kt")
public void testInCharSequence() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inCharSequence.kt");
doTest(fileName);
}
@TestMetadata("inComparableRange.kt")
public void testInComparableRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inComparableRange.kt");
@@ -13195,6 +13207,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("inIterable.kt")
public void testInIterable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inIterable.kt");
doTest(fileName);
}
@TestMetadata("inOptimizableDoubleRange.kt")
public void testInOptimizableDoubleRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inOptimizableDoubleRange.kt");
@@ -13219,6 +13237,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("inPrimitiveProgression.kt")
public void testInPrimitiveProgression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inPrimitiveProgression.kt");
doTest(fileName);
}
@TestMetadata("inPrimitiveRange.kt")
public void testInPrimitiveRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inPrimitiveRange.kt");
doTest(fileName);
}
@TestMetadata("inRangeWithCustomContains.kt")
public void testInRangeWithCustomContains() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
@@ -13177,6 +13177,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/contains"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("inArray.kt")
public void testInArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inArray.kt");
doTest(fileName);
}
@TestMetadata("inCharSequence.kt")
public void testInCharSequence() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inCharSequence.kt");
doTest(fileName);
}
@TestMetadata("inComparableRange.kt")
public void testInComparableRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inComparableRange.kt");
@@ -13195,6 +13207,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("inIterable.kt")
public void testInIterable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inIterable.kt");
doTest(fileName);
}
@TestMetadata("inOptimizableDoubleRange.kt")
public void testInOptimizableDoubleRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inOptimizableDoubleRange.kt");
@@ -13219,6 +13237,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("inPrimitiveProgression.kt")
public void testInPrimitiveProgression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inPrimitiveProgression.kt");
doTest(fileName);
}
@TestMetadata("inPrimitiveRange.kt")
public void testInPrimitiveRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inPrimitiveRange.kt");
doTest(fileName);
}
@TestMetadata("inRangeWithCustomContains.kt")
public void testInRangeWithCustomContains() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
@@ -1853,6 +1853,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/ranges"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("ifNotInCollection.kt")
public void testIfNotInCollection() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/ifNotInCollection.kt");
doTest(fileName);
}
@TestMetadata("inNonMatchingRange.kt")
public void testInNonMatchingRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/inNonMatchingRange.kt");
@@ -13177,6 +13177,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/contains"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("inArray.kt")
public void testInArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inArray.kt");
doTest(fileName);
}
@TestMetadata("inCharSequence.kt")
public void testInCharSequence() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inCharSequence.kt");
doTest(fileName);
}
@TestMetadata("inComparableRange.kt")
public void testInComparableRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inComparableRange.kt");
@@ -13195,6 +13207,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("inIterable.kt")
public void testInIterable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inIterable.kt");
doTest(fileName);
}
@TestMetadata("inOptimizableDoubleRange.kt")
public void testInOptimizableDoubleRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inOptimizableDoubleRange.kt");
@@ -13219,6 +13237,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("inPrimitiveProgression.kt")
public void testInPrimitiveProgression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inPrimitiveProgression.kt");
doTest(fileName);
}
@TestMetadata("inPrimitiveRange.kt")
public void testInPrimitiveRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inPrimitiveRange.kt");
doTest(fileName);
}
@TestMetadata("inRangeWithCustomContains.kt")
public void testInRangeWithCustomContains() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
@@ -14785,6 +14785,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/contains"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("inArray.kt")
public void testInArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inArray.kt");
doTest(fileName);
}
@TestMetadata("inCharSequence.kt")
public void testInCharSequence() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inCharSequence.kt");
doTest(fileName);
}
@TestMetadata("inComparableRange.kt")
public void testInComparableRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inComparableRange.kt");
@@ -14821,6 +14833,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("inIterable.kt")
public void testInIterable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inIterable.kt");
doTest(fileName);
}
@TestMetadata("inOptimizableDoubleRange.kt")
public void testInOptimizableDoubleRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inOptimizableDoubleRange.kt");
@@ -14869,6 +14887,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("inPrimitiveProgression.kt")
public void testInPrimitiveProgression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inPrimitiveProgression.kt");
doTest(fileName);
}
@TestMetadata("inPrimitiveRange.kt")
public void testInPrimitiveRange() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inPrimitiveRange.kt");
doTest(fileName);
}
@TestMetadata("inRangeWithCustomContains.kt")
public void testInRangeWithCustomContains() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");