JS: bound callable references (KT-13573).
This commit is contained in:
-3
@@ -1,6 +1,3 @@
|
||||
// TODO investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
class A {
|
||||
companion object {
|
||||
fun ok() = "OK"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
enum class E {
|
||||
A, B;
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
inline fun foo(x: () -> String) = x()
|
||||
|
||||
fun String.id() = this
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
inline fun go(f: () -> String) = f()
|
||||
|
||||
fun String.id(): String = this
|
||||
|
||||
+1
-4
@@ -1,8 +1,5 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// Enable when callable references to builtin members is supported
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
// See KT-12995
|
||||
|
||||
fun box(): String {
|
||||
var state = 0
|
||||
val name = (state++)::toString.name
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// Enable when callable references to builtin members is supported
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
fun <T> get(t: T): () -> String {
|
||||
return t::toString
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
class A(var v: Int) {
|
||||
fun f(x: Int) = x * v
|
||||
}
|
||||
|
||||
fun A.g(x: Int) = x * f(x);
|
||||
|
||||
var A.w: Int
|
||||
get() = 1000 * v
|
||||
set(c: Int) {
|
||||
v = c + 10
|
||||
}
|
||||
|
||||
object F {
|
||||
var u = 0
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = A(5)
|
||||
|
||||
val av = a::v
|
||||
if (av() != 5) return "fail1: ${av()}"
|
||||
if (av.get() != 5) return "fail2: ${av.get()}"
|
||||
av.set(7)
|
||||
if (a.v != 7) return "fail3: ${a.v}"
|
||||
|
||||
val af = a::f
|
||||
if (af(10) != 70) return "fail4: ${af(10)}"
|
||||
|
||||
val ag = a::g
|
||||
if (ag(10) != 700) return "fail5: ${ag(10)}"
|
||||
|
||||
val aw = a::w
|
||||
if (aw() != 7000) return "fail6: ${aw()}"
|
||||
if (aw.get() != 7000) return "fail7: ${aw.get()}"
|
||||
aw.set(5)
|
||||
if (a.v != 15) return "fail8: ${a.v}"
|
||||
|
||||
val fu = F::u
|
||||
if (fu() != 0) return "fail9: ${fu()}"
|
||||
if (fu.get() != 0) return "fail10: ${fu.get()}"
|
||||
fu.set(8)
|
||||
if (F.u != 8) return "fail11: ${F.u}"
|
||||
|
||||
val x = 100
|
||||
|
||||
fun A.lf() = v * x;
|
||||
val alf = a::lf
|
||||
if (alf() != 1500) return "fail9: ${alf()}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -1,8 +1,3 @@
|
||||
// TODO: investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
// See https://youtrack.jetbrains.com/issue/KT-14939
|
||||
|
||||
val String?.ok: String
|
||||
get() = "OK"
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// TODO investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
object Singleton {
|
||||
fun ok() = "OK"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// Enable when callable references to builtin members is supported
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
fun box(): String {
|
||||
val f = "KOTLIN"::get
|
||||
return "${f(1)}${f(0)}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// Enable when callable references to builtin members are supported.
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
fun box(): String {
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: A.java
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Enable when callable references to builtin members is supported
|
||||
// IGNORE_BACKEND: JS
|
||||
// FILE: 1.kt
|
||||
|
||||
package test
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Enable when using lambdas as extension lambdas is supported (KT-13312)
|
||||
// IGNORE_BACKEND: JS
|
||||
// FILE: 1.kt
|
||||
|
||||
package test
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Enable when using lambdas as extension lambdas is supported (KT-13312)
|
||||
// IGNORE_BACKEND: JS
|
||||
// FILE: 1.kt
|
||||
|
||||
package test
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Enable when callable references to builtin members and using lambdas as extension lambdas (KT-13312) is supported
|
||||
// IGNORE_BACKEND: JS
|
||||
// FILE: 1.kt
|
||||
|
||||
package test
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Enable when callable references to builtin members and using lambdas as extension lambdas (KT-13312) is supported
|
||||
// IGNORE_BACKEND: JS
|
||||
// FILE: 1.kt
|
||||
|
||||
package test
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Enable when using lambdas as extension lambdas is supported (KT-13312)
|
||||
// IGNORE_BACKEND: JS
|
||||
// FILE: 1.kt
|
||||
|
||||
package test
|
||||
|
||||
+6
@@ -1525,6 +1525,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiCase.kt")
|
||||
public void testMultiCase() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/multiCase.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullReceiver.kt")
|
||||
public void testNullReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.kt");
|
||||
|
||||
@@ -1525,6 +1525,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiCase.kt")
|
||||
public void testMultiCase() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/multiCase.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullReceiver.kt")
|
||||
public void testNullReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.kt");
|
||||
|
||||
@@ -1200,13 +1200,17 @@ fun main(args: Array<String>) {
|
||||
model("codegen/boxInline/nonLocalReturns/", targetBackend = TargetBackend.JS)
|
||||
}
|
||||
|
||||
testClass<AbstractPropertyAccessorsInlineTests>() {
|
||||
testClass<AbstractPropertyAccessorsInlineTests> {
|
||||
model("codegen/boxInline/property/", targetBackend = TargetBackend.JS)
|
||||
}
|
||||
|
||||
testClass<AbstractNoInlineTests>() {
|
||||
testClass<AbstractNoInlineTests> {
|
||||
model("codegen/boxInline/noInline/", targetBackend = TargetBackend.JS)
|
||||
}
|
||||
|
||||
testClass<AbstractCallableReferenceInlineTests> {
|
||||
model("codegen/boxInline/callableReference/", targetBackend = TargetBackend.JS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.test.semantics;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/callableReference")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class CallableReferenceInlineTestsGenerated extends AbstractCallableReferenceInlineTests {
|
||||
public void testAllFilesPresentInCallableReference() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/callableReference"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classLevel.kt")
|
||||
public void testClassLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/classLevel.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("classLevel2.kt")
|
||||
public void testClassLevel2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/classLevel2.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("constructor.kt")
|
||||
public void testConstructor() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/constructor.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("intrinsic.kt")
|
||||
public void testIntrinsic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/intrinsic.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyIntrinsic.kt")
|
||||
public void testPropertyIntrinsic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/propertyIntrinsic.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyReference.kt")
|
||||
public void testPropertyReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/propertyReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/topLevel.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelExtension.kt")
|
||||
public void testTopLevelExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/topLevelExtension.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelProperty.kt")
|
||||
public void testTopLevelProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/topLevelProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/callableReference/bound")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Bound extends AbstractCallableReferenceInlineTests {
|
||||
public void testAllFilesPresentInBound() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/callableReference/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classProperty.kt")
|
||||
public void testClassProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/classProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("expression.kt")
|
||||
public void testExpression() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/expression.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionReceiver.kt")
|
||||
public void testExtensionReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/extensionReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("filter.kt")
|
||||
public void testFilter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/filter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("intrinsic.kt")
|
||||
public void testIntrinsic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/intrinsic.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("map.kt")
|
||||
public void testMap() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/map.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("objectProperty.kt")
|
||||
public void testObjectProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/objectProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyImportedFromObject.kt")
|
||||
public void testPropertyImportedFromObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/propertyImportedFromObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelExtensionProperty.kt")
|
||||
public void testTopLevelExtensionProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/topLevelExtensionProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-47
@@ -1877,13 +1877,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("companionObjectReceiver.kt")
|
||||
public void testCompanionObjectReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.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("enumEntryMember.kt")
|
||||
@@ -1922,28 +1916,22 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("multiCase.kt")
|
||||
public void testMultiCase() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/multiCase.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullReceiver.kt")
|
||||
public void testNullReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.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("objectReceiver.kt")
|
||||
public void testObjectReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/objectReceiver.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("primitiveReceiver.kt")
|
||||
@@ -1976,18 +1964,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("syntheticExtensionOnLHS.kt")
|
||||
public void testSyntheticExtensionOnLHS() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/syntheticExtensionOnLHS.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/equals")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -2056,25 +2032,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/inline/simple.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("simpleVal.kt")
|
||||
public void testSimpleVal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/inline/simpleVal.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -33,6 +33,8 @@ abstract class AbstractPropertyAccessorsInlineTests : BorrowedInlineTest("proper
|
||||
|
||||
abstract class AbstractNoInlineTests : BorrowedInlineTest("noInline/")
|
||||
|
||||
abstract class AbstractCallableReferenceInlineTests : BorrowedInlineTest("callableReference/")
|
||||
|
||||
abstract class AbstractBoxJsTest() : BasicBoxTest(
|
||||
BasicBoxTest.TEST_DATA_DIR_PATH + "box/",
|
||||
BasicBoxTest.TEST_DATA_DIR_PATH + "out/box/"
|
||||
|
||||
@@ -77,12 +77,17 @@ public final class Namer {
|
||||
public static final String OUTER_FIELD_NAME = "$outer";
|
||||
|
||||
private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction";
|
||||
private static final String BOUND_CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getBoundCallableRefForMemberFunction";
|
||||
private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction";
|
||||
private static final String BOUND_CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getBoundCallableRefForExtensionFunction";
|
||||
private static final String CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getCallableRefForLocalExtensionFunction";
|
||||
private static final String BOUND_CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getBoundCallableRefForLocalExtensionFunction";
|
||||
private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor";
|
||||
private static final String CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY = "getCallableRefForTopLevelProperty";
|
||||
private static final String CALLABLE_REF_FOR_MEMBER_PROPERTY = "getCallableRefForMemberProperty";
|
||||
private static final String BOUND_CALLABLE_REF_FOR_MEMBER_PROPERTY = "getBoundCallableRefForMemberProperty";
|
||||
private static final String CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getCallableRefForExtensionProperty";
|
||||
private static final String BOUND_CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getBoundCallableRefForExtensionProperty";
|
||||
|
||||
private static final String DELEGATE = "$delegate";
|
||||
|
||||
@@ -191,18 +196,28 @@ public final class Namer {
|
||||
@NotNull
|
||||
private final JsName callableRefForMemberFunctionName;
|
||||
@NotNull
|
||||
private final JsName boundCallableRefForMemberFunctionName;
|
||||
@NotNull
|
||||
private final JsName callableRefForExtensionFunctionName;
|
||||
@NotNull
|
||||
private final JsName boundCallableRefForExtensionFunctionName;
|
||||
@NotNull
|
||||
private final JsName callableRefForLocalExtensionFunctionName;
|
||||
@NotNull
|
||||
private final JsName boundCallableRefForLocalExtensionFunctionName;
|
||||
@NotNull
|
||||
private final JsName callableRefForConstructorName;
|
||||
@NotNull
|
||||
private final JsName callableRefForTopLevelProperty;
|
||||
@NotNull
|
||||
private final JsName callableRefForMemberProperty;
|
||||
@NotNull
|
||||
private final JsName boundCallableRefForMemberProperty;
|
||||
@NotNull
|
||||
private final JsName callableRefForExtensionProperty;
|
||||
@NotNull
|
||||
private final JsName boundCallableRefForExtensionProperty;
|
||||
@NotNull
|
||||
private final JsExpression callGetProperty;
|
||||
@NotNull
|
||||
private final JsExpression callSetProperty;
|
||||
@@ -217,12 +232,17 @@ public final class Namer {
|
||||
callSetProperty = kotlin("callSetter");
|
||||
|
||||
callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
|
||||
boundCallableRefForMemberFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
|
||||
callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
|
||||
boundCallableRefForExtensionFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
|
||||
callableRefForLocalExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME);
|
||||
boundCallableRefForLocalExtensionFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME);
|
||||
callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME);
|
||||
callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY);
|
||||
callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY);
|
||||
boundCallableRefForMemberProperty = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_MEMBER_PROPERTY);
|
||||
callableRefForExtensionProperty = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_PROPERTY);
|
||||
boundCallableRefForExtensionProperty = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_EXTENSION_PROPERTY);
|
||||
|
||||
isTypeName = kotlinScope.declareName("isType");
|
||||
}
|
||||
@@ -243,16 +263,31 @@ public final class Namer {
|
||||
return kotlin(callableRefForMemberFunctionName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression boundCallableRefForMemberFunctionReference() {
|
||||
return kotlin(boundCallableRefForMemberFunctionName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForExtensionFunctionReference() {
|
||||
return kotlin(callableRefForExtensionFunctionName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression boundCallableRefForExtensionFunctionReference() {
|
||||
return kotlin(boundCallableRefForExtensionFunctionName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForLocalExtensionFunctionReference() {
|
||||
return kotlin(callableRefForLocalExtensionFunctionName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression boundCallableRefForLocalExtensionFunctionReference() {
|
||||
return kotlin(boundCallableRefForLocalExtensionFunctionName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForConstructorReference() {
|
||||
return kotlin(callableRefForConstructorName);
|
||||
@@ -268,11 +303,21 @@ public final class Namer {
|
||||
return kotlin(callableRefForMemberProperty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression boundCallableRefForMemberPropertyReference() {
|
||||
return kotlin(boundCallableRefForMemberProperty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForExtensionPropertyReference() {
|
||||
return kotlin(callableRefForExtensionProperty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression boundCallableRefForExtensionPropertyReference() {
|
||||
return kotlin(boundCallableRefForExtensionProperty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression throwNPEFunctionRef() {
|
||||
return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
|
||||
|
||||
+96
-38
@@ -21,20 +21,41 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.utils.*
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import java.util.*
|
||||
|
||||
object CallableReferenceTranslator {
|
||||
|
||||
fun translate(expression: KtCallableReferenceExpression, context: TranslationContext): JsExpression {
|
||||
val descriptor = BindingUtils.getDescriptorForReferenceExpression(context.bindingContext(), expression.callableReference)
|
||||
|
||||
val receiver = expression.receiverExpression?.let { r ->
|
||||
if (context.bindingContext().get(BindingContext.DOUBLE_COLON_LHS, r) is DoubleColonLHS.Expression) {
|
||||
val block = JsBlock()
|
||||
val e = Translation.translateAsExpression(r, context, block)
|
||||
if (!block.isEmpty) {
|
||||
context.addStatementsToCurrentBlockFrom(block)
|
||||
}
|
||||
e
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
} ?: (descriptor as? PropertyImportedFromObject)?.let {
|
||||
ReferenceTranslator.translateAsValueReference(it.containingObject, context)
|
||||
}
|
||||
|
||||
return when (descriptor) {
|
||||
is PropertyDescriptor ->
|
||||
translateForProperty(descriptor, context, expression)
|
||||
translateForProperty(descriptor, context, expression, receiver)
|
||||
is FunctionDescriptor ->
|
||||
translateForFunction(descriptor, context, expression)
|
||||
translateForFunction(descriptor, context, expression, receiver)
|
||||
else ->
|
||||
throw IllegalArgumentException("Expected property or function: $descriptor, expression=${expression.text}")
|
||||
}
|
||||
@@ -45,31 +66,41 @@ object CallableReferenceTranslator {
|
||||
return JsLiteral.NULL
|
||||
}
|
||||
|
||||
private fun translateForFunction(descriptor: FunctionDescriptor, context: TranslationContext, expression: KtCallableReferenceExpression): JsExpression {
|
||||
private fun translateForFunction(
|
||||
descriptor: FunctionDescriptor,
|
||||
context: TranslationContext,
|
||||
expression: KtCallableReferenceExpression,
|
||||
receiver: JsExpression?
|
||||
): JsExpression {
|
||||
return when {
|
||||
// TODO Support for callable reference to builtin functions and members
|
||||
// TODO Support for callable reference to builtin functions and members
|
||||
KotlinBuiltIns.isBuiltIn(descriptor) ->
|
||||
reportNotSupported(context, expression)
|
||||
isConstructor(descriptor) ->
|
||||
translateForConstructor(descriptor, context)
|
||||
isExtension(descriptor) ->
|
||||
translateForExtensionFunction(descriptor, context)
|
||||
translateForExtensionFunction(descriptor, context, receiver)
|
||||
isMember(descriptor) ->
|
||||
translateForMemberFunction(descriptor, context)
|
||||
translateForMemberFunction(descriptor, context, receiver)
|
||||
else ->
|
||||
ReferenceTranslator.translateAsValueReference(descriptor, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForProperty(descriptor: PropertyDescriptor, context: TranslationContext, expression: KtCallableReferenceExpression): JsExpression {
|
||||
private fun translateForProperty(
|
||||
descriptor: PropertyDescriptor,
|
||||
context: TranslationContext,
|
||||
expression: KtCallableReferenceExpression,
|
||||
receiver: JsExpression?
|
||||
): JsExpression {
|
||||
return when {
|
||||
// TODO Support for callable reference to builtin properties
|
||||
// TODO Support for callable reference to builtin properties
|
||||
KotlinBuiltIns.isBuiltIn(descriptor) ->
|
||||
reportNotSupported(context, expression)
|
||||
isExtension(descriptor) ->
|
||||
translateForExtensionProperty(descriptor, context)
|
||||
translateForExtensionProperty(descriptor, context, receiver)
|
||||
isMember(descriptor) ->
|
||||
translateForMemberProperty(descriptor, context)
|
||||
translateForMemberProperty(descriptor, context, receiver)
|
||||
else ->
|
||||
translateForTopLevelProperty(descriptor, context)
|
||||
}
|
||||
@@ -137,27 +168,49 @@ object CallableReferenceTranslator {
|
||||
return function
|
||||
}
|
||||
|
||||
private fun translateForMemberProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
||||
private fun translateForMemberProperty(
|
||||
descriptor: PropertyDescriptor,
|
||||
context: TranslationContext,
|
||||
receiver: JsExpression?
|
||||
): JsExpression {
|
||||
val jsPropertyName = context.getNameForDescriptor(descriptor)
|
||||
val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString())
|
||||
return JsInvocation(context.namer().callableRefForMemberPropertyReference(), jsPropertyNameAsString, isVar(descriptor))
|
||||
if (receiver == null) {
|
||||
return JsInvocation(context.namer().callableRefForMemberPropertyReference(), jsPropertyNameAsString, isVar(descriptor))
|
||||
}
|
||||
else {
|
||||
return JsInvocation(context.namer().boundCallableRefForMemberPropertyReference(), receiver, jsPropertyNameAsString,
|
||||
isVar(descriptor))
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForExtensionProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
||||
private fun translateForExtensionProperty(
|
||||
descriptor: PropertyDescriptor,
|
||||
context: TranslationContext,
|
||||
receiver: JsExpression?
|
||||
): JsExpression {
|
||||
val jsGetterNameRef = ReferenceTranslator.translateAsValueReference(descriptor.getter!!, context)
|
||||
val propertyName = descriptor.name
|
||||
val jsPropertyNameAsString = context.program().getStringLiteral(propertyName.asString())
|
||||
val argumentList = ArrayList<JsExpression>(3)
|
||||
val argumentList = ArrayList<JsExpression>(4)
|
||||
if (receiver != null) {
|
||||
argumentList.add(receiver)
|
||||
}
|
||||
argumentList.add(jsPropertyNameAsString)
|
||||
argumentList.add(jsGetterNameRef)
|
||||
if (descriptor.isVar) {
|
||||
val jsSetterNameRef = ReferenceTranslator.translateAsValueReference(descriptor.setter!!, context)
|
||||
argumentList.add(jsSetterNameRef)
|
||||
}
|
||||
return if (AnnotationsUtils.isNativeObject(descriptor))
|
||||
translateForMemberProperty(descriptor, context)
|
||||
else
|
||||
return if (AnnotationsUtils.isNativeObject(descriptor)) {
|
||||
translateForMemberProperty(descriptor, context, receiver)
|
||||
}
|
||||
else if (receiver == null) {
|
||||
JsInvocation(context.namer().callableRefForExtensionPropertyReference(), argumentList)
|
||||
}
|
||||
else {
|
||||
JsInvocation(context.namer().boundCallableRefForExtensionPropertyReference(), argumentList)
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForConstructor(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
||||
@@ -165,39 +218,44 @@ object CallableReferenceTranslator {
|
||||
return JsInvocation(context.namer().callableRefForConstructorReference(), jsFunctionRef)
|
||||
}
|
||||
|
||||
private fun translateForExtensionFunction(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
||||
val receiverParameterDescriptor = descriptor.extensionReceiverParameter ?:
|
||||
error("receiverParameter for extension should not be null")
|
||||
|
||||
private fun translateForExtensionFunction(descriptor: FunctionDescriptor,
|
||||
context: TranslationContext,
|
||||
receiver: JsExpression?
|
||||
): JsExpression {
|
||||
val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context)
|
||||
if (descriptor.visibility == Visibilities.LOCAL) {
|
||||
return JsInvocation(context.namer().callableRefForLocalExtensionFunctionReference(), jsFunctionRef)
|
||||
if (receiver == null) {
|
||||
return JsInvocation(context.namer().callableRefForLocalExtensionFunctionReference(), jsFunctionRef)
|
||||
}
|
||||
else {
|
||||
return JsInvocation(context.namer().boundCallableRefForLocalExtensionFunctionReference(), receiver, jsFunctionRef)
|
||||
}
|
||||
}
|
||||
|
||||
else if (AnnotationsUtils.isNativeObject(descriptor)) {
|
||||
val jetType = receiverParameterDescriptor.type
|
||||
val receiverClassDescriptor = DescriptorUtils.getClassDescriptorForType(jetType)
|
||||
return translateAsMemberFunctionReference(descriptor, receiverClassDescriptor, context)
|
||||
return translateForMemberFunction(descriptor, context, receiver)
|
||||
}
|
||||
else {
|
||||
return JsInvocation(context.namer().callableRefForExtensionFunctionReference(), jsFunctionRef)
|
||||
if (receiver == null) {
|
||||
return JsInvocation(context.namer().callableRefForExtensionFunctionReference(), jsFunctionRef)
|
||||
}
|
||||
else {
|
||||
return JsInvocation(context.namer().boundCallableRefForExtensionFunctionReference(), receiver, jsFunctionRef)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForMemberFunction(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
||||
val classDescriptor = JsDescriptorUtils.getContainingDeclaration(descriptor) as? ClassDescriptor ?:
|
||||
throw IllegalArgumentException("Expected ClassDescriptor: $descriptor")
|
||||
return translateAsMemberFunctionReference(descriptor, classDescriptor, context)
|
||||
}
|
||||
|
||||
private fun translateAsMemberFunctionReference(
|
||||
private fun translateForMemberFunction(
|
||||
descriptor: CallableDescriptor,
|
||||
classDescriptor: ClassDescriptor,
|
||||
context: TranslationContext
|
||||
context: TranslationContext,
|
||||
receiver: JsExpression?
|
||||
): JsExpression {
|
||||
val jsClassNameRef = ReferenceTranslator.translateAsTypeReference(classDescriptor, context)
|
||||
val funName = context.getNameForDescriptor(descriptor)
|
||||
val funNameAsString = context.program().getStringLiteral(funName.toString())
|
||||
return JsInvocation(context.namer().callableRefForMemberFunctionReference(), jsClassNameRef, funNameAsString)
|
||||
if (receiver == null) {
|
||||
return JsInvocation(context.namer().callableRefForMemberFunctionReference(), funNameAsString)
|
||||
}
|
||||
else {
|
||||
return JsInvocation(context.namer().boundCallableRefForMemberFunctionReference(), receiver, funNameAsString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-1
@@ -142,7 +142,7 @@
|
||||
}
|
||||
|
||||
// TODO Store callable references for members in class
|
||||
Kotlin.getCallableRefForMemberFunction = function (klass, memberName) {
|
||||
Kotlin.getCallableRefForMemberFunction = function (memberName) {
|
||||
return function () {
|
||||
var args = [].slice.call(arguments);
|
||||
var instance = args.shift();
|
||||
@@ -150,6 +150,12 @@
|
||||
};
|
||||
};
|
||||
|
||||
Kotlin.getBoundCallableRefForMemberFunction = function (receiver, memberName) {
|
||||
return function () {
|
||||
return receiver[memberName].apply(receiver, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
// TODO Store callable references for extension functions in class
|
||||
// extFun expected receiver as the first argument
|
||||
Kotlin.getCallableRefForExtensionFunction = function (extFun) {
|
||||
@@ -158,6 +164,14 @@
|
||||
};
|
||||
};
|
||||
|
||||
Kotlin.getBoundCallableRefForExtensionFunction = function (receiver, extFun) {
|
||||
return function () {
|
||||
var args = [].slice.call(arguments);
|
||||
args.unshift(receiver);
|
||||
return extFun.apply(null, args);
|
||||
};
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForLocalExtensionFunction = function (extFun) {
|
||||
return function () {
|
||||
var args = [].slice.call(arguments);
|
||||
@@ -166,6 +180,12 @@
|
||||
};
|
||||
};
|
||||
|
||||
Kotlin.getBoundCallableRefForLocalExtensionFunction = function (receiver, extFun) {
|
||||
return function () {
|
||||
return extFun.apply(receiver, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForConstructor = function (klass) {
|
||||
return function () {
|
||||
var obj = Object.create(klass.prototype);
|
||||
@@ -185,11 +205,25 @@
|
||||
return getPropertyRefClass(getFun, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg);
|
||||
};
|
||||
|
||||
Kotlin.getBoundCallableRefForMemberProperty = function(receiver, name, isVar) {
|
||||
var getFun = Function("receiver", "return function " + name + "() { return receiver['" + name + "']; }")(receiver);
|
||||
var setFun = isVar ? function(value) { receiver[name] = value; } : null;
|
||||
return getPropertyRefClass(getFun, "get", setFun, "set_za3rmp$", propertyRefClassMetadataCache.oneArg);
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForExtensionProperty = function(name, getFun, setFun) {
|
||||
var getFunWrapper = Function("getFun", "return function " + name + "(receiver, extensionReceiver) { return getFun(receiver, extensionReceiver) }")(getFun);
|
||||
return getPropertyRefClass(getFunWrapper, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg);
|
||||
};
|
||||
|
||||
Kotlin.getBoundCallableRefForExtensionProperty = function(receiver, name, getFun, setFun) {
|
||||
var getFunWrapper = Function("receiver", "getFun", "return function " + name + "(extensionReceiver) { return getFun(receiver, extensionReceiver) }")(receiver, getFun);
|
||||
if (setFun) {
|
||||
setFun = setFun.bind(null, receiver);
|
||||
}
|
||||
return getPropertyRefClass(getFunWrapper, "get", setFun, "set_za3rmp$", propertyRefClassMetadataCache.oneArg);
|
||||
};
|
||||
|
||||
function getPropertyRefClass(getFun, getName, setFun, setName, cache) {
|
||||
var obj = getFun;
|
||||
var isMutable = typeof setFun === "function";
|
||||
|
||||
Vendored
+2
-2
@@ -2,10 +2,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="../../../dist/js/kotlin.js"></script>
|
||||
<script type="application/javascript" src="out/box/native/eval_v5.js"></script>
|
||||
<script type="application/javascript" src="out/codegen/boxInline/callableReference/bound/topLevelExtensionProperty_v5.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
console.log(JS_TESTS.foo.box());
|
||||
console.log(JS_TESTS.box());
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user