@@ -3,25 +3,37 @@ package io.github.stslex.compiler_plugin.utils
33import io.github.stslex.compiler_plugin.DistinctChangeCache
44import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
55import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
6+ import org.jetbrains.kotlin.backend.jvm.ir.fileParentOrNull
7+ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
68import org.jetbrains.kotlin.descriptors.Modality
79import org.jetbrains.kotlin.ir.builders.declarations.buildFun
810import org.jetbrains.kotlin.ir.declarations.IrClass
11+ import org.jetbrains.kotlin.ir.declarations.IrConstructor
912import org.jetbrains.kotlin.ir.declarations.IrDeclaration
1013import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
1114import org.jetbrains.kotlin.ir.declarations.IrFunction
1215import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
1316import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
17+ import org.jetbrains.kotlin.ir.declarations.createExpressionBody
1418import org.jetbrains.kotlin.ir.expressions.IrBody
1519import org.jetbrains.kotlin.ir.expressions.IrExpression
1620import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
1721import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
22+ import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
1823import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl
24+ import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
25+ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
26+ import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
27+ import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
28+ import org.jetbrains.kotlin.ir.types.defaultType
1929import org.jetbrains.kotlin.ir.types.typeWith
2030import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
31+ import org.jetbrains.kotlin.ir.util.defaultType
2132import org.jetbrains.kotlin.ir.util.dump
33+ import org.jetbrains.kotlin.ir.util.file
2234import org.jetbrains.kotlin.ir.util.kotlinFqName
35+ import org.jetbrains.kotlin.ir.util.parentClassOrNull
2336import org.jetbrains.kotlin.ir.util.patchDeclarationParents
24- import org.jetbrains.kotlin.name.CallableId
2537import org.jetbrains.kotlin.name.ClassId
2638import org.jetbrains.kotlin.name.FqName
2739import org.jetbrains.kotlin.name.Name
@@ -88,39 +100,117 @@ internal val IrFunction.fullyQualifiedName: String
88100/* *
89101 * Create call for [DistinctChangeCache.invoke]
90102 */
103+ @OptIn(UnsafeDuringIrConstructionAPI ::class )
91104internal fun IrPluginContext.buildSaveInCacheCall (
92105 keyLiteral : IrExpression ,
93106 argsListExpr : IrExpression ,
94107 lambdaExpr : IrExpression ,
95108 function : IrSimpleFunction ,
96- qualifierArgs : IrExpression ,
97- logger : CompileLogger
109+ logger : CompileLogger ,
110+ backingField : IrFieldSymbolImpl
98111): IrExpression {
99- logger.i(" buildSaveInCacheCall for ${function.name} , args: ${argsListExpr.dump()} with config: ${qualifierArgs.dump()} " )
112+ logger.i(" buildSaveInCacheCall for ${function.name} , args: ${argsListExpr.dump()} " )
113+
114+ val distinctChangeClassSymbol = referenceClass(DistinctChangeCache ::class .toClassId())
115+ ? : error(" Cannot find DistinctChangeCache" )
116+
117+ val invokeFunSymbol = distinctChangeClassSymbol.owner.declarations
118+ .filterIsInstance<IrSimpleFunction >()
119+ .firstOrNull { it.name == Name .identifier(" invoke" ) }
120+ ? : error(" Cannot find DistinctChangeCache.invoke" )
100121
101- val memoizeFunction = referenceFunctions(
102- CallableId (
103- classId = DistinctChangeCache ::class .toClassId(),
104- callableName = Name .identifier(" invoke" )
105- )
122+ val getDistCacheField = IrGetFieldImpl (
123+ startOffset = function.startOffset,
124+ endOffset = function.endOffset,
125+ symbol = backingField,
126+ type = distinctChangeClassSymbol.owner.defaultType,
127+ receiver = function.dispatchReceiverParameter?.let { thisReceiver ->
128+ IrGetValueImpl (
129+ startOffset = function.startOffset,
130+ endOffset = function.endOffset,
131+ symbol = thisReceiver.symbol,
132+ type = thisReceiver.type
133+ )
134+ },
135+ origin = null
106136 )
107- .singleOrNull()
108- ? : error(" Cannot find function DistinctChangeCache.memorize" )
109137
110138 return IrCallImpl (
111139 startOffset = function.startOffset,
112140 endOffset = function.endOffset,
113141 type = function.returnType,
114- symbol = memoizeFunction ,
142+ symbol = invokeFunSymbol.symbol ,
115143 typeArgumentsCount = 1 ,
116- valueArgumentsCount = 4
144+ valueArgumentsCount = 3 ,
145+ origin = null
117146 )
118- .also { call -> call .patchDeclarationParents(function) }
147+ .also { it .patchDeclarationParents(function.parent ) }
119148 .apply {
149+ dispatchReceiver = getDistCacheField
150+
120151 putTypeArgument(0 , function.returnType)
121152 putValueArgument(0 , keyLiteral)
122153 putValueArgument(1 , argsListExpr)
123154 putValueArgument(2 , lambdaExpr)
124- putValueArgument(3 , qualifierArgs)
125155 }
156+ }
157+
158+ @OptIn(UnsafeDuringIrConstructionAPI ::class )
159+ internal fun IrPluginContext.generateFields (
160+ function : IrSimpleFunction ,
161+ qualifierArgs : IrExpression ,
162+ logger : CompileLogger
163+ ): IrFieldSymbolImpl {
164+ logger.i(" generateFields for ${function.name} parent: ${function.file} " )
165+
166+ val parentClass = function.parentClassOrNull
167+ val parentFile = function.fileParentOrNull
168+
169+ val errorNotFound =
170+ " function ${function.name} in ${function.file} couldn't be used with @DistinctUntilChangeFun"
171+
172+ if (parentClass == null && parentFile == null ) error(errorNotFound)
173+
174+
175+ val startOffset = parentClass?.startOffset ? : parentFile?.startOffset ? : error(errorNotFound)
176+ val endOffset = parentClass?.endOffset ? : parentFile?.endOffset ? : error(errorNotFound)
177+
178+ val fieldSymbol = IrFieldSymbolImpl ()
179+
180+ val distinctChangeClass = referenceClass(DistinctChangeCache ::class .toClassId())
181+ ? : error(" couldn't find DistinctChangeCache" )
182+
183+ val backingField = irFactory.createField(
184+ startOffset = startOffset,
185+ endOffset = endOffset,
186+ origin = IrDeclarationOrigin .PROPERTY_BACKING_FIELD ,
187+ symbol = fieldSymbol,
188+ name = Name .identifier(" _distinctCache" ),
189+ type = distinctChangeClass.defaultType,
190+ visibility = DescriptorVisibilities .PRIVATE ,
191+ isFinal = true ,
192+ isExternal = false ,
193+ isStatic = parentClass == null ,
194+ )
195+
196+ val constructorSymbol = distinctChangeClass.owner.declarations
197+ .filterIsInstance<IrConstructor >()
198+ .firstOrNull { it.isPrimary }
199+ ? : error(" Cannot find primary constructor of DistinctChangeCache" )
200+
201+ val callDistInit = IrConstructorCallImpl .fromSymbolOwner(
202+ startOffset = startOffset,
203+ endOffset = endOffset,
204+ type = distinctChangeClass.defaultType,
205+ constructorSymbol = constructorSymbol.symbol
206+ )
207+ .apply {
208+ putValueArgument(0 , qualifierArgs)
209+ }
210+
211+ backingField.parent = function.parent
212+ backingField.initializer = irFactory.createExpressionBody(callDistInit)
213+ (function.parentClassOrNull ? : function.fileParentOrNull)?.declarations?.add(backingField)
214+
215+ return fieldSymbol
126216}
0 commit comments