From 00be512532dd88ce31a2bc8d579f8821f62020ed Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 15 Sep 2017 20:15:28 +0300 Subject: [PATCH] Revert "Temporarily remove isInitialized and tests, but keep the implementation" This reverts commit 234148518ed6491e4cb2c951727cd05be0f96426. --- .../innerSubclass.kt | 35 ++++++++ .../sideEffects.kt | 21 +++++ .../simpleIsInitialized.kt | 36 ++++++++ .../topLevelProperty.kt | 12 +++ .../testsWithStdLib/lateinit/isInitialized.kt | 88 +++++++++++++++++++ .../lateinit/isInitialized.txt | 78 ++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 33 +++++++ .../DiagnosticsTestWithStdLibGenerated.java | 15 ++++ ...ticsTestWithStdLibUsingJavacGenerated.java | 15 ++++ .../codegen/BlackBoxCodegenTestGenerated.java | 33 +++++++ .../LightAnalysisModeTestGenerated.java | 33 +++++++ .../semantics/JsCodegenBoxTestGenerated.java | 9 ++ .../stdlib/src/kotlin/internal/Annotations.kt | 9 ++ libraries/stdlib/src/kotlin/util/Lateinit.kt | 19 ++++ 14 files changed, 436 insertions(+) create mode 100644 compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt create mode 100644 compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt create mode 100644 compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt create mode 100644 compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.txt create mode 100644 libraries/stdlib/src/kotlin/util/Lateinit.kt diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt new file mode 100644 index 00000000000..78947e1a378 --- /dev/null +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt @@ -0,0 +1,35 @@ +// TARGET_BACKEND: JVM +// LANGUAGE_VERSION: 1.2 +// WITH_RUNTIME + +open class Foo { + lateinit var bar: String + + private lateinit var baz: String + + fun test(): String { + val isBarInitialized: () -> Boolean = { this::bar.isInitialized } + if (isBarInitialized()) return "Fail 1" + bar = "bar" + if (!isBarInitialized()) return "Fail 2" + baz = "baz" + return InnerSubclass().testInner() + } + + inner class InnerSubclass : Foo() { + fun testInner(): String { + // This is access to InnerSubclass.bar which is inherited from Foo.bar + if (this::bar.isInitialized) return "Fail 3" + bar = "OK" + if (!this::bar.isInitialized) return "Fail 4" + + // This is access to Foo.bar declared lexically above + if (!this@Foo::bar.isInitialized) return "Fail 5" + return "OK" + } + } +} + +fun box(): String { + return Foo().test() +} diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt new file mode 100644 index 00000000000..e6d1e9f8a4c --- /dev/null +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt @@ -0,0 +1,21 @@ +// TARGET_BACKEND: JVM +// LANGUAGE_VERSION: 1.2 +// WITH_RUNTIME + +class Foo { + lateinit var bar: String + + fun test(): String { + var state = 0 + if (run { state++; this }::bar.isInitialized) return "Fail 1" + + bar = "A" + if (!run { state++; this }::bar.isInitialized) return "Fail 3" + + return if (state == 2) "OK" else "Fail: state=$state" + } +} + +fun box(): String { + return Foo().test() +} diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt new file mode 100644 index 00000000000..a91306584e4 --- /dev/null +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt @@ -0,0 +1,36 @@ +// TARGET_BACKEND: JVM +// LANGUAGE_VERSION: 1.2 +// WITH_RUNTIME + +// FILE: J.java + +public class J { + public static void deinitialize(Foo foo) { + foo.bar = null; + } +} + +// FILE: main.kt + +class Foo { + lateinit var bar: String + + fun test(): String { + if (this::bar.isInitialized) return "Fail 1" + J.deinitialize(this) + if (this::bar.isInitialized) return "Fail 2" + + bar = "A" + if (!this::bar.isInitialized) return "Fail 3" + J.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() +} diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt new file mode 100644 index 00000000000..4be6e0b48bf --- /dev/null +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt @@ -0,0 +1,12 @@ +// TARGET_BACKEND: JVM +// LANGUAGE_VERSION: 1.2 +// WITH_RUNTIME + +lateinit var bar: String + +fun box(): String { + if (::bar.isInitialized) return "Fail 1" + bar = "OK" + if (!::bar.isInitialized) return "Fail 2" + return bar +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.kt b/compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.kt new file mode 100644 index 00000000000..9264c2b8174 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.kt @@ -0,0 +1,88 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE +// !API_VERSION: 1.2 +// FILE: test.kt + +interface Base { + var x: String +} + +open class Foo : Base { + override lateinit var x: String + private lateinit var y: String + + var nonLateInit: Int = 1 + + fun ok() { + val b: Boolean = this::x.isInitialized + + val otherInstance = Foo() + otherInstance::x.isInitialized + + (this::x).isInitialized + (@Suppress("ALL") (this::x)).isInitialized + + object { + fun local() { + class Local { + val xx = this@Foo::x.isInitialized + val yy = this@Foo::y.isInitialized + } + } + } + } + + fun onLiteral() { + val p = this::x + p.isInitialized + } + + fun onNonLateinit() { + this::nonLateInit.isInitialized + } + + inline fun inlineFun() { + this::x.isInitialized + + object { + val z = this@Foo::x.isInitialized + } + } + + inner class InnerSubclass : Foo() { + fun innerOk() { + // This is access to Foo.x declared lexically above + this@Foo::x.isInitialized + + // This is access to InnerSubclass.x which is inherited from Foo.x + this::x.isInitialized + } + } +} + +fun onNonAccessible() { + Foo()::x.isInitialized +} + +fun onNonLateinit() { + Foo()::nonLateInit.isInitialized +} + +object Unrelated { + fun onNonAccessible() { + Foo()::x.isInitialized + } +} + +class FooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} + +// FILE: other.kt + +class OtherFooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.txt b/compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.txt new file mode 100644 index 00000000000..5dac30967cc --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.txt @@ -0,0 +1,78 @@ +package + +public fun onNonAccessible(): kotlin.Unit +public fun onNonLateinit(): kotlin.Unit + +public interface Base { + public abstract var x: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class Foo : Base { + public constructor Foo() + public final var nonLateInit: kotlin.Int + public open override /*1*/ lateinit var x: kotlin.String + private final lateinit var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final inline fun inlineFun(): kotlin.Unit + public final fun ok(): kotlin.Unit + public final fun onLiteral(): kotlin.Unit + public final fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final inner class InnerSubclass : Foo { + public constructor InnerSubclass() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final inline override /*1*/ /*fake_override*/ fun inlineFun(): kotlin.Unit + public final fun innerOk(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public final class FooImpl : Foo { + public constructor FooImpl() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final inline override /*1*/ /*fake_override*/ fun inlineFun(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final fun onNonAccessible(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OtherFooImpl : Foo { + public constructor OtherFooImpl() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final inline override /*1*/ /*fake_override*/ fun inlineFun(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final fun onNonAccessible(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Unrelated { + private constructor Unrelated() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun onNonAccessible(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index e7ce3771971..25a8f36bdcd 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -13861,6 +13861,39 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class IsInitializedAndDeinitialize extends AbstractIrBlackBoxCodegenTest { + public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, 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("simpleIsInitialized.kt") + public void testSimpleIsInitialized() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.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") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 53c109a5af8..5bdb1e92356 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -1371,6 +1371,21 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/lateinit") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Lateinit extends AbstractDiagnosticsTestWithStdLib { + public void testAllFilesPresentInLateinit() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/lateinit"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("isInitialized.kt") + public void testIsInitialized() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/native") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index ddeb90b278b..ffe2fef9a30 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -1371,6 +1371,21 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/lateinit") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Lateinit extends AbstractDiagnosticsTestWithStdLibUsingJavac { + public void testAllFilesPresentInLateinit() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/lateinit"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("isInitialized.kt") + public void testIsInitialized() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/native") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index bbc03016e9d..ba43bcb20e1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13861,6 +13861,39 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class IsInitializedAndDeinitialize extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, 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("simpleIsInitialized.kt") + public void testSimpleIsInitialized() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.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") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index c26d042e53c..2984ab8475f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13861,6 +13861,39 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class IsInitializedAndDeinitialize extends AbstractLightAnalysisModeTest { + public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, 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("simpleIsInitialized.kt") + public void testSimpleIsInitialized() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.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") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 03ff4053da0..9f7bb5c523c 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -15229,6 +15229,15 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class IsInitializedAndDeinitialize 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("compiler/testData/codegen/box/properties/lateinit/local") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/libraries/stdlib/src/kotlin/internal/Annotations.kt b/libraries/stdlib/src/kotlin/internal/Annotations.kt index 76e74713b7a..543e6f3d1b1 100644 --- a/libraries/stdlib/src/kotlin/internal/Annotations.kt +++ b/libraries/stdlib/src/kotlin/internal/Annotations.kt @@ -66,6 +66,15 @@ internal annotation class InlineOnly @Retention(AnnotationRetention.BINARY) internal annotation class DynamicExtension +/** + * The value of this parameter should be a property reference expression (`this::foo`), referencing a `lateinit` property, + * the backing field of which is accessible at the point where the corresponding argument is passed. + */ +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.BINARY) +@SinceKotlin("1.2") +internal annotation class AccessibleLateinitPropertyLiteral + /** * Specifies that this declaration is only completely supported since the specified version. * diff --git a/libraries/stdlib/src/kotlin/util/Lateinit.kt b/libraries/stdlib/src/kotlin/util/Lateinit.kt new file mode 100644 index 00000000000..a7f9602b3a6 --- /dev/null +++ b/libraries/stdlib/src/kotlin/util/Lateinit.kt @@ -0,0 +1,19 @@ +@file:kotlin.jvm.JvmName("LateinitKt") +@file:kotlin.jvm.JvmVersion +@file:Suppress("unused") + +package kotlin + +import kotlin.internal.InlineOnly +import kotlin.internal.AccessibleLateinitPropertyLiteral +import kotlin.reflect.KProperty0 + +/** + * Returns `true` if this lateinit property has been assigned a value, and `false` otherwise. + * + * Cannot be used in an inline function, to avoid binary compatibility issues. + */ +@SinceKotlin("1.2") +@InlineOnly +inline val @receiver:AccessibleLateinitPropertyLiteral KProperty0<*>.isInitialized: Boolean + get() = throw NotImplementedError("Implementation is intrinsic")