[FIR] Introduce builders API for generating declarations in compiler plugins

^KT-53096 Fixed
This commit is contained in:
Dmitriy Novozhilov
2022-12-21 23:15:16 +02:00
committed by Space Team
parent 6783621eb0
commit 185e57e601
9 changed files with 964 additions and 0 deletions
+2
View File
@@ -160,6 +160,7 @@ val firCompilerCoreModules = arrayOf(
":compiler:fir:resolve",
":compiler:fir:fir-serialization",
":compiler:fir:fir-deserialization",
":compiler:fir:plugin-utils",
":compiler:fir:tree",
":compiler:fir:java",
":compiler:fir:raw-fir:raw-fir.common",
@@ -358,6 +359,7 @@ val projectsWithEnabledContextReceivers by extra {
":core:descriptors.jvm",
":compiler:frontend.common",
":compiler:fir:resolve",
":compiler:fir:plugin-utils",
":compiler:fir:fir2ir",
":kotlin-lombok-compiler-plugin.k1",
":kotlinx-serialization-compiler-plugin.k2",
@@ -0,0 +1,25 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
kotlin {
explicitApiWarning()
}
dependencies {
api(project(":core:compiler.common"))
api(project(":compiler:resolution.common"))
api(project(":compiler:fir:cones"))
api(project(":compiler:fir:tree"))
api(project(":compiler:fir:providers"))
api(project(":compiler:fir:semantics"))
implementation(project(":core:util.runtime"))
compileOnly(commonDependency("com.google.guava:guava"))
}
sourceSets {
"main" { projectDefault() }
"test" { none() }
}
@@ -0,0 +1,156 @@
/*
* Copyright 2010-2022 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.plugin
import org.jetbrains.kotlin.GeneratedDeclarationKey
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.containingClassForLocalAttr
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.builder.buildOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
import org.jetbrains.kotlin.fir.declarations.origin
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
public class ClassBuildingContext(
session: FirSession,
key: GeneratedDeclarationKey,
owner: FirClassSymbol<*>?,
private val classId: ClassId,
private val classKind: ClassKind,
) : DeclarationBuildingContext<FirRegularClass>(session, key, owner) {
private val superTypeProviders = mutableListOf<(List<FirTypeParameterRef>) -> ConeKotlinType>()
/**
* Adds [type] as supertype for constructed class
*
* If no supertypes are declared [kotlin.Any] supertype will be
* added automatically
*/
public fun superType(type: ConeKotlinType) {
superTypeProviders += { type }
}
/**
* Adds type created by [typeProvider] as supertype for constructed class
* Use this overload when supertype uses type parameters of constructed class
*
* If no supertypes are declared [kotlin.Any] supertype will be
* added automatically
*/
public fun superType(typeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType) {
superTypeProviders += typeProvider
}
override fun build(): FirRegularClass {
return buildRegularClass {
resolvePhase = FirResolvePhase.BODY_RESOLVE
moduleData = session.moduleData
origin = key.origin
classKind = this@ClassBuildingContext.classKind
scopeProvider = session.kotlinScopeProvider
status = generateStatus()
name = classId.shortClassName
symbol = FirRegularClassSymbol(classId)
if (status.isInner) {
requireNotNull(owner) { "Inner class must have owner" }
owner.typeParameterSymbols.mapTo(typeParameters) { buildOuterClassTypeParameterRef { symbol = it } }
}
val ownParameters = this@ClassBuildingContext.typeParameters.map {
generateTypeParameter(it, symbol)
}
typeParameters += ownParameters
initTypeParameterBounds(typeParameters, ownParameters)
if (superTypeProviders.isEmpty()) {
superTypeRefs += session.builtinTypes.anyType
} else {
superTypeProviders.mapTo(this.superTypeRefs) {
buildResolvedTypeRef { type = it(this@buildRegularClass.typeParameters) }
}
}
}.apply {
if (owner?.isLocal == true) {
containingClassForLocalAttr = owner.toLookupTag()
}
}
}
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Creates top-level class with given [classId]
* All declarations in class should be generated using methods from [FirDeclarationGenerationExtension]
*
* If no supertypes added then [kotlin.Any] supertype will be added automatically
*
* Created class won't have a constructor; constructor can be added separately with [createConstructor] function
*/
public fun FirDeclarationGenerationExtension.createTopLevelClass(
classId: ClassId,
key: GeneratedDeclarationKey,
classKind: ClassKind = ClassKind.CLASS,
config: ClassBuildingContext.() -> Unit = {}
): FirRegularClass {
return ClassBuildingContext(session, key, owner = null, classId, classKind).apply(config).build()
}
/**
* Creates nested class for [owner] class with name [name]
* All declarations in class should be generated using methods from [FirDeclarationGenerationExtension]
*
* If no supertypes added then [kotlin.Any] supertype will be added automatically
*
* Created class won't have a constructor; constructor can be added separately with [createConstructor] function
*
* By default, the class is only nested; to create an inner class, create nested class and add inner status via status()
*/
public fun FirDeclarationGenerationExtension.createNestedClass(
owner: FirClassSymbol<*>,
name: Name,
key: GeneratedDeclarationKey,
classKind: ClassKind = ClassKind.CLASS,
config: ClassBuildingContext.() -> Unit = {}
): FirRegularClass {
return ClassBuildingContext(session, key, owner, owner.classId.createNestedClassId(name), classKind).apply(config).build()
}
/**
* Creates companion object for [owner] class
* All declarations in class should be generated using methods from [FirDeclarationGenerationExtension]
*
* If no supertypes added then [kotlin.Any] supertype will be added automatically
*
* Created class won't have a constructor; constructor can be added separately with [createDefaultPrivateConstructor] function
*/
public fun FirDeclarationGenerationExtension.createCompanionObject(
owner: FirClassSymbol<*>,
key: GeneratedDeclarationKey,
config: ClassBuildingContext.() -> Unit = {}
): FirRegularClass {
val classId = owner.classId.createNestedClassId(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT)
return ClassBuildingContext(session, key, owner, classId, ClassKind.OBJECT).apply(config).apply {
modality = Modality.FINAL
status {
isCompanion = true
}
}.build()
}
@@ -0,0 +1,178 @@
/*
* Copyright 2010-2022 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.plugin
import org.jetbrains.kotlin.GeneratedDeclarationKey
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.origin
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.expressions.buildResolvedArgumentList
import org.jetbrains.kotlin.fir.expressions.builder.buildDelegatedConstructorCall
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.getContainingClassLookupTag
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.callableIdForConstructor
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
public class ConstructorBuildingContext(
session: FirSession,
key: GeneratedDeclarationKey,
owner: FirClassSymbol<*>,
private val isPrimary: Boolean
) : FunctionBuildingContext<FirConstructor>(owner.classId.callableIdForConstructor(), session, key, owner) {
override fun build(): FirConstructor {
requireNotNull(owner)
val init: FirAbstractConstructorBuilder.() -> Unit = {
symbol = FirConstructorSymbol(owner.classId)
resolvePhase = FirResolvePhase.BODY_RESOLVE
moduleData = session.moduleData
origin = key.origin
owner.typeParameterSymbols.mapTo(typeParameters) { buildConstructedClassTypeParameterRef { symbol = it } }
returnTypeRef = owner.defaultType().toFirResolvedTypeRef()
status = generateStatus()
if (owner.isInner) {
val parentSymbol = owner.getContainingClassLookupTag()?.toSymbol(session) as? FirClassSymbol<*>
?: error("Symbol for parent of $owner not found")
dispatchReceiverType = parentSymbol.defaultType()
}
this@ConstructorBuildingContext.valueParameters.mapTo(valueParameters) { generateValueParameter(it, symbol, typeParameters) }
if (owner is FirRegularClassSymbol) {
owner.resolvedContextReceivers.mapTo(contextReceivers) {
buildContextReceiver { typeRef = it.typeRef.coneType.toFirResolvedTypeRef() }
}
}
}
val constructor = if (isPrimary) {
buildPrimaryConstructor(init)
} else {
buildConstructor(init)
}
constructor.containingClassForStaticMemberAttr = owner.toLookupTag()
return constructor
}
/**
* Type parameters of constructor are inherited from constructed class
*/
@Deprecated("This function does nothing and should not be called", level = DeprecationLevel.HIDDEN)
override fun typeParameter(
name: Name,
variance: Variance,
isReified: Boolean,
key: GeneratedDeclarationKey,
config: TypeParameterBuildingContext.() -> Unit
) {
shouldNotBeCalled()
}
/**
* Context receivers of constructor are inherited from constructed class
*/
@Deprecated("This function does nothing and should not be called", level = DeprecationLevel.HIDDEN)
override fun contextReceiver(type: ConeKotlinType) {
shouldNotBeCalled()
}
/**
* Context receivers of constructor are inherited from constructed class
*/
@Deprecated("This function does nothing and should not be called", level = DeprecationLevel.HIDDEN)
override fun contextReceiver(typeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType) {
shouldNotBeCalled()
}
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Creates constructor for [owner] class
*
* Setting [generateDelegatedNoArgConstructorCall] to true automatically generates delegating constructor call to superclass
* This generation works only if single superclass of the class contains constructor without arguments
*
* If you want to create custom delegated constructor call please do it in the [IrGenerationExtension]
*/
public fun FirDeclarationGenerationExtension.createConstructor(
owner: FirClassSymbol<*>,
key: GeneratedDeclarationKey,
isPrimary: Boolean = false,
generateDelegatedNoArgConstructorCall: Boolean = false,
config: ConstructorBuildingContext.() -> Unit = {}
): FirConstructor {
return ConstructorBuildingContext(session, key, owner, isPrimary).apply(config).build().also {
if (generateDelegatedNoArgConstructorCall) {
it.generateNoArgDelegatingConstructorCall()
}
}
}
/**
* Creates constructor for [owner] object
* This constructor will be private primary constructor without parameters
*
* This is a shorthand for createConstructor() which is useful for creating constructors for companions and other objects, as they should be private
*
* Setting [generateDelegatedNoArgConstructorCall] to true automatically generates delegating constructor call to superclass
* This generation works only if single superclass of the class contains constructor without arguments
*
* If you want to create custom delegated constructor call please do it in the [IrGenerationExtension]
*/
public fun FirDeclarationGenerationExtension.createDefaultPrivateConstructor(
owner: FirClassSymbol<*>,
key: GeneratedDeclarationKey,
generateDelegatedNoArgConstructorCall: Boolean = true
): FirConstructor {
return createConstructor(owner, key, isPrimary = true, generateDelegatedNoArgConstructorCall) {
visibility = Visibilities.Private
}
}
context(FirDeclarationGenerationExtension)
private fun FirConstructor.generateNoArgDelegatingConstructorCall() {
val owner = returnTypeRef.coneType.toSymbol(session) as? FirClassSymbol<*>
requireNotNull(owner)
val delegatingConstructorCall = buildDelegatedConstructorCall {
val superClasses = owner.resolvedSuperTypes.filter { it.toRegularClassSymbol(session)?.classKind == ClassKind.CLASS }
val singleSupertype = when (superClasses.size) {
0 -> session.builtinTypes.anyType.type
1 -> superClasses.first()
else -> error("Object $owner has more than one class supertypes: $superClasses")
}
constructedTypeRef = singleSupertype.toFirResolvedTypeRef()
val superSymbol = singleSupertype.toRegularClassSymbol(session) ?: error("Symbol for supertype $singleSupertype not found")
val superConstructorSymbol = superSymbol.declaredMemberScope(session)
.getDeclaredConstructors()
.firstOrNull { it.valueParameterSymbols.isEmpty() }
?: error("No arguments constructor for class $singleSupertype not found")
calleeReference = buildResolvedNamedReference {
name = superConstructorSymbol.name
resolvedSymbol = superConstructorSymbol
}
argumentList = buildResolvedArgumentList(LinkedHashMap())
isThis = false
}
replaceDelegatedConstructor(delegatingConstructorCall)
}
@@ -0,0 +1,172 @@
/*
* Copyright 2010-2022 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.plugin
import org.jetbrains.kotlin.GeneratedDeclarationKey
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildContextReceiver
import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.toEffectiveVisibility
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.toFirResolvedTypeRef
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
public sealed class DeclarationBuildingContext<T : FirDeclaration>(
protected val session: FirSession,
protected val key: GeneratedDeclarationKey,
protected val owner: FirClassSymbol<*>?
) {
/**
* Allows to set visibility of the declaration
*/
public var visibility: Visibility = Visibilities.Public
/**
* Allows to set modality of the declaration
*/
public var modality: Modality = Modality.FINAL
/**
* Allows to configure flags in status of declaration
* For full list of possible flags refer to [FirDeclarationStatus] class
* Note that not all flags are meaningful for each declaration
* E.g. there is no point to mark function as inner
*/
public fun status(statusConfig: FirResolvedDeclarationStatusImpl.() -> Unit) {
statusConfigs += statusConfig
}
/**
* Adds type parameter with specified [name] and [variance] to declaration
*
* Upper bounds of type parameters can be configured in [config] lambda
*
* If no bounds passed then `kotlin.Any?` bound will be added automatically
*/
public open fun typeParameter(
name: Name,
variance: Variance = Variance.INVARIANT,
isReified: Boolean = false,
key: GeneratedDeclarationKey = this@DeclarationBuildingContext.key,
config: TypeParameterBuildingContext.() -> Unit = {}
) {
typeParameters += TypeParameterData(name, variance, isReified, TypeParameterBuildingContext().apply(config).boundProviders, key)
}
public class TypeParameterBuildingContext {
/**
* Declares [type] as upper bound of type parameter
*/
public fun bound(type: ConeKotlinType) {
bound { type }
}
/**
* Type produced by [typeProvider] will be an upper bound of the type parameter
*
* Use this method when bounds of your type parameters depend on each other
* For example, in this case:
* ```
* interface Out<out X>
*
* fun <T, R> foo() where T : R, R : Out<T> {}
* ```
*/
public fun bound(typeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType) {
boundProviders += typeProvider
}
internal val boundProviders: MutableList<(List<FirTypeParameterRef>) -> ConeKotlinType> = mutableListOf()
}
private val contextReceiverTypeProviders: MutableList<(List<FirTypeParameterRef>) -> ConeKotlinType> = mutableListOf()
/**
* Adds context receiver with [type] type to declaration
*/
public open fun contextReceiver(type: ConeKotlinType) {
contextReceiver { type }
}
/**
* Adds context receiver with type provided by [typeProvider] to declaration
* Use this overload when context receiver type uses type parameters of constructed declaration
*/
public open fun contextReceiver(typeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType) {
contextReceiverTypeProviders += typeProvider
}
protected fun produceContextReceiversTo(destination: MutableList<FirContextReceiver>, typeParameters: List<FirTypeParameterRef>) {
contextReceiverTypeProviders.mapTo(destination) {
buildContextReceiver { typeRef = it.invoke(typeParameters).toFirResolvedTypeRef() }
}
}
protected data class TypeParameterData(
val name: Name,
val variance: Variance,
val isReified: Boolean,
val boundProviders: List<(List<FirTypeParameterRef>) -> ConeKotlinType>,
val key: GeneratedDeclarationKey
)
protected val typeParameters: MutableList<TypeParameterData> = mutableListOf()
private val statusConfigs: MutableList<FirResolvedDeclarationStatusImpl.() -> Unit> = mutableListOf()
public abstract fun build(): T
protected fun generateStatus(): FirResolvedDeclarationStatusImpl {
return FirResolvedDeclarationStatusImpl(
visibility,
modality,
visibility.toEffectiveVisibility(owner, forClass = true)
).also {
for (statusConfig in statusConfigs) {
it.apply(statusConfig)
}
}
}
protected fun generateTypeParameter(
typeParameter: TypeParameterData,
containingDeclarationSymbol: FirBasedSymbol<*>
): FirTypeParameter {
return buildTypeParameter {
resolvePhase = FirResolvePhase.BODY_RESOLVE
moduleData = session.moduleData
origin = typeParameter.key.origin
name = typeParameter.name
symbol = FirTypeParameterSymbol()
this.containingDeclarationSymbol = containingDeclarationSymbol
variance = typeParameter.variance
isReified = typeParameter.isReified
}
}
protected fun initTypeParameterBounds(allParameters: List<FirTypeParameterRef>, ownTypeParameters: List<FirTypeParameter>) {
for ((typeParameter, data) in ownTypeParameters.zip(typeParameters)) {
val coneBounds = data.boundProviders.map { it.invoke(allParameters) }
val bounds = if (coneBounds.isEmpty()) {
listOf(session.builtinTypes.nullableAnyType)
} else {
coneBounds.map { it.toFirResolvedTypeRef() }
}
typeParameter.replaceBounds(bounds)
}
}
}
@@ -0,0 +1,99 @@
/*
* Copyright 2010-2022 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.plugin
import org.jetbrains.kotlin.GeneratedDeclarationKey
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionStub
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.toFirResolvedTypeRef
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
public sealed class FunctionBuildingContext<T : FirFunction>(
protected val callableId: CallableId,
session: FirSession,
key: GeneratedDeclarationKey,
owner: FirClassSymbol<*>?
) : DeclarationBuildingContext<T>(session, key, owner) {
protected data class ValueParameterData(
val name: Name,
val typeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType,
val isCrossinline: Boolean,
val isNoinline: Boolean,
val isVararg: Boolean,
val hasDefaultValue: Boolean,
val key: GeneratedDeclarationKey
)
protected val valueParameters: MutableList<ValueParameterData> = mutableListOf()
/**
* Adds value parameter with [type] type to constructed function
*
* If you set [hasDefaultValue] to true then you need to generate actual default value
* in [IrGenerationExtension]
*/
public fun valueParameter(
name: Name,
type: ConeKotlinType,
isCrossinline: Boolean = false,
isNoinline: Boolean = false,
isVararg: Boolean = false,
hasDefaultValue: Boolean = false,
key: GeneratedDeclarationKey = this@FunctionBuildingContext.key
) {
valueParameter(name, { type }, isCrossinline, isNoinline, isVararg, hasDefaultValue, key)
}
/**
* Adds value parameter with type provided by [typeProvider] to constructed function
* Use this overload when parameter type uses type parameters of constructed declaration
*
* If you set [hasDefaultValue] to true then you need to generate actual default value
* in [IrGenerationExtension]
*/
public fun valueParameter(
name: Name,
typeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType,
isCrossinline: Boolean = false,
isNoinline: Boolean = false,
isVararg: Boolean = false,
hasDefaultValue: Boolean = false,
key: GeneratedDeclarationKey = this@FunctionBuildingContext.key
) {
valueParameters += ValueParameterData(name, typeProvider, isCrossinline, isNoinline, isVararg, hasDefaultValue, key)
}
protected fun generateValueParameter(
valueParameter: ValueParameterData,
containingFunctionSymbol: FirFunctionSymbol<*>,
functionTypeParameters: List<FirTypeParameterRef>
): FirValueParameter {
return buildValueParameter {
resolvePhase = FirResolvePhase.BODY_RESOLVE
moduleData = session.moduleData
origin = valueParameter.key.origin
returnTypeRef = valueParameter.typeProvider.invoke(functionTypeParameters).toFirResolvedTypeRef()
name = valueParameter.name
symbol = FirValueParameterSymbol(name)
if (valueParameter.hasDefaultValue) {
// TODO: check how it will actually work in fir2ir
defaultValue = buildExpressionStub { typeRef = session.builtinTypes.nothingType }
}
this.containingFunctionSymbol = containingFunctionSymbol
isCrossinline = valueParameter.isCrossinline
isNoinline = valueParameter.isNoinline
isVararg = valueParameter.isVararg
}
}
}
@@ -0,0 +1,184 @@
/*
* Copyright 2010-2022 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.plugin
import org.jetbrains.kotlin.GeneratedDeclarationKey
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyBackingField
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.toFirResolvedTypeRef
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
public class PropertyBuildingContext(
session: FirSession,
key: GeneratedDeclarationKey,
owner: FirClassSymbol<*>?,
private val callableId: CallableId,
private val returnTypeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType,
private val isVal: Boolean,
private val hasBackingField: Boolean,
) : DeclarationBuildingContext<FirProperty>(session, key, owner) {
private var setterVisibility: Visibility? = null
private var extensionReceiverTypeProvider: ((List<FirTypeParameter>) -> ConeKotlinType)? = null
/**
* Sets [type] as extension receiver type of constructed property
*/
public fun extensionReceiverType(type: ConeKotlinType) {
extensionReceiverType { type }
}
/**
* Sets type, provided by [typeProvider], as extension receiver type of constructed property
*
* Use this overload when extension receiver type uses type parameters of constructed property
*/
public fun extensionReceiverType(typeProvider: (List<FirTypeParameter>) -> ConeKotlinType) {
extensionReceiverTypeProvider = typeProvider
}
/**
* Declares [visibility] of property setter if property marked as var
* If this function is not called then setter will have same visibility
* as property itself
*/
public fun setter(visibility: Visibility) {
setterVisibility = visibility
}
override fun build(): FirProperty {
return buildProperty {
resolvePhase = FirResolvePhase.BODY_RESOLVE
moduleData = session.moduleData
origin = key.origin
symbol = FirPropertySymbol(callableId)
name = callableId.callableName
val resolvedStatus = generateStatus()
status = resolvedStatus
dispatchReceiverType = owner?.defaultType()
this@PropertyBuildingContext.typeParameters.mapTo(typeParameters) {
generateTypeParameter(it, symbol)
}
initTypeParameterBounds(typeParameters, typeParameters)
returnTypeRef = returnTypeProvider.invoke(typeParameters).toFirResolvedTypeRef()
extensionReceiverTypeProvider?.invoke(typeParameters)?.let {
receiverParameter = buildReceiverParameter {
typeRef = it.toFirResolvedTypeRef()
}
}
produceContextReceiversTo(contextReceivers, typeParameters)
isVar = !isVal
getter = FirDefaultPropertyGetter(
source = null, session.moduleData, key.origin, returnTypeRef, status.visibility, symbol,
Modality.FINAL, resolvedStatus.effectiveVisibility
)
if (isVar) {
setter = FirDefaultPropertySetter(
source = null, session.moduleData, key.origin, returnTypeRef, setterVisibility ?: status.visibility,
symbol, Modality.FINAL, resolvedStatus.effectiveVisibility
)
} else {
require(setterVisibility == null) { "isVar = false but setterVisibility is specified. Did you forget to set isVar = true?" }
}
if (hasBackingField) {
backingField = FirDefaultPropertyBackingField(session.moduleData, mutableListOf(), returnTypeRef, isVar, symbol, status)
}
isLocal = false
bodyResolveState = FirPropertyBodyResolveState.EVERYTHING_RESOLVED
}
}
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Creates a member property for [owner] class with [returnType] return type
*/
public fun FirDeclarationGenerationExtension.createMemberProperty(
owner: FirClassSymbol<*>,
key: GeneratedDeclarationKey,
name: Name,
returnType: ConeKotlinType,
isVal: Boolean = true,
hasBackingField: Boolean = true,
config: PropertyBuildingContext.() -> Unit = {}
): FirProperty {
return createMemberProperty(owner, key, name, { returnType }, isVal, hasBackingField, config)
}
/**
* Creates a member property for [owner] class with return type provided by [returnTypeProvider]
* Use this overload when those types use type parameters of constructed property
*/
public fun FirDeclarationGenerationExtension.createMemberProperty(
owner: FirClassSymbol<*>,
key: GeneratedDeclarationKey,
name: Name,
returnTypeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType,
isVal: Boolean = true,
hasBackingField: Boolean = true,
config: PropertyBuildingContext.() -> Unit = {}
): FirProperty {
val callableId = CallableId(owner.classId, name)
return PropertyBuildingContext(session, key, owner, callableId, returnTypeProvider, isVal, hasBackingField).apply(config).build()
}
/**
* Creates a top-level property class with [returnType] return type
*
* If you create top-level extension property don't forget to set [hasBackingField] to false,
* since such properties never have backing fields
*/
public fun FirDeclarationGenerationExtension.createTopLevelProperty(
key: GeneratedDeclarationKey,
callableId: CallableId,
returnType: ConeKotlinType,
isVal: Boolean = true,
hasBackingField: Boolean = true,
config: PropertyBuildingContext.() -> Unit = {}
): FirProperty {
return createTopLevelProperty(key, callableId, { returnType }, isVal, hasBackingField, config)
}
/**
* Creates a top-level property with return type provided by [returnTypeProvider]
*
* If you create top-level extension property don't forget to set [hasBackingField] to false,
* since such properties never have backing fields
*
* Use this overload when those types use type parameters of constructed property
*/
public fun FirDeclarationGenerationExtension.createTopLevelProperty(
key: GeneratedDeclarationKey,
callableId: CallableId,
returnTypeProvider: (List<FirTypeParameterRef>) -> ConeKotlinType,
isVal: Boolean = true,
hasBackingField: Boolean = true,
config: PropertyBuildingContext.() -> Unit = {}
): FirProperty {
require(callableId.classId == null)
return PropertyBuildingContext(session, key, owner = null, callableId, returnTypeProvider, isVal, hasBackingField).apply(config).build()
}
@@ -0,0 +1,147 @@
/*
* Copyright 2010-2022 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.plugin
import org.jetbrains.kotlin.GeneratedDeclarationKey
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.origin
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.toFirResolvedTypeRef
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
public class SimpleFunctionBuildingContext(
session: FirSession,
key: GeneratedDeclarationKey,
owner: FirClassSymbol<*>?,
callableId: CallableId,
private val returnTypeProvider: (List<FirTypeParameter>) -> ConeKotlinType,
) : FunctionBuildingContext<FirSimpleFunction>(callableId, session, key, owner) {
private var extensionReceiverTypeProvider: ((List<FirTypeParameter>) -> ConeKotlinType)? = null
/**
* Sets [type] as extension receiver type of constructed function
*/
public fun extensionReceiverType(type: ConeKotlinType) {
extensionReceiverType { type }
}
/**
* Sets type, provided by [typeProvider], as extension receiver type of constructed function
*
* Use this overload when extension receiver type uses type parameters of constructed function
*/
public fun extensionReceiverType(typeProvider: (List<FirTypeParameter>) -> ConeKotlinType) {
require(extensionReceiverTypeProvider == null) { "Extension receiver type is already initialized" }
extensionReceiverTypeProvider = typeProvider
}
override fun build(): FirSimpleFunction {
return buildSimpleFunction {
resolvePhase = FirResolvePhase.BODY_RESOLVE
moduleData = session.moduleData
origin = key.origin
symbol = FirNamedFunctionSymbol(callableId)
name = callableId.callableName
status = generateStatus()
dispatchReceiverType = owner?.defaultType()
this@SimpleFunctionBuildingContext.typeParameters.mapTo(typeParameters) {
generateTypeParameter(it, symbol)
}
initTypeParameterBounds(typeParameters, typeParameters)
produceContextReceiversTo(contextReceivers, typeParameters)
this@SimpleFunctionBuildingContext.valueParameters.mapTo(valueParameters) {
generateValueParameter(it, symbol, typeParameters)
}
returnTypeRef = returnTypeProvider(typeParameters).toFirResolvedTypeRef()
extensionReceiverTypeProvider?.invoke(typeParameters)?.let {
receiverParameter = buildReceiverParameter {
typeRef = it.toFirResolvedTypeRef()
}
}
}
}
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Creates a member function for [owner] class with [returnType] return type
*
* Type and value parameters can be configured with [config] builder lambda
*/
public fun FirDeclarationGenerationExtension.createMemberFunction(
owner: FirClassSymbol<*>,
key: GeneratedDeclarationKey,
name: Name,
returnType: ConeKotlinType,
config: SimpleFunctionBuildingContext.() -> Unit = {}
): FirSimpleFunction {
return createMemberFunction(owner, key, name, { returnType }, config)
}
/**
* Creates a member function for [owner] class with return type provided by [returnTypeProvider]
* Use this overload when return type uses type parameters of constructed property
*
* Type and value parameters can be configured with [config] builder lambda
*/
public fun FirDeclarationGenerationExtension.createMemberFunction(
owner: FirClassSymbol<*>,
key: GeneratedDeclarationKey,
name: Name,
returnTypeProvider: (List<FirTypeParameter>) -> ConeKotlinType,
config: SimpleFunctionBuildingContext.() -> Unit = {}
): FirSimpleFunction {
val callableId = CallableId(owner.classId, name)
return SimpleFunctionBuildingContext(session, key, owner, callableId, returnTypeProvider).apply(config).build()
}
/**
* Creates a top-level function with [returnType] return type
*
* Type and value parameters can be configured with [config] builder lambda
*/
public fun FirDeclarationGenerationExtension.createTopLevelFunction(
key: GeneratedDeclarationKey,
callableId: CallableId,
returnType: ConeKotlinType,
config: SimpleFunctionBuildingContext.() -> Unit = {}
): FirSimpleFunction {
return createTopLevelFunction(key, callableId, { returnType }, config)
}
/**
* Creates a top-level function for [owner] class with return type provided by [returnTypeProvider]
* Use this overload when those types use type parameters of constructed property
*
* Type and value parameters can be configured with [config] builder lambda
*/
public fun FirDeclarationGenerationExtension.createTopLevelFunction(
key: GeneratedDeclarationKey,
callableId: CallableId,
returnTypeProvider: (List<FirTypeParameter>) -> ConeKotlinType,
config: SimpleFunctionBuildingContext.() -> Unit = {}
): FirSimpleFunction {
require(callableId.classId == null)
return SimpleFunctionBuildingContext(session, key, owner = null, callableId, returnTypeProvider).apply(config).build()
}
+1
View File
@@ -319,6 +319,7 @@ include ":compiler:fir",
":compiler:fir:providers",
":compiler:fir:semantics",
":compiler:fir:resolve",
":compiler:fir:plugin-utils",
":compiler:fir:fir-serialization",
":compiler:fir:fir-deserialization",
":compiler:fir:java",