Provide intrinsic for in/in! expression with range of Comparable
This commit is contained in:
@@ -20,8 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.RANGES_PACKAGE_FQ_NAME
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.RANGES_PACKAGE_FQ_NAME
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitiveNumberClassDescriptor
|
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitiveNumberClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -128,6 +127,27 @@ fun isCharSequenceIndices(descriptor: CallableDescriptor): Boolean {
|
|||||||
return KotlinBuiltIns.isCharSequenceOrNullableCharSequence(extensionReceiverType)
|
return KotlinBuiltIns.isCharSequenceOrNullableCharSequence(extensionReceiverType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isComparableRangeTo(descriptor: CallableDescriptor): Boolean {
|
||||||
|
if (!isTopLevelInPackage(descriptor, "rangeTo", "kotlin.ranges")) return false
|
||||||
|
|
||||||
|
val extensionReceiver = descriptor.original.extensionReceiverParameter ?: return false
|
||||||
|
val extensionReceiverTypeDescriptor = extensionReceiver.type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false
|
||||||
|
val upperBoundType = extensionReceiverTypeDescriptor.upperBounds.singleOrNull() ?: return false
|
||||||
|
val upperBoundClassDescriptor = upperBoundType.constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||||
|
if (!isTopLevelInPackage(upperBoundClassDescriptor, "Comparable", "kotlin")) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun isClosedRangeContains(descriptor: CallableDescriptor): Boolean {
|
||||||
|
if (descriptor.name.asString() != "contains") return false
|
||||||
|
val containingClassDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return false
|
||||||
|
if (!isTopLevelInPackage(containingClassDescriptor, "ClosedRange", "kotlin.ranges")) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
fun isPrimitiveRangeToExtension(operationReference: KtSimpleNameExpression, bindingContext: BindingContext): Boolean {
|
fun isPrimitiveRangeToExtension(operationReference: KtSimpleNameExpression, bindingContext: BindingContext): Boolean {
|
||||||
val resolvedCall = operationReference.getResolvedCallWithAssert(bindingContext)
|
val resolvedCall = operationReference.getResolvedCallWithAssert(bindingContext)
|
||||||
val receiver = resolvedCall.dispatchReceiver as? ExpressionReceiver ?: return false
|
val receiver = resolvedCall.dispatchReceiver as? ExpressionReceiver ?: return false
|
||||||
@@ -164,7 +184,7 @@ fun isPrimitiveRangeSpecializationOfType(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isTopLevelInPackage(descriptor: CallableDescriptor, name: String, packageName: String): Boolean {
|
private fun isTopLevelInPackage(descriptor: DeclarationDescriptor, name: String, packageName: String): Boolean {
|
||||||
if (name != descriptor.name.asString()) return false
|
if (name != descriptor.name.asString()) return false
|
||||||
|
|
||||||
val containingDeclaration = descriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
val containingDeclaration = descriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
||||||
|
|||||||
+64
-145
@@ -16,160 +16,79 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.range
|
package org.jetbrains.kotlin.codegen.range
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.codegen.getPrimitiveRangeElementType
|
||||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.org.objectweb.asm.Label
|
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.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
abstract class AbstractInPrimitiveNumberRangeExpressionGenerator(
|
abstract class AbstractInPrimitiveNumberRangeExpressionGenerator(
|
||||||
val codegen: ExpressionCodegen,
|
codegen: ExpressionCodegen,
|
||||||
operatorReference: KtSimpleNameExpression,
|
operatorReference: KtSimpleNameExpression,
|
||||||
rangeCall: ResolvedCall<*>,
|
rangeCall: ResolvedCall<*>,
|
||||||
private val isInclusiveHighBound: Boolean
|
isInclusiveHighBound: Boolean
|
||||||
) : InExpressionGenerator {
|
) : AbstractInRangeWithKnownBoundsExpressionGenerator(
|
||||||
protected val asmElementType =
|
codegen, operatorReference, isInclusiveHighBound, AsmTypes.valueTypeForPrimitive(getPrimitiveRangeElementType(rangeCall.resultingDescriptor.returnType!!))
|
||||||
AsmTypes.valueTypeForPrimitive(
|
) {
|
||||||
getPrimitiveRangeElementType(rangeCall.resultingDescriptor.returnType!!)
|
override val comparisonGenerator: ComparisonGenerator =
|
||||||
)
|
when (asmElementType) {
|
||||||
|
Type.INT_TYPE, Type.SHORT_TYPE, Type.BYTE_TYPE, Type.CHAR_TYPE -> PrimitiveIntegerComparisonGenerator
|
||||||
private val isInverted =
|
Type.LONG_TYPE -> PrimitiveLongComparisonGenerator
|
||||||
operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
|
Type.FLOAT_TYPE, Type.DOUBLE_TYPE -> PrimitiveFloatComparisonGenerator(asmElementType)
|
||||||
|
else -> throw UnsupportedOperationException("Unexpected type: " + asmElementType)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object PrimitiveIntegerComparisonGenerator : ComparisonGenerator {
|
||||||
|
override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) = v.ificmpge(label)
|
||||||
|
override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) = v.ificmple(label)
|
||||||
|
override fun jumpIfGreater(v: InstructionAdapter, label: Label) = v.ificmpgt(label)
|
||||||
|
override fun jumpIfLess(v: InstructionAdapter, label: Label) = v.ificmplt(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
private object PrimitiveLongComparisonGenerator : ComparisonGenerator {
|
||||||
|
override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) {
|
||||||
|
v.lcmp()
|
||||||
|
v.ifge(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) {
|
||||||
|
v.lcmp()
|
||||||
|
v.ifle(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfGreater(v: InstructionAdapter, label: Label) {
|
||||||
|
v.lcmp()
|
||||||
|
v.ifgt(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfLess(v: InstructionAdapter, label: Label) {
|
||||||
|
v.lcmp()
|
||||||
|
v.iflt(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PrimitiveFloatComparisonGenerator(val floatType: Type) : ComparisonGenerator {
|
||||||
|
override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) {
|
||||||
|
v.cmpg(floatType)
|
||||||
|
v.ifge(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) {
|
||||||
|
v.cmpg(floatType)
|
||||||
|
v.ifle(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfGreater(v: InstructionAdapter, label: Label) {
|
||||||
|
v.cmpg(floatType)
|
||||||
|
v.ifgt(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfLess(v: InstructionAdapter, label: Label) {
|
||||||
|
v.cmpg(floatType)
|
||||||
|
v.iflt(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* 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.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 AbstractInRangeWithKnownBoundsExpressionGenerator(
|
||||||
|
val codegen: ExpressionCodegen,
|
||||||
|
operatorReference: KtSimpleNameExpression,
|
||||||
|
protected val isInclusiveHighBound: Boolean,
|
||||||
|
protected val asmElementType: Type
|
||||||
|
) : InExpressionGenerator {
|
||||||
|
private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
|
||||||
|
|
||||||
|
protected abstract fun genLowBound(): StackValue
|
||||||
|
protected abstract fun genHighBound(): StackValue
|
||||||
|
|
||||||
|
protected interface ComparisonGenerator {
|
||||||
|
fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label)
|
||||||
|
fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label)
|
||||||
|
fun jumpIfGreater(v: InstructionAdapter, label: Label)
|
||||||
|
fun jumpIfLess(v: InstructionAdapter, label: Label)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract val comparisonGenerator: ComparisonGenerator
|
||||||
|
|
||||||
|
override fun generate(argument: StackValue): BranchedValue =
|
||||||
|
gen(argument).let { if (isNotIn) 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)
|
||||||
|
comparisonGenerator.jumpIfGreaterOrEqual(v, cmpHighLabel)
|
||||||
|
|
||||||
|
AsmUtil.pop(v, operandType)
|
||||||
|
v.goTo(jumpLabel)
|
||||||
|
|
||||||
|
v.mark(cmpHighLabel)
|
||||||
|
genHighBound().put(operandType, v)
|
||||||
|
if (isInclusiveHighBound) {
|
||||||
|
comparisonGenerator.jumpIfGreater(v, jumpLabel)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
comparisonGenerator.jumpIfGreaterOrEqual(v, 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)
|
||||||
|
comparisonGenerator.jumpIfLess(v, trueLabel1)
|
||||||
|
|
||||||
|
genHighBound().put(operandType, v)
|
||||||
|
if (isInclusiveHighBound) {
|
||||||
|
comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
comparisonGenerator.jumpIfLess(v, jumpLabel)
|
||||||
|
}
|
||||||
|
v.goTo(trueLabel2)
|
||||||
|
|
||||||
|
v.mark(trueLabel1)
|
||||||
|
AsmUtil.pop(v, operandType)
|
||||||
|
|
||||||
|
v.mark(trueLabel2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.CallableDescriptor
|
||||||
|
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
|
||||||
|
import org.jetbrains.org.objectweb.asm.Label
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
|
class InComparableRangeLiteralGenerator(
|
||||||
|
codegen: ExpressionCodegen,
|
||||||
|
operatorReference: KtSimpleNameExpression,
|
||||||
|
rangeCall: ResolvedCall<out CallableDescriptor>
|
||||||
|
) : AbstractInRangeWithKnownBoundsExpressionGenerator(
|
||||||
|
codegen, operatorReference, true,
|
||||||
|
Type.getType("Ljava/lang/Comparable;")
|
||||||
|
) {
|
||||||
|
private val from: ReceiverValue = rangeCall.extensionReceiver!!
|
||||||
|
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!
|
||||||
|
|
||||||
|
override fun genLowBound(): StackValue = codegen.generateReceiverValue(from, false)
|
||||||
|
|
||||||
|
override fun genHighBound(): StackValue = codegen.gen(to)
|
||||||
|
|
||||||
|
override val comparisonGenerator: ComparisonGenerator = ComparableComparisonGenerator
|
||||||
|
|
||||||
|
private object ComparableComparisonGenerator : ComparisonGenerator {
|
||||||
|
override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) {
|
||||||
|
invokeCompare(v)
|
||||||
|
v.ifge(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) {
|
||||||
|
invokeCompare(v)
|
||||||
|
v.ifle(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfGreater(v: InstructionAdapter, label: Label) {
|
||||||
|
invokeCompare(v)
|
||||||
|
v.ifgt(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun jumpIfLess(v: InstructionAdapter, label: Label) {
|
||||||
|
invokeCompare(v)
|
||||||
|
v.iflt(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invokeCompare(v: InstructionAdapter) {
|
||||||
|
v.invokeinterface("java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.codegen.range
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||||
import org.jetbrains.kotlin.codegen.forLoop.*
|
import org.jetbrains.kotlin.codegen.forLoop.*
|
||||||
|
import org.jetbrains.kotlin.codegen.isClosedRangeContains
|
||||||
import org.jetbrains.kotlin.codegen.isPrimitiveRange
|
import org.jetbrains.kotlin.codegen.isPrimitiveRange
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtForExpression
|
import org.jetbrains.kotlin.psi.KtForExpression
|
||||||
@@ -86,7 +87,7 @@ abstract class CallIntrinsicRangeValue(protected val rangeCall: ResolvedCall<out
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class PrimitiveNumberRangeIntrinsicRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(rangeCall) {
|
abstract class PrimitiveNumberRangeIntrinsicRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(rangeCall) {
|
||||||
override fun isIntrinsicInCall(resolvedCallForIn: ResolvedCall<out CallableDescriptor>): Boolean =
|
override fun isIntrinsicInCall(resolvedCallForIn: ResolvedCall<out CallableDescriptor>) =
|
||||||
resolvedCallForIn.resultingDescriptor.dispatchReceiverParameter?.let {
|
resolvedCallForIn.resultingDescriptor.dispatchReceiverParameter?.let {
|
||||||
isPrimitiveRange(it.type)
|
isPrimitiveRange(it.type)
|
||||||
} ?: false
|
} ?: false
|
||||||
@@ -96,7 +97,7 @@ class PrimitiveNumberRangeLiteralRangeValue(rangeCall: ResolvedCall<out Callable
|
|||||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
ForInRangeLiteralLoopGenerator(codegen, forExpression, rangeCall)
|
ForInRangeLiteralLoopGenerator(codegen, forExpression, rangeCall)
|
||||||
|
|
||||||
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression) =
|
||||||
InPrimitiveNumberRangeLiteralGenerator(codegen, operatorReference, rangeCall)
|
InPrimitiveNumberRangeLiteralGenerator(codegen, operatorReference, rangeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ class DownToProgressionRangeValue(rangeCall: ResolvedCall<out CallableDescriptor
|
|||||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
ForInDownToProgressionLoopGenerator(codegen, forExpression, rangeCall)
|
ForInDownToProgressionLoopGenerator(codegen, forExpression, rangeCall)
|
||||||
|
|
||||||
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression) =
|
||||||
InPrimitiveNumberDownToGenerator(codegen, operatorReference, rangeCall)
|
InPrimitiveNumberDownToGenerator(codegen, operatorReference, rangeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +113,7 @@ class PrimitiveNumberUntilRangeValue(rangeCall: ResolvedCall<out CallableDescrip
|
|||||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
ForInUntilRangeLoopGenerator(codegen, forExpression, rangeCall)
|
ForInUntilRangeLoopGenerator(codegen, forExpression, rangeCall)
|
||||||
|
|
||||||
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression) =
|
||||||
InPrimitiveNumberUntilGenerator(codegen, operatorReference, rangeCall)
|
InPrimitiveNumberUntilGenerator(codegen, operatorReference, rangeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ class ArrayIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): P
|
|||||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
ForInArrayIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
ForInArrayIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
||||||
|
|
||||||
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression) =
|
||||||
InArrayIndicesGenerator(codegen, operatorReference, rangeCall)
|
InArrayIndicesGenerator(codegen, operatorReference, rangeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ class CollectionIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor
|
|||||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
ForInCollectionIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
ForInCollectionIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
||||||
|
|
||||||
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression) =
|
||||||
InCollectionIndicesGenerator(codegen, operatorReference, rangeCall)
|
InCollectionIndicesGenerator(codegen, operatorReference, rangeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +137,17 @@ class CharSequenceIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescript
|
|||||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
ForInCharSequenceIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
ForInCharSequenceIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
||||||
|
|
||||||
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression) =
|
||||||
InCharSequenceIndicesGenerator(codegen, operatorReference, rangeCall)
|
InCharSequenceIndicesGenerator(codegen, operatorReference, rangeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ComparableRangeLiteralRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(rangeCall) {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
IteratorForLoopGenerator(codegen, forExpression)
|
||||||
|
|
||||||
|
override fun isIntrinsicInCall(resolvedCallForIn: ResolvedCall<out CallableDescriptor>) =
|
||||||
|
isClosedRangeContains(resolvedCallForIn.resultingDescriptor)
|
||||||
|
|
||||||
|
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression)=
|
||||||
|
InComparableRangeLiteralGenerator(codegen, operatorReference, rangeCall)
|
||||||
|
}
|
||||||
@@ -95,6 +95,8 @@ private fun createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall<out Calla
|
|||||||
CollectionIndicesRangeValue(rangeCall)
|
CollectionIndicesRangeValue(rangeCall)
|
||||||
isCharSequenceIndices(rangeCallee) ->
|
isCharSequenceIndices(rangeCallee) ->
|
||||||
CharSequenceIndicesRangeValue(rangeCall)
|
CharSequenceIndicesRangeValue(rangeCall)
|
||||||
|
isComparableRangeTo(rangeCallee) ->
|
||||||
|
ComparableRangeLiteralRangeValue(rangeCall)
|
||||||
else ->
|
else ->
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if ("z" in "Alpha" .. "Omega") return "Fail 1"
|
||||||
|
if ("Gamma" !in "Alpha" .. "Omega") return "Fail 2"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+6
@@ -13249,6 +13249,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inRangeOfComparable.kt")
|
||||||
|
public void testInRangeOfComparable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inRangeWithCustomContains.kt")
|
@TestMetadata("inRangeWithCustomContains.kt")
|
||||||
public void testInRangeWithCustomContains() throws Exception {
|
public void testInRangeWithCustomContains() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
|
||||||
|
|||||||
@@ -13249,6 +13249,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inRangeOfComparable.kt")
|
||||||
|
public void testInRangeOfComparable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inRangeWithCustomContains.kt")
|
@TestMetadata("inRangeWithCustomContains.kt")
|
||||||
public void testInRangeWithCustomContains() throws Exception {
|
public void testInRangeWithCustomContains() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
|
||||||
|
|||||||
@@ -13249,6 +13249,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inRangeOfComparable.kt")
|
||||||
|
public void testInRangeOfComparable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inRangeWithCustomContains.kt")
|
@TestMetadata("inRangeWithCustomContains.kt")
|
||||||
public void testInRangeWithCustomContains() throws Exception {
|
public void testInRangeWithCustomContains() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
|
||||||
|
|||||||
@@ -14899,6 +14899,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inRangeOfComparable.kt")
|
||||||
|
public void testInRangeOfComparable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inRangeWithCustomContains.kt")
|
@TestMetadata("inRangeWithCustomContains.kt")
|
||||||
public void testInRangeWithCustomContains() throws Exception {
|
public void testInRangeWithCustomContains() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user