@@ -3,25 +3,37 @@ package io.github.stslex.compiler_plugin.utils
3
3
import io.github.stslex.compiler_plugin.DistinctChangeCache
4
4
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
5
5
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
6
+ import org.jetbrains.kotlin.backend.jvm.ir.fileParentOrNull
7
+ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
6
8
import org.jetbrains.kotlin.descriptors.Modality
7
9
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
8
10
import org.jetbrains.kotlin.ir.declarations.IrClass
11
+ import org.jetbrains.kotlin.ir.declarations.IrConstructor
9
12
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
10
13
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
11
14
import org.jetbrains.kotlin.ir.declarations.IrFunction
12
15
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
13
16
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
17
+ import org.jetbrains.kotlin.ir.declarations.createExpressionBody
14
18
import org.jetbrains.kotlin.ir.expressions.IrBody
15
19
import org.jetbrains.kotlin.ir.expressions.IrExpression
16
20
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
17
21
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
22
+ import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
18
23
import 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
19
29
import org.jetbrains.kotlin.ir.types.typeWith
20
30
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
31
+ import org.jetbrains.kotlin.ir.util.defaultType
21
32
import org.jetbrains.kotlin.ir.util.dump
33
+ import org.jetbrains.kotlin.ir.util.file
22
34
import org.jetbrains.kotlin.ir.util.kotlinFqName
35
+ import org.jetbrains.kotlin.ir.util.parentClassOrNull
23
36
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
24
- import org.jetbrains.kotlin.name.CallableId
25
37
import org.jetbrains.kotlin.name.ClassId
26
38
import org.jetbrains.kotlin.name.FqName
27
39
import org.jetbrains.kotlin.name.Name
@@ -88,39 +100,117 @@ internal val IrFunction.fullyQualifiedName: String
88
100
/* *
89
101
* Create call for [DistinctChangeCache.invoke]
90
102
*/
103
+ @OptIn(UnsafeDuringIrConstructionAPI ::class )
91
104
internal fun IrPluginContext.buildSaveInCacheCall (
92
105
keyLiteral : IrExpression ,
93
106
argsListExpr : IrExpression ,
94
107
lambdaExpr : IrExpression ,
95
108
function : IrSimpleFunction ,
96
- qualifierArgs : IrExpression ,
97
- logger : CompileLogger
109
+ logger : CompileLogger ,
110
+ backingField : IrFieldSymbolImpl
98
111
): 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" )
100
121
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
106
136
)
107
- .singleOrNull()
108
- ? : error(" Cannot find function DistinctChangeCache.memorize" )
109
137
110
138
return IrCallImpl (
111
139
startOffset = function.startOffset,
112
140
endOffset = function.endOffset,
113
141
type = function.returnType,
114
- symbol = memoizeFunction ,
142
+ symbol = invokeFunSymbol.symbol ,
115
143
typeArgumentsCount = 1 ,
116
- valueArgumentsCount = 4
144
+ valueArgumentsCount = 3 ,
145
+ origin = null
117
146
)
118
- .also { call -> call .patchDeclarationParents(function) }
147
+ .also { it .patchDeclarationParents(function.parent ) }
119
148
.apply {
149
+ dispatchReceiver = getDistCacheField
150
+
120
151
putTypeArgument(0 , function.returnType)
121
152
putValueArgument(0 , keyLiteral)
122
153
putValueArgument(1 , argsListExpr)
123
154
putValueArgument(2 , lambdaExpr)
124
- putValueArgument(3 , qualifierArgs)
125
155
}
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
126
216
}
0 commit comments