diff --git a/build-logic/src/main/kotlin/ConfigureLateInitAnnotation.kt b/build-logic/src/main/kotlin/ConfigureLateInitAnnotation.kt
new file mode 100644
index 00000000..cbd90c1f
--- /dev/null
+++ b/build-logic/src/main/kotlin/ConfigureLateInitAnnotation.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
+ *
+ * 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
+ *
+ * https://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.
+ */
+import groovy.util.Node
+import groovy.xml.XmlParser
+import groovy.xml.XmlUtil
+import org.gradle.api.DefaultTask
+import org.gradle.api.tasks.TaskAction
+
+abstract class ConfigureLateInitAnnotation : DefaultTask() {
+ private val miscXmlFile = project.rootProject.file(".idea/misc.xml")
+
+ init {
+ inputs.file(miscXmlFile)
+ outputs.file(miscXmlFile)
+ }
+
+ @TaskAction
+ fun run() {
+ val annotationName = "org.pkl.core.util.LateInit"
+
+ if (!miscXmlFile.exists()) {
+ miscXmlFile.writeText(
+ """
+
+
+
+ """
+ .trimIndent()
+ .trim()
+ )
+ }
+
+ val root = XmlParser().parse(miscXmlFile)
+
+ fun Node.childNodes() = children().filterIsInstance()
+
+ var entryPointsManager =
+ root.childNodes().find {
+ it.name() == "component" && it.attribute("name") == "EntryPointsManager"
+ }
+ if (entryPointsManager == null) {
+ entryPointsManager = root.appendNode("component", mapOf("name" to "EntryPointsManager"))
+ }
+
+ var writeAnnotations = entryPointsManager.childNodes().find { it.name() == "writeAnnotations" }
+ if (writeAnnotations == null) {
+ writeAnnotations = entryPointsManager.appendNode("writeAnnotations")
+ }
+
+ val alreadyExists =
+ writeAnnotations.childNodes().any {
+ it.name() == "writeAnnotation" && it.attribute("name") == annotationName
+ }
+
+ if (!alreadyExists) {
+ writeAnnotations.appendNode("writeAnnotation", mapOf("name" to annotationName))
+ miscXmlFile.writeText(XmlUtil.serialize(root))
+ logger.lifecycle("Updated .idea/misc.xml")
+ } else {
+ logger.info("$annotationName is already configured in .idea/misc.xml")
+ }
+ }
+}
diff --git a/build.gradle.kts b/build.gradle.kts
index 52395855..1270141a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -17,6 +17,7 @@
import org.jetbrains.gradle.ext.ActionDelegationConfig
import org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.PLATFORM
import org.jetbrains.gradle.ext.ProjectSettings
+import org.jetbrains.gradle.ext.taskTriggers
plugins {
id("pklAllProjects")
@@ -36,6 +37,8 @@ nexusPublishing {
}
}
+val configureLateInitAnnotation by tasks.registering(ConfigureLateInitAnnotation::class)
+
idea {
project {
this as ExtensionAware
@@ -45,6 +48,7 @@ idea {
delegateBuildRunToGradle = true
testRunner = PLATFORM
}
+ taskTriggers.afterSync(configureLateInitAnnotation)
}
}
}
diff --git a/pkl-core/src/main/java/org/pkl/core/TypeAlias.java b/pkl-core/src/main/java/org/pkl/core/TypeAlias.java
index 07653cc7..77f7a404 100644
--- a/pkl-core/src/main/java/org/pkl/core/TypeAlias.java
+++ b/pkl-core/src/main/java/org/pkl/core/TypeAlias.java
@@ -47,6 +47,7 @@ public final class TypeAlias extends Member implements Value {
}
public void initAliasedType(PType type) {
+ //noinspection ConstantValue
assert aliasedType == null;
aliasedType = type;
}
@@ -80,6 +81,7 @@ public final class TypeAlias extends Member implements Value {
/** Returns the type that this type alias stands for. */
public PType getAliasedType() {
+ //noinspection ConstantValue
assert aliasedType != null;
return aliasedType;
}