Generate synthetic functions for local functions with default values, by

re-ordering the lowering phases.

The changes in InterfaceLowering are necessary so that IrElements that
target the removed functions are re-targeted to the new functions in
DefaultImpls. This affects local functions in interface functions since
now LocalDeclarationsLowering comes before InterfaceLowering.
This commit is contained in:
Mark Punzalan
2019-06-26 21:01:06 -07:00
committed by max-kammerer
parent d2f1852c5e
commit 1abdf0561a
26 changed files with 239 additions and 89 deletions
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.ir.backend.js.lower.calls
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
@@ -48,7 +47,7 @@ internal fun <K> MutableMap<K, (IrFunctionAccessExpression) -> IrExpression>.add
internal typealias MemberToTransformer = HashMap<SimpleMemberKey, (IrFunctionAccessExpression) -> IrExpression>
internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunctionSymbol) {
add(type, name) { irCall(it, v, dispatchReceiverAsFirstArgument = true) }
add(type, name) { irCall(it, v, dispatchReceiverAsArgument = true) }
}
internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunction) {
@@ -53,7 +53,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
comparator.owner.returnType,
comparator
).apply {
putValueArgument(0, irCall(call, intrinsics.longCompareToLong, firstArgumentAsDispatchReceiver = true))
putValueArgument(0, irCall(call, intrinsics.longCompareToLong, argumentAsDispatchReceiver = true))
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, 0))
}
}
@@ -95,7 +95,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
chooseEqualityOperatorForPrimitiveTypes(call)
!isLhsPrimitive && !lhs.type.isNullable() && equalsMethod != null ->
irCall(call, equalsMethod.symbol, firstArgumentAsDispatchReceiver = true)
irCall(call, equalsMethod.symbol, argumentAsDispatchReceiver = true)
else ->
irCall(call, intrinsics.jsEquals)
@@ -127,7 +127,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
// Use runtime function call in case when receiverType is a primitive JS type that doesn't have `compareTo` method,
// or has a potential to be primitive type (being fake overridden from `Comparable`)
function.isMethodOfPrimitiveJSType() || function.isFakeOverriddenFromComparable() ->
irCall(call, intrinsics.jsCompareTo, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsCompareTo, dispatchReceiverAsArgument = true)
// Valid `compareTo` method must be present at this point
else ->
@@ -144,12 +144,12 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
// `Any.equals` works as identity operator
call.isSuperToAny() ->
irCall(call, intrinsics.jsEqeqeq, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsEqeqeq, dispatchReceiverAsArgument = true)
// Use runtime function call in case when receiverType is a primitive JS type that doesn't have `equals` method,
// or has a potential to be primitive type (being fake overridden from `Any`)
function.isMethodOfPotentiallyPrimitiveJSType() ->
irCall(call, intrinsics.jsEquals, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsEquals, dispatchReceiverAsArgument = true)
// Valid `equals` method must be present at this point
else -> call
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.types.isAny
import org.jetbrains.kotlin.ir.types.isArray
import org.jetbrains.kotlin.ir.types.isString
import org.jetbrains.kotlin.ir.util.isFakeOverriddenFromAny
import org.jetbrains.kotlin.ir.util.isNullable
import org.jetbrains.kotlin.ir.util.isSuperToAny
import org.jetbrains.kotlin.name.Name
@@ -30,9 +29,9 @@ class MethodsOfAnyCallsTransformer(context: JsIrBackendContext) : CallsTransform
put(Name.identifier("toString")) { call ->
if (shouldReplaceToStringWithRuntimeCall(call)) {
if ((call as IrCall).isSuperToAny()) {
irCall(call, intrinsics.jsAnyToString, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsAnyToString, dispatchReceiverAsArgument = true)
} else {
irCall(call, intrinsics.jsToString, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsToString, dispatchReceiverAsArgument = true)
}
} else {
call
@@ -42,9 +41,9 @@ class MethodsOfAnyCallsTransformer(context: JsIrBackendContext) : CallsTransform
put(Name.identifier("hashCode")) { call ->
if (call.symbol.owner.isFakeOverriddenFromAny()) {
if ((call as IrCall).isSuperToAny()) {
irCall(call, intrinsics.jsGetObjectHashCode, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsGetObjectHashCode, dispatchReceiverAsArgument = true)
} else {
irCall(call, intrinsics.jsHashCode, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsHashCode, dispatchReceiverAsArgument = true)
}
} else {
call
@@ -46,9 +46,9 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
irBuiltIns.booleanType.let {
// These operators are not short-circuit -- using bitwise operators '&', '|', '^' followed by coercion to boolean
add(it, OperatorNames.AND) { call -> toBoolean(irCall(call, intrinsics.jsBitAnd, dispatchReceiverAsFirstArgument = true)) }
add(it, OperatorNames.OR) { call -> toBoolean(irCall(call, intrinsics.jsBitOr, dispatchReceiverAsFirstArgument = true)) }
add(it, OperatorNames.XOR) { call -> toBoolean(irCall(call, intrinsics.jsBitXor, dispatchReceiverAsFirstArgument = true)) }
add(it, OperatorNames.AND) { call -> toBoolean(irCall(call, intrinsics.jsBitAnd, dispatchReceiverAsArgument = true)) }
add(it, OperatorNames.OR) { call -> toBoolean(irCall(call, intrinsics.jsBitOr, dispatchReceiverAsArgument = true)) }
add(it, OperatorNames.XOR) { call -> toBoolean(irCall(call, intrinsics.jsBitXor, dispatchReceiverAsArgument = true)) }
add(it, OperatorNames.NOT, intrinsics.jsNot)
}
@@ -88,9 +88,9 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
return with(call.symbol.owner.valueParameters[0].type) {
when {
isByte() || isShort() || isInt() ->
irCall(call, intrinsics.jsNumberRangeToNumber, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsNumberRangeToNumber, dispatchReceiverAsArgument = true)
isLong() ->
irCall(call, intrinsics.jsNumberRangeToLong, dispatchReceiverAsFirstArgument = true)
irCall(call, intrinsics.jsNumberRangeToLong, dispatchReceiverAsArgument = true)
else -> call
}
}
@@ -101,7 +101,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
intrinsic: IrFunctionSymbol,
toInt32: Boolean = false
): IrExpression {
val newCall = irCall(call, intrinsic, dispatchReceiverAsFirstArgument = true)
val newCall = irCall(call, intrinsic, dispatchReceiverAsArgument = true)
if (toInt32)
return toInt32(newCall)
return newCall
@@ -152,7 +152,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
transformCrement(call, intrinsics.jsMinus)
private fun transformCrement(call: IrFunctionAccessExpression, correspondingBinaryOp: IrFunctionSymbol): IrExpression {
val operation = irCall(call, correspondingBinaryOp, dispatchReceiverAsFirstArgument = true).apply {
val operation = irCall(call, correspondingBinaryOp, dispatchReceiverAsArgument = true).apply {
putValueArgument(1, buildInt(1))
}
@@ -161,7 +161,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
private fun transformUnaryMinus(call: IrFunctionAccessExpression) =
convertResultToPrimitiveType(
irCall(call, intrinsics.jsUnaryMinus, dispatchReceiverAsFirstArgument = true),
irCall(call, intrinsics.jsUnaryMinus, dispatchReceiverAsArgument = true),
call.type
)