Ranges: introduce RangeValue class
The overall idea is to unify intrinsics for 'for-in' loop generation and for 'in'/'!in' expression generation.
This commit is contained in:
@@ -40,10 +40,11 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
|||||||
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
|
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
|
||||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||||
import org.jetbrains.kotlin.codegen.forLoop.AbstractForLoopGenerator;
|
import org.jetbrains.kotlin.codegen.forLoop.AbstractForLoopGenerator;
|
||||||
import org.jetbrains.kotlin.codegen.forLoop.ForLoopGeneratorsKt;
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.*;
|
import org.jetbrains.kotlin.codegen.inline.*;
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
|
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
|
||||||
|
import org.jetbrains.kotlin.codegen.range.RangeValue;
|
||||||
|
import org.jetbrains.kotlin.codegen.range.RangeValuesKt;
|
||||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
@@ -599,7 +600,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void generateFor(@NotNull KtForExpression forExpression) {
|
private void generateFor(@NotNull KtForExpression forExpression) {
|
||||||
generateForLoop(ForLoopGeneratorsKt.getForLoopGenerator(this, forExpression));
|
KtExpression range = forExpression.getLoopRange();
|
||||||
|
assert range != null : "No loop range in for expression";
|
||||||
|
RangeValue rangeValue = RangeValuesKt.createRangeValueForExpression(this, range);
|
||||||
|
generateForLoop(rangeValue.createForLoopGenerator(this, forExpression));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.forLoop
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
|
||||||
import org.jetbrains.kotlin.codegen.RangeCodegenUtil
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
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.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
|
||||||
|
|
||||||
fun ExpressionCodegen.getForLoopGenerator(forExpression: KtForExpression) : AbstractForLoopGenerator {
|
|
||||||
getLoopRangeResolvedCall(forExpression, bindingContext)?.let { loopRangeCall ->
|
|
||||||
createOptimizedForLoopGeneratorOrNull(forExpression, loopRangeCall)?.let {
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val loopRange = forExpression.loopRange!!
|
|
||||||
val loopRangeType = bindingContext.getType(loopRange)!!
|
|
||||||
val asmLoopRangeType = asmType(loopRangeType)
|
|
||||||
|
|
||||||
return when {
|
|
||||||
asmLoopRangeType.sort == Type.ARRAY ->
|
|
||||||
ForInArrayLoopGenerator(this, forExpression)
|
|
||||||
RangeCodegenUtil.isRange(loopRangeType) ->
|
|
||||||
ForInRangeInstanceLoopGenerator(this, forExpression)
|
|
||||||
RangeCodegenUtil.isProgression(loopRangeType) ->
|
|
||||||
ForInProgressionExpressionLoopGenerator(this, forExpression)
|
|
||||||
isSubtypeOfCharSequence(loopRangeType, state.module.builtIns) ->
|
|
||||||
ForInCharSequenceLoopGenerator(this, forExpression)
|
|
||||||
else ->
|
|
||||||
IteratorForLoopGenerator(this, forExpression)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSubtypeOfCharSequence(type: KotlinType, builtIns: KotlinBuiltIns) =
|
|
||||||
KotlinTypeChecker.DEFAULT.isSubtypeOf(type, builtIns.getBuiltInClassByName(Name.identifier("CharSequence")).defaultType)
|
|
||||||
|
|
||||||
private fun ExpressionCodegen.createOptimizedForLoopGeneratorOrNull(
|
|
||||||
forExpression: KtForExpression,
|
|
||||||
loopRangeCall: ResolvedCall<out CallableDescriptor>
|
|
||||||
): AbstractForLoopGenerator? {
|
|
||||||
val loopRangeCallee = loopRangeCall.resultingDescriptor
|
|
||||||
|
|
||||||
return when {
|
|
||||||
RangeCodegenUtil.isPrimitiveNumberRangeTo(loopRangeCallee) ->
|
|
||||||
ForInRangeLiteralLoopGenerator(this, forExpression, loopRangeCall)
|
|
||||||
RangeCodegenUtil.isPrimitiveNumberDownTo(loopRangeCallee) ->
|
|
||||||
ForInDownToProgressionLoopGenerator(this, forExpression, loopRangeCall)
|
|
||||||
RangeCodegenUtil.isPrimitiveNumberUntil(loopRangeCallee) ->
|
|
||||||
ForInUntilRangeLoopGenerator(this, forExpression, loopRangeCall)
|
|
||||||
RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(loopRangeCallee) ->
|
|
||||||
ForInArrayIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
|
|
||||||
RangeCodegenUtil.isCollectionIndices(loopRangeCallee) ->
|
|
||||||
ForInCollectionIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
|
|
||||||
RangeCodegenUtil.isCharSequenceIndices(loopRangeCallee) ->
|
|
||||||
ForInCharSequenceIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLoopRangeResolvedCall(forExpression: KtForExpression, bindingContext: BindingContext): ResolvedCall<out CallableDescriptor>? {
|
|
||||||
val loopRange = KtPsiUtil.deparenthesize(forExpression.loopRange)
|
|
||||||
|
|
||||||
when (loopRange) {
|
|
||||||
is KtQualifiedExpression -> {
|
|
||||||
val qualifiedExpression = loopRange as KtQualifiedExpression?
|
|
||||||
val selector = qualifiedExpression!!.selectorExpression
|
|
||||||
if (selector is KtCallExpression || selector is KtSimpleNameExpression) {
|
|
||||||
return selector.getResolvedCall(bindingContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtSimpleNameExpression, is KtCallExpression -> return loopRange.getResolvedCall(bindingContext)
|
|
||||||
is KtBinaryExpression -> return loopRange.operationReference.getResolvedCall(bindingContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.forLoop.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.KtForExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
|
||||||
|
interface RangeValue {
|
||||||
|
fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): AbstractForLoopGenerator
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArrayRangeValue : RangeValue {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInArrayLoopGenerator(codegen, forExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrimitiveRangeRangeValue : RangeValue {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInRangeInstanceLoopGenerator(codegen, forExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrimitiveProgressionRangeValue : RangeValue {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInProgressionExpressionLoopGenerator(codegen, forExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CharSequenceRangeValue : RangeValue {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInCharSequenceLoopGenerator(codegen, forExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
class IterableRangeValue : RangeValue {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
IteratorForLoopGenerator(codegen, forExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class CallIntrinsicRangeValue(protected val loopRangeCall: ResolvedCall<out CallableDescriptor>): RangeValue
|
||||||
|
|
||||||
|
class PrimitiveNumberRangeToRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInRangeLiteralLoopGenerator(codegen, forExpression, loopRangeCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownToProgressionRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInDownToProgressionLoopGenerator(codegen, forExpression, loopRangeCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrimitiveNumberUntilRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInUntilRangeLoopGenerator(codegen, forExpression, loopRangeCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArrayIndicesRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInArrayIndicesRangeLoopGenerator(codegen, forExpression, loopRangeCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionIndicesRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInCollectionIndicesRangeLoopGenerator(codegen, forExpression, loopRangeCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CharSequenceIndicesRangeValue(loopRangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(loopRangeCall) {
|
||||||
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||||
|
ForInCharSequenceIndicesRangeLoopGenerator(codegen, forExpression, loopRangeCall)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||||
|
import org.jetbrains.kotlin.codegen.RangeCodegenUtil
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
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.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
|
fun ExpressionCodegen.createRangeValueForExpression(rangeExpression: KtExpression): RangeValue {
|
||||||
|
getResolvedCallForRangeExpression(bindingContext, rangeExpression)?.let {
|
||||||
|
createIntrinsifiedRangeValueOrNull(it)?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val rangeType = bindingContext.getType(rangeExpression)!!
|
||||||
|
val asmRangeType = asmType(rangeType)
|
||||||
|
|
||||||
|
return when {
|
||||||
|
asmRangeType.sort == Type.ARRAY ->
|
||||||
|
ArrayRangeValue()
|
||||||
|
RangeCodegenUtil.isRange(rangeType) ->
|
||||||
|
PrimitiveRangeRangeValue()
|
||||||
|
RangeCodegenUtil.isProgression(rangeType) ->
|
||||||
|
PrimitiveProgressionRangeValue()
|
||||||
|
isSubtypeOfCharSequence(rangeType, state.module.builtIns) ->
|
||||||
|
CharSequenceRangeValue()
|
||||||
|
else ->
|
||||||
|
IterableRangeValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSubtypeOfCharSequence(type: KotlinType, builtIns: KotlinBuiltIns) =
|
||||||
|
KotlinTypeChecker.DEFAULT.isSubtypeOf(type, builtIns.getBuiltInClassByName(Name.identifier("CharSequence")).defaultType)
|
||||||
|
|
||||||
|
private fun getResolvedCallForRangeExpression(
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
rangeExpression: KtExpression
|
||||||
|
): ResolvedCall<out CallableDescriptor>? {
|
||||||
|
val expression = KtPsiUtil.deparenthesize(rangeExpression) ?: return null
|
||||||
|
|
||||||
|
return when (expression) {
|
||||||
|
is KtQualifiedExpression ->
|
||||||
|
expression.selectorExpression.let { selector ->
|
||||||
|
if (selector is KtCallExpression || selector is KtSimpleNameExpression)
|
||||||
|
selector.getResolvedCall(bindingContext)
|
||||||
|
else
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
is KtSimpleNameExpression, is KtCallExpression ->
|
||||||
|
expression.getResolvedCall(bindingContext)
|
||||||
|
is KtBinaryExpression ->
|
||||||
|
expression.operationReference.getResolvedCall(bindingContext)
|
||||||
|
else ->
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall<out CallableDescriptor>): RangeValue? {
|
||||||
|
val rangeCallee = rangeCall.resultingDescriptor
|
||||||
|
|
||||||
|
return when {
|
||||||
|
RangeCodegenUtil.isPrimitiveNumberRangeTo(rangeCallee) ->
|
||||||
|
PrimitiveNumberRangeToRangeValue(rangeCall)
|
||||||
|
RangeCodegenUtil.isPrimitiveNumberDownTo(rangeCallee) ->
|
||||||
|
DownToProgressionRangeValue(rangeCall)
|
||||||
|
RangeCodegenUtil.isPrimitiveNumberUntil(rangeCallee) ->
|
||||||
|
PrimitiveNumberUntilRangeValue(rangeCall)
|
||||||
|
RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(rangeCallee) ->
|
||||||
|
ArrayIndicesRangeValue(rangeCall)
|
||||||
|
RangeCodegenUtil.isCollectionIndices(rangeCallee) ->
|
||||||
|
CollectionIndicesRangeValue(rangeCall)
|
||||||
|
RangeCodegenUtil.isCharSequenceIndices(rangeCallee) ->
|
||||||
|
CharSequenceIndicesRangeValue(rangeCall)
|
||||||
|
else ->
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user