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
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// IGNORE_BACKEND: NATIVE
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// IGNORE_BACKEND: NATIVE
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ var JsInvocation.inlineStrategy: InlineStrategy? by MetadataProperty(default = n
|
|||||||
|
|
||||||
var JsInvocation.isCallableReference by MetadataProperty(default = false)
|
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.descriptor: CallableDescriptor? by MetadataProperty(default = null)
|
||||||
|
|
||||||
var JsInvocation.psiElement: PsiElement? by MetadataProperty(default = null)
|
var JsInvocation.psiElement: PsiElement? by MetadataProperty(default = null)
|
||||||
|
|||||||
@@ -7193,6 +7193,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("staticAccessorsWithJsName.kt")
|
||||||
public void testStaticAccessorsWithJsName() throws Exception {
|
public void testStaticAccessorsWithJsName() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/staticAccessorsWithJsName.kt");
|
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 {
|
public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
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")
|
@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.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
|
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsInvocation;
|
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.JsNameRef;
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||||
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
|
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
|
||||||
import org.jetbrains.kotlin.js.patterns.NamePredicate;
|
import org.jetbrains.kotlin.js.patterns.NamePredicate;
|
||||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo;
|
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.FunctionIntrinsic;
|
||||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed;
|
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.JsAstUtils;
|
||||||
|
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.UtilsKt;
|
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.DescriptorFactory;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
|
|
||||||
import java.util.List;
|
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() {
|
private static final FunctionIntrinsic STRING_SUBSTRING = new FunctionIntrinsicWithReceiverComputed() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public JsExpression apply(
|
public JsExpression apply(
|
||||||
@Nullable JsExpression receiver,
|
@Nullable JsExpression receiver,
|
||||||
@NotNull List<? extends JsExpression> arguments,
|
@NotNull List<? extends JsExpression> arguments,
|
||||||
@NotNull TranslationContext context
|
@NotNull TranslationContext context
|
||||||
) {
|
) {
|
||||||
return new JsInvocation(new JsNameRef("substring", receiver), arguments);
|
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", "enumValues"), ENUM_VALUES_INTRINSIC);
|
||||||
add(pattern("kotlin", "enumValueOf"), ENUM_VALUE_OF_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.backend.common.CodegenUtil
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
|
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||||
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.callTranslator.CallTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
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))
|
function.body.statements += JsReturn(TranslationUtils.coerce(context, invocation, context.currentModule.builtIns.anyType))
|
||||||
|
|
||||||
val rawCallableRef = bindIfNecessary(function, receiver)
|
val rawCallableRef = bindIfNecessary(function, receiver)
|
||||||
return context.wrapFunctionCallableRef(expression.callableReference.getReferencedName(), rawCallableRef)
|
return context.wrapFunctionCallableRef(receiver, expression.callableReference.getReferencedName(), rawCallableRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateForProperty(
|
private fun translateForProperty(
|
||||||
@@ -243,10 +240,12 @@ object CallableReferenceTranslator {
|
|||||||
if (setter != null) {
|
if (setter != null) {
|
||||||
invocation.arguments += setter
|
invocation.arguments += setter
|
||||||
}
|
}
|
||||||
|
invocation.callableReferenceReceiver = receiver
|
||||||
return invocation
|
return invocation
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TranslationContext.wrapFunctionCallableRef(
|
private fun TranslationContext.wrapFunctionCallableRef(
|
||||||
|
receiver: JsExpression?,
|
||||||
name: String,
|
name: String,
|
||||||
function: JsExpression
|
function: JsExpression
|
||||||
): JsExpression {
|
): JsExpression {
|
||||||
@@ -256,6 +255,7 @@ object CallableReferenceTranslator {
|
|||||||
val invocation = JsInvocation(invokeFun, nameLiteral, function)
|
val invocation = JsInvocation(invokeFun, nameLiteral, function)
|
||||||
invocation.isCallableReference = true
|
invocation.isCallableReference = true
|
||||||
invocation.sideEffects = SideEffectKind.PURE
|
invocation.sideEffects = SideEffectKind.PURE
|
||||||
|
invocation.callableReferenceReceiver = receiver
|
||||||
return invocation
|
return invocation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,12 +170,12 @@ public final class JsDescriptorUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static FunctionDescriptor findRealDeclaration(@NotNull FunctionDescriptor descriptor) {
|
public static CallableMemberDescriptor findRealDeclaration(@NotNull CallableMemberDescriptor descriptor) {
|
||||||
if (descriptor.getModality() == Modality.ABSTRACT) return null;
|
if (descriptor.getModality() == Modality.ABSTRACT) return null;
|
||||||
if (descriptor.getKind().isReal()) return descriptor;
|
if (descriptor.getKind().isReal()) return descriptor;
|
||||||
|
|
||||||
for (FunctionDescriptor o : descriptor.getOverriddenDescriptors()) {
|
for (CallableMemberDescriptor o : descriptor.getOverriddenDescriptors()) {
|
||||||
FunctionDescriptor child = findRealDeclaration(o);
|
CallableMemberDescriptor child = findRealDeclaration(o);
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
return child;
|
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.backend.ast.JsBinaryOperator.*;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
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.*;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.createDataDescriptor;
|
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
|
||||||
|
|
||||||
public final class TranslationUtils {
|
public final class TranslationUtils {
|
||||||
|
|
||||||
@@ -173,16 +171,22 @@ public final class TranslationUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@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();
|
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
||||||
JsName backingFieldName = containingDescriptor instanceof PackageFragmentDescriptor ?
|
|
||||||
context.getInnerNameForDescriptor(descriptor) :
|
|
||||||
context.getNameForDescriptor(descriptor);
|
|
||||||
|
|
||||||
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && !(containingDescriptor instanceof PackageFragmentDescriptor)) {
|
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;
|
JsExpression receiver;
|
||||||
if (containingDescriptor instanceof PackageFragmentDescriptor) {
|
if (containingDescriptor instanceof PackageFragmentDescriptor) {
|
||||||
receiver = null;
|
receiver = null;
|
||||||
@@ -191,7 +195,7 @@ public final class TranslationUtils {
|
|||||||
receiver = context.getDispatchReceiver(JsDescriptorUtils.getReceiverParameterForDeclaration(containingDescriptor));
|
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));
|
MetadataProperties.setType(result, getReturnTypeForCoercion(descriptor));
|
||||||
|
|
||||||
return result;
|
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.JvmName("LateinitKt")
|
||||||
@file:kotlin.jvm.JvmVersion
|
|
||||||
@file:Suppress("unused")
|
@file:Suppress("unused")
|
||||||
|
|
||||||
package kotlin
|
package kotlin
|
||||||
|
|||||||
Reference in New Issue
Block a user