SwitchCodegenUtil: convert to Kotlin and cleanup

This commit is contained in:
Dmitry Petrov
2017-08-04 11:36:37 +03:00
parent c5772e5549
commit 435cfeea0a
@@ -14,166 +14,123 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.codegen.when; package org.jetbrains.kotlin.codegen.`when`
import kotlin.jvm.functions.Function1; import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.ExpressionCodegen; import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant
import org.jetbrains.kotlin.resolve.constants.ConstantValue; import org.jetbrains.kotlin.resolve.constants.NullValue
import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant; import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.constants.NullValue; import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.kotlin.resolve.constants.StringValue;
import org.jetbrains.org.objectweb.asm.Type;
import java.util.ArrayList; import java.util.ArrayList
import java.util.List;
public class SwitchCodegenUtil { object SwitchCodegenUtil {
public static boolean checkAllItemsAreConstantsSatisfying( @JvmStatic
@NotNull KtWhenExpression expression, fun checkAllItemsAreConstantsSatisfying(
@NotNull BindingContext bindingContext, expression: KtWhenExpression,
boolean shouldInlineConstVals, bindingContext: BindingContext,
Function1<ConstantValue<?>, Boolean> predicate shouldInlineConstVals: Boolean,
) { predicate: Function1<ConstantValue<*>, Boolean>
for (KtWhenEntry entry : expression.getEntries()) { ): Boolean =
for (KtWhenCondition condition : entry.getConditions()) { expression.entries.all { entry ->
if (!(condition instanceof KtWhenConditionWithExpression)) { entry.conditions.all { condition ->
return false; if (condition !is KtWhenConditionWithExpression) return false
} val patternExpression = condition.expression ?: return false
val constant = ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals) ?: return false
// ensure that expression is constant predicate.invoke(constant)
KtExpression patternExpression = ((KtWhenConditionWithExpression) condition).getExpression();
if (patternExpression == null) return false;
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals);
if (constant == null || !predicate.invoke(constant)) {
return false;
} }
} }
}
return true; @JvmStatic
} fun getAllConstants(
expression: KtWhenExpression,
bindingContext: BindingContext,
shouldInlineConstVals: Boolean
): Iterable<ConstantValue<*>?> =
ArrayList<ConstantValue<*>?>().apply {
for (entry in expression.entries) {
addConstantsFromConditions(entry, bindingContext, shouldInlineConstVals)
}
}
@NotNull @JvmStatic
public static Iterable<ConstantValue<?>> getAllConstants( fun getConstantsFromEntry(
@NotNull KtWhenExpression expression, entry: KtWhenEntry,
@NotNull BindingContext bindingContext, bindingContext: BindingContext,
boolean shouldInlineConstVals shouldInlineConstVals: Boolean
): Iterable<ConstantValue<*>?> =
ArrayList<ConstantValue<*>?>().apply {
addConstantsFromConditions(entry, bindingContext, shouldInlineConstVals)
}
private fun ArrayList<ConstantValue<*>?>.addConstantsFromConditions(
entry: KtWhenEntry,
bindingContext: BindingContext,
shouldInlineConstVals: Boolean
) { ) {
List<ConstantValue<?>> result = new ArrayList<>(); for (condition in entry.conditions) {
if (condition !is KtWhenConditionWithExpression) continue
for (KtWhenEntry entry : expression.getEntries()) { val patternExpression = condition.expression ?: throw AssertionError("expression in when should not be null")
addConstantsFromEntry(result, entry, bindingContext, shouldInlineConstVals); add(ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals))
}
return result;
}
private static void addConstantsFromEntry(
@NotNull List<ConstantValue<?>> result,
@NotNull KtWhenEntry entry,
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals
) {
for (KtWhenCondition condition : entry.getConditions()) {
if (!(condition instanceof KtWhenConditionWithExpression)) continue;
KtExpression patternExpression = ((KtWhenConditionWithExpression) condition).getExpression();
assert patternExpression != null : "expression in when should not be null";
result.add(ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals));
} }
} }
@NotNull @JvmStatic
public static Iterable<ConstantValue<?>> getConstantsFromEntry( fun buildAppropriateSwitchCodegenIfPossible(
@NotNull KtWhenEntry entry, expression: KtWhenExpression,
@NotNull BindingContext bindingContext, isStatement: Boolean,
boolean shouldInlineConstVals isExhaustive: Boolean,
) { codegen: ExpressionCodegen
List<ConstantValue<?>> result = new ArrayList<>(); ): SwitchCodegen? {
addConstantsFromEntry(result, entry, bindingContext, shouldInlineConstVals); val bindingContext = codegen.bindingContext
return result; val shouldInlineConstVals = codegen.state.shouldInlineConstVals
}
@Nullable
public static SwitchCodegen buildAppropriateSwitchCodegenIfPossible(
@NotNull KtWhenExpression expression,
boolean isStatement,
boolean isExhaustive,
@NotNull ExpressionCodegen codegen
) {
BindingContext bindingContext = codegen.getBindingContext();
boolean shouldInlineConstVals = codegen.getState().getShouldInlineConstVals();
if (!isThereConstantEntriesButNulls(expression, bindingContext, shouldInlineConstVals)) { if (!isThereConstantEntriesButNulls(expression, bindingContext, shouldInlineConstVals)) {
return null; return null
} }
Type subjectType = codegen.expressionType(expression.getSubjectExpression()); val subjectType = codegen.expressionType(expression.subjectExpression)
WhenByEnumsMapping mapping = codegen.getBindingContext().get(CodegenBinding.MAPPING_FOR_WHEN_BY_ENUM, expression); val mapping = codegen.bindingContext.get(CodegenBinding.MAPPING_FOR_WHEN_BY_ENUM, expression)
if (mapping != null) { return when {
return new EnumSwitchCodegen(expression, isStatement, isExhaustive, codegen, mapping); mapping != null ->
EnumSwitchCodegen(expression, isStatement, isExhaustive, codegen, mapping)
isIntegralConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals) ->
IntegralConstantsSwitchCodegen(expression, isStatement, isExhaustive, codegen)
isStringConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals) ->
StringSwitchCodegen(expression, isStatement, isExhaustive, codegen)
else -> null
} }
if (isIntegralConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals)) {
return new IntegralConstantsSwitchCodegen(expression, isStatement, isExhaustive, codegen);
}
if (isStringConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals)) {
return new StringSwitchCodegen(expression, isStatement, isExhaustive, codegen);
}
return null;
} }
private static boolean isThereConstantEntriesButNulls( private fun isThereConstantEntriesButNulls(
@NotNull KtWhenExpression expression, expression: KtWhenExpression,
@NotNull BindingContext bindingContext, bindingContext: BindingContext,
boolean shouldInlineConstVals shouldInlineConstVals: Boolean
) { ): Boolean =
for (ConstantValue<?> constant : getAllConstants(expression, bindingContext, shouldInlineConstVals)) { getAllConstants(expression, bindingContext, shouldInlineConstVals).any { it != null && it !is NullValue }
if (constant != null && !(constant instanceof NullValue)) return true;
}
return false; private fun isIntegralConstantsSwitch(
} expression: KtWhenExpression,
subjectType: Type,
bindingContext: BindingContext,
shouldInlineConstVals: Boolean
): Boolean =
AsmUtil.isIntPrimitive(subjectType) &&
checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals) { it is IntegerValueConstant<*> }
private static boolean isIntegralConstantsSwitch( private fun isStringConstantsSwitch(
@NotNull KtWhenExpression expression, expression: KtWhenExpression,
@NotNull Type subjectType, subjectType: Type,
@NotNull BindingContext bindingContext, bindingContext: BindingContext,
boolean shouldInlineConstVals shouldInlineConstVals: Boolean
) { ): Boolean =
int typeSort = subjectType.getSort(); subjectType.className == String::class.java.name &&
checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals) { it is StringValue || it is NullValue }
if (typeSort != Type.INT && typeSort != Type.CHAR && typeSort != Type.SHORT && typeSort != Type.BYTE) {
return false;
}
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals,
constant -> constant instanceof IntegerValueConstant);
}
private static boolean isStringConstantsSwitch(
@NotNull KtWhenExpression expression,
@NotNull Type subjectType,
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals
) {
if (!subjectType.getClassName().equals(String.class.getName())) {
return false;
}
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals,
constant -> constant instanceof StringValue || constant instanceof NullValue);
}
} }