diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/UnresolvedExpressionTypeAccess.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/UnresolvedExpressionTypeAccess.kt new file mode 100644 index 00000000000..a69882cb1b0 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/UnresolvedExpressionTypeAccess.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.expressions + +@RequiresOptIn("Accessing `coneTypeOrNull` hides potential bugs if at the given point all expression and their types should be resolved. Consider using `resolvedType` instead.") +annotation class UnresolvedExpressionTypeAccess diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index 3cf9d70dbb1..204f5b11e15 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -132,7 +132,9 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild } expression.configure { - +field("coneTypeOrNull", coneKotlinTypeType, nullable = true, withReplace = true) + +field("coneTypeOrNull", coneKotlinTypeType, nullable = true, withReplace = true).apply { + optInAnnotation = unresolvedExpressionTypeAccessImport + } +annotations } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/importables.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/importables.kt index 5e4b1a5467f..d12e72a6d72 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/importables.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/importables.kt @@ -20,3 +20,5 @@ val coneTypeOrNullImport = ArbitraryImportable("org.jetbrains.kotlin.fir.types", val fakeSourceElementKindImport = ArbitraryImportable("org.jetbrains.kotlin", "KtFakeSourceElementKind") val fakeElementImport = ArbitraryImportable("org.jetbrains.kotlin", "fakeElement") + +val unresolvedExpressionTypeAccessImport = ArbitraryImportable("org.jetbrains.kotlin.fir.expressions","UnresolvedExpressionTypeAccess") diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/builder.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/builder.kt index e430d5ec329..a131f587785 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/builder.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/builder.kt @@ -280,9 +280,11 @@ private fun SmartPrinter.printDslBuildFunction( private fun SmartPrinter.printDslBuildCopyFunction( builder: LeafBuilder, - hasRequiredFields: Boolean + hasRequiredFields: Boolean, ) { - println("@OptIn(ExperimentalContracts::class)") + val optIns = + builder.allFields.filter { !it.invisibleField }.mapNotNullTo(mutableSetOf("ExperimentalContracts")) { it.optInAnnotation?.type } + println("@OptIn(${optIns.joinToString { "$it::class" }})") print("inline ") print("fun ") builder.implementation.element.typeArguments.takeIf { it.isNotEmpty() }?.let { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt index 60345335bfa..e2d81b48db6 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt @@ -79,10 +79,11 @@ fun SmartPrinter.printElement(element: Element) { withIndent { allFields.forEach { field -> if (field.isFinal && field.fromParent || field.isParameter) return@forEach - if (!field.isFinal) { - abstract() + printField(field, isImplementation = false, override = field.fromParent) { + if (!field.isFinal) { + abstract() + } } - printField(field, isImplementation = false, override = field.fromParent, end = "") } if (allFields.isNotEmpty()) { println() diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt index a5b227b2c07..58a69662b7a 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt @@ -9,15 +9,17 @@ import org.jetbrains.kotlin.fir.tree.generator.model.Field import org.jetbrains.kotlin.utils.SmartPrinter -fun SmartPrinter.printField(field: Field, isImplementation: Boolean, override: Boolean, end: String, notNull: Boolean = false) { +fun SmartPrinter.printField(field: Field, isImplementation: Boolean, override: Boolean, inConstructor: Boolean = false, notNull: Boolean = false, modifiers: SmartPrinter.() -> Unit = {}) { if (!field.isVal && field.isVolatile) { println("@Volatile") } field.optInAnnotation?.let { - println("@${it.type}") + println(if (inConstructor) "@property:${it.type}" else "@${it.type}") } + modifiers() + if (override) { print("override ") } @@ -30,13 +32,18 @@ fun SmartPrinter.printField(field: Field, isImplementation: Boolean, override: B print("val") } val type = if (isImplementation) field.getMutableType(notNull = notNull) else field.getTypeWithArguments(notNull = notNull) - println(" ${field.name}: $type$end") + print(" ${field.name}: $type") + if (inConstructor) print(",") + println() } fun SmartPrinter.printFieldWithDefaultInImplementation(field: Field) { if (!field.isVal && field.isVolatile) { println("@Volatile") } + field.optInAnnotation?.let { + println("@OptIn(${it.type}::class)") + } val defaultValue = field.defaultValueInImplementation print("override ") if (field.isVal) { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt index 712e4e59603..cc79c946e34 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.tree.generator.model.* import org.jetbrains.kotlin.fir.tree.generator.model.Implementation.Kind import org.jetbrains.kotlin.fir.tree.generator.pureAbstractElementType import org.jetbrains.kotlin.utils.SmartPrinter +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import org.jetbrains.kotlin.utils.withIndent import java.io.File @@ -50,9 +51,18 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { } with(implementation) { - if (requiresOptIn) { - println("@OptIn(FirImplementationDetail::class)") + buildSet { + if (requiresOptIn) { + add("FirImplementationDetail") + } + + for (field in fieldsWithoutDefault) { + field.optInAnnotation?.let { add(it.type) } + } + }.ifNotEmpty { + println("@OptIn(${joinToString { "$it::class" }})") } + if (!isPublic) { print("internal ") } @@ -78,7 +88,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { if (field.isParameter) { println("${field.name}: ${field.typeWithArguments},") } else if (!field.isFinal) { - printField(field, isImplementation = true, override = true, end = ",", notNull = field.notNull) + printField(field, isImplementation = true, override = true, inConstructor = true, notNull = field.notNull) } } } @@ -96,7 +106,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { allFields.forEach { abstract() - printField(it, isImplementation = true, override = true, end = "", notNull = it.notNull) + printField(it, isImplementation = true, override = true, notNull = it.notNull) } } else { fieldsWithDefault.forEach { @@ -127,10 +137,6 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { } for (customCall in customCalls) { - customCall.optInAnnotation?.let { - println("@OptIn(${it.type}::class)") - } - println("${customCall.name} = ${customCall.customInitializationCall}") } }