@@ -34,6 +34,7 @@ import androidx.compose.compiler.plugins.kotlin.analysis.knownUnstable
34
34
import androidx.compose.compiler.plugins.kotlin.irTrace
35
35
import com.intellij.openapi.progress.ProcessCanceledException
36
36
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
37
+ import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
37
38
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
38
39
import org.jetbrains.kotlin.builtins.PrimitiveType
39
40
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -45,10 +46,11 @@ import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
45
46
import org.jetbrains.kotlin.ir.builders.declarations.buildField
46
47
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
47
48
import org.jetbrains.kotlin.ir.builders.declarations.buildProperty
49
+ import org.jetbrains.kotlin.ir.builders.irBlockBody
50
+ import org.jetbrains.kotlin.ir.builders.irReturn
48
51
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
49
52
import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer
50
53
import org.jetbrains.kotlin.ir.declarations.IrClass
51
- import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
52
54
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
53
55
import org.jetbrains.kotlin.ir.declarations.IrField
54
56
import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -86,6 +88,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
86
88
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
87
89
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
88
90
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
91
+ import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
89
92
import org.jetbrains.kotlin.ir.expressions.impl.IrElseBranchImpl
90
93
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl
91
94
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
@@ -128,6 +131,7 @@ import org.jetbrains.kotlin.ir.types.typeWith
128
131
import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper
129
132
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
130
133
import org.jetbrains.kotlin.ir.util.addChild
134
+ import org.jetbrains.kotlin.ir.util.constructors
131
135
import org.jetbrains.kotlin.ir.util.defaultType
132
136
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
133
137
import org.jetbrains.kotlin.ir.util.functions
@@ -155,11 +159,23 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
155
159
import org.jetbrains.kotlin.util.OperatorNameConventions
156
160
import org.jetbrains.kotlin.utils.DFS
157
161
162
+ import androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc.hiddenFromObjCClassId
163
+ import org.jetbrains.kotlin.GeneratedDeclarationKey
164
+ import org.jetbrains.kotlin.descriptors.ClassDescriptor
165
+ import org.jetbrains.kotlin.fir.declarations.utils.klibSourceFile
166
+ import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
167
+ import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
168
+ import org.jetbrains.kotlin.ir.util.packageFqName
169
+ import org.jetbrains.kotlin.library.metadata.DeserializedSourceFile
170
+
171
+ object ComposeCompilerKey : GeneratedDeclarationKey()
172
+
158
173
abstract class AbstractComposeLowering (
159
174
val context : IrPluginContext ,
160
175
val symbolRemapper : DeepCopySymbolRemapper ,
161
176
val metrics : ModuleMetrics ,
162
- val stabilityInferencer : StabilityInferencer
177
+ val stabilityInferencer : StabilityInferencer ,
178
+ protected val unstableClassesWarning : MutableSet <ClassDescriptor >? = null
163
179
) : IrElementTransformerVoid(), ModuleLoweringPass {
164
180
protected val builtIns = context.irBuiltIns
165
181
@@ -379,15 +395,7 @@ abstract class AbstractComposeLowering(
379
395
null
380
396
381
397
is Stability .Parameter -> resolve(parameter)
382
- is Stability .Runtime -> {
383
- val stableField = declaration.makeStabilityField()
384
- IrGetFieldImpl (
385
- UNDEFINED_OFFSET ,
386
- UNDEFINED_OFFSET ,
387
- stableField.symbol,
388
- stableField.type
389
- )
390
- }
398
+ is Stability .Runtime -> declaration.getRuntimeStabilityValue()
391
399
392
400
is Stability .Unknown -> null
393
401
}
@@ -778,6 +786,15 @@ abstract class AbstractComposeLowering(
778
786
return irGet(variable.type, variable.symbol)
779
787
}
780
788
789
+ protected fun irGetField (field : IrField ): IrGetField {
790
+ return IrGetFieldImpl (
791
+ UNDEFINED_OFFSET ,
792
+ UNDEFINED_OFFSET ,
793
+ field.symbol,
794
+ field.type
795
+ )
796
+ }
797
+
781
798
protected fun irIf (condition : IrExpression , body : IrExpression ): IrExpression {
782
799
return IrIfThenElseImpl (
783
800
UNDEFINED_OFFSET ,
@@ -898,61 +915,146 @@ abstract class AbstractComposeLowering(
898
915
kotlinFqName.asString().replace(" ." , " _" ) + KtxNameConventions .STABILITY_PROP_FLAG
899
916
)
900
917
901
- fun IrClass.makeStabilityField (): IrField {
918
+ private fun IrClass.uniqueStabilityGetterName (): Name = Name .identifier(
919
+ kotlinFqName.asString().replace(" ." , " _" ) + KtxNameConventions .STABILITY_GETTER_FLAG
920
+ )
921
+
922
+ private fun IrClass.getMetadataStabilityGetterFun (): IrSimpleFunctionSymbol ? {
923
+ val suitableFunctions = context.referenceFunctions(CallableId (this .packageFqName!! , uniqueStabilityGetterName()))
924
+ return suitableFunctions.singleOrNull()
925
+ }
926
+
927
+ private fun IrClass.getRuntimeStabilityValue (): IrExpression {
928
+ if (context.platform.isJvm()) {
929
+ val stableField = this .makeStabilityFieldJvm()
930
+ return irGetField(stableField)
931
+ } else {
932
+ // since k2.0.10 compiler plugin adds special getter function that should be visible in metadata declarations
933
+ val stabilityGetter = getMetadataStabilityGetterFun()
934
+ if (stabilityGetter != null ) {
935
+ return irCall(stabilityGetter)
936
+ }
937
+
938
+ // in case we have not found getter function and dependency was compiled with k1.9, we can rely on
939
+ // IrGetField over property backing field because it was generated with `isConst = true` and should be initialized
940
+ val classKotlinVersion =
941
+ ((this as ? Fir2IrLazyClass )?.fir?.klibSourceFile as ? DeserializedSourceFile )?.library?.versions?.compilerVersion
942
+ if (classKotlinVersion != null && classKotlinVersion.startsWith(" 1.9" )) {
943
+ val stableField = this .buildStabilityProp(false )
944
+ val backingField = stableField.backingField!!
945
+
946
+ return irGetField(backingField)
947
+ }
948
+
949
+ // if we can not find stability getter function in metadata, dependency was compiled with older version of compiler plugin,
950
+ // so we can not trust value produced from `irGetField` because it may contain uninitialized data on native targets
951
+ // (there is no guarantees that any of static/toplevel functions were called at this point,
952
+ // so no guarantees that package initializer was called and field value was initialized)
953
+ // we treat those classes as `Unstable` and produce compilation warning that user may observe additional recompositions
954
+ // and may need to update dependencies to version compiled with newer compiler plugin to get rid of them
955
+ unstableClassesWarning?.add(this .descriptor)
956
+ return irConst(StabilityBits .UNSTABLE .bitsForSlot(0 ))
957
+ }
958
+ }
959
+
960
+ internal fun IrClass.makeStabilityField (): IrField {
902
961
return if (context.platform.isJvm()) {
903
- this . makeStabilityFieldJvm()
962
+ makeStabilityFieldJvm()
904
963
} else {
905
- this . makeStabilityFieldNonJvm()
964
+ makeStabilityFieldNonJvm()
906
965
}
907
966
}
908
967
909
968
private fun IrClass.makeStabilityFieldJvm (): IrField {
910
- return context.irFactory.buildField {
911
- startOffset = SYNTHETIC_OFFSET
912
- endOffset = SYNTHETIC_OFFSET
913
- name = KtxNameConventions .STABILITY_FLAG
914
- isStatic = true
915
- isFinal = true
916
- type = context.irBuiltIns.intType
917
- visibility = DescriptorVisibilities .PUBLIC
918
- }.also { stabilityField ->
969
+ return buildStabilityField(KtxNameConventions .STABILITY_FLAG ).also { stabilityField ->
919
970
stabilityField.parent = this @makeStabilityFieldJvm
971
+ declarations + = stabilityField
920
972
}
921
973
}
922
974
923
975
private fun IrClass.makeStabilityFieldNonJvm (): IrField {
924
- val stabilityFieldName = this .uniqueStabilityFieldName()
925
- val fieldParent = this .getPackageFragment()
976
+ val prop = this .buildStabilityProp(true )
977
+ return prop.backingField!!
978
+ }
926
979
980
+ private fun buildStabilityField (fieldName : Name ): IrField {
927
981
return context.irFactory.buildField {
928
982
startOffset = SYNTHETIC_OFFSET
929
983
endOffset = SYNTHETIC_OFFSET
930
- name = stabilityFieldName
984
+ name = fieldName
931
985
isStatic = true
932
986
isFinal = true
933
987
type = context.irBuiltIns.intType
934
988
visibility = DescriptorVisibilities .PUBLIC
935
- }.also { stabilityField ->
936
- stabilityField.parent = fieldParent
937
- makeStabilityProp(stabilityField, fieldParent)
938
989
}
939
990
}
940
991
941
- private fun IrClass.makeStabilityProp (
942
- stabilityField : IrField ,
943
- fieldParent : IrDeclarationContainer
944
- ): IrProperty {
945
- return context.irFactory.buildProperty {
992
+ private fun IrClass.buildStabilityProp (buildGetter : Boolean ): IrProperty {
993
+ val parent = this .getPackageFragment()
994
+
995
+ val propName = this .uniqueStabilityPropertyName()
996
+ val existingProp = parent.declarations.firstOrNull {
997
+ it is IrProperty && it.name == propName
998
+ } as ? IrProperty
999
+ if (existingProp != null ) {
1000
+ return existingProp
1001
+ }
1002
+
1003
+ val stabilityField = buildStabilityField(uniqueStabilityFieldName()).also {
1004
+ it.parent = parent
1005
+ }
1006
+
1007
+ val property = context.irFactory.buildProperty {
946
1008
startOffset = SYNTHETIC_OFFSET
947
1009
endOffset = SYNTHETIC_OFFSET
948
- name = this @makeStabilityProp.uniqueStabilityPropertyName()
1010
+ name = propName
949
1011
visibility = DescriptorVisibilities .PUBLIC
950
1012
}.also { property ->
951
- property.parent = fieldParent
1013
+ property.parent = parent
952
1014
stabilityField.correspondingPropertySymbol = property.symbol
953
1015
property.backingField = stabilityField
954
- fieldParent .addChild(property)
1016
+ parent .addChild(property)
955
1017
}
1018
+
1019
+ if (buildGetter) {
1020
+ this .buildStabilityGetter(property, parent)
1021
+ }
1022
+
1023
+ return property
1024
+ }
1025
+
1026
+ private val hiddenFromObjCAnnotationSymbol: IrClassSymbol = getTopLevelClass(hiddenFromObjCClassId)
1027
+ private val hiddenFromObjCAnnotation = IrConstructorCallImpl .fromSymbolOwner(
1028
+ type = hiddenFromObjCAnnotationSymbol.defaultType,
1029
+ constructorSymbol = hiddenFromObjCAnnotationSymbol.constructors.first()
1030
+ )
1031
+
1032
+ private fun IrClass.buildStabilityGetter (stabilityProp : IrProperty , parent : IrPackageFragment ) {
1033
+ val getterName = uniqueStabilityGetterName()
1034
+
1035
+ val stabilityField = stabilityProp.backingField!!
1036
+
1037
+ // we could have created getter instead of separate function,
1038
+ // but `registerFunctionAsMetadataVisible` is not working for field getter for some reason
1039
+ // and there is no api to register properties as metadata-visible
1040
+ val stabilityGetter = context.irFactory.buildFun {
1041
+ startOffset = SYNTHETIC_OFFSET
1042
+ endOffset = SYNTHETIC_OFFSET
1043
+ name = getterName
1044
+ returnType = stabilityField.type
1045
+ visibility = DescriptorVisibilities .PUBLIC
1046
+ origin = IrDeclarationOrigin .GeneratedByPlugin (ComposeCompilerKey )
1047
+ annotations = listOf (hiddenFromObjCAnnotation)
1048
+ }.also { fn ->
1049
+ fn.parent = parent
1050
+ fn.body = DeclarationIrBuilder (context, fn.symbol).irBlockBody {
1051
+ + irReturn(irGetField(stabilityField))
1052
+ }
1053
+ parent.addChild(fn)
1054
+ }
1055
+
1056
+ context.metadataDeclarationRegistrar.addMetadataVisibleAnnotationsToElement(stabilityGetter, hiddenFromObjCAnnotation)
1057
+ context.metadataDeclarationRegistrar.registerFunctionAsMetadataVisible(stabilityGetter)
956
1058
}
957
1059
958
1060
fun IrExpression.isStatic (): Boolean {
0 commit comments