JS: Support isInitialized intrisic for lateinit properties
This commit is contained in:
committed by
Ilya Gorbunov
parent
5cbcbe4a9c
commit
ac508a510e
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@ var JsInvocation.inlineStrategy: InlineStrategy? by MetadataProperty(default = n
|
||||
|
||||
var JsInvocation.isCallableReference by MetadataProperty(default = false)
|
||||
|
||||
var JsInvocation.callableReferenceReceiver: JsExpression? by MetadataProperty(default = null)
|
||||
|
||||
var JsInvocation.descriptor: CallableDescriptor? by MetadataProperty(default = null)
|
||||
|
||||
var JsInvocation.psiElement: PsiElement? by MetadataProperty(default = null)
|
||||
|
||||
@@ -7193,6 +7193,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleLateInitIsInitialized.kt")
|
||||
public void testSimpleLateInitIsInitialized() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/simpleLateInitIsInitialized.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("staticAccessorsWithJsName.kt")
|
||||
public void testStaticAccessorsWithJsName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/staticAccessorsWithJsName.kt");
|
||||
|
||||
+18
@@ -15245,6 +15245,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("innerSubclass.kt")
|
||||
public void testInnerSubclass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sideEffects.kt")
|
||||
public void testSideEffects() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelProperty.kt")
|
||||
public void testTopLevelProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
||||
|
||||
+39
-2
@@ -20,10 +20,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsInvocation;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
|
||||
import org.jetbrains.kotlin.js.patterns.NamePredicate;
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo;
|
||||
@@ -32,10 +35,15 @@ 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.JsDescriptorUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.UtilsKt;
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression;
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.List;
|
||||
@@ -150,13 +158,39 @@ public final class TopLevelFIF extends CompositeFIF {
|
||||
}
|
||||
};
|
||||
|
||||
private static final FunctionIntrinsic LATEINIT_KPROPERTY_ISINITIALIZED_INTRINSIC = new FunctionIntrinsic() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(
|
||||
@NotNull CallInfo callInfo,
|
||||
@NotNull List<? extends JsExpression> arguments,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
ResolvedCall<? extends CallableDescriptor> call = callInfo.getResolvedCall();
|
||||
ExpressionReceiver receiver = (ExpressionReceiver) call.getExtensionReceiver();
|
||||
|
||||
KtCallableReferenceExpression expression =
|
||||
(KtCallableReferenceExpression) KtPsiUtil.safeDeparenthesize(receiver.getExpression());
|
||||
ResolvedCall<? extends CallableDescriptor> referencedProperty =
|
||||
CallUtilKt.getResolvedCall(expression.getCallableReference(), context.bindingContext());
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) referencedProperty.getResultingDescriptor();
|
||||
|
||||
JsExpression receiverExpression =
|
||||
MetadataProperties.getCallableReferenceReceiver((JsInvocation) callInfo.getExtensionReceiver());
|
||||
JsName backingFieldName = TranslationUtils.getNameForBackingField(
|
||||
context, (PropertyDescriptor) JsDescriptorUtils.findRealDeclaration(propertyDescriptor));
|
||||
JsNameRef backingFieldRef = new JsNameRef(backingFieldName, receiverExpression);
|
||||
return TranslationUtils.nullCheck(backingFieldRef, true);
|
||||
}
|
||||
};
|
||||
|
||||
private static final FunctionIntrinsic STRING_SUBSTRING = new FunctionIntrinsicWithReceiverComputed() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<? extends JsExpression> arguments,
|
||||
@NotNull TranslationContext context
|
||||
@NotNull List<? extends JsExpression> arguments,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
return new JsInvocation(new JsNameRef("substring", receiver), arguments);
|
||||
}
|
||||
@@ -202,6 +236,9 @@ public final class TopLevelFIF extends CompositeFIF {
|
||||
|
||||
add(pattern("kotlin", "enumValues"), ENUM_VALUES_INTRINSIC);
|
||||
add(pattern("kotlin", "enumValueOf"), ENUM_VALUE_OF_INTRINSIC);
|
||||
|
||||
add(pattern("kotlin", "<get-isInitialized>").isExtensionOf("kotlin.reflect.KProperty0"),
|
||||
LATEINIT_KPROPERTY_ISINITIALIZED_INTRINSIC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.js.translate.reference
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
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.backend.ast.metadata.*
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
@@ -135,7 +132,7 @@ object CallableReferenceTranslator {
|
||||
function.body.statements += JsReturn(TranslationUtils.coerce(context, invocation, context.currentModule.builtIns.anyType))
|
||||
|
||||
val rawCallableRef = bindIfNecessary(function, receiver)
|
||||
return context.wrapFunctionCallableRef(expression.callableReference.getReferencedName(), rawCallableRef)
|
||||
return context.wrapFunctionCallableRef(receiver, expression.callableReference.getReferencedName(), rawCallableRef)
|
||||
}
|
||||
|
||||
private fun translateForProperty(
|
||||
@@ -243,10 +240,12 @@ object CallableReferenceTranslator {
|
||||
if (setter != null) {
|
||||
invocation.arguments += setter
|
||||
}
|
||||
invocation.callableReferenceReceiver = receiver
|
||||
return invocation
|
||||
}
|
||||
|
||||
private fun TranslationContext.wrapFunctionCallableRef(
|
||||
receiver: JsExpression?,
|
||||
name: String,
|
||||
function: JsExpression
|
||||
): JsExpression {
|
||||
@@ -256,6 +255,7 @@ object CallableReferenceTranslator {
|
||||
val invocation = JsInvocation(invokeFun, nameLiteral, function)
|
||||
invocation.isCallableReference = true
|
||||
invocation.sideEffects = SideEffectKind.PURE
|
||||
invocation.callableReferenceReceiver = receiver
|
||||
return invocation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,12 +170,12 @@ public final class JsDescriptorUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static FunctionDescriptor findRealDeclaration(@NotNull FunctionDescriptor descriptor) {
|
||||
public static CallableMemberDescriptor findRealDeclaration(@NotNull CallableMemberDescriptor descriptor) {
|
||||
if (descriptor.getModality() == Modality.ABSTRACT) return null;
|
||||
if (descriptor.getKind().isReal()) return descriptor;
|
||||
|
||||
for (FunctionDescriptor o : descriptor.getOverriddenDescriptors()) {
|
||||
FunctionDescriptor child = findRealDeclaration(o);
|
||||
for (CallableMemberDescriptor o : descriptor.getOverriddenDescriptors()) {
|
||||
CallableMemberDescriptor child = findRealDeclaration(o);
|
||||
if (child != null) {
|
||||
return child;
|
||||
}
|
||||
|
||||
@@ -55,9 +55,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator.*;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.assignment;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.createDataDescriptor;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*;
|
||||
|
||||
public final class TranslationUtils {
|
||||
|
||||
@@ -173,16 +171,22 @@ public final class TranslationUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsNameRef backingFieldReference(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
|
||||
public static JsName getNameForBackingField(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
|
||||
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
||||
JsName backingFieldName = containingDescriptor instanceof PackageFragmentDescriptor ?
|
||||
context.getInnerNameForDescriptor(descriptor) :
|
||||
context.getNameForDescriptor(descriptor);
|
||||
|
||||
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && !(containingDescriptor instanceof PackageFragmentDescriptor)) {
|
||||
backingFieldName = context.getNameForBackingField(descriptor);
|
||||
return context.getNameForBackingField(descriptor);
|
||||
}
|
||||
|
||||
return containingDescriptor instanceof PackageFragmentDescriptor ?
|
||||
context.getInnerNameForDescriptor(descriptor) :
|
||||
context.getNameForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsNameRef backingFieldReference(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
|
||||
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
||||
|
||||
JsExpression receiver;
|
||||
if (containingDescriptor instanceof PackageFragmentDescriptor) {
|
||||
receiver = null;
|
||||
@@ -191,7 +195,7 @@ public final class TranslationUtils {
|
||||
receiver = context.getDispatchReceiver(JsDescriptorUtils.getReceiverParameterForDeclaration(containingDescriptor));
|
||||
}
|
||||
|
||||
JsNameRef result = new JsNameRef(backingFieldName, receiver);
|
||||
JsNameRef result = new JsNameRef(getNameForBackingField(context, descriptor), receiver);
|
||||
MetadataProperties.setType(result, getReturnTypeForCoercion(descriptor));
|
||||
|
||||
return result;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1035
|
||||
// LANGUAGE_VERSION: 1.2
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun deinitialize(foo: dynamic) {
|
||||
foo.bar = null
|
||||
}
|
||||
|
||||
class Foo {
|
||||
lateinit var bar: String
|
||||
|
||||
fun test(): String {
|
||||
if (this::bar.isInitialized) return "Fail 1"
|
||||
deinitialize(this)
|
||||
if (this::bar.isInitialized) return "Fail 2"
|
||||
|
||||
bar = "A"
|
||||
if (!this::bar.isInitialized) return "Fail 3"
|
||||
deinitialize(this)
|
||||
if (this::bar.isInitialized) return "Fail 4"
|
||||
|
||||
bar = "OK"
|
||||
if (!this::bar.isInitialized) return "Fail 5"
|
||||
return bar
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return Foo().test()
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
@file:kotlin.jvm.JvmName("LateinitKt")
|
||||
@file:kotlin.jvm.JvmVersion
|
||||
@file:Suppress("unused")
|
||||
|
||||
package kotlin
|
||||
|
||||
Reference in New Issue
Block a user