| /* |
| * Copyright 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.compose.compiler.plugins.kotlin.lower |
| |
| import androidx.compose.compiler.plugins.kotlin.ComposeFqNames |
| import androidx.compose.compiler.plugins.kotlin.KtxNameConventions |
| import androidx.compose.compiler.plugins.kotlin.allowsComposableCalls |
| import androidx.compose.compiler.plugins.kotlin.analysis.ComposeWritableSlices |
| import androidx.compose.compiler.plugins.kotlin.irTrace |
| import androidx.compose.compiler.plugins.kotlin.isComposableCallable |
| import androidx.compose.compiler.plugins.kotlin.isMarkedStable |
| import androidx.compose.compiler.plugins.kotlin.isSpecialType |
| import org.jetbrains.kotlin.backend.common.descriptors.isFunctionOrKFunctionType |
| import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder |
| import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext |
| import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl |
| import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi |
| import org.jetbrains.kotlin.builtins.KotlinBuiltIns |
| import org.jetbrains.kotlin.builtins.extractParameterNameFromFunctionTypeArgument |
| import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor |
| import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType |
| import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType |
| import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType |
| import org.jetbrains.kotlin.descriptors.CallableDescriptor |
| import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor |
| import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor |
| import org.jetbrains.kotlin.descriptors.ClassDescriptor |
| import org.jetbrains.kotlin.descriptors.ClassKind |
| import org.jetbrains.kotlin.descriptors.DeclarationDescriptor |
| import org.jetbrains.kotlin.descriptors.FunctionDescriptor |
| import org.jetbrains.kotlin.descriptors.Modality |
| import org.jetbrains.kotlin.descriptors.ParameterDescriptor |
| import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor |
| import org.jetbrains.kotlin.descriptors.SourceElement |
| import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor |
| import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor |
| import org.jetbrains.kotlin.descriptors.Visibilities |
| import org.jetbrains.kotlin.descriptors.annotations.Annotations |
| import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies |
| import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor |
| import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl |
| import org.jetbrains.kotlin.incremental.components.NoLookupLocation |
| import org.jetbrains.kotlin.ir.IrStatement |
| import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET |
| import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames |
| import org.jetbrains.kotlin.ir.builders.IrBlockBodyBuilder |
| import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope |
| import org.jetbrains.kotlin.ir.builders.irBlock |
| import org.jetbrains.kotlin.ir.builders.irBlockBody |
| import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer |
| import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin |
| import org.jetbrains.kotlin.ir.declarations.IrFunction |
| import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction |
| import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration |
| import org.jetbrains.kotlin.ir.declarations.IrValueParameter |
| import org.jetbrains.kotlin.ir.declarations.IrVariable |
| import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl |
| import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl |
| import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl |
| import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl |
| import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl |
| import org.jetbrains.kotlin.ir.expressions.IrBranch |
| import org.jetbrains.kotlin.ir.expressions.IrCall |
| import org.jetbrains.kotlin.ir.expressions.IrConst |
| import org.jetbrains.kotlin.ir.expressions.IrConstKind |
| import org.jetbrains.kotlin.ir.expressions.IrExpression |
| import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression |
| import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin |
| import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrElseBranchImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrIfThenElseImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrSetVariableImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrWhenImpl |
| import org.jetbrains.kotlin.ir.expressions.typeParametersCount |
| import org.jetbrains.kotlin.ir.expressions.IrConstructorCall |
| import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl |
| import org.jetbrains.kotlin.ir.expressions.impl.IrWhileLoopImpl |
| import org.jetbrains.kotlin.ir.symbols.IrClassSymbol |
| import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol |
| import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol |
| import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol |
| import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol |
| import org.jetbrains.kotlin.ir.symbols.IrSymbol |
| import org.jetbrains.kotlin.ir.symbols.IrValueSymbol |
| import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl |
| import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl |
| import org.jetbrains.kotlin.ir.types.IrType |
| import org.jetbrains.kotlin.ir.types.classOrNull |
| import org.jetbrains.kotlin.ir.types.defaultType |
| import org.jetbrains.kotlin.ir.types.isNullable |
| import org.jetbrains.kotlin.ir.types.isPrimitiveType |
| import org.jetbrains.kotlin.ir.types.makeNullable |
| import org.jetbrains.kotlin.ir.types.toKotlinType |
| import org.jetbrains.kotlin.ir.types.typeWith |
| import org.jetbrains.kotlin.ir.util.ConstantValueGenerator |
| import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper |
| import org.jetbrains.kotlin.ir.util.TypeTranslator |
| import org.jetbrains.kotlin.ir.util.defaultType |
| import org.jetbrains.kotlin.ir.util.endOffset |
| import org.jetbrains.kotlin.ir.util.functions |
| import org.jetbrains.kotlin.ir.util.getPrimitiveArrayElementType |
| import org.jetbrains.kotlin.ir.util.getPropertyGetter |
| import org.jetbrains.kotlin.ir.util.primaryConstructor |
| import org.jetbrains.kotlin.ir.util.referenceFunction |
| import org.jetbrains.kotlin.ir.util.startOffset |
| import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid |
| import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi |
| import org.jetbrains.kotlin.name.ClassId |
| import org.jetbrains.kotlin.name.FqName |
| import org.jetbrains.kotlin.resolve.BindingTrace |
| import org.jetbrains.kotlin.name.Name |
| import org.jetbrains.kotlin.psi.KtFunctionLiteral |
| import org.jetbrains.kotlin.resolve.DescriptorFactory |
| import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe |
| import org.jetbrains.kotlin.resolve.inline.InlineUtil |
| import org.jetbrains.kotlin.resolve.isInlineClassType |
| import org.jetbrains.kotlin.resolve.unsubstitutedUnderlyingType |
| import org.jetbrains.kotlin.types.KotlinType |
| import org.jetbrains.kotlin.types.isError |
| import org.jetbrains.kotlin.types.isNullable |
| import org.jetbrains.kotlin.types.typeUtil.isTypeParameter |
| import org.jetbrains.kotlin.types.typeUtil.makeNotNullable |
| import org.jetbrains.kotlin.utils.DFS |
| |
| @Suppress("DEPRECATION") |
| abstract class AbstractComposeLowering( |
| val context: IrPluginContext, |
| val symbolRemapper: DeepCopySymbolRemapper, |
| val bindingTrace: BindingTrace |
| ) : IrElementTransformerVoid() { |
| |
| protected val typeTranslator = |
| TypeTranslator( |
| context.symbolTable, |
| context.languageVersionSettings, |
| context.builtIns |
| ).apply { |
| constantValueGenerator = ConstantValueGenerator( |
| context.moduleDescriptor, |
| context.symbolTable |
| ) |
| constantValueGenerator.typeTranslator = this |
| } |
| |
| protected val builtIns = context.irBuiltIns |
| |
| protected val composerTypeDescriptor = context.moduleDescriptor |
| .findClassAcrossModuleDependencies(ClassId.topLevel(ComposeFqNames.Composer) |
| ) ?: error("Cannot find the Composer class") |
| |
| private val symbolTable get() = context.symbolTable |
| |
| fun referenceFunction(descriptor: CallableDescriptor): IrFunctionSymbol { |
| return symbolRemapper.getReferencedFunction(symbolTable.referenceFunction(descriptor)) |
| } |
| |
| fun referenceSimpleFunction(descriptor: SimpleFunctionDescriptor): IrSimpleFunctionSymbol { |
| return symbolRemapper.getReferencedSimpleFunction( |
| symbolTable.referenceSimpleFunction(descriptor) |
| ) |
| } |
| |
| fun referenceConstructor(descriptor: ClassConstructorDescriptor): IrConstructorSymbol { |
| return symbolRemapper.getReferencedConstructor(symbolTable.referenceConstructor(descriptor)) |
| } |
| |
| fun getTopLevelClass(fqName: FqName): IrClassSymbol { |
| val descriptor = context.moduleDescriptor.getPackage(fqName.parent()).memberScope |
| .getContributedClassifier( |
| fqName.shortName(), NoLookupLocation.FROM_BACKEND |
| ) as ClassDescriptor? ?: error("Class is not found: $fqName") |
| return symbolTable.referenceClass(descriptor) |
| } |
| |
| fun getTopLevelFunction(fqName: FqName): IrFunctionSymbol { |
| val descriptor = context.moduleDescriptor.getPackage(fqName.parent()).memberScope |
| .getContributedFunctions( |
| fqName.shortName(), NoLookupLocation.FROM_BACKEND |
| ).singleOrNull() ?: error("Function not found $fqName") |
| return symbolRemapper.getReferencedFunction( |
| symbolTable.referenceSimpleFunction(descriptor) |
| ) |
| } |
| |
| fun getInternalFunction(name: String) = getTopLevelFunction( |
| ComposeFqNames.internalFqNameFor(name) |
| ) |
| |
| fun getInternalClass(name: String) = getTopLevelClass( |
| ComposeFqNames.internalFqNameFor(name) |
| ) |
| |
| fun getTopLevelPropertyGetter(fqName: FqName): IrFunctionSymbol { |
| val descriptor = context.moduleDescriptor.getPackage(fqName.parent()).memberScope |
| .getContributedVariables( |
| fqName.shortName(), NoLookupLocation.FROM_BACKEND |
| ).singleOrNull() ?: error("Function not found $fqName") |
| return symbolRemapper.getReferencedFunction( |
| symbolTable.referenceSimpleFunction(descriptor.getter!!) |
| ) |
| } |
| |
| fun KotlinType.toIrType(): IrType = typeTranslator.translateType(this) |
| |
| fun IrType.unboxInlineClass() = unboxType() ?: this |
| |
| fun <T : IrSymbol> T.bindIfNecessary(): T { |
| if (!isBound) { |
| (context as IrPluginContextImpl).linker.getDeclaration(this) |
| } |
| return this |
| } |
| |
| // IR external stubs don't have their value parameters' parent properly mapped to the |
| // function itself. This normally isn't a problem because nothing in the IR lowerings ask for |
| // the parent of the parameters, but we do. I believe this should be considered a bug in |
| // kotlin proper, but this works around it. |
| fun IrValueParameter.hasDefaultValueSafe(): Boolean = DFS.ifAny( |
| listOf(this), |
| { current -> |
| (current.parent as? IrSimpleFunction)?.overriddenSymbols?.map { fn -> |
| fn.owner.valueParameters[current.index].also { p -> |
| p.parent = fn.owner |
| } |
| } ?: listOf() |
| }, |
| { current -> current.defaultValue != null } |
| ) |
| |
| // NOTE(lmr): This implementation mimics the kotlin-provided unboxInlineClass method, except |
| // this one makes sure to bind the symbol if it is unbound, so is a bit safer to use. |
| fun IrType.unboxType(): IrType? { |
| val classSymbol = classOrNull ?: return null |
| val klass = classSymbol.bindIfNecessary().owner |
| if (!klass.isInline) return null |
| |
| // TODO: Apply type substitutions |
| val underlyingType = InlineClassAbi.getUnderlyingType(klass).unboxInlineClass() |
| if (!isNullable()) return underlyingType |
| if (underlyingType.isNullable() || underlyingType.isPrimitiveType()) |
| return null |
| return underlyingType.makeNullable() |
| } |
| |
| protected fun IrExpression.unboxValueIfInline(): IrExpression { |
| if (type.isNullable()) return this |
| val classSymbol = type.classOrNull ?: return this |
| val klass = classSymbol.bindIfNecessary().owner |
| if (klass.isInline) { |
| val primaryValueParameter = klass |
| .primaryConstructor |
| ?.valueParameters |
| ?.get(0) ?: error("Expected a value parameter") |
| val fieldGetter = klass.getPropertyGetter(primaryValueParameter.name.identifier) |
| ?: error("Expected a getter") |
| return irCall( |
| symbol = fieldGetter, |
| dispatchReceiver = this |
| ).unboxValueIfInline() |
| } |
| return this |
| } |
| |
| fun IrAnnotationContainer.hasComposableAnnotation(): Boolean { |
| return annotations.hasAnnotation(ComposeFqNames.Composable) |
| } |
| |
| fun IrAnnotationContainer.hasStableAnnotation(): Boolean { |
| return annotations.hasAnnotation(ComposeFqNames.Stable) |
| } |
| |
| fun List<IrConstructorCall>.hasAnnotation(fqName: FqName): Boolean = |
| any { it.symbol.descriptor.constructedClass.fqNameSafe == fqName } |
| |
| fun IrCall.isInvoke(): Boolean { |
| return origin == IrStatementOrigin.INVOKE || symbol.descriptor is FunctionInvokeDescriptor |
| } |
| |
| fun IrCall.isTransformedComposableCall(): Boolean { |
| return context.irTrace[ComposeWritableSlices.IS_COMPOSABLE_CALL, this] ?: false |
| } |
| |
| fun IrCall.isSyntheticComposableCall(): Boolean { |
| return context.irTrace[ComposeWritableSlices.IS_SYNTHETIC_COMPOSABLE_CALL, this] == true |
| } |
| |
| fun IrFunction.isInlinedLambda(): Boolean { |
| descriptor.findPsi()?.let { psi -> |
| (psi as? KtFunctionLiteral)?.let { |
| if (InlineUtil.isInlinedArgument( |
| it, |
| context.bindingContext, |
| false |
| ) |
| ) |
| return true |
| } |
| } |
| return false |
| } |
| |
| protected val KotlinType.isEnum |
| get() = |
| (constructor.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.ENUM_CLASS |
| |
| protected fun KotlinType?.isStable(): Boolean { |
| if (this == null) return false |
| |
| val trace = bindingTrace |
| val calculated = trace.get(ComposeWritableSlices.STABLE_TYPE, this) |
| return if (calculated == null) { |
| val isStable = !isError && |
| !isTypeParameter() && |
| !isSpecialType && |
| ( |
| KotlinBuiltIns.isPrimitiveType(this) || |
| isFunctionOrKFunctionType || |
| isEnum || |
| KotlinBuiltIns.isString(this) || |
| isMarkedStable() || |
| ( |
| isNullable() && |
| makeNotNullable().isStable() |
| ) || |
| ( |
| isInlineClassType() && |
| unsubstitutedUnderlyingType().isStable() |
| ) |
| ) |
| trace.record(ComposeWritableSlices.STABLE_TYPE, this, isStable) |
| isStable |
| } else calculated |
| } |
| |
| fun FunctionDescriptor.isComposableCallable(): Boolean { |
| return isComposableCallable(context.bindingContext) |
| } |
| |
| fun FunctionDescriptor.allowsComposableCalls(): Boolean { |
| return allowsComposableCalls(context.bindingContext) |
| } |
| |
| fun IrFunctionExpression.allowsComposableCalls(): Boolean = |
| function.descriptor.allowsComposableCalls(context.bindingContext) |
| |
| private fun IrFunction.createParameterDeclarations() { |
| fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl( |
| this.startOffset ?: UNDEFINED_OFFSET, |
| this.endOffset ?: UNDEFINED_OFFSET, |
| IrDeclarationOrigin.DEFINED, |
| this, |
| type.toIrType(), |
| (this as? ValueParameterDescriptor)?.varargElementType?.toIrType() |
| ).also { |
| it.parent = this@createParameterDeclarations |
| } |
| |
| fun TypeParameterDescriptor.irTypeParameter() = IrTypeParameterImpl( |
| this.startOffset ?: UNDEFINED_OFFSET, |
| this.endOffset ?: UNDEFINED_OFFSET, |
| IrDeclarationOrigin.DEFINED, |
| IrTypeParameterSymbolImpl(this), |
| this.name, |
| this.index, |
| this.isReified, |
| this.variance |
| ).also { |
| it.parent = this@createParameterDeclarations |
| } |
| |
| dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter() |
| extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter() |
| |
| valueParameters = descriptor.valueParameters.map { it.irValueParameter() } |
| |
| typeParameters = descriptor.typeParameters.map { it.irTypeParameter() } |
| } |
| |
| protected fun IrBuilderWithScope.irLambdaExpression( |
| descriptor: FunctionDescriptor, |
| type: IrType, |
| body: IrBlockBodyBuilder.(IrFunction) -> Unit |
| ) = irLambdaExpression(this.startOffset, this.endOffset, descriptor, type, body) |
| |
| protected fun IrBuilderWithScope.irLambdaExpression( |
| startOffset: Int, |
| endOffset: Int, |
| descriptor: FunctionDescriptor, |
| type: IrType, |
| body: IrBlockBodyBuilder.(IrFunction) -> Unit |
| ): IrExpression { |
| val symbol = IrSimpleFunctionSymbolImpl(descriptor) |
| |
| val returnType = descriptor.returnType!!.toIrType() |
| |
| val lambda = IrFunctionImpl( |
| startOffset, endOffset, |
| IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA, |
| symbol, |
| name = descriptor.name, |
| visibility = descriptor.visibility, |
| modality = descriptor.modality, |
| returnType = returnType, |
| isInline = descriptor.isInline, |
| isExternal = descriptor.isExternal, |
| isTailrec = descriptor.isTailrec, |
| isSuspend = descriptor.isSuspend, |
| isOperator = descriptor.isOperator, |
| isExpect = descriptor.isExpect |
| ).also { |
| it.parent = scope.getLocalDeclarationParent() |
| it.createParameterDeclarations() |
| it.body = DeclarationIrBuilder(this@AbstractComposeLowering.context, symbol) |
| .irBlockBody { body(it) } |
| } |
| |
| return irBlock( |
| startOffset = startOffset, |
| endOffset = endOffset, |
| origin = IrStatementOrigin.LAMBDA, |
| resultType = type |
| ) { |
| +lambda |
| +IrFunctionReferenceImpl( |
| startOffset = startOffset, |
| endOffset = endOffset, |
| type = type, |
| symbol = symbol, |
| typeArgumentsCount = descriptor.typeParametersCount, |
| reflectionTarget = null, |
| origin = IrStatementOrigin.LAMBDA |
| ) |
| } |
| } |
| |
| protected fun IrBuilderWithScope.createFunctionDescriptor( |
| type: KotlinType, |
| owner: DeclarationDescriptor = scope.scopeOwner |
| ): FunctionDescriptor { |
| return AnonymousFunctionDescriptor( |
| owner, |
| Annotations.EMPTY, |
| CallableMemberDescriptor.Kind.SYNTHESIZED, |
| SourceElement.NO_SOURCE, |
| false |
| ).apply { |
| initialize( |
| type.getReceiverTypeFromFunctionType()?.let { |
| DescriptorFactory.createExtensionReceiverParameterForCallable( |
| this, |
| it, |
| Annotations.EMPTY |
| ) |
| }, |
| null, |
| emptyList(), |
| type.getValueParameterTypesFromFunctionType().mapIndexed { i, t -> |
| ValueParameterDescriptorImpl( |
| containingDeclaration = this, |
| original = null, |
| index = i, |
| annotations = Annotations.EMPTY, |
| name = t.type.extractParameterNameFromFunctionTypeArgument() |
| ?: Name.identifier("p$i"), |
| outType = t.type, |
| declaresDefaultValue = false, |
| isCrossinline = false, |
| isNoinline = false, |
| varargElementType = null, |
| source = SourceElement.NO_SOURCE |
| ) |
| }, |
| type.getReturnTypeFromFunctionType(), |
| Modality.FINAL, |
| Visibilities.LOCAL, |
| null |
| ) |
| isOperator = false |
| isInfix = false |
| isExternal = false |
| isInline = false |
| isTailrec = false |
| isSuspend = false |
| isExpect = false |
| isActual = false |
| } |
| } |
| |
| // set the bit at a certain index |
| protected fun Int.withBit(index: Int, value: Boolean): Int { |
| return if (value) { |
| this or (1 shl index) |
| } else { |
| this and (1 shl index).inv() |
| } |
| } |
| |
| protected operator fun Int.get(index: Int): Boolean { |
| return this and (1 shl index) != 0 |
| } |
| |
| // create a bitmask with the following bits |
| protected fun bitMask(vararg values: Boolean): Int = values.foldIndexed(0) { i, mask, bit -> |
| mask.withBit(i, bit) |
| } |
| |
| protected fun irGetBit(param: IrDefaultBitMaskValue, index: Int): IrExpression { |
| // value and (1 shl index) != 0 |
| return irNotEqual( |
| param.irIsolateBitAtIndex(index), |
| irConst(0) |
| ) |
| } |
| |
| protected fun irSet(variable: IrVariable, value: IrExpression): IrExpression { |
| return IrSetVariableImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| context.irBuiltIns.unitType, |
| variable.symbol, |
| value = value, |
| origin = null |
| ) |
| } |
| |
| protected fun irCall( |
| symbol: IrFunctionSymbol, |
| origin: IrStatementOrigin? = null, |
| dispatchReceiver: IrExpression? = null, |
| extensionReceiver: IrExpression? = null, |
| vararg args: IrExpression |
| ): IrCallImpl { |
| symbol.bindIfNecessary() |
| return IrCallImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| symbol.owner.returnType, |
| symbol, |
| origin |
| ).also { |
| if (dispatchReceiver != null) it.dispatchReceiver = dispatchReceiver |
| if (extensionReceiver != null) it.extensionReceiver = extensionReceiver |
| args.forEachIndexed { index, arg -> |
| it.putValueArgument(index, arg) |
| } |
| } |
| } |
| |
| protected fun irAnd(lhs: IrExpression, rhs: IrExpression): IrCallImpl { |
| return irCall( |
| context.symbols.intAnd, |
| null, |
| lhs, |
| null, |
| rhs |
| ) |
| } |
| |
| protected fun irInv(lhs: IrExpression): IrCallImpl { |
| val int = context.builtIns.intType |
| return irCall( |
| context.symbols.getUnaryOperator(OperatorNames.INV, int), |
| null, |
| lhs |
| ) |
| } |
| |
| protected fun irOr(lhs: IrExpression, rhs: IrExpression): IrCallImpl { |
| val int = context.builtIns.intType |
| return irCall( |
| context.symbols.getBinaryOperator(OperatorNames.OR, int, int), |
| null, |
| lhs, |
| null, |
| rhs |
| ) |
| } |
| |
| protected fun irBooleanOr(lhs: IrExpression, rhs: IrExpression): IrCallImpl { |
| val boolean = context.builtIns.booleanType |
| return irCall( |
| context.symbols.getBinaryOperator(OperatorNames.OR, boolean, boolean), |
| null, |
| lhs, |
| null, |
| rhs |
| ) |
| } |
| |
| protected fun irOrOr(lhs: IrExpression, rhs: IrExpression): IrExpression { |
| return IrWhenImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| origin = IrStatementOrigin.OROR, |
| type = context.irBuiltIns.booleanType, |
| branches = listOf( |
| IrBranchImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| condition = lhs, |
| result = irConst(true) |
| ), |
| IrElseBranchImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| condition = irConst(true), |
| result = rhs |
| ) |
| ) |
| ) |
| } |
| |
| protected fun irAndAnd(lhs: IrExpression, rhs: IrExpression): IrExpression { |
| return IrWhenImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| origin = IrStatementOrigin.ANDAND, |
| type = context.irBuiltIns.booleanType, |
| branches = listOf( |
| IrBranchImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| condition = lhs, |
| result = rhs |
| ), |
| IrElseBranchImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| condition = irConst(true), |
| result = irConst(false) |
| ) |
| ) |
| ) |
| } |
| |
| protected fun irXor(lhs: IrExpression, rhs: IrExpression): IrCallImpl { |
| val int = context.builtIns.intType |
| return irCall( |
| context.symbols.getBinaryOperator(OperatorNames.XOR, int, int), |
| null, |
| lhs, |
| null, |
| rhs |
| ) |
| } |
| |
| protected fun irReturn( |
| target: IrReturnTargetSymbol, |
| value: IrExpression, |
| type: IrType = value.type |
| ): IrExpression { |
| return IrReturnImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| type, |
| target, |
| value |
| ) |
| } |
| |
| protected fun irEqual(lhs: IrExpression, rhs: IrExpression): IrExpression { |
| return irCall( |
| context.irBuiltIns.eqeqeqSymbol, |
| null, |
| null, |
| null, |
| lhs, |
| rhs |
| ) |
| } |
| |
| protected fun irNot(value: IrExpression): IrExpression { |
| return irCall( |
| context.irBuiltIns.booleanNotSymbol, |
| dispatchReceiver = value |
| ) |
| } |
| |
| protected fun irNotEqual(lhs: IrExpression, rhs: IrExpression): IrExpression { |
| return irNot(irEqual(lhs, rhs)) |
| } |
| |
| // context.irIntrinsics.symbols.intAnd |
| // context.irIntrinsics.symbols.getBinaryOperator(name, lhs, rhs) |
| // context.irBuiltIns.booleanNotSymbol |
| // context.irBuiltIns.eqeqeqSymbol |
| // context.irBuiltIns.eqeqSymbol |
| // context.irBuiltIns.greaterFunByOperandType |
| |
| protected fun irConst(value: Int): IrConst<Int> = IrConstImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| context.irBuiltIns.intType, |
| IrConstKind.Int, |
| value |
| ) |
| |
| protected fun irConst(value: String): IrConst<String> = IrConstImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| context.irBuiltIns.stringType, |
| IrConstKind.String, |
| value |
| ) |
| |
| protected fun irConst(value: Boolean) = IrConstImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| context.irBuiltIns.booleanType, |
| IrConstKind.Boolean, |
| value |
| ) |
| |
| protected fun irNull() = IrConstImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| context.irBuiltIns.anyNType, |
| IrConstKind.Null, |
| null |
| ) |
| |
| protected fun irForLoop( |
| scope: DeclarationDescriptor, |
| elementType: IrType, |
| subject: IrExpression, |
| loopBody: (IrValueDeclaration) -> IrExpression |
| ): IrStatement { |
| val primitiveType = subject.type.getPrimitiveArrayElementType() |
| val iteratorSymbol = primitiveType?.let { |
| context.symbols.primitiveIteratorsByType[it] |
| } ?: context.symbols.iterator |
| val unitType = context.irBuiltIns.unitType |
| |
| subject.type.classOrNull!!.functions |
| .single { it.descriptor.name.asString() == "iterator" } |
| |
| val getIteratorSymbol = subject.type.classOrNull!!.functions |
| .single { it.descriptor.name.asString() == "iterator" } |
| |
| getIteratorSymbol.bindIfNecessary() |
| |
| if (getIteratorSymbol is IrConstructorSymbol) { |
| throw AssertionError("Should be IrConstructorCall: ${getIteratorSymbol.descriptor}") |
| } |
| getIteratorSymbol.descriptor.typeParametersCount |
| getIteratorSymbol.descriptor.valueParameters.size |
| |
| iteratorSymbol.owner.defaultType.classOrNull!!.functions |
| .single { it.descriptor.name.asString() == "next" } |
| val nextSymbol = iteratorSymbol.owner.defaultType.classOrNull!!.functions |
| .single { it.descriptor.name.asString() == "next" } |
| val hasNextSymbol = iteratorSymbol.owner.defaultType.classOrNull!!.functions |
| .single { it.descriptor.name.asString() == "hasNext" } |
| getIteratorSymbol.bindIfNecessary() |
| getIteratorSymbol.owner |
| |
| val call = IrCallImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| iteratorSymbol.typeWith(elementType), |
| getIteratorSymbol, |
| IrStatementOrigin.FOR_LOOP_ITERATOR |
| ) |
| |
| call.also { |
| it.dispatchReceiver = subject |
| } |
| |
| val iteratorVar = irTemporary( |
| containingDeclaration = scope, |
| value = call, |
| isVar = false, |
| name = "tmp0_iterator", |
| irType = iteratorSymbol.defaultType, |
| origin = IrDeclarationOrigin.FOR_LOOP_ITERATOR |
| ) |
| return irBlock( |
| type = unitType, |
| origin = IrStatementOrigin.FOR_LOOP, |
| statements = listOf( |
| iteratorVar, |
| IrWhileLoopImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| unitType, |
| IrStatementOrigin.FOR_LOOP_INNER_WHILE |
| ).apply { |
| val loopVar = irTemporary( |
| containingDeclaration = scope, |
| value = irCall( |
| symbol = nextSymbol, |
| origin = IrStatementOrigin.FOR_LOOP_NEXT, |
| dispatchReceiver = irGet(iteratorVar) |
| ), |
| origin = IrDeclarationOrigin.FOR_LOOP_VARIABLE, |
| isVar = false, |
| name = "value", |
| irType = elementType |
| ) |
| condition = irCall( |
| symbol = hasNextSymbol, |
| origin = IrStatementOrigin.FOR_LOOP_HAS_NEXT, |
| dispatchReceiver = irGet(iteratorVar) |
| ) |
| body = irBlock( |
| type = unitType, |
| origin = IrStatementOrigin.FOR_LOOP_INNER_WHILE, |
| statements = listOf( |
| loopVar, |
| loopBody(loopVar) |
| ) |
| ) |
| } |
| ) |
| ) |
| } |
| |
| protected fun irTemporary( |
| containingDeclaration: DeclarationDescriptor, |
| value: IrExpression, |
| name: String, |
| irType: IrType = value.type, |
| isVar: Boolean = false, |
| origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE |
| ): IrVariableImpl { |
| val tempVarDescriptor = IrTemporaryVariableDescriptorImpl( |
| containingDeclaration, |
| Name.identifier(name), |
| irType.toKotlinType(), |
| isVar |
| ) |
| return IrVariableImpl( |
| value.startOffset, |
| value.endOffset, |
| origin, |
| tempVarDescriptor, |
| irType, |
| value |
| ) |
| } |
| |
| protected fun irGet(type: IrType, symbol: IrValueSymbol): IrExpression { |
| return IrGetValueImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| type, |
| symbol |
| ) |
| } |
| |
| protected fun irGet(variable: IrValueDeclaration): IrExpression { |
| return irGet(variable.type, variable.symbol) |
| } |
| |
| protected fun irIf(condition: IrExpression, body: IrExpression): IrExpression { |
| return IrIfThenElseImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| context.irBuiltIns.unitType, |
| origin = IrStatementOrigin.IF |
| ).also { |
| it.branches.add( |
| IrBranchImpl(condition, body) |
| ) |
| } |
| } |
| |
| protected fun irIfThenElse( |
| type: IrType = context.irBuiltIns.unitType, |
| condition: IrExpression, |
| thenPart: IrExpression, |
| elsePart: IrExpression |
| ) = |
| IrIfThenElseImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, IrStatementOrigin.IF).apply { |
| branches.add(IrBranchImpl(startOffset, endOffset, condition, thenPart)) |
| branches.add(irElseBranch(elsePart)) |
| } |
| |
| protected fun irWhen( |
| type: IrType = context.irBuiltIns.unitType, |
| origin: IrStatementOrigin? = null, |
| branches: List<IrBranch> |
| ) = IrWhenImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| type, |
| origin, |
| branches |
| ) |
| protected fun irBranch( |
| condition: IrExpression, |
| result: IrExpression |
| ): IrBranch { |
| return IrBranchImpl(condition, result) |
| } |
| |
| protected fun irElseBranch(expression: IrExpression) = |
| IrElseBranchImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irConst(true), expression) |
| |
| protected fun irBlock( |
| type: IrType = context.irBuiltIns.unitType, |
| origin: IrStatementOrigin? = null, |
| statements: List<IrStatement> |
| ): IrExpression { |
| return IrBlockImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| type, |
| origin, |
| statements |
| ) |
| } |
| |
| protected fun irComposite( |
| type: IrType = context.irBuiltIns.unitType, |
| origin: IrStatementOrigin? = null, |
| statements: List<IrStatement> |
| ): IrExpression { |
| return IrCompositeImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| type, |
| origin, |
| statements |
| ) |
| } |
| |
| protected fun irLambda(function: IrFunction, type: IrType): IrExpression { |
| return irBlock( |
| type, |
| origin = IrStatementOrigin.LAMBDA, |
| statements = listOf( |
| function, |
| IrFunctionReferenceImpl( |
| UNDEFINED_OFFSET, |
| UNDEFINED_OFFSET, |
| type, |
| function.symbol, |
| function.typeParameters.size, |
| null, |
| IrStatementOrigin.LAMBDA |
| ) |
| ) |
| ) |
| } |
| } |
| |
| fun IrFunction.composerParam(): IrValueParameter? { |
| for (param in valueParameters.asReversed()) { |
| if (param.isComposerParam()) return param |
| if (!param.name.asString().startsWith('$')) return null |
| } |
| return null |
| } |
| |
| fun IrValueParameter.isComposerParam(): Boolean = |
| @Suppress("DEPRECATION") |
| (descriptor as? ValueParameterDescriptor)?.isComposerParam() ?: false |
| |
| fun ValueParameterDescriptor.isComposerParam(): Boolean = |
| name == KtxNameConventions.COMPOSER_PARAMETER && |
| type.constructor.declarationDescriptor?.fqNameSafe == ComposeFqNames.Composer |
| |
| object COMPOSE_STATEMENT_ORIGIN : IrStatementOriginImpl("COMPOSE_STATEMENT_ORIGIN") |