mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-06 00:21:32 +00:00
Add mechanism for type coercion in JS
Use it for char boxing/unboxing and unit materialization. Possible to use for other purposes, for example, to add type checks to dynamics. See KT-18793, KT-17915, KT-19081, KT-18216, KT-12970, KT-17014, KT-13932, KT-13930
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
// IGNORE_BACKEND: JS
|
||||
// JS backend does not support Unit well. See KT-13932
|
||||
|
||||
val foo: () -> Unit = {}
|
||||
|
||||
fun box(): String {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
fun println(s: String) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
fun println(s: String) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND: JS
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS
|
||||
// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit!
|
||||
|
||||
val nx: Any? = '0'
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class D {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
fun foo() {}
|
||||
|
||||
fun box(): String {
|
||||
|
||||
3
compiler/testData/codegen/box/unit/kt4212.kt
vendored
3
compiler/testData/codegen/box/unit/kt4212.kt
vendored
@@ -1,6 +1,3 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
fun foo(): Any? = bar()
|
||||
|
||||
fun bar() {}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
var JsName.staticRef: JsNode? by MetadataProperty(default = null)
|
||||
|
||||
@@ -56,12 +57,16 @@ var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false)
|
||||
|
||||
var JsInvocation.typeCheck: TypeCheck? by MetadataProperty(default = null)
|
||||
|
||||
var JsInvocation.boxing: Boolean by MetadataProperty(default = false)
|
||||
var JsInvocation.boxing: BoxingKind by MetadataProperty(default = BoxingKind.NONE)
|
||||
|
||||
var JsVars.exportedPackage: String? by MetadataProperty(default = null)
|
||||
|
||||
var JsExpressionStatement.exportedTag: String? by MetadataProperty(default = null)
|
||||
|
||||
var JsExpression.type: KotlinType? by MetadataProperty(default = null)
|
||||
|
||||
var JsExpression.isUnit: Boolean by MetadataProperty(default = false)
|
||||
|
||||
/**
|
||||
* For function and lambda bodies indicates what declaration corresponds to.
|
||||
* When absent (`null`) on body of a named function, this function is from external JS module.
|
||||
@@ -142,4 +147,10 @@ enum class SpecialFunction(val suggestedName: String) {
|
||||
WRAP_FUNCTION("wrapFunction"),
|
||||
TO_BOXED_CHAR("toBoxedChar"),
|
||||
UNBOX_CHAR("unboxChar"),
|
||||
}
|
||||
|
||||
enum class BoxingKind {
|
||||
NONE,
|
||||
BOXING,
|
||||
UNBOXING
|
||||
}
|
||||
@@ -59,7 +59,24 @@ fun charArray(size: Int, init: dynamic): Array<Char> {
|
||||
}
|
||||
|
||||
@JsName("charArrayF")
|
||||
inline fun charArrayWithFun(size: Int, init: (Int) -> Char): Array<Char> = fillArrayFun(charArray(size, null), init)
|
||||
inline fun charArrayWithFun(size: Int, init: (Int) -> Char): Array<Char> {
|
||||
val array = charArray(size, null)
|
||||
for (i in 0..array.size - 1) {
|
||||
val value = init(i)
|
||||
js("array[i] = value;")
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
@JsName("untypedCharArrayF")
|
||||
inline fun untypedCharArrayWithFun(size: Int, init: (Int) -> Char): Array<Char> {
|
||||
val array = Array<Char>(size)
|
||||
for (i in 0..array.size - 1) {
|
||||
val value = init(i)
|
||||
js("array[i] = value;")
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
@JsName("longArray")
|
||||
fun longArray(size: Int, init: dynamic): Array<Long> {
|
||||
|
||||
@@ -24,4 +24,4 @@ internal external annotation class JsName(val name: String)
|
||||
|
||||
internal external annotation class native
|
||||
|
||||
internal external fun js(code: String): dynamic
|
||||
external fun js(code: String): dynamic
|
||||
@@ -60,12 +60,6 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("charBoxing.kt")
|
||||
public void testCharBoxing() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/charBoxing.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("classCapturingLocals.kt")
|
||||
public void testClassCapturingLocals() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/classCapturingLocals.kt");
|
||||
|
||||
@@ -795,6 +795,117 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("js/js.translator/testData/box/coercion")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Coercion extends AbstractBoxJsTest {
|
||||
public void testAllFilesPresentInCoercion() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/coercion"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classProperty.kt")
|
||||
public void testClassProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/classProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("derivedFunctionReturningChar.kt")
|
||||
public void testDerivedFunctionReturningChar() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/derivedFunctionReturningChar.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("derivedFunctionReturningUnit.kt")
|
||||
public void testDerivedFunctionReturningUnit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/derivedFunctionReturningUnit.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("destructuringToUnit.kt")
|
||||
public void testDestructuringToUnit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/destructuringToUnit.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionReceiver.kt")
|
||||
public void testExtensionReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/extensionReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ifWithUnit.kt")
|
||||
public void testIfWithUnit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/ifWithUnit.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunReturningUnit.kt")
|
||||
public void testInlineFunReturningUnit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/inlineFunReturningUnit.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaParameters.kt")
|
||||
public void testLambdaParameters() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/lambdaParameters.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("loopOverUnits.kt")
|
||||
public void testLoopOverUnits() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/loopOverUnits.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("receiverSmartCast.kt")
|
||||
public void testReceiverSmartCast() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/receiverSmartCast.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallLetReturningUnit.kt")
|
||||
public void testSafeCallLetReturningUnit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/safeCallLetReturningUnit.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelProperty.kt")
|
||||
public void testTopLevelProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/topLevelProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("tryWithEmptyCatch.kt")
|
||||
public void testTryWithEmptyCatch() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/tryWithEmptyCatch.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unitAsExtensionReceiver.kt")
|
||||
public void testUnitAsExtensionReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/unitAsExtensionReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unitIsAs.kt")
|
||||
public void testUnitIsAs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/unitIsAs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unitSafeCall.kt")
|
||||
public void testUnitSafeCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/unitSafeCall.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithUnit.kt")
|
||||
public void testWhenWithUnit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/whenWithUnit.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("js/js.translator/testData/box/crossModuleRef")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -7802,6 +7913,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("charArrayGetSet.kt")
|
||||
public void testCharArrayGetSet() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/standardClasses/charArrayGetSet.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("hashMapTypeOfElement.kt")
|
||||
public void testHashMapTypeOfElement() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/standardClasses/hashMapTypeOfElement.kt");
|
||||
|
||||
@@ -2966,13 +2966,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("lambdaToUnitCast.kt")
|
||||
public void testLambdaToUnitCast() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("notIs.kt")
|
||||
@@ -2990,13 +2984,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("unitAsAny.kt")
|
||||
public void testUnitAsAny() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/unitAsAny.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unitAsInt.kt")
|
||||
@@ -3014,13 +3002,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("unitAsSafeAny.kt")
|
||||
public void testUnitAsSafeAny() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/unitAsSafeAny.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unitNullableCast.kt")
|
||||
@@ -6694,13 +6676,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("suspendNonLocalReturn.kt")
|
||||
public void testSuspendNonLocalReturn() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/unitTypeReturn/suspendNonLocalReturn.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("suspendReturn.kt")
|
||||
@@ -14247,13 +14223,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("primitiveEqObjectChar.kt")
|
||||
public void testPrimitiveEqObjectChar() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/generated/primitiveEqObjectChar.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveEqObjectInt.kt")
|
||||
@@ -14792,13 +14762,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("kt4383.kt")
|
||||
public void testKt4383() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/kt4383.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt613.kt")
|
||||
@@ -23603,13 +23567,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("kt4212.kt")
|
||||
public void testKt4212() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/unit/kt4212.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt4265.kt")
|
||||
@@ -23651,13 +23609,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("UnitValue.kt")
|
||||
public void testUnitValue() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/unit/UnitValue.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,14 @@
|
||||
package org.jetbrains.kotlin.js.translate.callTranslator
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsBlock
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsConditional
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNullLiteral
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.type
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator
|
||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
||||
@@ -31,6 +35,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
|
||||
interface CallInfo {
|
||||
val context: TranslationContext
|
||||
@@ -99,10 +104,6 @@ fun TranslationContext.getCallInfo(
|
||||
return FunctionCallInfo(callInfo, argumentsInfo)
|
||||
}
|
||||
|
||||
private fun TranslationContext.boxIfNeedeed(v: ReceiverValue?, d: ReceiverParameterDescriptor?, r: JsExpression?): JsExpression? {
|
||||
return r?.let { receiver -> TranslationUtils.boxCastIfNeeded(this, receiver, v?.type, d?.type) }
|
||||
}
|
||||
|
||||
private fun TranslationContext.getDispatchReceiver(receiverValue: ReceiverValue): JsExpression {
|
||||
return getDispatchReceiver(getReceiverParameterForReceiver(receiverValue))
|
||||
}
|
||||
@@ -134,6 +135,10 @@ private fun TranslationContext.createCallInfo(
|
||||
}
|
||||
|
||||
var dispatchReceiver = getDispatchReceiver()
|
||||
var dispatchReceiverType = resolvedCall.smartCastDispatchReceiverType ?: resolvedCall.dispatchReceiver?.type
|
||||
if (dispatchReceiverType != null && (resolvedCall.resultingDescriptor as? FunctionDescriptor)?.kind?.isReal == false) {
|
||||
dispatchReceiverType = TranslationUtils.getDispatchReceiverTypeForCoercion(resolvedCall.resultingDescriptor)
|
||||
}
|
||||
var extensionReceiver = getExtensionReceiver()
|
||||
var notNullConditional: JsConditional? = null
|
||||
|
||||
@@ -154,16 +159,19 @@ private fun TranslationContext.createCallInfo(
|
||||
val container = resolvedCall.resultingDescriptor.containingDeclaration
|
||||
if (DescriptorUtils.isObject(container)) {
|
||||
dispatchReceiver = ReferenceTranslator.translateAsValueReference(container, this)
|
||||
dispatchReceiverType = (container as ClassDescriptor).defaultType
|
||||
}
|
||||
}
|
||||
|
||||
dispatchReceiver = boxIfNeedeed(resolvedCall.dispatchReceiver,
|
||||
resolvedCall.candidateDescriptor.dispatchReceiverParameter,
|
||||
dispatchReceiver)
|
||||
if (dispatchReceiverType != null) {
|
||||
dispatchReceiver = dispatchReceiver?.let {
|
||||
TranslationUtils.coerce(this, it, dispatchReceiverType!!)
|
||||
}
|
||||
}
|
||||
|
||||
extensionReceiver = boxIfNeedeed(resolvedCall.extensionReceiver,
|
||||
resolvedCall.candidateDescriptor.extensionReceiverParameter,
|
||||
extensionReceiver)
|
||||
extensionReceiver = extensionReceiver?.let {
|
||||
TranslationUtils.coerce(this, it, resolvedCall.candidateDescriptor.extensionReceiverParameter!!.type)
|
||||
}
|
||||
|
||||
|
||||
return object : AbstractCallInfo(), CallInfo {
|
||||
@@ -179,7 +187,9 @@ private fun TranslationContext.createCallInfo(
|
||||
result
|
||||
}
|
||||
else {
|
||||
notNullConditionalForSafeCall.thenExpression = result
|
||||
val type = resolvedCall.getReturnType()
|
||||
result.type = type
|
||||
notNullConditionalForSafeCall.thenExpression = TranslationUtils.coerce(context, result, type.makeNullable())
|
||||
notNullConditionalForSafeCall
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,14 @@ import org.jetbrains.kotlin.js.translate.utils.*
|
||||
import org.jetbrains.kotlin.psi.Call.CallType
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
|
||||
object CallTranslator {
|
||||
@JvmOverloads
|
||||
@@ -52,7 +55,9 @@ object CallTranslator {
|
||||
extensionOrDispatchReceiver: JsExpression? = null
|
||||
): JsExpression {
|
||||
val variableAccessInfo = VariableAccessInfo(context.getCallInfo(resolvedCall, extensionOrDispatchReceiver), null)
|
||||
return variableAccessInfo.translateVariableAccess().source(resolvedCall.call.callElement)
|
||||
val result = variableAccessInfo.translateVariableAccess().source(resolvedCall.call.callElement)
|
||||
result.type = TranslationUtils.getReturnTypeForCoercion(resolvedCall.resultingDescriptor.original)
|
||||
return result
|
||||
}
|
||||
|
||||
fun translateSet(context: TranslationContext,
|
||||
@@ -61,7 +66,9 @@ object CallTranslator {
|
||||
extensionOrDispatchReceiver: JsExpression? = null
|
||||
): JsExpression {
|
||||
val variableAccessInfo = VariableAccessInfo(context.getCallInfo(resolvedCall, extensionOrDispatchReceiver), value)
|
||||
return variableAccessInfo.translateVariableAccess().source(resolvedCall.call.callElement)
|
||||
val result = variableAccessInfo.translateVariableAccess().source(resolvedCall.call.callElement)
|
||||
result.type = context.currentModule.builtIns.unitType
|
||||
return result
|
||||
}
|
||||
|
||||
fun buildCall(context: TranslationContext,
|
||||
@@ -95,7 +102,7 @@ private fun translateCall(
|
||||
assert(explicitReceivers.extensionReceiver == null) { "VariableAsFunctionResolvedCall must have one receiver" }
|
||||
val variableCall = resolvedCall.variableCall
|
||||
|
||||
return if (variableCall.expectedReceivers()) {
|
||||
val result = if (variableCall.expectedReceivers()) {
|
||||
val newReceiver = CallTranslator.translateGet(context, variableCall, explicitReceivers.extensionOrDispatchReceiver)
|
||||
translateFunctionCall(context, resolvedCall.functionCall, resolvedCall.variableCall, ExplicitReceivers(newReceiver))
|
||||
} else {
|
||||
@@ -110,6 +117,8 @@ private fun translateCall(
|
||||
ExplicitReceivers(dispatchReceiver, explicitReceivers.extensionOrDispatchReceiver))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
val call = resolvedCall.call
|
||||
@@ -151,9 +160,13 @@ private fun translateFunctionCall(
|
||||
callExpression.isTailCallSuspend = true
|
||||
}
|
||||
}
|
||||
|
||||
callExpression.type = resolvedCall.getReturnType().let { if (resolvedCall.call.isSafeCall()) it.makeNullable() else it }
|
||||
return callExpression
|
||||
}
|
||||
|
||||
fun ResolvedCall<out CallableDescriptor>.getReturnType(): KotlinType = TranslationUtils.getReturnTypeForCoercion(resultingDescriptor)
|
||||
|
||||
private val TranslationContext.isInStateMachine
|
||||
get() = (declarationDescriptor as? FunctionDescriptor)?.requiresStateMachineTransformation(this) == true
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public final class TemporaryConstVariable extends TemporaryVariable{
|
||||
private boolean initialized = false;
|
||||
|
||||
public TemporaryConstVariable(@NotNull JsName variableName, @NotNull JsExpression assignmentExpression) {
|
||||
super(variableName, assignmentExpression);
|
||||
super(variableName, assignmentExpression, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -21,33 +21,40 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
public class TemporaryVariable {
|
||||
|
||||
/*package*/ static TemporaryVariable create(@NotNull JsName temporaryName, @Nullable JsExpression initExpression) {
|
||||
JsBinaryOperation rhs = null;
|
||||
KotlinType type = null;
|
||||
if (initExpression != null) {
|
||||
rhs = JsAstUtils.assignment(temporaryName.makeRef(), initExpression);
|
||||
rhs.source(initExpression.getSource());
|
||||
MetadataProperties.setSynthetic(rhs, true);
|
||||
type = MetadataProperties.getType(initExpression);
|
||||
}
|
||||
return new TemporaryVariable(temporaryName, rhs);
|
||||
return new TemporaryVariable(temporaryName, rhs, type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private final JsExpression assignmentExpression;
|
||||
@NotNull
|
||||
private final JsName variableName;
|
||||
@Nullable
|
||||
private final KotlinType type;
|
||||
|
||||
protected TemporaryVariable(@NotNull JsName temporaryName, @Nullable JsExpression assignmentExpression) {
|
||||
protected TemporaryVariable(@NotNull JsName temporaryName, @Nullable JsExpression assignmentExpression, @Nullable KotlinType type) {
|
||||
this.variableName = temporaryName;
|
||||
this.assignmentExpression = assignmentExpression;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef reference() {
|
||||
JsNameRef result = variableName.makeRef();
|
||||
MetadataProperties.setSynthetic(result, true);
|
||||
MetadataProperties.setType(result, type);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.*
|
||||
import org.jetbrains.kotlin.js.translate.utils.finalElement
|
||||
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.addParameter
|
||||
@@ -172,7 +173,7 @@ fun TranslationContext.translateDelegateOrInitializerExpression(expression: KtPr
|
||||
CallTranslator.translate(innerContext, provideDelegateCall, initializer)
|
||||
}
|
||||
else {
|
||||
initializer
|
||||
TranslationUtils.coerce(this, initializer, propertyDescriptor.type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,8 +84,7 @@ public class DestructuringDeclarationTranslator extends AbstractTranslator {
|
||||
setInlineCallMetadata(entryInitializer, entry, entryInitCall, context());
|
||||
}
|
||||
|
||||
entryInitializer = TranslationUtils.boxCastIfNeeded(context(), entryInitializer, candidateDescriptor.getReturnType(),
|
||||
descriptor.getType());
|
||||
entryInitializer = TranslationUtils.coerce(context(), entryInitializer, descriptor.getType());
|
||||
|
||||
JsName name = context().getNameForDescriptor(descriptor);
|
||||
if (isVarCapturedInClosure(context().bindingContext(), descriptor)) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention;
|
||||
@@ -39,6 +38,8 @@ import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.UtilsKt;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.CoercionMutator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.LastExpressionMutator;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
@@ -107,6 +108,11 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
jsBlock.getStatements().add(jsStatement);
|
||||
}
|
||||
}
|
||||
if (statements.isEmpty()) {
|
||||
ClassDescriptor unitClass = context.getCurrentModule().getBuiltIns().getUnit();
|
||||
jsBlock.getStatements().add(JsAstUtils.asSyntheticStatement(
|
||||
ReferenceTranslator.translateAsValueReference(unitClass, context)));
|
||||
}
|
||||
return jsBlock;
|
||||
}
|
||||
|
||||
@@ -135,6 +141,8 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
return new JsReturn(ref.source(jetReturnExpression));
|
||||
}
|
||||
|
||||
FunctionDescriptor returnTarget = getNonLocalReturnTarget(jetReturnExpression, context);
|
||||
|
||||
JsReturn jsReturn;
|
||||
if (returned == null) {
|
||||
jsReturn = new JsReturn(null);
|
||||
@@ -146,15 +154,19 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
assert returnedType != null : "Resolved return expression is expected to have type: " +
|
||||
PsiUtilsKt.getTextWithLocation(jetReturnExpression);
|
||||
|
||||
if (KotlinBuiltIns.isCharOrNullableChar(returnedType) &&
|
||||
TranslationUtils.shouldBoxReturnValue((CallableDescriptor)context.getDeclarationDescriptor())) {
|
||||
jsReturnExpression = TranslationUtils.charToBoxedChar(context, jsReturnExpression);
|
||||
CallableDescriptor returnTargetOrCurrentFunction = returnTarget;
|
||||
if (returnTargetOrCurrentFunction == null) {
|
||||
returnTargetOrCurrentFunction = (CallableDescriptor) context.getDeclarationDescriptor();
|
||||
}
|
||||
if (returnTargetOrCurrentFunction != null) {
|
||||
jsReturnExpression = TranslationUtils.coerce(context, jsReturnExpression,
|
||||
TranslationUtils.getReturnTypeForCoercion(returnTargetOrCurrentFunction));
|
||||
}
|
||||
|
||||
jsReturn = new JsReturn(jsReturnExpression);
|
||||
}
|
||||
|
||||
MetadataProperties.setReturnTarget(jsReturn, getNonLocalReturnTarget(jetReturnExpression, context));
|
||||
MetadataProperties.setReturnTarget(jsReturn, returnTarget);
|
||||
|
||||
return jsReturn.source(jetReturnExpression);
|
||||
}
|
||||
@@ -245,10 +257,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
|
||||
if (lhs instanceof DoubleColonLHS.Expression && !((DoubleColonLHS.Expression) lhs).isObjectQualifier()) {
|
||||
JsExpression receiver = translateAsExpression(receiverExpression, context);
|
||||
KotlinType type = context.bindingContext().getType(receiverExpression);
|
||||
if (type != null && KotlinBuiltIns.isChar(type)) {
|
||||
receiver = TranslationUtils.charToBoxedChar(context, receiver);
|
||||
}
|
||||
receiver = TranslationUtils.coerce(context, receiver, context.getCurrentModule().getBuiltIns().getAnyType());
|
||||
return new JsInvocation(context.namer().kotlin(GET_KCLASS_FROM_EXPRESSION), receiver);
|
||||
}
|
||||
|
||||
@@ -270,6 +279,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
public JsNode visitIfExpression(@NotNull KtIfExpression expression, @NotNull TranslationContext context) {
|
||||
assert expression.getCondition() != null : "condition should not ne null: " + expression.getText();
|
||||
JsExpression testExpression = Translation.translateAsExpression(expression.getCondition(), context);
|
||||
KotlinType type = context.bindingContext().getType(expression);
|
||||
|
||||
boolean isKotlinExpression = BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext());
|
||||
|
||||
@@ -281,6 +291,15 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
JsStatement elseStatement =
|
||||
elseExpression != null ? Translation.translateAsStatementAndMergeInBlockIfNeeded(elseExpression, context) : null;
|
||||
|
||||
if (type != null) {
|
||||
if (thenStatement != null) {
|
||||
thenStatement = LastExpressionMutator.mutateLastExpression(thenStatement, new CoercionMutator(type, context));
|
||||
}
|
||||
if (elseStatement != null) {
|
||||
elseStatement = LastExpressionMutator.mutateLastExpression(elseStatement, new CoercionMutator(type, context));
|
||||
}
|
||||
}
|
||||
|
||||
if (isKotlinExpression) {
|
||||
JsExpression jsThenExpression = JsAstUtils.extractExpressionFromStatement(thenStatement);
|
||||
JsExpression jsElseExpression = JsAstUtils.extractExpressionFromStatement(elseStatement);
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.functionDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.hasDefaultValue
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.type
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.shouldBeExported
|
||||
import org.jetbrains.kotlin.js.inline.util.FunctionWithWrapper
|
||||
@@ -58,7 +59,9 @@ fun TranslationContext.translateAndAliasParameters(
|
||||
|
||||
if (descriptor.requiresExtensionReceiverParameter) {
|
||||
val receiverParameterName = JsScope.declareTemporaryName(Namer.getReceiverParameterName())
|
||||
aliases[descriptor.extensionReceiverParameter!!] = receiverParameterName.makeRef()
|
||||
val receiverRef = receiverParameterName.makeRef()
|
||||
receiverRef.type = descriptor.extensionReceiverParameter!!.type
|
||||
aliases[descriptor.extensionReceiverParameter!!] = receiverRef
|
||||
targetList += JsParameter(receiverParameterName)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.jetbrains.kotlin.js.translate.expression
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
||||
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.js.translate.utils.BindingUtils.*
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*
|
||||
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getLoopRange
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
@@ -142,7 +144,10 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
||||
|
||||
val currentVarInit =
|
||||
if (destructuringParameter == null) {
|
||||
newVar(parameterName, itemValue).apply { source = expression.loopRange }
|
||||
val loopParameterDescriptor = (getDescriptorForElement(context.bindingContext(), loopParameter) as CallableDescriptor)
|
||||
val loopParameterType = loopParameterDescriptor.returnType ?: context.currentModule.builtIns.anyType
|
||||
val coercedItemValue = itemValue?.let { TranslationUtils.coerce(context, it, loopParameterType) }
|
||||
newVar(parameterName, coercedItemValue).apply { source = expression.loopRange }
|
||||
}
|
||||
else {
|
||||
val innerBlockContext = context.innerBlock(block)
|
||||
@@ -224,7 +229,7 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
||||
|
||||
fun translateForOverArray(): JsStatement {
|
||||
val rangeExpression = context.defineTemporary(Translation.translateAsExpression(loopRange, context))
|
||||
val length = ArrayFIF.LENGTH_PROPERTY_INTRINSIC.apply(rangeExpression, listOf<JsExpression>(), context)
|
||||
val length = ArrayFIF.LENGTH_PROPERTY_INTRINSIC.apply(rangeExpression, listOf(), context)
|
||||
val end = context.defineTemporary(length)
|
||||
val index = context.declareTemporary(JsIntLiteral(0), expression)
|
||||
|
||||
|
||||
@@ -81,10 +81,8 @@ public final class PatternTranslator extends AbstractTranslator {
|
||||
KtTypeReference typeReference = expression.getRight();
|
||||
assert typeReference != null: "Cast expression must have type reference";
|
||||
|
||||
KotlinType leftType = context().bindingContext().getType(left);
|
||||
if (leftType != null && KotlinBuiltIns.isChar(leftType)) {
|
||||
expressionToCast = TranslationUtils.charToBoxedChar(context(), expressionToCast);
|
||||
}
|
||||
KotlinType anyType = context().getCurrentModule().getBuiltIns().getAnyType();
|
||||
expressionToCast = TranslationUtils.coerce(context(), expressionToCast, anyType);
|
||||
|
||||
TemporaryVariable temporary = context().declareTemporary(expressionToCast, expression);
|
||||
JsExpression isCheck = translateIsCheck(temporary.assignmentExpression(), typeReference);
|
||||
@@ -102,12 +100,11 @@ public final class PatternTranslator extends AbstractTranslator {
|
||||
|
||||
JsExpression result = new JsConditional(isCheck, temporary.reference(), onFail);
|
||||
|
||||
KotlinType expressionType = context().bindingContext().getType(expression);
|
||||
if (expressionType != null && KotlinBuiltIns.isCharOrNullableChar(expressionType)) {
|
||||
result = TranslationUtils.boxedCharToChar(context(), result);
|
||||
KotlinType targetType = getTypeByReference(bindingContext(), typeReference);
|
||||
if (isSafeCast(expression)) {
|
||||
targetType = targetType.unwrap().makeNullableAsSpecified(true);
|
||||
}
|
||||
|
||||
return result;
|
||||
return TranslationUtils.coerce(context(), result, targetType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -115,10 +112,8 @@ public final class PatternTranslator extends AbstractTranslator {
|
||||
KtExpression left = expression.getLeftHandSide();
|
||||
JsExpression expressionToCheck = Translation.translateAsExpression(left, context());
|
||||
|
||||
KotlinType leftType = context().bindingContext().getType(left);
|
||||
if (leftType != null && KotlinBuiltIns.isChar(leftType)) {
|
||||
expressionToCheck = TranslationUtils.charToBoxedChar(context(), expressionToCheck);
|
||||
}
|
||||
KotlinType anyType = context().getCurrentModule().getBuiltIns().getAnyType();
|
||||
expressionToCheck = TranslationUtils.coerce(context(), expressionToCheck, anyType);
|
||||
|
||||
KtTypeReference typeReference = expression.getTypeReference();
|
||||
assert typeReference != null;
|
||||
|
||||
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||
import org.jetbrains.kotlin.js.translate.operation.InOperationTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.CoercionMutator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.LastExpressionMutator;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
|
||||
@@ -50,6 +52,9 @@ public final class WhenTranslator extends AbstractTranslator {
|
||||
@Nullable
|
||||
private final JsExpression expressionToMatch;
|
||||
|
||||
@Nullable
|
||||
private final KotlinType type;
|
||||
|
||||
private WhenTranslator(@NotNull KtWhenExpression expression, @NotNull TranslationContext context) {
|
||||
super(context);
|
||||
|
||||
@@ -57,6 +62,8 @@ public final class WhenTranslator extends AbstractTranslator {
|
||||
|
||||
KtExpression subject = expression.getSubjectExpression();
|
||||
expressionToMatch = subject != null ? context.defineTemporary(Translation.translateAsExpression(subject, context)) : null;
|
||||
|
||||
type = context().bindingContext().getType(expression);
|
||||
}
|
||||
|
||||
private JsNode translate() {
|
||||
@@ -106,13 +113,18 @@ public final class WhenTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsStatement translateEntryExpression(
|
||||
private JsStatement translateEntryExpression(
|
||||
@NotNull KtWhenEntry entry,
|
||||
@NotNull TranslationContext context,
|
||||
@NotNull JsBlock block) {
|
||||
KtExpression expressionToExecute = entry.getExpression();
|
||||
assert expressionToExecute != null : "WhenEntry should have whenExpression to execute.";
|
||||
return Translation.translateAsStatement(expressionToExecute, context, block);
|
||||
JsStatement result = Translation.translateAsStatement(expressionToExecute, context, block);
|
||||
if (type != null) {
|
||||
return LastExpressionMutator.mutateLastExpression(result, new CoercionMutator(type, context));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||
import org.jetbrains.kotlin.js.facade.MainCallParameters;
|
||||
import org.jetbrains.kotlin.js.facade.TranslationUnit;
|
||||
@@ -123,6 +124,15 @@ public final class Translation {
|
||||
) {
|
||||
KotlinType expectedType = context.bindingContext().getType(expression);
|
||||
ConstantValue<?> constant = compileTimeValue.toConstantValue(expectedType != null ? expectedType : TypeUtils.NO_EXPECTED_TYPE);
|
||||
JsExpression result = translateConstantWithoutType(constant);
|
||||
if (result != null) {
|
||||
MetadataProperties.setType(result, expectedType);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JsExpression translateConstantWithoutType(@NotNull ConstantValue<?> constant) {
|
||||
if (constant instanceof NullValue) {
|
||||
return new JsNullLiteral();
|
||||
}
|
||||
@@ -187,10 +197,17 @@ public final class Translation {
|
||||
@NotNull JsBlock block
|
||||
) {
|
||||
JsNode jsNode = translateExpression(expression, context, block);
|
||||
|
||||
if (jsNode instanceof JsExpression) {
|
||||
KotlinType expressionType = context.bindingContext().getType(expression);
|
||||
return unboxIfNeeded(context, (JsExpression) jsNode,
|
||||
expressionType != null && KotlinBuiltIns.isCharOrNullableChar(expressionType));
|
||||
JsExpression jsExpression = (JsExpression) jsNode;
|
||||
KotlinType type = context.bindingContext().getType(expression);
|
||||
if (MetadataProperties.getType(jsExpression) == null) {
|
||||
MetadataProperties.setType(jsExpression, type);
|
||||
}
|
||||
else if (type != null) {
|
||||
jsExpression = TranslationUtils.coerce(context, jsExpression, type);
|
||||
}
|
||||
return jsExpression;
|
||||
}
|
||||
|
||||
assert jsNode instanceof JsStatement : "Unexpected node of type: " + jsNode.getClass().toString();
|
||||
@@ -198,27 +215,15 @@ public final class Translation {
|
||||
TemporaryVariable result = context.declareTemporary(null, expression);
|
||||
AssignToExpressionMutator saveResultToTemporaryMutator = new AssignToExpressionMutator(result.reference());
|
||||
block.getStatements().add(mutateLastExpression(jsNode, saveResultToTemporaryMutator));
|
||||
return result.reference();
|
||||
JsExpression tmpVar = result.reference();
|
||||
MetadataProperties.setType(tmpVar, context.bindingContext().getType(expression));
|
||||
return tmpVar;
|
||||
}
|
||||
|
||||
block.getStatements().add(convertToStatement(jsNode));
|
||||
return new JsNullLiteral().source(expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression unboxIfNeeded(
|
||||
@NotNull TranslationContext context,
|
||||
@NotNull JsExpression expression,
|
||||
boolean charOrNullableChar
|
||||
) {
|
||||
if (charOrNullableChar &&
|
||||
(expression instanceof JsInvocation || expression instanceof JsNameRef || expression instanceof JsArrayAccess)
|
||||
) {
|
||||
expression = TranslationUtils.boxedCharToChar(context, expression);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsStatement translateAsStatement(@NotNull KtExpression expression, @NotNull TranslationContext context) {
|
||||
return translateAsStatement(expression, context, context.dynamicContext().jsBlock());
|
||||
|
||||
@@ -50,6 +50,7 @@ public final class FunctionIntrinsics {
|
||||
register(NumberAndCharConversionFIF.INSTANCE);
|
||||
register(ThrowableConstructorIntrinsicFactory.INSTANCE);
|
||||
register(ExceptionPropertyIntrinsicFactory.INSTANCE);
|
||||
register(AsDynamicFIF.INSTANCE);
|
||||
}
|
||||
|
||||
private void register(@NotNull FunctionIntrinsicFactory instance) {
|
||||
|
||||
@@ -43,7 +43,7 @@ import java.util.*
|
||||
|
||||
object ArrayFIF : CompositeFIF() {
|
||||
@JvmField
|
||||
val GET_INTRINSIC = intrinsify { callInfo, arguments, _ ->
|
||||
val GET_INTRINSIC = intrinsify { callInfo, arguments, context ->
|
||||
assert(arguments.size == 1) { "Array get expression must have one argument." }
|
||||
val (indexExpression) = arguments
|
||||
JsArrayAccess(callInfo.dispatchReceiver, indexExpression)
|
||||
@@ -108,7 +108,12 @@ object ArrayFIF : CompositeFIF() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
"kotlin.newArrayF"
|
||||
if (primitiveType == CHAR) {
|
||||
"kotlin.untypedCharArrayF"
|
||||
}
|
||||
else {
|
||||
"kotlin.newArrayF"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +188,7 @@ object ArrayFIF : CompositeFIF() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
JsAstUtils.invokeKotlinFunction("newArrayF", size, fn)
|
||||
JsAstUtils.invokeKotlinFunction(if (type == CHAR) "untypedCharArrayF" else "newArrayF", size, fn)
|
||||
}
|
||||
invocation.inlineStrategy = InlineStrategy.IN_PLACE
|
||||
val descriptor = callInfo.resolvedCall.resultingDescriptor.original
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.js.translate.intrinsic.functions.factories
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.js.patterns.PatternBuilder
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
|
||||
object AsDynamicFIF : CompositeFIF() {
|
||||
init {
|
||||
add(PatternBuilder.pattern("kotlin.js.asDynamic()"), object : FunctionIntrinsic() {
|
||||
override fun apply(callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext): JsExpression =
|
||||
TranslationUtils.coerce(context, callInfo.extensionReceiver!!, callInfo.resolvedCall.extensionReceiver!!.type)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic;
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.UtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
@@ -166,13 +167,14 @@ public final class TopLevelFIF extends CompositeFIF {
|
||||
public static final KotlinFunctionIntrinsic TO_STRING = new KotlinFunctionIntrinsic("toString");
|
||||
|
||||
@NotNull
|
||||
public static final FunctionIntrinsic CHAR_TO_STRING = new FunctionIntrinsicWithReceiverComputed() {
|
||||
private static final FunctionIntrinsic CHAR_TO_STRING = new FunctionIntrinsicWithReceiverComputed() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver, @NotNull List<? extends JsExpression> arguments, @NotNull TranslationContext context
|
||||
) {
|
||||
assert receiver != null;
|
||||
receiver = TranslationUtils.coerce(context, receiver, context.getCurrentModule().getBuiltIns().getCharType());
|
||||
return JsAstUtils.charToString(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNullLiteral
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken
|
||||
@@ -57,13 +56,15 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||
|
||||
val ktLeft = checkNotNull(expression.left) { "No left-hand side: " + expression.text }
|
||||
val ktRight = checkNotNull(expression.right) { "No right-hand side: " + expression.text }
|
||||
val leftType = getRefinedType(ktLeft, context)?.let { KotlinBuiltIns.getPrimitiveType(it) }
|
||||
val rightType = getRefinedType(ktRight, context)?.let { KotlinBuiltIns.getPrimitiveType(it) }
|
||||
val leftKotlinType = getRefinedType(ktLeft, context)
|
||||
val rightKotlinType = getRefinedType(ktRight, context)
|
||||
val leftType = leftKotlinType?.let { KotlinBuiltIns.getPrimitiveType(it) }
|
||||
val rightType = rightKotlinType?.let { KotlinBuiltIns.getPrimitiveType(it) }
|
||||
|
||||
if (leftType != null && (leftType in SIMPLE_PRIMITIVES || leftType == rightType && leftType != PrimitiveType.LONG)) {
|
||||
return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ,
|
||||
Translation.unboxIfNeeded(context, left, leftType == PrimitiveType.CHAR),
|
||||
Translation.unboxIfNeeded(context, right, rightType == PrimitiveType.CHAR))
|
||||
val coercedLeft = TranslationUtils.coerce(context, left, leftKotlinType)
|
||||
val coercedRight = TranslationUtils.coerce(context, right, rightKotlinType!!)
|
||||
return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ, coercedLeft, coercedRight)
|
||||
}
|
||||
|
||||
val resolvedCall = expression.getResolvedCall(context.bindingContext())
|
||||
@@ -77,10 +78,10 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||
return JsBinaryOperation(if (isNegated) JsBinaryOperator.NEQ else JsBinaryOperator.EQ, left, right)
|
||||
}
|
||||
|
||||
val maybeBoxedLeft = if (leftType == PrimitiveType.CHAR) TranslationUtils.charToBoxedChar(context, left) else left
|
||||
val maybeBoxedRight = if (rightType == PrimitiveType.CHAR) TranslationUtils.charToBoxedChar(context, right) else right
|
||||
|
||||
val result = TopLevelFIF.KOTLIN_EQUALS.apply(maybeBoxedLeft, Arrays.asList<JsExpression>(maybeBoxedRight), context)
|
||||
val anyType = context.currentModule.builtIns.anyType
|
||||
val coercedLeft = TranslationUtils.coerce(context, left, anyType)
|
||||
val coercedRight = TranslationUtils.coerce(context, right, anyType)
|
||||
val result = TopLevelFIF.KOTLIN_EQUALS.apply(coercedLeft, listOf(coercedRight), context)
|
||||
return if (isNegated) JsAstUtils.not(result) else result
|
||||
}
|
||||
|
||||
|
||||
@@ -126,15 +126,14 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
||||
@NotNull
|
||||
private JsExpression translateElvis() {
|
||||
KotlinType expressionType = context().bindingContext().getType(expression);
|
||||
assert expressionType != null;
|
||||
|
||||
JsExpression leftExpression = TranslationUtils.boxCastIfNeeded(
|
||||
context(), Translation.translateAsExpression(leftKtExpression, context()),
|
||||
context().bindingContext().getType(leftKtExpression), expressionType);
|
||||
JsExpression leftExpression = TranslationUtils.coerce(
|
||||
context(), Translation.translateAsExpression(leftKtExpression, context()), expressionType);
|
||||
|
||||
JsBlock rightBlock = new JsBlock();
|
||||
JsExpression rightExpression = TranslationUtils.boxCastIfNeeded(
|
||||
context(),Translation.translateAsExpression(rightKtExpression, context(), rightBlock),
|
||||
context().bindingContext().getType(rightKtExpression), expressionType);
|
||||
JsExpression rightExpression = TranslationUtils.coerce(
|
||||
context(), Translation.translateAsExpression(rightKtExpression, context(), rightBlock), expressionType);
|
||||
|
||||
if (rightBlock.isEmpty()) {
|
||||
return TranslationUtils.notNullConditional(leftExpression, rightExpression, context());
|
||||
|
||||
@@ -66,7 +66,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
||||
if (leftType != null && KotlinBuiltIns.isStringOrNullableString(leftType)) {
|
||||
result = JsAstUtils.charToString(result);
|
||||
}
|
||||
else if (leftType == null || !KotlinBuiltIns.isCharOrNullableChar(leftType)) {
|
||||
else if (leftType != null && !KotlinBuiltIns.isCharOrNullableChar(leftType)) {
|
||||
result = TranslationUtils.charToBoxedChar(context, result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
package org.jetbrains.kotlin.js.translate.reference
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineOrReturn
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
@@ -36,9 +37,9 @@ import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.getReferenceToJsClass
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
@@ -191,18 +192,15 @@ class CallArgumentTranslator private constructor(
|
||||
val parenthisedArgumentExpression = arg.getArgumentExpression()
|
||||
|
||||
val param = argsToParameters[arg]!!.original
|
||||
val parameterType = if (resolvedCall.call.callType == Call.CallType.INVOKE) {
|
||||
DefaultBuiltIns.Instance.anyType
|
||||
}
|
||||
else {
|
||||
param.varargElementType ?: param.type
|
||||
val isLambda = resolvedCall.resultingDescriptor.let { it.getFunctionalClassKind() != null || it is FunctionInvokeDescriptor }
|
||||
val parameterType = if (!isLambda) param.varargElementType ?: param.type else context.currentModule.builtIns.anyType
|
||||
|
||||
var argJs = Translation.translateAsExpression(parenthisedArgumentExpression!!, argumentContext)
|
||||
if (!param.isVararg || arg.getSpreadElement() == null) {
|
||||
argJs = TranslationUtils.coerce(context, argJs, parameterType)
|
||||
}
|
||||
|
||||
val argType = context.bindingContext().getType(parenthisedArgumentExpression!!)
|
||||
|
||||
val argJs = Translation.translateAsExpression(parenthisedArgumentExpression, argumentContext)
|
||||
|
||||
arg to TranslationUtils.boxCastIfNeeded(context, argJs, argType, parameterType)
|
||||
arg to argJs
|
||||
}
|
||||
|
||||
val resolvedOrder = resolvedCall.valueArgumentsByIndex.orEmpty()
|
||||
|
||||
@@ -22,11 +22,13 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.isCallableReference
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.type
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.finalElement
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
@@ -107,15 +109,19 @@ object CallableReferenceTranslator {
|
||||
null
|
||||
}
|
||||
|
||||
val functionDescriptor = realResolvedCall.resultingDescriptor
|
||||
val aliases = mutableMapOf<KtExpression, JsExpression>()
|
||||
for ((index, valueArg) in fakeCall.valueArguments.withIndex()) {
|
||||
val paramName = JsScope.declareTemporaryName(descriptor.valueParameters[index].name.asString())
|
||||
function.parameters += JsParameter(paramName)
|
||||
aliases[valueArg.getArgumentExpression()!!] = paramName.makeRef()
|
||||
val paramRef = paramName.makeRef()
|
||||
paramRef.type = context.currentModule.builtIns.anyType
|
||||
val type = functionDescriptor.valueParameters[index].type
|
||||
aliases[valueArg.getArgumentExpression()!!] = TranslationUtils.coerce(context, paramRef, type)
|
||||
}
|
||||
val functionContext = context.innerBlock(function.body).innerContextWithAliasesForExpressions(aliases)
|
||||
val invocation = CallTranslator.translate(functionContext, fakeResolvedCall, receiverParam)
|
||||
function.body.statements += JsReturn(invocation)
|
||||
function.body.statements += JsReturn(TranslationUtils.coerce(context, invocation, context.currentModule.builtIns.anyType))
|
||||
|
||||
val rawCallableRef = bindIfNecessary(function, receiver)
|
||||
return wrapFunctionCallableRef(expression.callableReference.getReferencedName(), rawCallableRef)
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
package org.jetbrains.kotlin.js.translate.reference;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsInvocation;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName;
|
||||
@@ -32,6 +35,7 @@ import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression;
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getSelectorAsSimpleName;
|
||||
@@ -49,6 +53,41 @@ public final class ReferenceTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsValueReference(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) {
|
||||
JsExpression result = translateAsValueReferenceWithoutType(descriptor, context);
|
||||
MetadataProperties.setType(result, getType(descriptor));
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
if (KotlinBuiltIns.isUnit(((ClassDescriptor) descriptor).getDefaultType())) {
|
||||
MetadataProperties.setUnit(result, true);
|
||||
MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
|
||||
MetadataProperties.setSynthetic(result, true);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static KotlinType getType(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return ((ClassDescriptor) descriptor).getDefaultType();
|
||||
}
|
||||
else if (descriptor instanceof CallableDescriptor) {
|
||||
if (descriptor instanceof ValueParameterDescriptor) {
|
||||
ValueParameterDescriptor parameter = (ValueParameterDescriptor) descriptor;
|
||||
if (parameter.getContainingDeclaration() instanceof AnonymousFunctionDescriptor) {
|
||||
return DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
||||
}
|
||||
}
|
||||
return ((CallableDescriptor) descriptor).getReturnType();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression translateAsValueReferenceWithoutType(
|
||||
@NotNull DeclarationDescriptor descriptor,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
if (AnnotationsUtils.isNativeObject(descriptor) || AnnotationsUtils.isLibraryObject(descriptor)) {
|
||||
return context.getInnerReference(descriptor);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.translate.utils;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
@@ -31,6 +32,7 @@ import org.jetbrains.kotlin.js.translate.expression.LocalFunctionCollector;
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
|
||||
import org.jetbrains.kotlin.psi.KtBlockExpression;
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
|
||||
@@ -120,6 +122,16 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
|
||||
|
||||
JsNode jsBody = Translation.translateExpression(jetBodyExpression, context(), jsBlock);
|
||||
jsBlock.getStatements().addAll(mayBeWrapWithReturn(jsBody).getStatements());
|
||||
|
||||
if (jetBodyExpression instanceof KtBlockExpression &&
|
||||
descriptor.getReturnType() != null && KotlinBuiltIns.isUnit(descriptor.getReturnType()) &&
|
||||
!KotlinBuiltIns.isUnit(TranslationUtils.getReturnTypeForCoercion(descriptor))) {
|
||||
ClassDescriptor unit = context().getCurrentModule().getBuiltIns().getUnit();
|
||||
JsReturn jsReturn = new JsReturn(ReferenceTranslator.translateAsValueReference(unit, context()));
|
||||
jsReturn.setSource(UtilsKt.getFinalElement(declaration));
|
||||
jsBlock.getStatements().add(jsReturn);
|
||||
}
|
||||
|
||||
return jsBlock;
|
||||
}
|
||||
|
||||
@@ -145,12 +157,8 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
assert declaration.getBodyExpression() != null;
|
||||
assert descriptor.getReturnType() != null;
|
||||
KotlinType bodyType = context().bindingContext().getType(declaration.getBodyExpression());
|
||||
if (bodyType == null && KotlinBuiltIns.isCharOrNullableChar(descriptor.getReturnType()) ||
|
||||
bodyType != null && KotlinBuiltIns.isCharOrNullableChar(bodyType) && TranslationUtils.shouldBoxReturnValue(descriptor)) {
|
||||
node = TranslationUtils.charToBoxedChar(context(), (JsExpression) node);
|
||||
}
|
||||
KotlinType returnType = TranslationUtils.getReturnTypeForCoercion(descriptor);
|
||||
node = TranslationUtils.coerce(context(), (JsExpression) node, returnType);
|
||||
|
||||
JsReturn jsReturn = new JsReturn((JsExpression) node);
|
||||
jsReturn.setSource(declaration.getBodyExpression());
|
||||
|
||||
@@ -19,12 +19,15 @@ package org.jetbrains.kotlin.js.translate.utils;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.FunctionTypesKt;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.BoxingKind;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||
@@ -43,11 +46,11 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
|
||||
import org.jetbrains.kotlin.types.DynamicTypesKt;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator.*;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||
@@ -186,7 +189,11 @@ public final class TranslationUtils {
|
||||
else {
|
||||
receiver = context.getDispatchReceiver(JsDescriptorUtils.getReceiverParameterForDeclaration(containingDescriptor));
|
||||
}
|
||||
return new JsNameRef(backingFieldName, receiver);
|
||||
|
||||
JsNameRef result = new JsNameRef(backingFieldName, receiver);
|
||||
MetadataProperties.setType(result, getReturnTypeForCoercion(descriptor));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -205,10 +212,9 @@ public final class TranslationUtils {
|
||||
if (initializer != null) {
|
||||
jsInitExpression = Translation.translateAsExpression(initializer, context);
|
||||
|
||||
KotlinType propertyType = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.VARIABLE, declaration).getType();
|
||||
KotlinType initType = context.bindingContext().getType(initializer);
|
||||
|
||||
jsInitExpression = boxCastIfNeeded(context, jsInitExpression, initType, propertyType);
|
||||
KotlinType propertyType = BindingContextUtils.getNotNull(
|
||||
context.bindingContext(), BindingContext.VARIABLE, declaration).getType();
|
||||
jsInitExpression = coerce(context, jsInitExpression, propertyType);
|
||||
}
|
||||
return jsInitExpression;
|
||||
}
|
||||
@@ -394,61 +400,139 @@ public final class TranslationUtils {
|
||||
ModalityKt.isOverridable(descriptor);
|
||||
}
|
||||
|
||||
private static boolean overridesReturnAny(CallableDescriptor c) {
|
||||
KotlinType returnType = c.getOriginal().getReturnType();
|
||||
assert returnType != null;
|
||||
if (KotlinBuiltIns.isAnyOrNullableAny(returnType) || TypeUtils.isTypeParameter(returnType)) return true;
|
||||
for (CallableDescriptor o : c.getOverriddenDescriptors()) {
|
||||
if (overridesReturnAny(o)) return true;
|
||||
@NotNull
|
||||
public static KotlinType getReturnTypeForCoercion(@NotNull CallableDescriptor descriptor) {
|
||||
descriptor = descriptor.getOriginal();
|
||||
|
||||
if (FunctionTypesKt.getFunctionalClassKind(descriptor) != null || descriptor instanceof AnonymousFunctionDescriptor) {
|
||||
return DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static boolean shouldBoxReturnValue(CallableDescriptor c) {
|
||||
return overridesReturnAny(c) || c instanceof CallableMemberDescriptor && ModalityKt.isOverridable((CallableMemberDescriptor)c);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression boxCastIfNeeded(
|
||||
@NotNull TranslationContext context,
|
||||
@NotNull JsExpression e,
|
||||
@Nullable KotlinType castFrom, @Nullable KotlinType castTo
|
||||
) {
|
||||
if (castFrom != null && KotlinBuiltIns.isCharOrNullableChar(castFrom) &&
|
||||
castTo != null && !KotlinBuiltIns.isCharOrNullableChar(castTo)
|
||||
) {
|
||||
return charToBoxedChar(context, e);
|
||||
Collection<? extends CallableDescriptor> overridden = descriptor.getOverriddenDescriptors();
|
||||
if (overridden.isEmpty()) {
|
||||
return descriptor.getReturnType() != null ?
|
||||
descriptor.getReturnType() :
|
||||
DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
||||
}
|
||||
return e;
|
||||
|
||||
Set<KotlinType> typesFromOverriddenCallables = overridden.stream()
|
||||
.map(TranslationUtils::getReturnTypeForCoercion)
|
||||
.collect(Collectors.toSet());
|
||||
return typesFromOverriddenCallables.size() == 1
|
||||
? typesFromOverriddenCallables.iterator().next()
|
||||
: DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression charToBoxedChar(@NotNull TranslationContext context, @NotNull JsExpression expression) {
|
||||
JsInvocation invocation = invokeSpecialFunction(context, SpecialFunction.TO_BOXED_CHAR, unnestBoxing(expression));
|
||||
invocation.setSource(expression.getSource());
|
||||
return withBoxingMetadata(invocation);
|
||||
public static KotlinType getDispatchReceiverTypeForCoercion(@NotNull CallableDescriptor descriptor) {
|
||||
descriptor = descriptor.getOriginal();
|
||||
if (descriptor.getDispatchReceiverParameter() == null) {
|
||||
throw new IllegalArgumentException("This method can only be used for class members; " +
|
||||
"given descriptor is not a member of a class " + descriptor);
|
||||
}
|
||||
|
||||
Collection<? extends CallableDescriptor> overridden = descriptor.getOverriddenDescriptors();
|
||||
if (overridden.isEmpty()) {
|
||||
return descriptor.getDispatchReceiverParameter().getType();
|
||||
}
|
||||
|
||||
Set<KotlinType> typesFromOverriddenCallables = overridden.stream()
|
||||
.map(TranslationUtils::getDispatchReceiverTypeForCoercion)
|
||||
.collect(Collectors.toSet());
|
||||
return typesFromOverriddenCallables.size() == 1
|
||||
? typesFromOverriddenCallables.iterator().next()
|
||||
: DescriptorUtils.getContainingModule(descriptor).getBuiltIns().getAnyType();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression boxedCharToChar(@NotNull TranslationContext context, @NotNull JsExpression expression) {
|
||||
JsInvocation invocation = invokeSpecialFunction(context, SpecialFunction.UNBOX_CHAR, unnestBoxing(expression));
|
||||
invocation.setSource(expression.getSource());
|
||||
return withBoxingMetadata(invocation);
|
||||
public static JsExpression coerce(@NotNull TranslationContext context, @NotNull JsExpression value, @NotNull KotlinType to) {
|
||||
if (DynamicTypesKt.isDynamic(to)) return value;
|
||||
|
||||
KotlinType from = MetadataProperties.getType(value);
|
||||
if (from == null) {
|
||||
from = context.getCurrentModule().getBuiltIns().getAnyType();
|
||||
}
|
||||
|
||||
if (from.equals(to)) return value;
|
||||
|
||||
if (KotlinBuiltIns.isCharOrNullableChar(to)) {
|
||||
if (!KotlinBuiltIns.isCharOrNullableChar(from) && !(value instanceof JsNullLiteral)) {
|
||||
value = boxedCharToChar(context, value);
|
||||
}
|
||||
}
|
||||
else if (KotlinBuiltIns.isUnit(to)) {
|
||||
if (!KotlinBuiltIns.isUnit(from)) {
|
||||
value = unitToVoid(value);
|
||||
}
|
||||
}
|
||||
else if (KotlinBuiltIns.isCharOrNullableChar(from)) {
|
||||
if (!KotlinBuiltIns.isCharOrNullableChar(to) && !(value instanceof JsNullLiteral)) {
|
||||
value = charToBoxedChar(context, value);
|
||||
}
|
||||
}
|
||||
else if (KotlinBuiltIns.isUnit(from)) {
|
||||
if (!KotlinBuiltIns.isUnit(to) && !MetadataProperties.isUnit(value)) {
|
||||
ClassDescriptor unit = context.getCurrentModule().getBuiltIns().getUnit();
|
||||
JsExpression unitRef = ReferenceTranslator.translateAsValueReference(unit, context);
|
||||
value = JsAstUtils.newSequence(Arrays.asList(value, unitRef));
|
||||
}
|
||||
}
|
||||
|
||||
MetadataProperties.setType(value, to);
|
||||
return value;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression unnestBoxing(@NotNull JsExpression expression) {
|
||||
if (expression instanceof JsInvocation && MetadataProperties.getBoxing((JsInvocation) expression)) {
|
||||
return ((JsInvocation) expression).getArguments().get(0);
|
||||
private static JsExpression unitToVoid(@NotNull JsExpression expression) {
|
||||
if (expression instanceof JsBinaryOperation) {
|
||||
JsBinaryOperation binary = (JsBinaryOperation) expression;
|
||||
if (binary.getOperator() == JsBinaryOperator.COMMA && MetadataProperties.isUnit(binary.getArg2())) {
|
||||
return binary.getArg1();
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsInvocation withBoxingMetadata(@NotNull JsInvocation call) {
|
||||
MetadataProperties.setBoxing(call, true);
|
||||
return call;
|
||||
public static JsExpression charToBoxedChar(@NotNull TranslationContext context, @NotNull JsExpression expression) {
|
||||
if (expression instanceof JsInvocation) {
|
||||
JsInvocation invocation = (JsInvocation) expression;
|
||||
BoxingKind existingKind = MetadataProperties.getBoxing(invocation);
|
||||
switch (existingKind) {
|
||||
case UNBOXING:
|
||||
return invocation.getArguments().get(0);
|
||||
case BOXING:
|
||||
return expression;
|
||||
case NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JsInvocation result = invokeSpecialFunction(context, SpecialFunction.TO_BOXED_CHAR, expression);
|
||||
result.setSource(expression.getSource());
|
||||
MetadataProperties.setBoxing(result, BoxingKind.BOXING);
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression boxedCharToChar(@NotNull TranslationContext context, @NotNull JsExpression expression) {
|
||||
if (expression instanceof JsInvocation) {
|
||||
JsInvocation invocation = (JsInvocation) expression;
|
||||
BoxingKind existingKind = MetadataProperties.getBoxing(invocation);
|
||||
switch (existingKind) {
|
||||
case BOXING:
|
||||
return invocation.getArguments().get(0);
|
||||
case UNBOXING:
|
||||
return expression;
|
||||
case NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JsInvocation result = invokeSpecialFunction(context, SpecialFunction.UNBOX_CHAR, expression);
|
||||
result.setSource(expression.getSource());
|
||||
MetadataProperties.setBoxing(result, BoxingKind.UNBOXING);
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.js.translate.utils.mutator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNode;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
public class CoercionMutator implements Mutator {
|
||||
private final KotlinType targetType;
|
||||
private final TranslationContext context;
|
||||
|
||||
public CoercionMutator(@NotNull KotlinType targetType, @NotNull TranslationContext context) {
|
||||
this.targetType = targetType;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsNode mutate(@NotNull JsNode node) {
|
||||
if (node instanceof JsExpression) {
|
||||
return TranslationUtils.coerce(context, (JsExpression) node, targetType);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
12
js/js.translator/testData/box/char/charEquals.kt
vendored
12
js/js.translator/testData/box/char/charEquals.kt
vendored
@@ -9,5 +9,15 @@ fun box(): String {
|
||||
assertEquals(false, 'A'== 'B')
|
||||
assertEquals(false, ('A' as Any) == (65 as Any))
|
||||
|
||||
assertTrue(bar('Q'))
|
||||
assertFalse(bar('W'))
|
||||
|
||||
assertTrue(baz('Q'))
|
||||
assertFalse(baz('W'))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(x: Char) = x.equals('Q')
|
||||
|
||||
fun baz(x: Any) = x.equals('Q')
|
||||
18
js/js.translator/testData/box/coercion/classProperty.kt
vendored
Normal file
18
js/js.translator/testData/box/coercion/classProperty.kt
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
class A {
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo()"
|
||||
}
|
||||
|
||||
val bar: Any = foo()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = A()
|
||||
if (a.bar != Unit) return "fail1: ${a.bar}"
|
||||
if (a.log != "foo()") return "fail2: ${a.log}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
17
js/js.translator/testData/box/coercion/derivedFunctionReturningChar.kt
vendored
Normal file
17
js/js.translator/testData/box/coercion/derivedFunctionReturningChar.kt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1006
|
||||
abstract class A<out T> {
|
||||
abstract fun foo(): T
|
||||
}
|
||||
|
||||
class B() : A<Char>() {
|
||||
override fun foo() = 'Q'
|
||||
}
|
||||
|
||||
private fun typeOf(x: dynamic) = js("typeof x")
|
||||
|
||||
fun box(): String {
|
||||
val a: A<Any> = B()
|
||||
if (typeOf(a.foo()) != "object") return "fail1"
|
||||
if (typeOf(B().foo()) != "number") return "fail2"
|
||||
return "OK"
|
||||
}
|
||||
20
js/js.translator/testData/box/coercion/derivedFunctionReturningUnit.kt
vendored
Normal file
20
js/js.translator/testData/box/coercion/derivedFunctionReturningUnit.kt
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1012
|
||||
var log = ""
|
||||
|
||||
abstract class A<out T> {
|
||||
abstract fun foo(): T
|
||||
}
|
||||
|
||||
class B() : A<Unit>() {
|
||||
override fun foo() {
|
||||
log += "B.foo()"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a: A<Any> = B()
|
||||
if (a.foo() != Unit) return "fail1"
|
||||
if (log != "B.foo()") return "fail2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
20
js/js.translator/testData/box/coercion/destructuringToUnit.kt
vendored
Normal file
20
js/js.translator/testData/box/coercion/destructuringToUnit.kt
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1006
|
||||
var log = ""
|
||||
|
||||
class A {
|
||||
operator fun component1() {
|
||||
log += "A.component1()"
|
||||
}
|
||||
|
||||
operator fun component2() = 23
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val (x: Any, y) = A()
|
||||
|
||||
if (x != Unit) return "fail1: $x"
|
||||
if (y != 23) return "fail2: $y"
|
||||
if (log != "A.component1()") return "fail3: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
14
js/js.translator/testData/box/coercion/extensionReceiver.kt
vendored
Normal file
14
js/js.translator/testData/box/coercion/extensionReceiver.kt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// EXPECTED_REACHABLE_NODES: 996
|
||||
fun box(): String {
|
||||
val a = 'Q'.foo()
|
||||
if (a != "number") return "fail1: $a"
|
||||
|
||||
val b = 'W'.bar()
|
||||
if (b != "object") return "fail2: $b"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun Char.foo() = jsTypeOf(this.asDynamic())
|
||||
|
||||
fun Any.bar() = jsTypeOf(this.asDynamic())
|
||||
19
js/js.translator/testData/box/coercion/ifWithUnit.kt
vendored
Normal file
19
js/js.translator/testData/box/coercion/ifWithUnit.kt
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1005
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo()"
|
||||
}
|
||||
|
||||
fun test(x: Int) = if (x < 10) foo() else 55
|
||||
|
||||
fun box(): String {
|
||||
val a = test(20)
|
||||
if (a !is Int) return "fail1: $a"
|
||||
|
||||
val b = test(5)
|
||||
if (b !is Unit) return "fail2: $b"
|
||||
if (log != "foo()") return "fail3: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
12
js/js.translator/testData/box/coercion/inlineFunReturningUnit.kt
vendored
Normal file
12
js/js.translator/testData/box/coercion/inlineFunReturningUnit.kt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1000
|
||||
inline fun foo(i : Int) = if (i % 2 == 0) {} else i
|
||||
|
||||
fun box(): String {
|
||||
val a = foo(1)
|
||||
if (a != 1) return "fail1: $a"
|
||||
|
||||
val b = foo(2)
|
||||
if (b != Unit) return "fail2: $b"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
22
js/js.translator/testData/box/coercion/lambdaParameters.kt
vendored
Normal file
22
js/js.translator/testData/box/coercion/lambdaParameters.kt
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// EXPECTED_REACHABLE_NODES: 997
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: function=toBoxedChar scope=box$lambda
|
||||
// CHECK_CALLED_IN_SCOPE: function=unboxChar scope=box$lambda
|
||||
// CHECK_CALLED_IN_SCOPE: function=toBoxedChar scope=box
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: function=unboxChar scope=box
|
||||
|
||||
fun <T> bar(x: T, y: (T) -> Boolean): Boolean = y(x) && jsTypeOf(x.asDynamic()) != "number"
|
||||
|
||||
fun typeOf(x: dynamic) = js("typeof x")
|
||||
|
||||
fun box(): String {
|
||||
val f = { x: Char ->
|
||||
val a: Char = x
|
||||
val b: Any = x
|
||||
typeOf(a) == "number" && typeOf(b) == "object"
|
||||
}
|
||||
|
||||
if (!f('Q')) return "fail1"
|
||||
if (!bar('W', f)) return "fail2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
25
js/js.translator/testData/box/coercion/loopOverUnits.kt
vendored
Normal file
25
js/js.translator/testData/box/coercion/loopOverUnits.kt
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1009
|
||||
class A {
|
||||
operator fun iterator() = B()
|
||||
}
|
||||
|
||||
class B() {
|
||||
private var count = 0
|
||||
|
||||
operator fun next() {
|
||||
count++
|
||||
}
|
||||
|
||||
operator fun hasNext() = count < 5
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var i = 0
|
||||
for (x: Any in A()) {
|
||||
if (x != Unit) return "fail1: $x"
|
||||
i++
|
||||
}
|
||||
if (i != 5) return "fail2: $i"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
32
js/js.translator/testData/box/coercion/receiverSmartCast.kt
vendored
Normal file
32
js/js.translator/testData/box/coercion/receiverSmartCast.kt
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// EXPECTED_REACHABLE_NODES: 997
|
||||
fun foo(x: Any): String {
|
||||
return when (x) {
|
||||
is Char -> "char: ${x.toInt()}"
|
||||
else -> "other: $x"
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(x: Any): String {
|
||||
return when (x) {
|
||||
is Char -> "char: ${x.baz()}"
|
||||
else -> "other: $x"
|
||||
}
|
||||
}
|
||||
|
||||
fun Char.baz(): Boolean = jsTypeOf(asDynamic()) == "number"
|
||||
|
||||
fun box(): String {
|
||||
val a = foo('0')
|
||||
if (a != "char: 48") return "fail1: $a"
|
||||
|
||||
val b = foo(23)
|
||||
if (b != "other: 23") return "fail2: $b"
|
||||
|
||||
val c = bar('0')
|
||||
if (c != "char: true") return "fail3: $c"
|
||||
|
||||
val d = bar(23)
|
||||
if (d != "other: 23") return "fail4: $d"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
19
js/js.translator/testData/box/coercion/safeCallLetReturningUnit.kt
vendored
Normal file
19
js/js.translator/testData/box/coercion/safeCallLetReturningUnit.kt
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
var log = ""
|
||||
|
||||
fun test(param: Any?) {
|
||||
param?.let {
|
||||
log += "test($param);"
|
||||
} ?: run {
|
||||
log += "test-null;"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test(null)
|
||||
test(23)
|
||||
|
||||
if (log != "test-null;test(23);") return "fail: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
15
js/js.translator/testData/box/coercion/topLevelProperty.kt
vendored
Normal file
15
js/js.translator/testData/box/coercion/topLevelProperty.kt
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1003
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo()"
|
||||
}
|
||||
|
||||
val bar: Any = foo()
|
||||
|
||||
fun box(): String {
|
||||
if (bar != Unit) return "fail1: $bar"
|
||||
if (log != "foo()") return "fail2: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
19
js/js.translator/testData/box/coercion/tryWithEmptyCatch.kt
vendored
Normal file
19
js/js.translator/testData/box/coercion/tryWithEmptyCatch.kt
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
fun test(x: Int): Any {
|
||||
return try {
|
||||
if (x % 2 == 0) throw RuntimeException()
|
||||
x
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = test(1)
|
||||
if (a != 1) return "fail1: $a"
|
||||
|
||||
val b = test(2)
|
||||
if (b != Unit) return "fail2: $b"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
17
js/js.translator/testData/box/coercion/unitAsExtensionReceiver.kt
vendored
Normal file
17
js/js.translator/testData/box/coercion/unitAsExtensionReceiver.kt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo"
|
||||
}
|
||||
|
||||
fun Unit.bar() = jsTypeOf(this.asDynamic()) == "undefined"
|
||||
|
||||
fun Any.baz() = jsTypeOf(this.asDynamic()) == "object"
|
||||
|
||||
fun box(): String {
|
||||
if (!foo().bar()) return "fail1"
|
||||
if (!foo().baz()) return "fail2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
14
js/js.translator/testData/box/coercion/unitIsAs.kt
vendored
Normal file
14
js/js.translator/testData/box/coercion/unitIsAs.kt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1002
|
||||
var log = ""
|
||||
|
||||
fun foo(): Unit {
|
||||
log += "foo();"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (foo() !is Any) return "fail1"
|
||||
if (foo() as Any != Unit) return "fail2"
|
||||
if (log != "foo();foo();") return "fail3: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
14
js/js.translator/testData/box/coercion/unitSafeCall.kt
vendored
Normal file
14
js/js.translator/testData/box/coercion/unitSafeCall.kt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1004
|
||||
class C {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a: C? = C()
|
||||
val b: C? = null
|
||||
|
||||
if (a?.foo() != Unit) return "fail1: ${a?.foo()}"
|
||||
if (b?.foo() != null) return "fail2: ${b?.foo()}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
22
js/js.translator/testData/box/coercion/whenWithUnit.kt
vendored
Normal file
22
js/js.translator/testData/box/coercion/whenWithUnit.kt
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1005
|
||||
var log = ""
|
||||
|
||||
fun foo() {
|
||||
log += "foo()"
|
||||
}
|
||||
|
||||
fun test(x: Int) = when (x) {
|
||||
in 0..10 -> foo()
|
||||
else -> 55
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = test(20)
|
||||
if (a !is Int) return "fail1: $a"
|
||||
|
||||
val b = test(5)
|
||||
if (b !is Unit) return "fail2: $b"
|
||||
if (log != "foo()") return "fail3: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// FILE: lib.kt
|
||||
package lib
|
||||
|
||||
external fun bar()
|
||||
external fun bar(): Int
|
||||
|
||||
val bar = 32
|
||||
|
||||
|
||||
26
js/js.translator/testData/box/standardClasses/charArrayGetSet.kt
vendored
Normal file
26
js/js.translator/testData/box/standardClasses/charArrayGetSet.kt
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// EXPECTED_REACHABLE_NODES: 997
|
||||
fun box(): String {
|
||||
val a = CharArray(1)
|
||||
val aType = jsTypeOf(a.asDynamic()[0])
|
||||
if (aType != "number") return "fail1: $aType"
|
||||
|
||||
a[0] = 'Q'
|
||||
val aType2 = jsTypeOf(a.asDynamic()[0])
|
||||
if (aType2 != "number") return "fail2: $aType2"
|
||||
|
||||
val aType3 = jsTypeOf(a[0].asDynamic())
|
||||
if (aType3 != "number") return "fail3: $aType3"
|
||||
|
||||
val b = Array<Char>(1) { 'Q' }
|
||||
val bType = jsTypeOf(b.asDynamic()[0])
|
||||
if (bType != "object") return "fail4: $bType"
|
||||
|
||||
b[0] = 'W'
|
||||
val bType2 = jsTypeOf(b.asDynamic()[0])
|
||||
if (bType2 != "object") return "fail5: $bType2"
|
||||
|
||||
val bType3 = jsTypeOf(b[0].asDynamic())
|
||||
if (bType3 != "number") return "fail6: $bType3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
var log = ""
|
||||
|
||||
inline fun String.foo(a: String): Int {
|
||||
log += "foo1"
|
||||
return asDynamic().indexOf(a)
|
||||
}
|
||||
|
||||
inline fun String.foo(a: Char): Int {
|
||||
log += "foo2"
|
||||
return indexOf(a.toString())
|
||||
}
|
||||
|
||||
fun bar(a: String, b: Char, x: Int) {
|
||||
log += if (x > 0)
|
||||
23
|
||||
else
|
||||
a.foo(b)
|
||||
}
|
||||
|
||||
// LINES: 6 4 4 5 5 8 8 8 8 8 8 8 11 9 9 10 10 8 8 8 8 18 14 14 14 14 14 15 17 17 9 9 14 10 17 10 14 14 * 1 * 1
|
||||
@@ -27,4 +27,4 @@ fun bar(f: (Pair<String, String>) -> Unit) {
|
||||
}
|
||||
|
||||
|
||||
// LINES: 22 16 16 17 18 20 20 21 21 23 9 9 9 9 4 9 9 9 5 5 6 7 11 11 12 12 15 15 27 26 26 * 1 * 1
|
||||
// LINES: 22 16 16 17 18 20 20 21 21 22 22 23 9 9 9 9 4 9 9 9 5 5 6 7 11 11 12 12 15 15 27 26 26 * 1 * 1
|
||||
@@ -32,4 +32,4 @@ inline operator fun P.component1() = a
|
||||
|
||||
inline operator fun P.component2() = b
|
||||
|
||||
// LINES: 22 17 17 31 18 18 33 20 20 21 21 23 9 9 9 9 4 9 9 9 6 6 31 7 7 33 11 11 12 12 15 15 27 26 26 29 29 29 * 31 31 31 33 33 33 * 1 * 1
|
||||
// LINES: 22 17 17 31 18 18 33 20 20 21 21 22 22 23 9 9 9 9 4 9 9 9 6 6 31 7 7 33 11 11 12 12 15 15 27 26 26 29 29 29 * 31 31 31 33 33 33 * 1 * 1
|
||||
@@ -4,4 +4,4 @@ fun foo(x: Int): () -> Unit = {
|
||||
|
||||
fun bar() = 23
|
||||
|
||||
// LINES: 1 1 1 2 2 1 1 1 5 5 5
|
||||
// LINES: 1 1 1 2 2 3 3 1 1 1 5 5 5
|
||||
Reference in New Issue
Block a user