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.extensions.ExpressionCodegenExtension;
|
||||
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.intrinsics.*;
|
||||
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.JvmSignatureWriter;
|
||||
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) {
|
||||
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
|
||||
|
||||
@@ -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