Implement "proper numeric comparisons" support in JVM BE

This commit is contained in:
Dmitry Petrov
2018-02-08 09:50:22 +03:00
parent e23a48e8d0
commit a790195808
18 changed files with 652 additions and 138 deletions
@@ -127,6 +127,12 @@ public class AsmUtil {
return primitiveTypeByBoxedType.get(boxedType);
}
@NotNull
public static Type unboxUnlessPrimitive(@NotNull Type boxedOrPrimitiveType) {
if (isPrimitive(boxedOrPrimitiveType)) return boxedOrPrimitiveType;
return unboxType(boxedOrPrimitiveType);
}
public static boolean isBoxedTypeOf(@NotNull Type boxedType, @NotNull Type unboxedType) {
return unboxPrimitiveTypeOrNull(boxedType) == unboxedType;
}
@@ -294,4 +294,84 @@ class PrimitiveToObjectEquality private constructor(
AsmUtil.isIntOrLongPrimitive(leftType) &&
rightType.sort == Type.OBJECT
}
}
class Ieee754Equality private constructor(
private val frameMap: FrameMap,
left: StackValue,
right: StackValue,
operandType: Type
) : NumberLikeCompare(left, right, operandType, KtTokens.EQEQ) {
init {
assert(operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) {
"Unexpected operandType for IEEE 754 equality (should be F or D): $operandType"
}
}
private val leftType = left.type
private val rightType = right.type
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
val leftIsBoxed = !AsmUtil.isPrimitive(leftType)
val rightIsBoxed = !AsmUtil.isPrimitive(rightType)
frameMap.evaluateOnce(arg1, leftType, v) { left ->
frameMap.evaluateOnce(arg2!!, rightType, v) { right ->
val endLabel = Label()
val bothNonNullLabel = Label()
when {
leftIsBoxed && rightIsBoxed -> {
val leftNonNullLabel = Label()
left.put(leftType, v)
v.ifnonnull(leftNonNullLabel)
// left == null
right.put(rightType, v)
v.ifnonnull(if (jumpIfFalse) jumpLabel else endLabel)
// left == null && right == null
if (jumpIfFalse) v.goTo(endLabel) else v.goTo(jumpLabel)
v.mark(leftNonNullLabel)
// left != null
right.put(rightType, v)
v.ifnull(if (jumpIfFalse) jumpLabel else endLabel)
}
leftIsBoxed -> {
left.put(leftType, v)
v.ifnull(if (jumpIfFalse) jumpLabel else endLabel)
}
rightIsBoxed -> {
right.put(rightType, v)
v.ifnull(if (jumpIfFalse) jumpLabel else endLabel)
}
}
v.mark(bothNonNullLabel)
left.put(operandType, v)
right.put(operandType, v)
v.cmpg(operandType)
if (jumpIfFalse) {
v.ifne(jumpLabel)
} else {
v.ifeq(jumpLabel)
}
v.mark(endLabel)
}
}
}
companion object {
@JvmStatic
fun create(frameMap: FrameMap, left: StackValue, right: StackValue, comparisonType: Type, opToken: IElementType) =
Ieee754Equality(frameMap, left, right, comparisonType).let {
when (opToken) {
KtTokens.EQEQ -> it
KtTokens.EXCLEQ -> Invert(it)
else -> throw AssertionError("Unexpected operator: $opToken")
}
}
}
}
@@ -124,7 +124,7 @@ open class BranchedValue(
IFEQ
)
fun cmp(opToken: IElementType, operandType: Type, left: StackValue, right: StackValue): StackValue =
fun cmp(opToken: IElementType, operandType: Type, left: StackValue, right: StackValue): BranchedValue =
if (operandType.sort == Type.OBJECT)
ObjectCompare(opToken, operandType, left, right)
else
@@ -62,6 +62,7 @@ import org.jetbrains.kotlin.resolve.calls.model.*;
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo;
import org.jetbrains.kotlin.resolve.constants.*;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluatorKt;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
@@ -100,9 +101,7 @@ import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
@@ -2991,7 +2990,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
else if (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ ||
opToken == KtTokens.EQEQEQ || opToken == KtTokens.EXCLEQEQEQ) {
return generateEquals(expression.getLeft(), expression.getRight(), opToken, null);
return generateEquals(
expression.getLeft(), expression.getRight(), opToken, null,
bindingContext.get(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, expression)
);
}
else if (opToken == KtTokens.LT || opToken == KtTokens.LTEQ ||
opToken == KtTokens.GT || opToken == KtTokens.GTEQ) {
@@ -3054,7 +3056,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@Nullable KtExpression left,
@Nullable KtExpression right,
@NotNull IElementType opToken,
@Nullable StackValue pregeneratedLeft
@Nullable StackValue pregeneratedLeft,
@Nullable PrimitiveNumericComparisonInfo primitiveNumericComparisonInfo
) {
Type leftType = expressionType(left);
Type rightType = expressionType(right);
@@ -3139,7 +3142,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
);
}
return genEqualsForExpressionsPreferIEEE754Arithmetic(left, right, opToken, leftType, rightType, pregeneratedLeft);
return genEqualsForExpressionsPreferIeee754Arithmetic(
left, right, opToken, leftType, rightType, pregeneratedLeft, primitiveNumericComparisonInfo
);
}
private boolean isSelectorPureNonNullType(@NotNull KtSafeQualifiedExpression safeExpression) {
@@ -3186,38 +3191,65 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
);
}
@Nullable
private static KotlinType getLeftOperandType(@Nullable PrimitiveNumericComparisonInfo numericComparisonInfo) {
if (numericComparisonInfo == null) return null;
return numericComparisonInfo.getLeftType();
}
@Nullable
private static KotlinType getRightOperandType(@Nullable PrimitiveNumericComparisonInfo numericComparisonInfo) {
if (numericComparisonInfo == null) return null;
return numericComparisonInfo.getRightType();
}
/*tries to use IEEE 754 arithmetic*/
private StackValue genEqualsForExpressionsPreferIEEE754Arithmetic(
private StackValue genEqualsForExpressionsPreferIeee754Arithmetic(
@Nullable KtExpression left,
@Nullable KtExpression right,
@NotNull IElementType opToken,
@NotNull Type leftType,
@NotNull Type rightType,
@Nullable StackValue pregeneratedLeft
@Nullable StackValue pregeneratedLeft,
@Nullable PrimitiveNumericComparisonInfo primitiveNumericComparisonInfo
) {
assert (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ) : "Optoken should be '==' or '!=', but: " + opToken;
TypeAndNullability left754Type = calcTypeForIEEE754ArithmeticIfNeeded(left);
TypeAndNullability right754Type = calcTypeForIEEE754ArithmeticIfNeeded(right);
if (left754Type != null && right754Type != null && left754Type.type.equals(right754Type.type)) {
//check nullability cause there is some optimizations in codegen for non-nullable case
if (left754Type.isNullable || right754Type.isNullable) {
if (state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_1) >= 0) {
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
generate754EqualsForNullableTypesViaIntrinsic(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
return Unit.INSTANCE;
});
TypeAndNullability left754Type = calcTypeForIeee754ArithmeticIfNeeded(left, getLeftOperandType(primitiveNumericComparisonInfo));
TypeAndNullability right754Type = calcTypeForIeee754ArithmeticIfNeeded(right, getRightOperandType(primitiveNumericComparisonInfo));
if (left754Type != null && right754Type != null) {
if (left754Type.type.equals(right754Type.type)) {
//check nullability cause there is some optimizations in codegen for non-nullable case
if (left754Type.isNullable || right754Type.isNullable) {
if (state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_1) >= 0) {
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
generate754EqualsForNullableTypesViaIntrinsic(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
return Unit.INSTANCE;
});
}
else {
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
generate754EqualsForNullableTypes(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
return Unit.INSTANCE;
});
}
}
else {
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
generate754EqualsForNullableTypes(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
return Unit.INSTANCE;
});
leftType = left754Type.type;
rightType = right754Type.type;
}
}
else {
leftType = left754Type.type;
rightType = right754Type.type;
else if (shouldUseProperNumberComparisons()) {
Type comparisonType = comparisonOperandType(left754Type.type, right754Type.type);
if (comparisonType == Type.FLOAT_TYPE || comparisonType == Type.DOUBLE_TYPE) {
return Ieee754Equality.create(
myFrameMap,
genLazy(left, boxIfNullable(left754Type)),
genLazy(right, boxIfNullable(right754Type)),
comparisonType,
opToken
);
}
}
}
@@ -3228,6 +3260,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
);
}
@NotNull
private static Type boxIfNullable(@NotNull TypeAndNullability ieee754Type) {
if (ieee754Type.isNullable) return AsmUtil.boxType(ieee754Type.type);
return ieee754Type.type;
}
private void generate754EqualsForNullableTypesViaIntrinsic(
@NotNull InstructionAdapter v,
@NotNull IElementType opToken,
@@ -3400,6 +3438,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
private StackValue generateComparison(KtBinaryExpression expression, StackValue receiver) {
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
PrimitiveNumericComparisonInfo primitiveNumericComparisonInfo =
bindingContext.get(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, expression);
KtExpression left = expression.getLeft();
KtExpression right = expression.getRight();
@@ -3409,12 +3449,20 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
StackValue rightValue;
Type leftType = expressionType(left);
Type rightType = expressionType(right);
TypeAndNullability left754Type = calcTypeForIEEE754ArithmeticIfNeeded(left);
TypeAndNullability right754Type = calcTypeForIEEE754ArithmeticIfNeeded(right);
TypeAndNullability left754Type = calcTypeForIeee754ArithmeticIfNeeded(left, getLeftOperandType(primitiveNumericComparisonInfo));
TypeAndNullability right754Type = calcTypeForIeee754ArithmeticIfNeeded(right, getRightOperandType(primitiveNumericComparisonInfo));
Callable callable = resolveToCallable((FunctionDescriptor) resolvedCall.getResultingDescriptor(), false, resolvedCall);
boolean is754Arithmetic = left754Type != null && right754Type != null && left754Type.type.equals(right754Type.type);
if (callable instanceof IntrinsicCallable && ((isPrimitive(leftType) && isPrimitive(rightType)) || is754Arithmetic)) {
type = is754Arithmetic ? left754Type.type : comparisonOperandType(leftType, rightType);
boolean isSame754ArithmeticTypes = left754Type != null && right754Type != null && left754Type.type.equals(right754Type.type);
boolean properNumberComparisons = shouldUseProperNumberComparisons();
if (properNumberComparisons && left754Type != null && right754Type != null) {
type = comparisonOperandType(leftType, rightType);
leftValue = gen(left);
rightValue = gen(right);
}
else if (!properNumberComparisons &&
callable instanceof IntrinsicCallable && ((isPrimitive(leftType) && isPrimitive(rightType)) || isSame754ArithmeticTypes)) {
type = isSame754ArithmeticTypes ? left754Type.type : comparisonOperandType(leftType, rightType);
leftValue = gen(left);
rightValue = gen(right);
}
@@ -3426,9 +3474,25 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return StackValue.cmp(expression.getOperationToken(), type, leftValue, rightValue);
}
private TypeAndNullability calcTypeForIEEE754ArithmeticIfNeeded(@Nullable KtExpression expression) {
return CodegenUtilKt.calcTypeForIEEE754ArithmeticIfNeeded(
expression, bindingContext, context.getFunctionDescriptor(), state.getLanguageVersionSettings());
@Nullable
private TypeAndNullability calcTypeForIeee754ArithmeticIfNeeded(
@Nullable KtExpression expression,
@Nullable KotlinType inferredPrimitiveType
) {
if (expression == null) {
return null;
}
else if (shouldUseProperNumberComparisons()) {
return Ieee754Kt.calcProperTypeForIeee754ArithmeticIfNeeded(expression, bindingContext, inferredPrimitiveType, typeMapper);
}
else {
return Ieee754Kt.legacyCalcTypeForIeee754ArithmeticIfNeeded(
expression, bindingContext, context.getFunctionDescriptor(), state.getLanguageVersionSettings());
}
}
private boolean shouldUseProperNumberComparisons() {
return state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ProperNumberComparisons);
}
private StackValue generateAssignmentExpression(KtBinaryExpression expression) {
@@ -4251,7 +4315,10 @@ The "returned" value of try expression with no finally is either the last expres
private StackValue generateExpressionMatch(StackValue expressionToMatch, KtExpression subjectExpression, KtExpression patternExpression) {
if (expressionToMatch != null) {
return generateEquals(subjectExpression, patternExpression, KtTokens.EQEQ, expressionToMatch);
return generateEquals(
subjectExpression, patternExpression, KtTokens.EQEQ, expressionToMatch,
bindingContext.get(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, patternExpression)
);
}
else {
return gen(patternExpression);
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
@@ -35,10 +34,8 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isSubclass
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.callUtil.getFirstArgumentExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
@@ -49,7 +46,6 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -274,38 +270,8 @@ private fun CallableDescriptor.isJvmStaticIn(predicate: (DeclarationDescriptor)
fun Collection<VariableDescriptor>.filterOutDescriptorsWithSpecialNames() = filterNot { it.name.isSpecial }
class TypeAndNullability(@JvmField val type: Type, @JvmField val isNullable: Boolean)
class JvmKotlinType(val type: Type, val kotlinType: KotlinType?)
fun calcTypeForIEEE754ArithmeticIfNeeded(
expression: KtExpression?,
bindingContext: BindingContext,
descriptor: DeclarationDescriptor,
languageVersionSettings: LanguageVersionSettings
): TypeAndNullability? {
val ktType = expression.kotlinType(bindingContext) ?: return null
if (KotlinBuiltIns.isDoubleOrNullableDouble(ktType)) {
return TypeAndNullability(Type.DOUBLE_TYPE, TypeUtils.isNullableType(ktType))
}
if (KotlinBuiltIns.isFloatOrNullableFloat(ktType)) {
return TypeAndNullability(Type.FLOAT_TYPE, TypeUtils.isNullableType(ktType))
}
val dataFlow = DataFlowValueFactory.createDataFlowValue(expression!!, ktType, bindingContext, descriptor)
val stableTypes = bindingContext.getDataFlowInfoBefore(expression).getStableTypes(dataFlow, languageVersionSettings)
return stableTypes.firstNotNullResult {
when {
KotlinBuiltIns.isDoubleOrNullableDouble(it) -> TypeAndNullability(Type.DOUBLE_TYPE, TypeUtils.isNullableType(it))
KotlinBuiltIns.isFloatOrNullableFloat(it) -> TypeAndNullability(Type.FLOAT_TYPE, TypeUtils.isNullableType(it))
else -> null
}
}
}
fun KotlinType.asmType(typeMapper: KotlinTypeMapper) = typeMapper.mapType(this)
fun KtExpression?.asmType(typeMapper: KotlinTypeMapper, bindingContext: BindingContext): Type =
@@ -439,3 +405,22 @@ val CodegenContext<*>.parentContexts
val CodegenContext<*>.contextStackText
get() = parentContextsWithSelf.joinToString(separator = "\n") { it.toString() }
inline fun FrameMap.evaluateOnce(
value: StackValue,
asType: Type,
v: InstructionAdapter,
body: (StackValue) -> Unit
) {
val valueOrTmp: StackValue =
if (value.canHaveSideEffects())
StackValue.local(enterTemp(asType), asType).apply { store(value, v) }
else
value
body(valueOrTmp)
if (valueOrTmp != value) {
leaveTemp(asType)
}
}
@@ -0,0 +1,83 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.org.objectweb.asm.Type
class TypeAndNullability(@JvmField val type: Type, @JvmField val isNullable: Boolean)
fun calcProperTypeForIeee754ArithmeticIfNeeded(
expression: KtExpression,
bindingContext: BindingContext,
inferredPrimitiveType: KotlinType?,
typeMapper: KotlinTypeMapper
): TypeAndNullability? {
if (inferredPrimitiveType == null) return null
val ktType = expression.kotlinType(bindingContext) ?: return null
val isNullable = TypeUtils.isNullableType(ktType)
val asmType = typeMapper.mapType(inferredPrimitiveType)
if (!AsmUtil.isPrimitive(asmType)) return null
return TypeAndNullability(asmType, isNullable)
}
fun legacyCalcTypeForIeee754ArithmeticIfNeeded(
expression: KtExpression?,
bindingContext: BindingContext,
descriptor: DeclarationDescriptor,
languageVersionSettings: LanguageVersionSettings
): TypeAndNullability? {
val ktType = expression.kotlinType(bindingContext) ?: return null
if (KotlinBuiltIns.isDoubleOrNullableDouble(ktType)) {
return TypeAndNullability(
Type.DOUBLE_TYPE,
TypeUtils.isNullableType(ktType)
)
}
if (KotlinBuiltIns.isFloatOrNullableFloat(ktType)) {
return TypeAndNullability(
Type.FLOAT_TYPE,
TypeUtils.isNullableType(ktType)
)
}
val dataFlow = DataFlowValueFactory.createDataFlowValue(
expression!!,
ktType,
bindingContext,
descriptor
)
val stableTypes = bindingContext.getDataFlowInfoBefore(expression).getStableTypes(dataFlow, languageVersionSettings)
return stableTypes.firstNotNullResult {
when {
KotlinBuiltIns.isDoubleOrNullableDouble(it) -> TypeAndNullability(
Type.DOUBLE_TYPE,
TypeUtils.isNullableType(
it
)
)
KotlinBuiltIns.isFloatOrNullableFloat(it) -> TypeAndNullability(
Type.FLOAT_TYPE,
TypeUtils.isNullableType(
it
)
)
else -> null
}
}
}
@@ -95,6 +95,7 @@ class InFloatingPointRangeLiteralExpressionGenerator(
}
// TODO evaluateOnce
private fun introduceTemporaryIfRequired(v: InstructionAdapter, value: StackValue, type: Type): Pair<StackValue, Type?> {
val resultValue: StackValue
val resultType: Type?
@@ -49,66 +49,67 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager
import java.io.File
class GenerationState private constructor(
val project: Project,
builderFactory: ClassBuilderFactory,
val module: ModuleDescriptor,
bindingContext: BindingContext,
val files: List<KtFile>,
val configuration: CompilerConfiguration,
val generateDeclaredClassFilter: GenerateClassFilter,
val codegenFactory: CodegenFactory,
val targetId: TargetId?,
moduleName: String?,
val outDirectory: File?,
private val onIndependentPartCompilationEnd: GenerationStateEventCallback,
wantsDiagnostics: Boolean
val project: Project,
builderFactory: ClassBuilderFactory,
val module: ModuleDescriptor,
bindingContext: BindingContext,
val files: List<KtFile>,
val configuration: CompilerConfiguration,
val generateDeclaredClassFilter: GenerateClassFilter,
val codegenFactory: CodegenFactory,
val targetId: TargetId?,
moduleName: String?,
val outDirectory: File?,
private val onIndependentPartCompilationEnd: GenerationStateEventCallback,
wantsDiagnostics: Boolean
) {
class Builder(
private val project: Project,
private val builderFactory: ClassBuilderFactory,
private val module: ModuleDescriptor,
private val bindingContext: BindingContext,
private val files: List<KtFile>,
private val configuration: CompilerConfiguration
private val project: Project,
private val builderFactory: ClassBuilderFactory,
private val module: ModuleDescriptor,
private val bindingContext: BindingContext,
private val files: List<KtFile>,
private val configuration: CompilerConfiguration
) {
private var generateDeclaredClassFilter: GenerateClassFilter = GenerateClassFilter.GENERATE_ALL
fun generateDeclaredClassFilter(v: GenerateClassFilter) =
apply { generateDeclaredClassFilter = v }
apply { generateDeclaredClassFilter = v }
private var codegenFactory: CodegenFactory = DefaultCodegenFactory
fun codegenFactory(v: CodegenFactory) =
apply { codegenFactory = v }
apply { codegenFactory = v }
private var targetId: TargetId? = null
fun targetId(v: TargetId?) =
apply { targetId = v }
apply { targetId = v }
private var moduleName: String? = configuration[CommonConfigurationKeys.MODULE_NAME]
fun moduleName(v: String?) =
apply { moduleName = v }
apply { moduleName = v }
// 'outDirectory' is a hack to correctly determine if a compiled class is from the same module as the callee during
// partial compilation. Module chunks are treated as a single module.
// TODO: get rid of it with the proper module infrastructure
private var outDirectory: File? = null
fun outDirectory(v: File?) =
apply { outDirectory = v }
apply { outDirectory = v }
private var onIndependentPartCompilationEnd: GenerationStateEventCallback = GenerationStateEventCallback.DO_NOTHING
fun onIndependentPartCompilationEnd(v: GenerationStateEventCallback) =
apply { onIndependentPartCompilationEnd = v }
apply { onIndependentPartCompilationEnd = v }
private var wantsDiagnostics: Boolean = true
fun wantsDiagnostics(v: Boolean) =
apply { wantsDiagnostics = v }
apply { wantsDiagnostics = v }
fun build() =
GenerationState(
project, builderFactory, module, bindingContext, files, configuration,
generateDeclaredClassFilter, codegenFactory, targetId,
moduleName, outDirectory, onIndependentPartCompilationEnd, wantsDiagnostics
)
GenerationState(
project, builderFactory, module, bindingContext, files, configuration,
generateDeclaredClassFilter, codegenFactory, targetId,
moduleName, outDirectory, onIndependentPartCompilationEnd, wantsDiagnostics
)
}
abstract class GenerateClassFilter {
@@ -119,7 +120,8 @@ class GenerationState private constructor(
open fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject)
companion object {
@JvmField val GENERATE_ALL: GenerateClassFilter = object : GenerateClassFilter() {
@JvmField
val GENERATE_ALL: GenerateClassFilter = object : GenerateClassFilter() {
override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean = true
override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean = true
@@ -137,7 +139,7 @@ class GenerationState private constructor(
val packagesWithObsoleteParts: Set<FqName>
val obsoleteMultifileClasses: List<FqName>
val deserializationConfiguration: DeserializationConfiguration =
CompilerDeserializationConfiguration(configuration.languageVersionSettings)
CompilerDeserializationConfiguration(configuration.languageVersionSettings)
val deprecationProvider = DeprecationResolver(LockBasedStorageManager.NO_LOCKS, configuration.languageVersionSettings)
@@ -152,15 +154,15 @@ class GenerationState private constructor(
obsoleteMultifileClasses = incrementalCacheForThisTarget.getObsoleteMultifileClasses().map {
JvmClassName.byInternalName(it).fqNameForClassNameWithoutDollars
}
}
else {
} else {
incrementalCacheForThisTarget = null
packagesWithObsoleteParts = emptySet()
obsoleteMultifileClasses = emptyList()
}
}
val extraJvmDiagnosticsTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "For extra diagnostics in ${this::class.java}", false)
val extraJvmDiagnosticsTrace: BindingTrace =
DelegatingBindingTrace(bindingContext, "For extra diagnostics in ${this::class.java}", false)
private val interceptedBuilderFactory: ClassBuilderFactory
private var used = false
@@ -174,21 +176,23 @@ class GenerationState private constructor(
val target = configuration.get(JVMConfigurationKeys.JVM_TARGET) ?: JvmTarget.DEFAULT
val isJvm8Target: Boolean = target == JvmTarget.JVM_1_8
val isJvm8TargetWithDefaults: Boolean = isJvm8Target && configuration.getBoolean(JVMConfigurationKeys.JVM8_TARGET_WITH_DEFAULTS)
val isJvm8TargetWithDefaults: Boolean = isJvm8Target && configuration.getBoolean(JVMConfigurationKeys.JVM8_TARGET_WITH_DEFAULTS)
val generateDefaultImplsForJvm8: Boolean = configuration.getBoolean(JVMConfigurationKeys.INTERFACE_COMPATIBILITY)
val moduleName: String = moduleName ?: JvmCodegenUtil.getModuleName(module)
val classBuilderMode: ClassBuilderMode = builderFactory.classBuilderMode
val bindingTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "trace in GenerationState",
filter = if (wantsDiagnostics) BindingTraceFilter.ACCEPT_ALL else BindingTraceFilter.NO_DIAGNOSTICS)
val bindingTrace: BindingTrace = DelegatingBindingTrace(
bindingContext, "trace in GenerationState",
filter = if (wantsDiagnostics) BindingTraceFilter.ACCEPT_ALL else BindingTraceFilter.NO_DIAGNOSTICS
)
val bindingContext: BindingContext = bindingTrace.bindingContext
val typeMapper: KotlinTypeMapper = KotlinTypeMapper(
this.bindingContext, classBuilderMode, IncompatibleClassTrackerImpl(extraJvmDiagnosticsTrace),
this.moduleName, isJvm8Target, isJvm8TargetWithDefaults
this.bindingContext, classBuilderMode, IncompatibleClassTrackerImpl(extraJvmDiagnosticsTrace),
this.moduleName, isJvm8Target, isJvm8TargetWithDefaults
)
val intrinsics: IntrinsicMethods = run {
val shouldUseConsistentEquals = languageVersionSettings.supportsFeature(LanguageFeature.ThrowNpeOnExplicitEqualsForBoxedNull) &&
!configuration.getBoolean(JVMConfigurationKeys.NO_EXCEPTION_ON_EXPLICIT_EQUALS_FOR_BOXED_NULL)
!configuration.getBoolean(JVMConfigurationKeys.NO_EXCEPTION_ON_EXPLICIT_EQUALS_FOR_BOXED_NULL)
IntrinsicMethods(target, shouldUseConsistentEquals)
}
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
@@ -210,8 +214,8 @@ class GenerationState private constructor(
val isCallAssertionsDisabled: Boolean = configuration.getBoolean(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS)
val isReceiverAssertionsDisabled: Boolean =
configuration.getBoolean(JVMConfigurationKeys.DISABLE_RECEIVER_ASSERTIONS) ||
!languageVersionSettings.supportsFeature(LanguageFeature.NullabilityAssertionOnExtensionReceiver)
configuration.getBoolean(JVMConfigurationKeys.DISABLE_RECEIVER_ASSERTIONS) ||
!languageVersionSettings.supportsFeature(LanguageFeature.NullabilityAssertionOnExtensionReceiver)
val isParamAssertionsDisabled: Boolean = configuration.getBoolean(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS)
val isInlineDisabled: Boolean = configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE)
val useTypeTableInSerializer: Boolean = configuration.getBoolean(JVMConfigurationKeys.USE_TYPE_TABLE)
@@ -225,26 +229,32 @@ class GenerationState private constructor(
val shouldInlineConstVals = languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals)
val constructorCallNormalizationMode = configuration.get(JVMConfigurationKeys.CONSTRUCTOR_CALL_NORMALIZATION_MODE,
JVMConstructorCallNormalizationMode.DEFAULT)
val constructorCallNormalizationMode = configuration.get(
JVMConfigurationKeys.CONSTRUCTOR_CALL_NORMALIZATION_MODE,
JVMConstructorCallNormalizationMode.DEFAULT
)
init {
val disableOptimization = configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false)
this.interceptedBuilderFactory = builderFactory
.wrapWith(
{ OptimizationClassBuilderFactory(it, disableOptimization, constructorCallNormalizationMode) },
{ BuilderFactoryForDuplicateSignatureDiagnostics(
it, this.bindingContext, diagnostics, this.moduleName,
shouldGenerate = { !shouldOnlyCollectSignatures(it) }
).apply { duplicateSignatureFactory = this } },
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, diagnostics) },
{ configuration.get(JVMConfigurationKeys.DECLARATIONS_JSON_PATH)
?.let { destination -> SignatureDumpingBuilderFactory(it, File(destination)) } ?: it }
)
.wrapWith(ClassBuilderInterceptorExtension.getInstances(project)) { builderFactory, extension ->
extension.interceptClassBuilderFactory(builderFactory, bindingContext, diagnostics)
.wrapWith(
{ OptimizationClassBuilderFactory(it, disableOptimization, constructorCallNormalizationMode) },
{
BuilderFactoryForDuplicateSignatureDiagnostics(
it, this.bindingContext, diagnostics, this.moduleName,
shouldGenerate = { !shouldOnlyCollectSignatures(it) }
).apply { duplicateSignatureFactory = this }
},
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, diagnostics) },
{
configuration.get(JVMConfigurationKeys.DECLARATIONS_JSON_PATH)
?.let { destination -> SignatureDumpingBuilderFactory(it, File(destination)) } ?: it
}
)
.wrapWith(ClassBuilderInterceptorExtension.getInstances(project)) { builderFactory, extension ->
extension.interceptClassBuilderFactory(builderFactory, bindingContext, diagnostics)
}
this.factory = ClassFileFactory(this, interceptedBuilderFactory)
}
@@ -269,13 +279,13 @@ class GenerationState private constructor(
interceptedBuilderFactory.close()
}
private fun shouldOnlyCollectSignatures(origin: JvmDeclarationOrigin)
= classBuilderMode == ClassBuilderMode.LIGHT_CLASSES && origin.originKind in doNotGenerateInLightClassMode
private fun shouldOnlyCollectSignatures(origin: JvmDeclarationOrigin) =
classBuilderMode == ClassBuilderMode.LIGHT_CLASSES && origin.originKind in doNotGenerateInLightClassMode
}
private val doNotGenerateInLightClassMode = setOf(CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL, BRIDGE, COLLECTION_STUB, AUGMENTED_BUILTIN_API)
private class LazyJvmDiagnostics(compute: () -> Diagnostics): Diagnostics {
private class LazyJvmDiagnostics(compute: () -> Diagnostics) : Diagnostics {
private val delegate by lazy(LazyThreadSafetyMode.SYNCHRONIZED, compute)
override val modificationTracker: ModificationTracker
@@ -283,7 +293,7 @@ private class LazyJvmDiagnostics(compute: () -> Diagnostics): Diagnostics {
override fun all(): Collection<Diagnostic> = delegate.all()
override fun forElement(psiElement: PsiElement) = delegate.forElement(psiElement)
override fun forElement(psiElement: PsiElement) = delegate.forElement(psiElement)
override fun isEmpty() = delegate.isEmpty()
@@ -294,17 +304,20 @@ private class LazyJvmDiagnostics(compute: () -> Diagnostics): Diagnostics {
interface GenerationStateEventCallback : (GenerationState) -> Unit {
companion object {
val DO_NOTHING = GenerationStateEventCallback { }
val DO_NOTHING = GenerationStateEventCallback { }
}
}
fun GenerationStateEventCallback(block: (GenerationState) -> Unit): GenerationStateEventCallback =
object : GenerationStateEventCallback {
override fun invoke(s: GenerationState) = block(s)
}
object : GenerationStateEventCallback {
override fun invoke(s: GenerationState) = block(s)
}
private fun ClassBuilderFactory.wrapWith(vararg wrappers: (ClassBuilderFactory) -> ClassBuilderFactory): ClassBuilderFactory =
wrappers.fold(this) { builderFactory, wrapper -> wrapper(builderFactory) }
wrappers.fold(this) { builderFactory, wrapper -> wrapper(builderFactory) }
private inline fun <T> ClassBuilderFactory.wrapWith(elements: Iterable<T>, wrapper: (ClassBuilderFactory, T) -> ClassBuilderFactory): ClassBuilderFactory =
elements.fold(this, wrapper)
private inline fun <T> ClassBuilderFactory.wrapWith(
elements: Iterable<T>,
wrapper: (ClassBuilderFactory, T) -> ClassBuilderFactory
): ClassBuilderFactory =
elements.fold(this, wrapper)
@@ -0,0 +1,11 @@
// LANGUAGE_VERSION: 1.3
fun less(x: Comparable<Float>, y: Float) = x is Float && x < y
fun less(x: Comparable<Double>, y: Double) = x is Double && x < y
fun box(): String {
if (less(-0.0F, 0.0F)) return "Fail F"
if (less(-0.0, 0.0)) return "Fail D"
return "OK"
}
@@ -0,0 +1,27 @@
// LANGUAGE_VERSION: 1.3
fun myEquals(a: Double?, b: Double?) = a == b
fun myEquals1(a: Double?, b: Double) = a == b
fun myEquals2(a: Double, b: Double?) = a == b
fun myEquals0(a: Double, b: Double) = a == b
fun box(): String {
if (!myEquals(null, null)) return "fail 1"
if (myEquals(null, 0.0)) return "fail 2"
if (myEquals(0.0, null)) return "fail 3"
if (!myEquals(0.0, 0.0)) return "fail 4"
if (myEquals1(null, 0.0)) return "fail 5"
if (!myEquals1(0.0, 0.0)) return "fail 6"
if (myEquals2(0.0, null)) return "fail 7"
if (!myEquals2(0.0, 0.0)) return "fail 8"
if (!myEquals0(0.0, 0.0)) return "fail 9"
return "OK"
}
@@ -0,0 +1,25 @@
// LANGUAGE_VERSION: 1.3
fun testF(x: Any) =
when (x) {
!is Float -> "!Float"
0.0F -> "0.0"
else -> "other"
}
fun testD(x: Any) =
when (x) {
!is Double -> "!Double"
0.0 -> "0.0"
else -> "other"
}
fun box(): String {
val tf = testF(0.0F)
if (tf != "0.0") return "Fail 1: $tf"
val td = testD(0.0)
if (td != "0.0") return "Fail 2: $td"
return "OK"
}
@@ -0,0 +1,13 @@
// LANGUAGE_VERSION: 1.3
fun ne(x: Any, y: Any) = x is Double && y is Float && x != y
fun lt(x: Any, y: Any) = x is Double && y is Float && x < y
fun gt(x: Any, y: Any) = x is Double && y is Float && x > y
fun box(): String {
if (ne(0.0, -0.0F)) return "fail 1"
if (lt(0.0, -0.0F)) return "fail 2"
if (gt(0.0, -0.0F)) return "fail 3"
return "OK"
}
@@ -0,0 +1,76 @@
// LANGUAGE_VERSION: 1.3
// IGNORE_BACKEND: JS
fun eqDI(x: Any?, y: Any?) = x is Double? && y is Int? && x == y
fun eqDL(x: Any?, y: Any?) = x is Double? && y is Long? && x == y
fun eqID(x: Any?, y: Any?) = x is Int? && y is Double? && x == y
fun eqLD(x: Any?, y: Any?) = x is Long? && y is Double? && x == y
fun eqFI(x: Any?, y: Any?) = x is Float? && y is Int? && x == y
fun eqFL(x: Any?, y: Any?) = x is Float? && y is Long? && x == y
fun eqIF(x: Any?, y: Any?) = x is Int? && y is Float? && x == y
fun eqLF(x: Any?, y: Any?) = x is Long? && y is Float? && x == y
fun testNullNull() {
if (!eqDI(null, null)) throw Exception()
if (!eqDL(null, null)) throw Exception()
if (!eqID(null, null)) throw Exception()
if (!eqLD(null, null)) throw Exception()
if (!eqFI(null, null)) throw Exception()
if (!eqFL(null, null)) throw Exception()
if (!eqIF(null, null)) throw Exception()
if (!eqLF(null, null)) throw Exception()
}
fun testNull0() {
if (eqDI(null, 0)) throw Exception()
if (eqDL(null, 0L)) throw Exception()
if (eqID(null, 0.0)) throw Exception()
if (eqLD(null, 0.0)) throw Exception()
if (eqFI(null, 0)) throw Exception()
if (eqFL(null, 0L)) throw Exception()
if (eqIF(null, 0.0F)) throw Exception()
if (eqLF(null, 0.0F)) throw Exception()
}
fun test0Null() {
if (eqDI(0.0, null)) throw Exception()
if (eqDL(0.0, null)) throw Exception()
if (eqID(0, null)) throw Exception()
if (eqLD(0L, null)) throw Exception()
if (eqFI(0.0F, null)) throw Exception()
if (eqFL(0.0F, null)) throw Exception()
if (eqIF(0, null)) throw Exception()
if (eqLF(0L, null)) throw Exception()
}
fun testPlusMinus0() {
if (!eqDI(-0.0, 0)) throw Exception()
if (!eqDL(-0.0, 0L)) throw Exception()
if (!eqID(0, -0.0)) throw Exception()
if (!eqLD(0L, -0.0)) throw Exception()
if (!eqFI(-0.0F, 0)) throw Exception()
if (!eqFL(-0.0F, 0L)) throw Exception()
if (!eqIF(0, -0.0F)) throw Exception()
if (!eqLF(0L, -0.0F)) throw Exception()
}
fun test01() {
if (eqDI(0.0, 1)) throw Exception()
if (eqDL(0.0, 1L)) throw Exception()
if (eqID(0, 1.0)) throw Exception()
if (eqLD(0L, 1.0)) throw Exception()
if (eqFI(0.0F, 1)) throw Exception()
if (eqFL(0.0F, 1L)) throw Exception()
if (eqIF(0, 1.0F)) throw Exception()
if (eqLF(0L, 1.0F)) throw Exception()
}
fun box(): String {
testNullNull()
testNull0()
test0Null()
testPlusMinus0()
test01()
return "OK"
}
@@ -9993,6 +9993,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("comparableToTWithTLV13.kt")
public void testComparableToTWithTLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableToTWithTLV13.kt");
doTest(fileName);
}
@TestMetadata("comparableTypeCast.kt")
public void testComparableTypeCast() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableTypeCast.kt");
@@ -10101,6 +10107,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("nullableDoubleEqualsLV13.kt")
public void testNullableDoubleEqualsLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/nullableDoubleEqualsLV13.kt");
doTest(fileName);
}
@TestMetadata("nullableDoubleNotEquals.kt")
public void testNullableDoubleNotEquals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/nullableDoubleNotEquals.kt");
@@ -10149,12 +10161,30 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("smartCastOnWhenSubjectAfterCheckInBranchLV13.kt")
public void testSmartCastOnWhenSubjectAfterCheckInBranchLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastOnWhenSubjectAfterCheckInBranchLV13.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypes.kt")
public void testSmartCastToDifferentTypes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypesLV13.kt")
public void testSmartCastToDifferentTypesLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesLV13.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypesWithNumericPromotionLV13.kt")
public void testSmartCastToDifferentTypesWithNumericPromotionLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotionLV13.kt");
doTest(fileName);
}
@TestMetadata("when.kt")
public void testWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/when.kt");
@@ -9993,6 +9993,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("comparableToTWithTLV13.kt")
public void testComparableToTWithTLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableToTWithTLV13.kt");
doTest(fileName);
}
@TestMetadata("comparableTypeCast.kt")
public void testComparableTypeCast() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableTypeCast.kt");
@@ -10101,6 +10107,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("nullableDoubleEqualsLV13.kt")
public void testNullableDoubleEqualsLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/nullableDoubleEqualsLV13.kt");
doTest(fileName);
}
@TestMetadata("nullableDoubleNotEquals.kt")
public void testNullableDoubleNotEquals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/nullableDoubleNotEquals.kt");
@@ -10149,12 +10161,30 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("smartCastOnWhenSubjectAfterCheckInBranchLV13.kt")
public void testSmartCastOnWhenSubjectAfterCheckInBranchLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastOnWhenSubjectAfterCheckInBranchLV13.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypes.kt")
public void testSmartCastToDifferentTypes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypesLV13.kt")
public void testSmartCastToDifferentTypesLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesLV13.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypesWithNumericPromotionLV13.kt")
public void testSmartCastToDifferentTypesWithNumericPromotionLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotionLV13.kt");
doTest(fileName);
}
@TestMetadata("when.kt")
public void testWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/when.kt");
@@ -9993,6 +9993,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("comparableToTWithTLV13.kt")
public void testComparableToTWithTLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableToTWithTLV13.kt");
doTest(fileName);
}
@TestMetadata("comparableTypeCast.kt")
public void testComparableTypeCast() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableTypeCast.kt");
@@ -10101,6 +10107,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("nullableDoubleEqualsLV13.kt")
public void testNullableDoubleEqualsLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/nullableDoubleEqualsLV13.kt");
doTest(fileName);
}
@TestMetadata("nullableDoubleNotEquals.kt")
public void testNullableDoubleNotEquals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/nullableDoubleNotEquals.kt");
@@ -10149,12 +10161,30 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("smartCastOnWhenSubjectAfterCheckInBranchLV13.kt")
public void testSmartCastOnWhenSubjectAfterCheckInBranchLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastOnWhenSubjectAfterCheckInBranchLV13.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypes.kt")
public void testSmartCastToDifferentTypes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypesLV13.kt")
public void testSmartCastToDifferentTypesLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesLV13.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypesWithNumericPromotionLV13.kt")
public void testSmartCastToDifferentTypesWithNumericPromotionLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotionLV13.kt");
doTest(fileName);
}
@TestMetadata("when.kt")
public void testWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/when.kt");
@@ -66,6 +66,7 @@ enum class LanguageFeature(
NestedClassesInAnnotations(KOTLIN_1_3),
JvmStaticInInterface(KOTLIN_1_3),
InlineClasses(KOTLIN_1_3),
ProperNumberComparisons(KOTLIN_1_3),
StrictJavaNullabilityAssertions(sinceVersion = null, defaultState = State.DISABLED),
@@ -10917,6 +10917,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("comparableToTWithTLV13.kt")
public void testComparableToTWithTLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableToTWithTLV13.kt");
doTest(fileName);
}
@TestMetadata("comparableTypeCast.kt")
public void testComparableTypeCast() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableTypeCast.kt");
@@ -11049,6 +11055,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("nullableDoubleEqualsLV13.kt")
public void testNullableDoubleEqualsLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/nullableDoubleEqualsLV13.kt");
doTest(fileName);
}
@TestMetadata("nullableDoubleNotEquals.kt")
public void testNullableDoubleNotEquals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/nullableDoubleNotEquals.kt");
@@ -11103,6 +11115,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("smartCastOnWhenSubjectAfterCheckInBranchLV13.kt")
public void testSmartCastOnWhenSubjectAfterCheckInBranchLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastOnWhenSubjectAfterCheckInBranchLV13.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypes.kt")
public void testSmartCastToDifferentTypes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt");
@@ -11115,6 +11133,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("smartCastToDifferentTypesLV13.kt")
public void testSmartCastToDifferentTypesLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesLV13.kt");
doTest(fileName);
}
@TestMetadata("smartCastToDifferentTypesWithNumericPromotionLV13.kt")
public void testSmartCastToDifferentTypesWithNumericPromotionLV13() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotionLV13.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("when.kt")
public void testWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/when.kt");