Safe calls.
This commit is contained in:
committed by
Dmitry Petrov
parent
985f3b20c7
commit
594a553a04
@@ -19,9 +19,13 @@ package org.jetbrains.kotlin.psi2ir
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi2ir.containsNull
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.isNullabilityFlexible
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
|
||||
fun IrVariable.defaultLoad(): IrExpression =
|
||||
IrGetVariableImpl(startOffset, endOffset, descriptor)
|
||||
IrGetVariableImpl(startOffset, endOffset, descriptor)
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
|
||||
fun KotlinType.containsNull() =
|
||||
KotlinTypeChecker.DEFAULT.isSubtypeOf(builtIns.nullableNothingType, this.upperIfFlexible())
|
||||
|
||||
fun KtElement.deparenthesize(): KtElement =
|
||||
if (this is KtExpression) KtPsiUtil.safeDeparenthesize(this) else this
|
||||
|
||||
val CallableDescriptor.explicitReceiverType: KotlinType?
|
||||
get() {
|
||||
extensionReceiverParameter?.let { return it.type }
|
||||
dispatchReceiverParameter?.let { return it.type }
|
||||
return null
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.isValueArgumentReorderingRequired(): Boolean {
|
||||
var lastValueParameterIndex = -1
|
||||
for (valueArgument in call.valueArguments) {
|
||||
val argumentMapping = getArgumentMapping(valueArgument)
|
||||
if (argumentMapping !is ArgumentMatch || argumentMapping.isError()) {
|
||||
throw AssertionError("Value argument in function call is mapped with error")
|
||||
}
|
||||
val argumentIndex = argumentMapping.valueParameter.index
|
||||
if (argumentIndex < lastValueParameterIndex) {
|
||||
return true
|
||||
}
|
||||
lastValueParameterIndex = argumentIndex
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
package org.jetbrains.kotlin.psi2ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModule
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.transformations.foldStringConcatenation
|
||||
import org.jetbrains.kotlin.psi2ir.transformations.inlineDesugaredBlocks
|
||||
import org.jetbrains.kotlin.psi2ir.transformations.insertImplicitCasts
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class Psi2IrTranslator(val configuration: Configuration = Configuration()) {
|
||||
@@ -39,8 +39,9 @@ class Psi2IrTranslator(val configuration: Configuration = Configuration()) {
|
||||
return irModule
|
||||
}
|
||||
|
||||
private fun postprocess(irElement: IrElement) {
|
||||
if (configuration.shouldInlineDesugaredBlocks) inlineDesugaredBlocks(irElement)
|
||||
if (configuration.shouldFoldStringConcatenation) foldStringConcatenation(irElement)
|
||||
private fun postprocess(irModule: IrModule) {
|
||||
insertImplicitCasts(irModule.irBuiltins.builtIns, irModule)
|
||||
if (configuration.shouldInlineDesugaredBlocks) inlineDesugaredBlocks(irModule)
|
||||
if (configuration.shouldFoldStringConcatenation) foldStringConcatenation(irModule)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.*
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
|
||||
fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): IntermediateValue? =
|
||||
receiver?.let { generateReceiver(ktDefaultElement, receiver) }
|
||||
|
||||
fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: ReceiverValue): IntermediateValue {
|
||||
val receiverExpression = when (receiver) {
|
||||
is ImplicitClassReceiver ->
|
||||
IrThisReferenceImpl(ktDefaultElement.startOffset, ktDefaultElement.startOffset, receiver.type, receiver.classDescriptor)
|
||||
is ThisClassReceiver ->
|
||||
(receiver as? ExpressionReceiver)?.expression?.let { receiverExpression ->
|
||||
IrThisReferenceImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type,
|
||||
receiver.classDescriptor)
|
||||
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
|
||||
is ExpressionReceiver ->
|
||||
generateExpression(receiver.expression)
|
||||
is ClassValueReceiver ->
|
||||
IrGetObjectValueImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
|
||||
receiver.classQualifier.descriptor)
|
||||
is ExtensionReceiver ->
|
||||
IrGetExtensionReceiverImpl(ktDefaultElement.startOffset, ktDefaultElement.startOffset, receiver.type,
|
||||
receiver.declarationDescriptor.extensionReceiverParameter!!)
|
||||
else ->
|
||||
TODO("Receiver: ${receiver.javaClass.simpleName}")
|
||||
}
|
||||
|
||||
return if (receiverExpression is IrExpressionWithCopy)
|
||||
RematerializableValue(receiverExpression)
|
||||
else
|
||||
OnceExpressionValue(receiverExpression)
|
||||
}
|
||||
|
||||
fun StatementGenerator.generateCallReceiver(
|
||||
ktDefaultElement: KtElement,
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
extensionReceiver: ReceiverValue?,
|
||||
isSafe: Boolean
|
||||
) : CallReceiver {
|
||||
val dispatchReceiverValue = generateReceiverOrNull(ktDefaultElement, dispatchReceiver)
|
||||
val extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver)
|
||||
|
||||
if (!isSafe) {
|
||||
return SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue)
|
||||
}
|
||||
else if (extensionReceiverValue != null) {
|
||||
return SafeCallReceiver(this, ktDefaultElement.startOffset, ktDefaultElement.endOffset,
|
||||
extensionReceiverValue.load(), dispatchReceiverValue)
|
||||
}
|
||||
else if (dispatchReceiverValue != null) {
|
||||
return SafeCallReceiver(this, ktDefaultElement.startOffset, ktDefaultElement.endOffset,
|
||||
dispatchReceiverValue.load(), null)
|
||||
}
|
||||
else {
|
||||
return throw AssertionError("Safe call should have an explicit receiver: ${ktDefaultElement.text}")
|
||||
}
|
||||
}
|
||||
|
||||
fun StatementGenerator.generateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? =
|
||||
when (valueArgument) {
|
||||
is DefaultValueArgument ->
|
||||
null
|
||||
is ExpressionValueArgument ->
|
||||
generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
|
||||
is VarargValueArgument ->
|
||||
createDummyExpression(valueArgument.arguments[0].getArgumentExpression()!!, "vararg")
|
||||
else ->
|
||||
TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}")
|
||||
}
|
||||
|
||||
fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>): PregeneratedCall {
|
||||
val call = pregenerateCallReceivers(resolvedCall)
|
||||
|
||||
resolvedCall.valueArgumentsByIndex!!.forEachIndexed { index, valueArgument ->
|
||||
call.irValueArgumentsByIndex[index] = generateValueArgument(valueArgument)
|
||||
}
|
||||
|
||||
return call
|
||||
}
|
||||
|
||||
fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): PregeneratedCall {
|
||||
val call = PregeneratedCall(resolvedCall)
|
||||
|
||||
val ktDefaultCallElement = resolvedCall.call.callElement
|
||||
call.callReceiver = generateCallReceiver(ktDefaultCallElement, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, resolvedCall.call.isSafeCall())
|
||||
|
||||
return call
|
||||
}
|
||||
+70
-133
@@ -16,109 +16,104 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.PregeneratedCall
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.getValueArgumentsInParameterOrder
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.isValueArgumentReorderingRequired
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
class CallGenerator(parentGenerator: StatementGenerator) : IrChildBodyGeneratorBase<StatementGenerator>(parentGenerator) {
|
||||
class CallGenerator(
|
||||
override val context: GeneratorContext,
|
||||
override val scope: Scope
|
||||
) : BodyGenerator {
|
||||
|
||||
constructor(parent: BodyGenerator) : this(parent.context, parent.scope)
|
||||
|
||||
fun generateCall(
|
||||
ktElement: KtElement,
|
||||
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
||||
operator: IrOperator? = null,
|
||||
superQualifier: ClassDescriptor? = null
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
call: PregeneratedCall,
|
||||
operator: IrOperator? = null
|
||||
): IrExpression {
|
||||
val descriptor = resolvedCall.resultingDescriptor
|
||||
val descriptor = call.descriptor
|
||||
|
||||
return when (descriptor) {
|
||||
is PropertyDescriptor ->
|
||||
generatePropertyGetterCall(descriptor, ktElement, resolvedCall)
|
||||
generatePropertyGetterCall(descriptor, startOffset, endOffset, call)
|
||||
is FunctionDescriptor ->
|
||||
generateFunctionCall(descriptor, ktElement, operator, resolvedCall, superQualifier)
|
||||
generateFunctionCall(descriptor, startOffset, endOffset, operator, call)
|
||||
else ->
|
||||
TODO("Unexpected callable descriptor: $descriptor ${descriptor.javaClass.simpleName}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun CallGenerator.generatePropertyGetterCall(
|
||||
private fun generatePropertyGetterCall(
|
||||
descriptor: PropertyDescriptor,
|
||||
ktElement: KtElement,
|
||||
resolvedCall: ResolvedCall<*>
|
||||
): IrGetterCallImpl {
|
||||
val returnType = getReturnType(resolvedCall)
|
||||
val dispatchReceiver = generateReceiver(ktElement, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter)
|
||||
val extensionReceiver = generateReceiver(ktElement, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter)
|
||||
return IrGetterCallImpl(ktElement.startOffset, ktElement.endOffset,
|
||||
returnType, descriptor.getter!!, resolvedCall.call.isSafeCall(),
|
||||
dispatchReceiver, extensionReceiver, IrOperator.GET_PROPERTY)
|
||||
}
|
||||
|
||||
private fun ResolvedCall<*>.requiresArgumentReordering(): Boolean {
|
||||
var lastValueParameterIndex = -1
|
||||
for (valueArgument in call.valueArguments) {
|
||||
val argumentMapping = getArgumentMapping(valueArgument)
|
||||
if (argumentMapping !is ArgumentMatch || argumentMapping.isError()) {
|
||||
error("Value argument in function call is mapped with error")
|
||||
}
|
||||
val argumentIndex = argumentMapping.valueParameter.index
|
||||
if (argumentIndex < lastValueParameterIndex) return true
|
||||
lastValueParameterIndex = argumentIndex
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
call: PregeneratedCall
|
||||
): IrExpression {
|
||||
return call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
IrGetterCallImpl(startOffset, endOffset, descriptor.getter!!,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
IrOperator.GET_PROPERTY)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun generateFunctionCall(
|
||||
descriptor: FunctionDescriptor,
|
||||
ktElement: KtElement,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
operator: IrOperator?,
|
||||
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
||||
superQualifier: ClassDescriptor?
|
||||
call: PregeneratedCall
|
||||
): IrExpression {
|
||||
val returnType = descriptor.returnType
|
||||
|
||||
val irCall = IrCallImpl(
|
||||
ktElement.startOffset, ktElement.endOffset, returnType,
|
||||
descriptor, resolvedCall.call.isSafeCall(), operator, superQualifier
|
||||
)
|
||||
irCall.dispatchReceiver = generateReceiver(ktElement, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter)
|
||||
irCall.extensionReceiver = generateReceiver(ktElement, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter)
|
||||
return call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val irCall = IrCallImpl(startOffset, endOffset, returnType, descriptor, operator, call.superQualifier)
|
||||
irCall.dispatchReceiver = dispatchReceiverValue?.load()
|
||||
irCall.extensionReceiver = extensionReceiverValue?.load()
|
||||
|
||||
return if (resolvedCall.requiresArgumentReordering()) {
|
||||
generateCallWithArgumentReordering(irCall, ktElement, resolvedCall, returnType)
|
||||
}
|
||||
else {
|
||||
val valueArguments = resolvedCall.valueArgumentsByIndex
|
||||
for (index in valueArguments!!.indices) {
|
||||
val valueArgument = valueArguments[index]
|
||||
val valueParameter = descriptor.valueParameters[index]
|
||||
val irArgument = generateValueArgument(valueArgument, valueParameter) ?: continue
|
||||
irCall.putArgument(index, irArgument)
|
||||
}
|
||||
irCall
|
||||
val irCallWithReordering =
|
||||
if (call.isValueArgumentReorderingRequired()) {
|
||||
generateCallWithArgumentReordering(irCall, startOffset, endOffset, call, returnType)
|
||||
}
|
||||
else {
|
||||
val valueArguments = call.getValueArgumentsInParameterOrder()
|
||||
for ((index, valueArgument) in valueArguments.withIndex()) {
|
||||
irCall.putArgument(index, valueArgument)
|
||||
}
|
||||
irCall
|
||||
}
|
||||
|
||||
irCallWithReordering
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateCallWithArgumentReordering(
|
||||
irCall: IrCall,
|
||||
ktElement: KtElement,
|
||||
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
call: PregeneratedCall,
|
||||
resultType: KotlinType?
|
||||
): IrExpression {
|
||||
// TODO use IrLetExpression?
|
||||
val resolvedCall = call.original
|
||||
|
||||
val valueArgumentsInEvaluationOrder = resolvedCall.valueArguments.values
|
||||
val valueParameters = resolvedCall.resultingDescriptor.valueParameters
|
||||
|
||||
val hasResult = isUsedAsExpression(ktElement)
|
||||
val irBlock = IrBlockImpl(ktElement.startOffset, ktElement.endOffset, resultType, hasResult,
|
||||
IrOperator.SYNTHETIC_BLOCK)
|
||||
val irBlock = IrBlockImpl(startOffset, endOffset, resultType, true, IrOperator.SYNTHETIC_BLOCK)
|
||||
|
||||
val valueArgumentsToValueParameters = HashMap<ResolvedValueArgument, ValueParameterDescriptor>()
|
||||
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
|
||||
@@ -126,86 +121,28 @@ class CallGenerator(parentGenerator: StatementGenerator) : IrChildBodyGeneratorB
|
||||
valueArgumentsToValueParameters[valueArgument] = valueParameter
|
||||
}
|
||||
|
||||
val reorderingScope = Scope(this.scope)
|
||||
val irArgumentValues = HashMap<ValueParameterDescriptor, IntermediateValue>()
|
||||
|
||||
for (valueArgument in valueArgumentsInEvaluationOrder) {
|
||||
val valueParameter = valueArgumentsToValueParameters[valueArgument]!!
|
||||
val irArgument = generateValueArgument(valueArgument, valueParameter) ?: continue
|
||||
val irTmpArg = reorderingScope.introduceTemporary(valueParameter, irArgument)
|
||||
irBlock.addIfNotNull(irTmpArg)
|
||||
val irArgument = call.getValueArgument(valueParameter) ?: continue
|
||||
val irArgumentValue = createRematerializableOrTemporary(scope, irArgument, irBlock, valueParameter.name.asString())
|
||||
irArgumentValues[valueParameter] = irArgumentValue
|
||||
}
|
||||
|
||||
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
|
||||
resolvedCall.valueArgumentsByIndex!!.forEachIndexed { index, valueArgument ->
|
||||
val valueParameter = valueParameters[index]
|
||||
val irGetTemporary = reorderingScope.valueOf(valueParameter)!!
|
||||
irCall.putArgument(index, toExpectedType(irGetTemporary, valueParameter.type))
|
||||
irCall.putArgument(index, irArgumentValues[valueParameter]?.load())
|
||||
}
|
||||
|
||||
irBlock.addStatement(irCall)
|
||||
|
||||
return irBlock
|
||||
}
|
||||
|
||||
fun generateReceiver(ktElement: KtElement, receiver: ReceiverValue?, receiverParameterDescriptor: ReceiverParameterDescriptor?) =
|
||||
generateReceiver(ktElement, receiver, receiverParameterDescriptor?.type)
|
||||
|
||||
fun generateReceiver(ktElement: KtElement, receiver: ReceiverValue?, expectedType: KotlinType?) =
|
||||
toExpectedTypeOrNull(generateReceiver(ktElement, receiver), expectedType)
|
||||
|
||||
fun generateReceiver(ktElement: KtElement, receiver: ReceiverValue?): IrExpression? =
|
||||
if (receiver == null)
|
||||
null
|
||||
else
|
||||
scope.valueOf(receiver) ?: doGenerateReceiver(ktElement, receiver)
|
||||
|
||||
fun doGenerateReceiver(ktElement: KtElement, receiver: ReceiverValue?): IrExpression? =
|
||||
when (receiver) {
|
||||
is ImplicitClassReceiver ->
|
||||
IrThisReferenceImpl(ktElement.startOffset, ktElement.startOffset, receiver.type, receiver.classDescriptor)
|
||||
is ThisClassReceiver ->
|
||||
(receiver as? ExpressionReceiver)?.expression?.let { receiverExpression ->
|
||||
IrThisReferenceImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor)
|
||||
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
|
||||
is ExpressionReceiver ->
|
||||
generateExpression(receiver.expression)
|
||||
is ClassValueReceiver ->
|
||||
IrGetObjectValueImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
|
||||
receiver.classQualifier.descriptor)
|
||||
is ExtensionReceiver ->
|
||||
IrGetExtensionReceiverImpl(ktElement.startOffset, ktElement.startOffset, receiver.type,
|
||||
receiver.declarationDescriptor.extensionReceiverParameter!!)
|
||||
null ->
|
||||
null
|
||||
else ->
|
||||
TODO("Receiver: ${receiver.javaClass.simpleName}")
|
||||
}
|
||||
|
||||
fun generateValueArgument(valueArgument: ResolvedValueArgument, valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
|
||||
generateValueArgument(valueArgument, valueParameterDescriptor, valueParameterDescriptor.type)
|
||||
|
||||
fun generateValueArgument(valueArgument: ResolvedValueArgument, valueParameterDescriptor: ValueParameterDescriptor, expectedType: KotlinType): IrExpression? =
|
||||
if (valueParameterDescriptor.varargElementType != null)
|
||||
doGenerateValueArgument(valueArgument, valueParameterDescriptor)
|
||||
else
|
||||
toExpectedTypeOrNull(doGenerateValueArgument(valueArgument, valueParameterDescriptor), expectedType)
|
||||
|
||||
private fun doGenerateValueArgument(valueArgument: ResolvedValueArgument, valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
|
||||
if (valueArgument is DefaultValueArgument)
|
||||
null
|
||||
else
|
||||
scope.valueOf(valueParameterDescriptor) ?: doGenerateValueArgument(valueArgument)
|
||||
|
||||
private fun doGenerateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? =
|
||||
when (valueArgument) {
|
||||
is ExpressionValueArgument ->
|
||||
generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
|
||||
is VarargValueArgument ->
|
||||
createDummyExpression(valueArgument.arguments[0].getArgumentExpression()!!, "vararg")
|
||||
else ->
|
||||
TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}")
|
||||
}
|
||||
|
||||
private fun generateExpression(ktExpression: KtExpression): IrExpression =
|
||||
scope.valueOf(ktExpression) ?: parentGenerator.generateExpression(ktExpression)
|
||||
|
||||
}
|
||||
|
||||
fun CallGenerator.generateCall(ktElement: KtElement, call: PregeneratedCall, operator: IrOperator? = null) =
|
||||
generateCall(ktElement.startOffset, ktElement.endOffset, call, operator)
|
||||
|
||||
fun CallGenerator.generateCall(irExpression: IrExpression, call: PregeneratedCall, operator: IrOperator? = null) =
|
||||
generateCall(irExpression.startOffset, irExpression.endOffset, call, operator)
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class DeclarationGenerator(override val context: GeneratorContext) : IrGenerator {
|
||||
class DeclarationGenerator(override val context: GeneratorContext) : Generator {
|
||||
fun generateAnnotationEntries(annotationEntries: List<KtAnnotationEntry>) {
|
||||
// TODO create IrAnnotation's for each KtAnnotationEntry
|
||||
}
|
||||
|
||||
+4
-4
@@ -25,13 +25,13 @@ import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
|
||||
class ExpressionBodyGenerator(val scopeOwner: CallableDescriptor, override val context: GeneratorContext): IrBodyGenerator {
|
||||
override val scope = Scope.rootScope(scopeOwner, this)
|
||||
class ExpressionBodyGenerator(val scopeOwner: CallableDescriptor, override val context: GeneratorContext): BodyGenerator {
|
||||
override val scope = Scope(scopeOwner)
|
||||
|
||||
fun generateFunctionBody(ktBody: KtExpression): IrExpression {
|
||||
resetInternalContext()
|
||||
|
||||
val irBodyExpression = createStatementGenerator().generateExpressionWithExpectedType(ktBody, scopeOwner.returnType)
|
||||
val irBodyExpression = createStatementGenerator().generateExpression(ktBody)
|
||||
|
||||
val irBodyExpressionAsBlock =
|
||||
if (ktBody is KtBlockExpression)
|
||||
@@ -52,7 +52,7 @@ class ExpressionBodyGenerator(val scopeOwner: CallableDescriptor, override val c
|
||||
}
|
||||
|
||||
fun generatePropertyInitializerBody(ktInitializer: KtExpression): IrExpression =
|
||||
createStatementGenerator().generateExpressionWithExpectedType(ktInitializer, scopeOwner.returnType!!)
|
||||
createStatementGenerator().generateExpression(ktInitializer)
|
||||
|
||||
private fun createStatementGenerator() =
|
||||
StatementGenerator(context, scopeOwner, this, scope)
|
||||
|
||||
+24
-21
@@ -35,35 +35,38 @@ import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
|
||||
import java.lang.AssertionError
|
||||
import java.lang.RuntimeException
|
||||
|
||||
interface IrGenerator {
|
||||
|
||||
interface Generator {
|
||||
val context: GeneratorContext
|
||||
}
|
||||
|
||||
fun <K, V : Any> IrGenerator.get(slice: ReadOnlySlice<K, V>, key: K): V? =
|
||||
interface BodyGenerator : Generator {
|
||||
val scope: Scope
|
||||
}
|
||||
|
||||
|
||||
fun <K, V : Any> Generator.get(slice: ReadOnlySlice<K, V>, key: K): V? =
|
||||
context.bindingContext[slice, key]
|
||||
|
||||
fun <K, V : Any> IrGenerator.getOrFail(slice: ReadOnlySlice<K, V>, key: K): V =
|
||||
fun <K, V : Any> Generator.getOrFail(slice: ReadOnlySlice<K, V>, key: K): V =
|
||||
context.bindingContext[slice, key] ?: throw RuntimeException("No $slice for $key")
|
||||
|
||||
inline fun <K, V : Any> IrGenerator.getOrFail(slice: ReadOnlySlice<K, V>, key: K, message: (K) -> String): V =
|
||||
inline fun <K, V : Any> Generator.getOrFail(slice: ReadOnlySlice<K, V>, key: K, message: (K) -> String): V =
|
||||
context.bindingContext[slice, key] ?: throw RuntimeException(message(key))
|
||||
|
||||
fun IrGenerator.getInferredTypeWithSmartcasts(key: KtExpression): KotlinType? =
|
||||
fun Generator.getInferredTypeWithSmartcasts(key: KtExpression): KotlinType? =
|
||||
context.bindingContext.getType(key)
|
||||
|
||||
fun IrGenerator.getExpectedTypeForLastInferredCall(key: KtExpression): KotlinType? =
|
||||
get(BindingContext.EXPECTED_EXPRESSION_TYPE, key)
|
||||
fun Generator.getInferredTypeWithSmartcastsOrFail(key: KtExpression): KotlinType =
|
||||
getInferredTypeWithSmartcasts(key) ?: throw AssertionError("No type for expression: ${key.text}")
|
||||
|
||||
fun IrGenerator.getInferredTypeWithSmarcastsOrFail(key: KtExpression): KotlinType =
|
||||
getInferredTypeWithSmartcasts(key) ?: TODO("No type for expression: ${key.text}")
|
||||
|
||||
fun IrGenerator.isUsedAsExpression(ktElement: KtElement) =
|
||||
fun Generator.isUsedAsExpression(ktElement: KtElement) =
|
||||
get(BindingContext.USED_AS_EXPRESSION, ktElement) ?: false
|
||||
|
||||
fun IrGenerator.getResolvedCall(key: KtExpression): ResolvedCall<out CallableDescriptor>? =
|
||||
fun Generator.getResolvedCall(key: KtExpression): ResolvedCall<out CallableDescriptor>? =
|
||||
key.getResolvedCall(context.bindingContext)
|
||||
|
||||
fun IrGenerator.getReturnType(key: KtExpression): KotlinType? {
|
||||
fun Generator.getReturnType(key: KtExpression): KotlinType? {
|
||||
val resolvedCall = getResolvedCall(key)
|
||||
if (resolvedCall != null) {
|
||||
return getReturnType(resolvedCall)
|
||||
@@ -78,21 +81,21 @@ fun IrGenerator.getReturnType(key: KtExpression): KotlinType? {
|
||||
}
|
||||
|
||||
fun getReturnType(resolvedCall: ResolvedCall<*>): KotlinType {
|
||||
val descriptor = resolvedCall.resultingDescriptor
|
||||
val returnType = getReturnType(resolvedCall.resultingDescriptor)
|
||||
return if (resolvedCall.call.isSafeCall()) returnType.makeNullable() else returnType
|
||||
}
|
||||
|
||||
fun getReturnType(descriptor: CallableDescriptor): KotlinType {
|
||||
return when (descriptor) {
|
||||
is ClassDescriptor ->
|
||||
descriptor.classValueType ?: throw AssertionError("Class descriptor without companion object: $descriptor")
|
||||
is CallableDescriptor -> {
|
||||
val returnType = descriptor.returnType ?: throw AssertionError("Callable descriptor without return type: $descriptor")
|
||||
if (resolvedCall.call.isSafeCall())
|
||||
returnType.makeNullable()
|
||||
else
|
||||
returnType
|
||||
descriptor.returnType ?: throw AssertionError("Callable descriptor without return type: $descriptor")
|
||||
}
|
||||
else ->
|
||||
throw AssertionError("Unexpected desciptor in resolved call: $descriptor")
|
||||
throw AssertionError("Unexpected descriptor in resolved call: $descriptor")
|
||||
}
|
||||
}
|
||||
|
||||
fun IrGenerator.createDummyExpression(ktExpression: KtExpression, description: String): IrDummyExpression =
|
||||
fun Generator.createDummyExpression(ktExpression: KtExpression, description: String): IrDummyExpression =
|
||||
IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, getInferredTypeWithSmartcasts(ktExpression), description)
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.assertCast
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
class IrBlockBuilder(val startOffset: Int, val endOffset: Int, val irOperator: IrOperator, val generator: IrBodyGenerator) {
|
||||
private val statements = SmartList<IrStatement>()
|
||||
private var resultType: KotlinType? = null
|
||||
private var hasResult = false
|
||||
val scope: Scope get() = generator.scope
|
||||
|
||||
fun <T : IrStatement?> add(irStatement: T): T {
|
||||
if (irStatement != null) {
|
||||
statements.add(irStatement)
|
||||
}
|
||||
return irStatement
|
||||
}
|
||||
|
||||
fun <T : IrExpression> result(irExpression: T): T {
|
||||
resultType = irExpression.type
|
||||
hasResult = true
|
||||
statements.add(irExpression)
|
||||
return irExpression
|
||||
}
|
||||
|
||||
fun build() =
|
||||
if (statements.size == 1)
|
||||
statements[0]
|
||||
else {
|
||||
val block = IrBlockImpl(startOffset, endOffset, resultType, hasResult, irOperator)
|
||||
statements.forEach { block.addStatement(it) }
|
||||
block
|
||||
}
|
||||
}
|
||||
|
||||
fun IrBodyGenerator.block(ktElement: KtElement, irOperator: IrOperator, body: IrBlockBuilder.() -> Unit): IrExpression =
|
||||
IrBlockBuilder(ktElement.startOffset, ktElement.endOffset, irOperator, this).apply(body).build().assertCast()
|
||||
|
||||
fun IrBodyGenerator.block(irExpression: IrExpression, irOperator: IrOperator, body: IrBlockBuilder.() -> Unit): IrExpression =
|
||||
IrBlockBuilder(irExpression.startOffset, irExpression.endOffset, irOperator, this).apply(body).build().assertCast()
|
||||
|
||||
fun IrBlockBuilder.constType(constKind: IrConstKind<*>): KotlinType =
|
||||
when (constKind) {
|
||||
IrConstKind.Null -> generator.context.builtIns.nullableNothingType
|
||||
IrConstKind.Boolean -> generator.context.builtIns.anyType
|
||||
IrConstKind.Byte -> generator.context.builtIns.byteType
|
||||
IrConstKind.Short -> generator.context.builtIns.shortType
|
||||
IrConstKind.Int -> generator.context.builtIns.intType
|
||||
IrConstKind.Long -> generator.context.builtIns.longType
|
||||
IrConstKind.String -> generator.context.builtIns.stringType
|
||||
IrConstKind.Float -> generator.context.builtIns.floatType
|
||||
IrConstKind.Double -> generator.context.builtIns.doubleType
|
||||
}
|
||||
|
||||
fun <T> IrBlockBuilder.const(constKind: IrConstKind<T>, value: T) =
|
||||
IrConstImpl(startOffset, endOffset, constType(constKind), constKind, value)
|
||||
|
||||
fun IrBlockBuilder.constNull() =
|
||||
const(IrConstKind.Null, null)
|
||||
|
||||
fun IrBlockBuilder.op0(operatorDescriptor: CallableDescriptor) =
|
||||
IrNullaryOperatorImpl(startOffset, endOffset, irOperator, operatorDescriptor)
|
||||
|
||||
fun IrBlockBuilder.op1(operatorDescriptor: CallableDescriptor, argument: IrExpression) =
|
||||
IrUnaryOperatorImpl(startOffset, endOffset, irOperator, operatorDescriptor, argument)
|
||||
|
||||
fun IrBlockBuilder.op2(operatorDescriptor: CallableDescriptor, argument1: IrExpression, argument2: IrExpression) =
|
||||
IrBinaryOperatorImpl(startOffset, endOffset, irOperator, operatorDescriptor, argument1, argument2)
|
||||
|
||||
fun IrBlockBuilder.equalsNull(argument: IrExpression) =
|
||||
op2(generator.context.irBuiltIns.eqeq, argument, constNull())
|
||||
|
||||
fun IrBlockBuilder.ifThenElse(type: KotlinType?, condition: IrExpression, thenBranch: IrExpression, elseBranch: IrExpression) =
|
||||
IrIfThenElseImpl(startOffset, endOffset, type, condition, thenBranch, elseBranch, irOperator)
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.isNullabilityFlexible
|
||||
|
||||
interface IrBodyGenerator : IrGenerator {
|
||||
val scope: Scope
|
||||
}
|
||||
|
||||
abstract class IrChildBodyGeneratorBase<out T : IrBodyGenerator>(
|
||||
val parentGenerator: T
|
||||
) : IrBodyGenerator {
|
||||
override val context: GeneratorContext get() = parentGenerator.context
|
||||
override val scope: Scope = Scope(parentGenerator.scope)
|
||||
}
|
||||
|
||||
fun IrBodyGenerator.toExpectedType(irExpression: IrExpression, expectedType: KotlinType?): IrExpression {
|
||||
if (irExpression is IrBlock && !irExpression.hasResult) return irExpression
|
||||
|
||||
if (expectedType == null) return irExpression
|
||||
if (KotlinBuiltIns.isUnit(expectedType)) return irExpression // TODO expose coercion to Unit in IR?
|
||||
|
||||
val valueType = irExpression.type ?: throw AssertionError("expectedType != null, valueType == null: $this")
|
||||
|
||||
if (valueType.isNullabilityFlexible() && !expectedType.isMarkedNullable) {
|
||||
return block(irExpression, IrOperator.IMPLICIT_NOTNULL) {
|
||||
add(scope.introduceTemporary(irExpression))
|
||||
result(ifThenElse(expectedType,
|
||||
equalsNull(scope.valueOf(irExpression)!!),
|
||||
op0(context.irBuiltIns.throwNpe),
|
||||
scope.valueOf(irExpression)!!))
|
||||
}
|
||||
}
|
||||
|
||||
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) {
|
||||
return IrTypeOperatorCallImpl(irExpression.startOffset, irExpression.endOffset, expectedType,
|
||||
IrTypeOperator.IMPLICIT_CAST, expectedType, irExpression)
|
||||
}
|
||||
|
||||
return irExpression
|
||||
}
|
||||
|
||||
fun StatementGenerator.generateExpressionWithExpectedType(ktExpression: KtExpression, expectedType: KotlinType?) =
|
||||
toExpectedType(generateExpression(ktExpression), expectedType)
|
||||
|
||||
fun IrBodyGenerator.toExpectedTypeOrNull(irExpression: IrExpression?, expectedType: KotlinType?): IrExpression? =
|
||||
irExpression?.let { toExpectedType(it, expectedType) }
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class ModuleGenerator(override val context: GeneratorContext) : IrGenerator {
|
||||
class ModuleGenerator(override val context: GeneratorContext) : Generator {
|
||||
fun generateModule(ktFiles: List<KtFile>): IrModule {
|
||||
val irDeclarationGenerator = DeclarationGenerator(context)
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.generators.operators
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||
+119
-99
@@ -25,15 +25,19 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.defaultLoad
|
||||
import org.jetbrains.kotlin.psi2ir.generators.operators.*
|
||||
import org.jetbrains.kotlin.psi2ir.generators.values.*
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import java.lang.AssertionError
|
||||
|
||||
|
||||
class OperatorExpressionGenerator(
|
||||
val statementGenerator: StatementGenerator
|
||||
) : BodyGenerator {
|
||||
override val scope: Scope get() = statementGenerator.scope
|
||||
override val context: GeneratorContext get() = statementGenerator.context
|
||||
|
||||
class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChildBodyGeneratorBase<StatementGenerator>(parentGenerator) {
|
||||
fun generatePrefixExpression(expression: KtPrefixExpression): IrExpression {
|
||||
val ktOperator = expression.operationReference.getReferencedNameElementType()
|
||||
val irOperator = getPrefixOperator(ktOperator)
|
||||
@@ -72,7 +76,7 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
}
|
||||
|
||||
return IrTypeOperatorCallImpl(expression.startOffset, expression.endOffset, resultType, irOperator, rhsType,
|
||||
parentGenerator.generateExpression(expression.left))
|
||||
statementGenerator.generateExpression(expression.left))
|
||||
}
|
||||
|
||||
fun generateInstanceOfExpression(expression: KtIsExpression): IrStatement {
|
||||
@@ -81,7 +85,7 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
val againstType = getOrFail(BindingContext.TYPE, expression.typeReference)
|
||||
|
||||
return IrTypeOperatorCallImpl(expression.startOffset, expression.endOffset, context.builtIns.booleanType, irOperator,
|
||||
againstType, parentGenerator.generateExpression(expression.leftHandSide))
|
||||
againstType, statementGenerator.generateExpression(expression.leftHandSide))
|
||||
}
|
||||
|
||||
fun generateBinaryExpression(expression: KtBinaryExpression): IrExpression {
|
||||
@@ -110,25 +114,28 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
private fun generateElvis(expression: KtBinaryExpression): IrExpression {
|
||||
val specialCallForElvis = getResolvedCall(expression)!!
|
||||
val returnType = specialCallForElvis.resultingDescriptor.returnType!!
|
||||
val irArgument0 = parentGenerator.generateExpressionWithExpectedType(expression.left!!, returnType.makeNullable())
|
||||
val irArgument1 = parentGenerator.generateExpressionWithExpectedType(expression.right!!, returnType)
|
||||
return block(expression, IrOperator.ELVIS) {
|
||||
add(scope.introduceTemporary(irArgument0))
|
||||
result(ifThenElse(returnType,
|
||||
equalsNull(scope.valueOf(irArgument0)!!),
|
||||
irArgument1,
|
||||
scope.valueOf(irArgument0)!!))
|
||||
}
|
||||
val irArgument0 = statementGenerator.generateExpression(expression.left!!)
|
||||
val irArgument1 = statementGenerator.generateExpression(expression.right!!)
|
||||
|
||||
val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, returnType, true, IrOperator.ELVIS)
|
||||
val irArgument0Value = createRematerializableOrTemporary(scope, irArgument0, irBlock, "elvis_lhs")
|
||||
irBlock.addStatement(IrIfThenElseImpl(
|
||||
expression.startOffset, expression.endOffset, returnType,
|
||||
equalsNull(expression.startOffset, expression.endOffset, irArgument0Value.load()),
|
||||
irArgument1,
|
||||
irArgument0Value.load()
|
||||
))
|
||||
return irBlock
|
||||
}
|
||||
|
||||
private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
|
||||
val irArgument0 = parentGenerator.generateExpressionWithExpectedType(expression.left!!, context.builtIns.booleanType)
|
||||
val irArgument1 = parentGenerator.generateExpressionWithExpectedType(expression.right!!, context.builtIns.booleanType)
|
||||
val irArgument0 = statementGenerator.generateExpression(expression.left!!)
|
||||
val irArgument1 = statementGenerator.generateExpression(expression.right!!)
|
||||
return when (irOperator) {
|
||||
IrOperator.OROR ->
|
||||
IrIfThenElseImpl.oror(expression.startOffset, expression.endOffset, irArgument0, irArgument1)
|
||||
oror(expression.startOffset, expression.endOffset, irArgument0, irArgument1)
|
||||
IrOperator.ANDAND ->
|
||||
IrIfThenElseImpl.andand(expression.startOffset, expression.endOffset, irArgument0, irArgument1)
|
||||
andand(expression.startOffset, expression.endOffset, irArgument0, irArgument1)
|
||||
else ->
|
||||
throw AssertionError("Unexpected binary boolean operator $irOperator")
|
||||
}
|
||||
@@ -137,7 +144,7 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
private fun generateInOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
|
||||
val containsCall = getResolvedCall(expression)!!
|
||||
|
||||
val irContainsCall = CallGenerator(parentGenerator).generateCall(expression, containsCall, irOperator)
|
||||
val irContainsCall = CallGenerator(this).generateCall(expression, statementGenerator.pregenerateCall(containsCall), irOperator)
|
||||
|
||||
return when (irOperator) {
|
||||
IrOperator.IN ->
|
||||
@@ -152,8 +159,8 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
}
|
||||
|
||||
private fun generateIdentityOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
|
||||
val irArgument0 = parentGenerator.generateExpression(expression.left!!)
|
||||
val irArgument1 = parentGenerator.generateExpression(expression.right!!)
|
||||
val irArgument0 = statementGenerator.generateExpression(expression.left!!)
|
||||
val irArgument1 = statementGenerator.generateExpression(expression.right!!)
|
||||
|
||||
|
||||
val irIdentityEquals = IrBinaryOperatorImpl(expression.startOffset, expression.endOffset, irOperator, context.irBuiltIns.eqeqeq,
|
||||
@@ -172,8 +179,8 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
}
|
||||
|
||||
private fun generateEqualityOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
|
||||
val irArgument0 = parentGenerator.generateExpression(expression.left!!)
|
||||
val irArgument1 = parentGenerator.generateExpression(expression.right!!)
|
||||
val irArgument0 = statementGenerator.generateExpression(expression.left!!)
|
||||
val irArgument1 = statementGenerator.generateExpression(expression.right!!)
|
||||
|
||||
val irEquals = IrBinaryOperatorImpl(expression.startOffset, expression.endOffset,
|
||||
irOperator, context.irBuiltIns.eqeq, irArgument0, irArgument1)
|
||||
@@ -193,8 +200,7 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
private fun generateComparisonOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
|
||||
val compareToCall = getResolvedCall(expression)!!
|
||||
|
||||
val irCallGenerator = CallGenerator(parentGenerator)
|
||||
val irCompareToCall = irCallGenerator.generateCall(expression, compareToCall, irOperator)
|
||||
val irCompareToCall = CallGenerator(this).generateCall(expression, statementGenerator.pregenerateCall(compareToCall), irOperator)
|
||||
|
||||
val compareToZeroDescriptor = when (irOperator) {
|
||||
IrOperator.LT -> context.irBuiltIns.lt0
|
||||
@@ -210,99 +216,102 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
|
||||
private fun generateBinaryOperatorAsCall(expression: KtBinaryExpression, irOperator: IrOperator?): IrExpression {
|
||||
val operatorCall = getResolvedCall(expression)!!
|
||||
return CallGenerator(parentGenerator).generateCall(expression, operatorCall, irOperator)
|
||||
return CallGenerator(this).generateCall(expression, statementGenerator.pregenerateCall(operatorCall), irOperator)
|
||||
}
|
||||
|
||||
private fun generatePrefixIncrementDecrementOperator(expression: KtPrefixExpression, irOperator: IrOperator): IrExpression {
|
||||
val opResolvedCall = getResolvedCall(expression)!!
|
||||
val ktBaseExpression = expression.baseExpression!!
|
||||
val irLValue = generateLValue(ktBaseExpression, irOperator)
|
||||
val operatorCall = getResolvedCall(expression)!!
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktBaseExpression, irOperator)
|
||||
|
||||
if (irLValue is IrLValueWithAugmentedStore) {
|
||||
return irLValue.prefixAugmentedStore(operatorCall, irOperator)
|
||||
return irAssignmentReceiver.assign { irLValue ->
|
||||
val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, irLValue.type, true, irOperator)
|
||||
|
||||
// VAR tmp = [lhs].inc()
|
||||
val opCall = statementGenerator.pregenerateCall(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(irLValue)
|
||||
val irOpCall = CallGenerator(this).generateCall(expression, opCall, irOperator)
|
||||
val irTmp = statementGenerator.scope.createTemporaryVariable(irOpCall)
|
||||
irBlock.addStatement(irTmp)
|
||||
|
||||
// [lhs] = tmp
|
||||
irBlock.addStatement(irLValue.store(irTmp.defaultLoad()))
|
||||
|
||||
// ^ tmp
|
||||
irBlock.addStatement(irTmp.defaultLoad())
|
||||
|
||||
irBlock
|
||||
}
|
||||
|
||||
val opCallGenerator = CallGenerator(parentGenerator).apply { scope.putValue(ktBaseExpression, irLValue) }
|
||||
val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, irLValue.type, true, irOperator)
|
||||
val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator)
|
||||
val irTmp = parentGenerator.scope.createTemporaryVariable(irOpCall)
|
||||
irBlock.addStatement(irTmp)
|
||||
irBlock.addStatement(irLValue.store(irTmp.defaultLoad()))
|
||||
irBlock.addStatement(irTmp.defaultLoad())
|
||||
return irBlock
|
||||
}
|
||||
|
||||
private fun generatePostfixIncrementDecrementOperator(expression: KtPostfixExpression, irOperator: IrOperator): IrExpression {
|
||||
val opResolvedCall = getResolvedCall(expression)!!
|
||||
val ktBaseExpression = expression.baseExpression!!
|
||||
val irLValue = generateLValue(ktBaseExpression, irOperator)
|
||||
val operatorCall = getResolvedCall(expression)!!
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktBaseExpression, irOperator)
|
||||
|
||||
if (irLValue is IrLValueWithAugmentedStore) {
|
||||
return irLValue.postfixAugmentedStore(operatorCall, irOperator)
|
||||
return irAssignmentReceiver.assign { irLValue ->
|
||||
val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, irLValue.type, true, irOperator)
|
||||
|
||||
// VAR tmp = [lhs]
|
||||
val irTmp = scope.createTemporaryVariable(irLValue.load())
|
||||
irBlock.addStatement(irTmp)
|
||||
|
||||
// [lhs] = tmp.inc()
|
||||
val opCall = statementGenerator.pregenerateCall(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(VariableLValue(irTmp))
|
||||
val irOpCall = CallGenerator(this).generateCall(expression, opCall, irOperator)
|
||||
irBlock.addStatement(irLValue.store(irOpCall))
|
||||
|
||||
// ^ tmp
|
||||
irBlock.addStatement(irTmp.defaultLoad())
|
||||
|
||||
irBlock
|
||||
}
|
||||
|
||||
val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, irLValue.type, true, irOperator)
|
||||
val opCallGenerator = CallGenerator(parentGenerator)
|
||||
|
||||
val irTmp = parentGenerator.scope.createTemporaryVariable(irLValue.load())
|
||||
irBlock.addStatement(irTmp)
|
||||
|
||||
opCallGenerator.scope.putValue(ktBaseExpression, VariableLValue(this, irTmp, irOperator))
|
||||
val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator)
|
||||
irBlock.addStatement(irLValue.store(irOpCall))
|
||||
|
||||
irBlock.addStatement(irTmp.defaultLoad())
|
||||
|
||||
return irBlock
|
||||
}
|
||||
|
||||
private fun generatePrefixOperatorAsCall(expression: KtPrefixExpression, irOperator: IrOperator): IrExpression {
|
||||
val resolvedCall = getResolvedCall(expression)!!
|
||||
return CallGenerator(parentGenerator).generateCall(expression, resolvedCall, irOperator)
|
||||
return CallGenerator(statementGenerator).generateCall(expression, statementGenerator.pregenerateCall(resolvedCall), irOperator)
|
||||
}
|
||||
|
||||
private fun generateAugmentedAssignment(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
|
||||
val ktLeft = expression.left!!
|
||||
val irLValue = generateLValue(ktLeft, irOperator)
|
||||
val operatorCall = getResolvedCall(expression)!!
|
||||
|
||||
val opResolvedCall = getResolvedCall(expression)!!
|
||||
val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false
|
||||
val ktLeft = expression.left!!
|
||||
val ktRight = expression.right!!
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, irOperator)
|
||||
|
||||
if (isSimpleAssignment && irLValue is IrLValueWithAugmentedStore) {
|
||||
return irLValue.augmentedStore(operatorCall, irOperator, parentGenerator.generateExpression(expression.right!!))
|
||||
}
|
||||
return irAssignmentReceiver.assign { irLValue ->
|
||||
val opCall = statementGenerator.pregenerateCall(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(irLValue)
|
||||
opCall.irValueArgumentsByIndex[0] = statementGenerator.generateExpression(ktRight)
|
||||
val irOpCall = CallGenerator(this).generateCall(expression, opCall, irOperator)
|
||||
|
||||
val opCallGenerator = CallGenerator(parentGenerator).apply { scope.putValue(ktLeft, irLValue) }
|
||||
val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator)
|
||||
|
||||
return if (isSimpleAssignment) {
|
||||
// Set( Op( Get(), RHS ) )
|
||||
irLValue.store(irOpCall)
|
||||
}
|
||||
else {
|
||||
// Op( Get(), RHS )
|
||||
irOpCall
|
||||
if (isSimpleAssignment) {
|
||||
// Set( Op( Get(), RHS ) )
|
||||
irLValue.store(irOpCall)
|
||||
}
|
||||
else {
|
||||
// Op( Get(), RHS )
|
||||
irOpCall
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateAssignment(expression: KtBinaryExpression): IrExpression {
|
||||
val ktLeft = expression.left!!
|
||||
val ktRight = expression.right!!
|
||||
val irLValue = generateLValue(ktLeft, IrOperator.EQ)
|
||||
return irLValue.store(parentGenerator.generateExpression(ktRight))
|
||||
val irRhs = statementGenerator.generateExpression(expression.right!!)
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, IrOperator.EQ)
|
||||
|
||||
return if (irAssignmentReceiver is IntermediateReference)
|
||||
irAssignmentReceiver.store(irRhs)
|
||||
else
|
||||
irAssignmentReceiver.assign { irLValue -> irLValue.store(irRhs) }
|
||||
}
|
||||
|
||||
private fun generateLValue(ktLeft: KtExpression, irOperator: IrOperator?): IrLValue {
|
||||
private fun generateAssignmentReceiver(ktLeft: KtExpression, irOperator: IrOperator): AssignmentReceiver {
|
||||
if (ktLeft is KtArrayAccessExpression) {
|
||||
val irArrayValue = parentGenerator.generateExpression(ktLeft.arrayExpression!!)
|
||||
val indexExpressions = ktLeft.indexExpressions.map { it to parentGenerator.generateExpression(it) }
|
||||
val indexedGetCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft)
|
||||
val indexedSetCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft)
|
||||
val type = indexedGetCall?.run { resultingDescriptor.returnType }
|
||||
?: indexedSetCall?.run { resultingDescriptor.valueParameters.last().type }
|
||||
?: throw AssertionError("Either 'get' or 'set' call should be present for an indexed LValue: ${ktLeft.text}")
|
||||
return IndexedLValue(parentGenerator, ktLeft, irOperator,
|
||||
irArrayValue, type, indexExpressions, indexedGetCall, indexedSetCall)
|
||||
return generateArrayAccessAssignmentReceiver(ktLeft, irOperator)
|
||||
}
|
||||
|
||||
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
|
||||
@@ -313,20 +322,31 @@ class OperatorExpressionGenerator(parentGenerator: StatementGenerator) : IrChild
|
||||
if (descriptor.isDelegated)
|
||||
TODO("Delegated local variable")
|
||||
else
|
||||
VariableLValue(this, ktLeft.startOffset, ktLeft.endOffset, descriptor, irOperator)
|
||||
is PropertyDescriptor ->
|
||||
CallGenerator(parentGenerator).run {
|
||||
PropertyLValue(
|
||||
this,
|
||||
ktLeft, irOperator, descriptor,
|
||||
generateReceiver(ktLeft, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter),
|
||||
generateReceiver(ktLeft, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter),
|
||||
resolvedCall.call.isSafeCall()
|
||||
)
|
||||
}
|
||||
VariableLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, irOperator)
|
||||
is PropertyDescriptor -> {
|
||||
val propertyReceiver = statementGenerator.generateCallReceiver(
|
||||
ktLeft, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, resolvedCall.call.isSafeCall()
|
||||
)
|
||||
SimplePropertyLValue(scope, ktLeft.startOffset, ktLeft.endOffset, irOperator, descriptor, propertyReceiver)
|
||||
}
|
||||
else ->
|
||||
TODO("Other cases of LHS")
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateArrayAccessAssignmentReceiver(ktLeft: KtArrayAccessExpression, irOperator: IrOperator): ArrayAccessAssignmentReceiver {
|
||||
val irArray = statementGenerator.generateExpression(ktLeft.arrayExpression!!)
|
||||
val irIndexExpressions = ktLeft.indexExpressions.map { statementGenerator.generateExpression(it) }
|
||||
|
||||
val indexedGetResolvedCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft)
|
||||
val indexedGetCall = indexedGetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) }
|
||||
|
||||
val indexedSetResolvedCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft)
|
||||
val indexedSetCall = indexedSetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) }
|
||||
|
||||
return ArrayAccessAssignmentReceiver(irArray, irIndexExpressions, indexedGetCall, indexedSetCall,
|
||||
CallGenerator(statementGenerator),
|
||||
ktLeft.startOffset, ktLeft.endOffset, irOperator)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
|
||||
fun primitiveOp1(startOffset: Int, endOffset: Int, primitiveOpDescriptor: CallableDescriptor, irOperator: IrOperator,
|
||||
argument: IrExpression): IrExpression =
|
||||
IrUnaryOperatorImpl(startOffset, endOffset, irOperator, primitiveOpDescriptor, argument)
|
||||
|
||||
fun primitiveOp2(startOffset: Int, endOffset: Int, primitiveOpDescriptor: CallableDescriptor, irOperator: IrOperator,
|
||||
argument1: IrExpression, argument2: IrExpression): IrExpression =
|
||||
IrBinaryOperatorImpl(startOffset, endOffset, irOperator, primitiveOpDescriptor, argument1, argument2)
|
||||
|
||||
fun Generator.constNull(startOffset: Int, endOffset: Int): IrExpression =
|
||||
IrConstImpl.constNull(startOffset, endOffset, context.builtIns.nullableNothingType)
|
||||
|
||||
fun Generator.equalsNull(startOffset: Int, endOffset: Int, argument: IrExpression): IrExpression =
|
||||
primitiveOp2(startOffset, endOffset, context.irBuiltIns.eqeq, IrOperator.EQEQ,
|
||||
argument, constNull(startOffset, endOffset))
|
||||
|
||||
// a || b == if (a) true else b
|
||||
fun Generator.oror(startOffset: Int, endOffset: Int, a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.OROR): IrWhen =
|
||||
IrIfThenElseImpl(startOffset, endOffset, context.builtIns.booleanType,
|
||||
a, IrConstImpl.constTrue(b.startOffset, b.endOffset, b.type!!), b,
|
||||
operator)
|
||||
|
||||
fun Generator.oror(a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.OROR): IrWhen =
|
||||
oror(b.startOffset, b.endOffset, a, b, operator)
|
||||
|
||||
fun Generator.whenComma(a: IrExpression, b: IrExpression): IrWhen =
|
||||
oror(a, b, IrOperator.WHEN_COMMA)
|
||||
|
||||
// a && b == if (a) b else false
|
||||
fun Generator.andand(startOffset: Int, endOffset: Int, a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.ANDAND): IrWhen =
|
||||
IrIfThenElseImpl(startOffset, endOffset, context.builtIns.booleanType,
|
||||
a, b, IrConstImpl.constFalse(b.startOffset, b.endOffset, b.type!!),
|
||||
operator)
|
||||
|
||||
fun Generator.andand(a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.ANDAND): IrWhen =
|
||||
andand(b.startOffset, b.endOffset, a, b, operator)
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginKind
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariableImpl
|
||||
@@ -25,42 +24,12 @@ import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi2ir.generators.values.IrValue
|
||||
import org.jetbrains.kotlin.psi2ir.generators.values.VariableLValue
|
||||
import org.jetbrains.kotlin.psi2ir.generators.values.createRematerializableValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
import java.lang.AssertionError
|
||||
|
||||
class Scope private constructor(val scopeOwner: DeclarationDescriptor, val parent: Scope? = null) {
|
||||
internal lateinit var generator: IrBodyGenerator
|
||||
|
||||
constructor(parent: Scope) : this(parent.scopeOwner, parent) {
|
||||
this.generator = parent.generator
|
||||
}
|
||||
|
||||
private var lastTemporaryIndex: Int = parent?.lastTemporaryIndex ?: 0
|
||||
private fun nextTemporaryIndex(): Int = parent?.nextTemporaryIndex() ?: lastTemporaryIndex++
|
||||
|
||||
private val values = HashMap<Any, IrValue>()
|
||||
|
||||
private inline fun introduceTemporary(irExpression: IrExpression, nameHint: String?, register: (IrValue) -> Unit): IrVariable? {
|
||||
val rematerializable = createRematerializableValue(irExpression)
|
||||
return if (rematerializable != null) {
|
||||
register(rematerializable)
|
||||
null
|
||||
}
|
||||
else {
|
||||
createTemporary(irExpression, nameHint, register)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun createTemporary(irExpression: IrExpression, nameHint: String?, register: (IrValue) -> Unit): IrVariable {
|
||||
val irTemporary = createTemporaryVariable(irExpression, nameHint)
|
||||
register(VariableLValue(generator, irTemporary))
|
||||
return irTemporary
|
||||
}
|
||||
class Scope(val scopeOwner: DeclarationDescriptor) {
|
||||
private var lastTemporaryIndex: Int = 0
|
||||
private fun nextTemporaryIndex(): Int = lastTemporaryIndex++
|
||||
|
||||
private fun createDescriptorForTemporaryVariable(type: KotlinType, nameHint: String? = null): IrTemporaryVariableDescriptor =
|
||||
IrTemporaryVariableDescriptorImpl(scopeOwner, Name.identifier(getNameForTemporary(nameHint)), type)
|
||||
@@ -79,52 +48,4 @@ class Scope private constructor(val scopeOwner: DeclarationDescriptor, val paren
|
||||
),
|
||||
irExpression
|
||||
)
|
||||
|
||||
fun introduceTemporary(ktExpression: KtExpression, irExpression: IrExpression, nameHint: String? = null): IrVariable? =
|
||||
introduceTemporary(irExpression, nameHint) { putValue(ktExpression, it) }
|
||||
|
||||
fun introduceTemporary(valueParameterDescriptor: ValueParameterDescriptor, irExpression: IrExpression): IrVariable? =
|
||||
introduceTemporary(irExpression, valueParameterDescriptor.name.asString()) { putValue(valueParameterDescriptor, it) }
|
||||
|
||||
fun introduceTemporary(irExpression: IrExpression): IrVariable? =
|
||||
introduceTemporary(irExpression, null) { putValue(irExpression, it) }
|
||||
|
||||
fun createTemporary(ktExpression: KtExpression, irExpression: IrExpression, nameHint: String?): IrVariable =
|
||||
createTemporary(irExpression, nameHint) { putValue(ktExpression, it) }
|
||||
|
||||
fun putValue(ktExpression: KtExpression, irValue: IrValue) {
|
||||
values[ktExpression] = irValue
|
||||
}
|
||||
|
||||
fun putValue(receiver: ReceiverValue, irValue: IrValue) {
|
||||
values[receiver] = irValue
|
||||
}
|
||||
|
||||
fun putValue(parameter: ValueParameterDescriptor, irValue: IrValue) {
|
||||
values[parameter] = irValue
|
||||
}
|
||||
|
||||
fun putValue(irExpression: IrExpression, irValue: IrValue) {
|
||||
values[irExpression] = irValue
|
||||
}
|
||||
|
||||
fun valueOf(ktExpression: KtExpression): IrExpression? =
|
||||
values[ktExpression]?.load() ?: parent?.valueOf(ktExpression)
|
||||
|
||||
fun valueOf(receiver: ReceiverValue): IrExpression? =
|
||||
values[receiver]?.load() ?: parent?.valueOf(receiver)
|
||||
|
||||
fun valueOf(parameter: ValueParameterDescriptor): IrExpression? =
|
||||
values[parameter]?.load() ?: parent?.valueOf(parameter)
|
||||
|
||||
fun valueOf(irExpression: IrExpression): IrExpression? =
|
||||
values[irExpression]?.load() ?: parent?.valueOf(irExpression)
|
||||
|
||||
companion object {
|
||||
fun rootScope(scopeOwner: DeclarationDescriptor, generator: IrBodyGenerator): Scope {
|
||||
val scope = Scope(scopeOwner)
|
||||
scope.generator = generator
|
||||
return scope
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+36
-36
@@ -26,7 +26,8 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
||||
import org.jetbrains.kotlin.psi2ir.generators.values.VariableLValue
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
@@ -41,14 +42,14 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.constant
|
||||
import java.lang.AssertionError
|
||||
|
||||
class StatementGenerator(
|
||||
override val context: GeneratorContext,
|
||||
val scopeOwner: DeclarationDescriptor,
|
||||
val expressionBodyGenerator: ExpressionBodyGenerator,
|
||||
@Suppress("unused") val expressionBodyGenerator: ExpressionBodyGenerator,
|
||||
override val scope: Scope
|
||||
) : KtVisitor<IrStatement, Nothing?>(), IrBodyGenerator {
|
||||
) : KtVisitor<IrStatement, Nothing?>(), BodyGenerator {
|
||||
fun generateExpression(ktExpression: KtExpression): IrExpression =
|
||||
ktExpression.genExpr()
|
||||
|
||||
@@ -67,10 +68,7 @@ class StatementGenerator(
|
||||
val variableDescriptor = getOrFail(BindingContext.VARIABLE, property)
|
||||
|
||||
val irLocalVariable = IrVariableImpl(property.startOffset, property.endOffset, IrDeclarationOriginKind.DEFINED, variableDescriptor)
|
||||
irLocalVariable.initializer = property.initializer?.let {
|
||||
toExpectedType(it.genExpr(), variableDescriptor.type)
|
||||
}
|
||||
|
||||
irLocalVariable.initializer = property.initializer?.genExpr()
|
||||
return irLocalVariable
|
||||
}
|
||||
|
||||
@@ -79,16 +77,19 @@ class StatementGenerator(
|
||||
|
||||
val irBlock = IrBlockImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, null, false, IrOperator.SYNTHETIC_BLOCK)
|
||||
val ktInitializer = multiDeclaration.initializer!!
|
||||
val irTmpInitializer = scope.createTemporaryVariable(ktInitializer.genExpr())
|
||||
irBlock.addStatement(irTmpInitializer)
|
||||
val irTmpInitializerValue = createRematerializableOrTemporary(scope, ktInitializer.genExpr(), irBlock, "container")
|
||||
|
||||
val irCallGenerator = CallGenerator(this)
|
||||
irCallGenerator.scope.putValue(ktInitializer, VariableLValue(this, irTmpInitializer))
|
||||
|
||||
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
|
||||
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
|
||||
|
||||
val componentSubstitutedCall = pregenerateCall(componentResolvedCall)
|
||||
componentSubstitutedCall.setExplicitReceiverValue(irTmpInitializerValue)
|
||||
|
||||
val componentVariable = getOrFail(BindingContext.VARIABLE, ktEntry)
|
||||
val irComponentCall = irCallGenerator.generateCall(ktEntry, componentResolvedCall, IrOperator.COMPONENT_N.withIndex(index + 1))
|
||||
val irComponentCall = irCallGenerator.generateCall(ktEntry.startOffset, ktEntry.endOffset, componentSubstitutedCall,
|
||||
IrOperator.COMPONENT_N.withIndex(index + 1))
|
||||
val irComponentVar = IrVariableImpl(ktEntry.startOffset, ktEntry.endOffset, IrDeclarationOriginKind.DEFINED,
|
||||
componentVariable, irComponentCall)
|
||||
irBlock.addStatement(irComponentVar)
|
||||
@@ -106,13 +107,8 @@ class StatementGenerator(
|
||||
|
||||
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrStatement {
|
||||
val returnTarget = getReturnExpressionTarget(expression)
|
||||
val irReturnedExpression = expression.returnedExpression?.let {
|
||||
toExpectedType(it.genExpr(), returnTarget.returnType)
|
||||
}
|
||||
return IrReturnImpl(
|
||||
expression.startOffset, expression.endOffset,
|
||||
returnTarget, irReturnedExpression
|
||||
)
|
||||
val irReturnedExpression = expression.returnedExpression?.genExpr()
|
||||
return IrReturnImpl(expression.startOffset, expression.endOffset, returnTarget, irReturnedExpression)
|
||||
}
|
||||
|
||||
private fun getReturnExpressionTarget(expression: KtReturnExpression): CallableDescriptor =
|
||||
@@ -137,7 +133,7 @@ class StatementGenerator(
|
||||
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression {
|
||||
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
|
||||
?: error("KtConstantExpression was not evaluated: ${expression.text}")
|
||||
val constantValue = compileTimeConstant.toConstantValue(getInferredTypeWithSmarcastsOrFail(expression))
|
||||
val constantValue = compileTimeConstant.toConstantValue(getInferredTypeWithSmartcastsOrFail(expression))
|
||||
val constantType = constantValue.type
|
||||
|
||||
return when (constantValue) {
|
||||
@@ -163,7 +159,7 @@ class StatementGenerator(
|
||||
return entry0.genExpr()
|
||||
}
|
||||
}
|
||||
entries.size == 0 -> return IrConstImpl.string(expression.startOffset, expression.endOffset, getInferredTypeWithSmarcastsOrFail(expression), "")
|
||||
entries.size == 0 -> return IrConstImpl.string(expression.startOffset, expression.endOffset, getInferredTypeWithSmartcastsOrFail(expression), "")
|
||||
}
|
||||
|
||||
val irStringTemplate = IrStringConcatenationImpl(expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression))
|
||||
@@ -191,19 +187,19 @@ class StatementGenerator(
|
||||
is FakeCallableDescriptorForObject ->
|
||||
generateExpressionForReferencedDescriptor(descriptor.getReferencedDescriptor(), expression, resolvedCall)
|
||||
is ClassDescriptor ->
|
||||
if (DescriptorUtils.isObject(descriptor))
|
||||
IrGetObjectValueImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor)
|
||||
else if (DescriptorUtils.isEnumEntry(descriptor))
|
||||
IrGetEnumValueImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor)
|
||||
else {
|
||||
val companionObjectDescriptor = descriptor.companionObjectDescriptor
|
||||
?: error("Class value without companion object: $descriptor")
|
||||
IrGetObjectValueImpl(expression.startOffset, expression.endOffset,
|
||||
descriptor.classValueType,
|
||||
companionObjectDescriptor)
|
||||
when {
|
||||
DescriptorUtils.isObject(descriptor) ->
|
||||
IrGetObjectValueImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor)
|
||||
DescriptorUtils.isEnumEntry(descriptor) ->
|
||||
IrGetEnumValueImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor)
|
||||
else -> {
|
||||
IrGetObjectValueImpl(expression.startOffset, expression.endOffset, descriptor.classValueType,
|
||||
descriptor.companionObjectDescriptor ?: throw AssertionError("Class value without companion object: $descriptor"))
|
||||
}
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
CallGenerator(this).generateCall(expression, resolvedCall)
|
||||
// TODO safe calls
|
||||
CallGenerator(this).generateCall(expression.startOffset, expression.endOffset, pregenerateCall(resolvedCall))
|
||||
}
|
||||
is VariableDescriptor ->
|
||||
IrGetVariableImpl(expression.startOffset, expression.endOffset, descriptor)
|
||||
@@ -221,7 +217,9 @@ class StatementGenerator(
|
||||
TODO("VariableAsFunctionResolvedCall = variable call + invoke call")
|
||||
}
|
||||
|
||||
return CallGenerator(this).generateCall(expression, resolvedCall)
|
||||
// TODO safe calls
|
||||
|
||||
return CallGenerator(this).generateCall(expression.startOffset, expression.endOffset, pregenerateCall(resolvedCall))
|
||||
}
|
||||
|
||||
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Nothing?): IrStatement =
|
||||
@@ -275,8 +273,8 @@ class StatementGenerator(
|
||||
var irElseBranch: IrExpression? = null
|
||||
|
||||
whenBranches@while (true) {
|
||||
val irCondition = generateExpressionWithExpectedType(ktLastIf.condition!!, context.builtIns.booleanType)
|
||||
val irThenBranch = generateExpressionWithExpectedType(ktLastIf.then!!, resultType)
|
||||
val irCondition = ktLastIf.condition!!.genExpr()
|
||||
val irThenBranch = ktLastIf.then!!.genExpr()
|
||||
irBranches.add(Pair(irCondition, irThenBranch))
|
||||
|
||||
val ktElse = ktLastIf.`else`?.deparenthesize()
|
||||
@@ -284,7 +282,7 @@ class StatementGenerator(
|
||||
null -> break@whenBranches
|
||||
is KtIfExpression -> ktLastIf = ktElse
|
||||
is KtExpression -> {
|
||||
irElseBranch = generateExpressionWithExpectedType(ktElse, resultType)
|
||||
irElseBranch = ktElse.genExpr()
|
||||
break@whenBranches
|
||||
}
|
||||
else -> throw AssertionError("Unexpected else expression: ${ktElse.text}")
|
||||
@@ -312,3 +310,5 @@ class StatementGenerator(
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+18
-21
@@ -22,16 +22,17 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.defaultLoad
|
||||
import org.jetbrains.kotlin.psi2ir.generators.operators.getInfixOperator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.getInfixOperator
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import java.lang.AssertionError
|
||||
|
||||
class WhenExpressionGenerator(parentGenerator: StatementGenerator) : IrChildBodyGeneratorBase<StatementGenerator>(parentGenerator) {
|
||||
fun generate(expression: KtWhenExpression): IrExpression {
|
||||
val conditionsGenerator = CallGenerator(parentGenerator)
|
||||
class WhenExpressionGenerator(val statementGenerator: StatementGenerator) : BodyGenerator {
|
||||
override val scope: Scope get() = statementGenerator.scope
|
||||
override val context: GeneratorContext get() = statementGenerator.context
|
||||
|
||||
fun generate(expression: KtWhenExpression): IrExpression {
|
||||
val irSubject = expression.subjectExpression?.let {
|
||||
conditionsGenerator.scope.createTemporary(it, parentGenerator.generateExpression(it), "subject")
|
||||
scope.createTemporaryVariable(statementGenerator.generateExpression(it), "subject")
|
||||
}
|
||||
|
||||
val resultType = getInferredTypeWithSmartcasts(expression)
|
||||
@@ -40,7 +41,7 @@ class WhenExpressionGenerator(parentGenerator: StatementGenerator) : IrChildBody
|
||||
|
||||
for (ktEntry in expression.entries) {
|
||||
if (ktEntry.isElse) {
|
||||
irWhen.elseBranch = parentGenerator.generateExpressionWithExpectedType(ktEntry.expression!!, resultType)
|
||||
irWhen.elseBranch = statementGenerator.generateExpression(ktEntry.expression!!)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -48,14 +49,14 @@ class WhenExpressionGenerator(parentGenerator: StatementGenerator) : IrChildBody
|
||||
for (ktCondition in ktEntry.conditions) {
|
||||
val irCondition =
|
||||
if (irSubject != null)
|
||||
generateWhenConditionWithSubject(ktCondition, conditionsGenerator, irSubject)
|
||||
generateWhenConditionWithSubject(ktCondition, irSubject)
|
||||
else
|
||||
generateWhenConditionNoSubject(ktCondition)
|
||||
irBranchCondition = irBranchCondition?.let { IrIfThenElseImpl.whenComma(it, irCondition) } ?: irCondition
|
||||
irBranchCondition = irBranchCondition?.let { whenComma(it, irCondition) } ?: irCondition
|
||||
|
||||
}
|
||||
|
||||
val irBranchResult = parentGenerator.generateExpressionWithExpectedType(ktEntry.expression!!, resultType)
|
||||
val irBranchResult = statementGenerator.generateExpression(ktEntry.expression!!)
|
||||
irWhen.addBranch(irBranchCondition!!, irBranchResult)
|
||||
}
|
||||
|
||||
@@ -85,19 +86,14 @@ class WhenExpressionGenerator(parentGenerator: StatementGenerator) : IrChildBody
|
||||
}
|
||||
|
||||
private fun generateWhenConditionNoSubject(ktCondition: KtWhenCondition): IrExpression =
|
||||
parentGenerator.generateExpressionWithExpectedType((ktCondition as KtWhenConditionWithExpression).expression!!,
|
||||
context.builtIns.booleanType)
|
||||
statementGenerator.generateExpression((ktCondition as KtWhenConditionWithExpression).expression!!)
|
||||
|
||||
private fun generateWhenConditionWithSubject(
|
||||
ktCondition: KtWhenCondition,
|
||||
conditionsGenerator: CallGenerator,
|
||||
irSubject: IrVariable
|
||||
): IrExpression {
|
||||
private fun generateWhenConditionWithSubject(ktCondition: KtWhenCondition, irSubject: IrVariable): IrExpression {
|
||||
return when (ktCondition) {
|
||||
is KtWhenConditionWithExpression ->
|
||||
generateEqualsCondition(irSubject, ktCondition)
|
||||
is KtWhenConditionInRange ->
|
||||
generateInRangeCondition(conditionsGenerator, ktCondition)
|
||||
generateInRangeCondition(irSubject, ktCondition)
|
||||
is KtWhenConditionIsPattern ->
|
||||
generateIsPatternCondition(irSubject, ktCondition)
|
||||
else ->
|
||||
@@ -113,10 +109,11 @@ class WhenExpressionGenerator(parentGenerator: StatementGenerator) : IrChildBody
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateInRangeCondition(conditionsGenerator: CallGenerator, ktCondition: KtWhenConditionInRange): IrExpression {
|
||||
val inResolvedCall = getResolvedCall(ktCondition.operationReference)!!
|
||||
private fun generateInRangeCondition(irSubject: IrVariable, ktCondition: KtWhenConditionInRange): IrExpression {
|
||||
val inCall = statementGenerator.pregenerateCall(getResolvedCall(ktCondition.operationReference)!!)
|
||||
inCall.irValueArgumentsByIndex[0] = irSubject.defaultLoad()
|
||||
val inOperator = getInfixOperator(ktCondition.operationReference.getReferencedNameElementType())
|
||||
val irInCall = conditionsGenerator.generateCall(ktCondition, inResolvedCall, inOperator)
|
||||
val irInCall = CallGenerator(statementGenerator).generateCall(ktCondition, inCall, inOperator)
|
||||
return when (inOperator) {
|
||||
IrOperator.IN -> irInCall
|
||||
IrOperator.NOT_IN ->
|
||||
@@ -129,6 +126,6 @@ class WhenExpressionGenerator(parentGenerator: StatementGenerator) : IrChildBody
|
||||
IrBinaryOperatorImpl(
|
||||
ktCondition.startOffset, ktCondition.endOffset,
|
||||
IrOperator.EQEQ, context.irBuiltIns.eqeq,
|
||||
irSubject.defaultLoad(), parentGenerator.generateExpression(ktCondition.expression!!)
|
||||
irSubject.defaultLoad(), statementGenerator.generateExpression(ktCondition.expression!!)
|
||||
)
|
||||
}
|
||||
-168
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.generators.values
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.defaultLoad
|
||||
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.Scope
|
||||
import org.jetbrains.kotlin.psi2ir.generators.StatementGenerator
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class IndexedLValue(
|
||||
val statementGenerator: StatementGenerator,
|
||||
val ktArrayAccessExpression: KtArrayAccessExpression,
|
||||
val irOperator: IrOperator?,
|
||||
val irArray: IrExpression,
|
||||
override val type: KotlinType?,
|
||||
val indexValues: List<Pair<KtExpression, IrExpression>>,
|
||||
val indexedGetCall: ResolvedCall<*>?,
|
||||
val indexedSetCall: ResolvedCall<*>?
|
||||
) : IrLValueWithAugmentedStore {
|
||||
override fun load(): IrExpression {
|
||||
if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}")
|
||||
|
||||
return generateGetOrSetCallAsDesugaredBlock(indexedGetCall)
|
||||
}
|
||||
|
||||
override fun store(irExpression: IrExpression): IrExpression {
|
||||
if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}")
|
||||
|
||||
return generateGetOrSetCallAsDesugaredBlock(indexedSetCall)
|
||||
}
|
||||
|
||||
private fun generateGetOrSetCallAsDesugaredBlock(call: ResolvedCall<*>, irArgument: IrExpression? = null): IrExpression {
|
||||
val callGenerator = CallGenerator(statementGenerator)
|
||||
setupCallGeneratorContext(callGenerator.scope)
|
||||
|
||||
if (irArgument != null) {
|
||||
callGenerator.scope.putValue(call.resultingDescriptor.valueParameters.last(), SingleExpressionValue(irArgument))
|
||||
}
|
||||
|
||||
return callGenerator.generateCall(ktArrayAccessExpression, call, irOperator)
|
||||
}
|
||||
|
||||
override fun prefixAugmentedStore(operatorCall: ResolvedCall<*>, irOperator: IrOperator): IrExpression {
|
||||
if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}")
|
||||
if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}")
|
||||
|
||||
val callGenerator = CallGenerator(statementGenerator)
|
||||
|
||||
val irBlock = createDesugaredBlockWithTemporaries(indexedSetCall, callGenerator, true, irOperator)
|
||||
|
||||
val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver
|
||||
val irGetCall = callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator)
|
||||
callGenerator.scope.putValue(operatorCallReceiver!!, SingleExpressionValue(irGetCall))
|
||||
|
||||
val irOpCall = callGenerator.generateCall(ktArrayAccessExpression, operatorCall, irOperator)
|
||||
val irTmp = callGenerator.scope.createTemporaryVariable(irOpCall)
|
||||
irBlock.addStatement(irTmp)
|
||||
|
||||
callGenerator.scope.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(), VariableLValue(callGenerator, irTmp))
|
||||
|
||||
irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator))
|
||||
|
||||
irBlock.addStatement(irTmp.defaultLoad())
|
||||
|
||||
return irBlock
|
||||
}
|
||||
|
||||
override fun postfixAugmentedStore(operatorCall: ResolvedCall<*>, irOperator: IrOperator): IrExpression {
|
||||
if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}")
|
||||
if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}")
|
||||
|
||||
val callGenerator = CallGenerator(statementGenerator)
|
||||
|
||||
val irBlock = createDesugaredBlockWithTemporaries(indexedSetCall, callGenerator, true, irOperator)
|
||||
|
||||
val irGetCall = callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator)
|
||||
val irTmp = callGenerator.scope.createTemporaryVariable(irGetCall)
|
||||
irBlock.addStatement(irTmp)
|
||||
|
||||
val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver
|
||||
callGenerator.scope.putValue(operatorCallReceiver!!, VariableLValue(callGenerator, irTmp))
|
||||
val irOpCall = callGenerator.generateCall(ktArrayAccessExpression, operatorCall, irOperator)
|
||||
callGenerator.scope.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(), SingleExpressionValue(irOpCall))
|
||||
val irSetCall = callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator)
|
||||
irBlock.addStatement(irSetCall)
|
||||
|
||||
irBlock.addStatement(irTmp.defaultLoad())
|
||||
|
||||
return irBlock
|
||||
}
|
||||
|
||||
override fun augmentedStore(operatorCall: ResolvedCall<*>, irOperator: IrOperator, irOperatorArgument: IrExpression): IrExpression {
|
||||
if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}")
|
||||
if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}")
|
||||
|
||||
val callGenerator = CallGenerator(statementGenerator)
|
||||
|
||||
val irBlock = createDesugaredBlockWithTemporaries(indexedSetCall, callGenerator, false, irOperator)
|
||||
|
||||
callGenerator.scope.putValue(operatorCall.resultingDescriptor.valueParameters[0], SingleExpressionValue(irOperatorArgument))
|
||||
|
||||
val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver
|
||||
callGenerator.scope.putValue(operatorCallReceiver!!,
|
||||
SingleExpressionValue(callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator)))
|
||||
|
||||
callGenerator.scope.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(),
|
||||
SingleExpressionValue(callGenerator.generateCall(ktArrayAccessExpression, operatorCall, irOperator)))
|
||||
|
||||
irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator))
|
||||
|
||||
return irBlock
|
||||
}
|
||||
|
||||
private fun createDesugaredBlockWithTemporaries(
|
||||
call: ResolvedCall<*>,
|
||||
callGenerator: CallGenerator,
|
||||
hasResult: Boolean,
|
||||
operator: IrOperator?
|
||||
): IrBlockImpl {
|
||||
val irBlock = createDesugaredBlock(call, hasResult, operator)
|
||||
defineTemporaryVariables(irBlock, callGenerator.scope)
|
||||
return irBlock
|
||||
}
|
||||
|
||||
private fun createDesugaredBlock(call: ResolvedCall<*>, hasResult: Boolean, operator: IrOperator?): IrBlockImpl {
|
||||
return IrBlockImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset,
|
||||
if (hasResult) type else call.resultingDescriptor.returnType,
|
||||
hasResult, operator)
|
||||
}
|
||||
|
||||
private fun defineTemporaryVariables(irBlock: IrBlockImpl, scope: Scope) {
|
||||
irBlock.addIfNotNull(scope.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array"))
|
||||
|
||||
var index = 0
|
||||
for ((ktIndexExpression, irIndexValue) in indexValues) {
|
||||
irBlock.addIfNotNull(scope.introduceTemporary(ktIndexExpression, irIndexValue, "index${index++}"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCallGeneratorContext(scope: Scope) {
|
||||
scope.putValue(ktArrayAccessExpression.arrayExpression!!, SingleExpressionValue(irArray))
|
||||
|
||||
for ((ktIndexExpression, irIndexValue) in indexValues) {
|
||||
scope.putValue(ktIndexExpression, SingleExpressionValue(irIndexValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.generators.values
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.generators.IrBodyGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.toExpectedType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class PropertyLValue(
|
||||
val irBodyGenerator: IrBodyGenerator,
|
||||
val ktElement: KtElement,
|
||||
val irOperator: IrOperator?,
|
||||
val descriptor: PropertyDescriptor,
|
||||
val dispatchReceiver: IrExpression?,
|
||||
val extensionReceiver: IrExpression?,
|
||||
val isSafe: Boolean
|
||||
) : IrLValue {
|
||||
override val type: KotlinType?
|
||||
get() = descriptor.type
|
||||
|
||||
override fun load(): IrExpression {
|
||||
val getter = descriptor.getter!!
|
||||
return IrGetterCallImpl(
|
||||
ktElement.startOffset, ktElement.endOffset,
|
||||
getter.returnType, getter, isSafe,
|
||||
dispatchReceiver, extensionReceiver, IrOperator.GET_PROPERTY
|
||||
)
|
||||
}
|
||||
|
||||
override fun store(irExpression: IrExpression): IrExpression {
|
||||
val setter = descriptor.setter!!
|
||||
val irArgument = irBodyGenerator.toExpectedType(irExpression, descriptor.type)
|
||||
val irCall = IrSetterCallImpl(ktElement.startOffset, ktElement.endOffset,
|
||||
setter.returnType, setter, isSafe,
|
||||
dispatchReceiver, extensionReceiver, irArgument, irOperator)
|
||||
return irCall
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.generators.values
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface IrRematerializableValue : IrValue {
|
||||
val irExpression: IrExpression
|
||||
|
||||
override val type: KotlinType?
|
||||
get() = irExpression.type
|
||||
}
|
||||
|
||||
fun createRematerializableValue(irExpression: IrExpression): IrRematerializableValue? =
|
||||
when (irExpression) {
|
||||
is IrConst<*> -> IrRematerializableLiteralValue(irExpression)
|
||||
is IrGetVariable -> IrRematerializableVariableValue(irExpression)
|
||||
is IrGetExtensionReceiver -> IrRematerializableExtensionReceiverValue(irExpression)
|
||||
is IrThisReference -> IrRematerializableThisValue(irExpression)
|
||||
else -> null
|
||||
}
|
||||
|
||||
class IrRematerializableLiteralValue(override val irExpression: IrConst<*>): IrRematerializableValue {
|
||||
override fun load(): IrExpression =
|
||||
IrConstImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type,
|
||||
irExpression.kind, irExpression.kind.valueOf(irExpression))
|
||||
}
|
||||
|
||||
class IrRematerializableVariableValue(override val irExpression: IrGetVariable) : IrRematerializableValue {
|
||||
override fun load(): IrExpression =
|
||||
IrGetVariableImpl(irExpression.startOffset, irExpression.endOffset, irExpression.descriptor)
|
||||
}
|
||||
|
||||
class IrRematerializableExtensionReceiverValue(override val irExpression: IrGetExtensionReceiver) : IrRematerializableValue {
|
||||
override fun load(): IrExpression =
|
||||
IrGetExtensionReceiverImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.descriptor)
|
||||
}
|
||||
|
||||
class IrRematerializableThisValue(override val irExpression: IrThisReference): IrRematerializableValue {
|
||||
override fun load(): IrExpression =
|
||||
IrThisReferenceImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.classDescriptor)
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.generators.values
|
||||
|
||||
import org.jetbrains.kotlin.ir.assertDetached
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface IrValue {
|
||||
fun load(): IrExpression
|
||||
val type: KotlinType?
|
||||
}
|
||||
|
||||
class SingleExpressionValue(val irExpression: IrExpression) : IrValue {
|
||||
init {
|
||||
irExpression.assertDetached()
|
||||
}
|
||||
|
||||
private var instantiated = false
|
||||
|
||||
override fun load() =
|
||||
if (!instantiated) {
|
||||
instantiated = true
|
||||
irExpression
|
||||
}
|
||||
else
|
||||
throw AssertionError("Single exprssion value is already instantiated")
|
||||
|
||||
override val type: KotlinType? get() = irExpression.type
|
||||
}
|
||||
|
||||
interface IrLValue : IrValue {
|
||||
fun store(irExpression: IrExpression): IrExpression
|
||||
}
|
||||
|
||||
interface IrLValueWithAugmentedStore : IrLValue {
|
||||
fun postfixAugmentedStore(operatorCall: ResolvedCall<*>, irOperator: IrOperator): IrExpression
|
||||
fun prefixAugmentedStore(operatorCall: ResolvedCall<*>, irOperator: IrOperator): IrExpression
|
||||
fun augmentedStore(operatorCall: ResolvedCall<*>, irOperator: IrOperator, irOperatorArgument: IrExpression): IrExpression
|
||||
}
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.lang.AssertionError
|
||||
|
||||
class ArrayAccessAssignmentReceiver(
|
||||
val irArray: IrExpression,
|
||||
val irIndices: List<IrExpression>,
|
||||
val indexedGetCall: PregeneratedCall?,
|
||||
val indexedSetCall: PregeneratedCall?,
|
||||
val callGenerator: CallGenerator,
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val operator: IrOperator
|
||||
) : AssignmentReceiver {
|
||||
private val type: KotlinType = indexedGetCall?.let { it.descriptor.returnType!! } ?:
|
||||
indexedSetCall?.let { it.descriptor.valueParameters.last().type } ?:
|
||||
throw AssertionError("Array access should have either indexed-get call or indexed-set call")
|
||||
|
||||
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression {
|
||||
val hasResult = operator.isAssignmentOperatorWithResult()
|
||||
val resultType = if (hasResult) type else callGenerator.context.builtIns.unitType
|
||||
val irBlock = IrBlockImpl(startOffset, endOffset, resultType, hasResult, operator)
|
||||
|
||||
val irArrayValue = createRematerializableOrTemporary(callGenerator.scope, irArray, irBlock, "array")
|
||||
|
||||
val irIndexValues = irIndices.mapIndexed { i, irIndex ->
|
||||
createRematerializableOrTemporary(callGenerator.scope, irIndex, irBlock, "index$i")
|
||||
}
|
||||
|
||||
indexedGetCall?.fillArrayAndIndexArguments(irArrayValue, irIndexValues)
|
||||
indexedSetCall?.fillArrayAndIndexArguments(irArrayValue, irIndexValues)
|
||||
val irLValue = LValueWithGetterAndSetterCalls(callGenerator, indexedGetCall, indexedSetCall, startOffset, endOffset, operator)
|
||||
irBlock.inlineStatement(withLValue(irLValue))
|
||||
|
||||
return irBlock
|
||||
}
|
||||
|
||||
private fun PregeneratedCall.fillArrayAndIndexArguments(arrayValue: IntermediateValue, indexValues: List<IntermediateValue>) {
|
||||
setExplicitReceiverValue(arrayValue)
|
||||
indexValues.forEachIndexed { i, irIndexValue ->
|
||||
irValueArgumentsByIndex[i] = irIndexValue.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.PregeneratedCall
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.argumentsCount
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class LValueWithGetterAndSetterCalls(
|
||||
val callGenerator: CallGenerator,
|
||||
val getterCall: PregeneratedCall?,
|
||||
val setterCall: PregeneratedCall?,
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val operator: IrOperator? = null
|
||||
) : IntermediateReference {
|
||||
private val descriptor: CallableDescriptor =
|
||||
getterCall?.descriptor ?: setterCall?.descriptor ?:
|
||||
throw AssertionError("Call-based LValue should have either a getter or a setter call")
|
||||
|
||||
private var getterInstantiated = false
|
||||
private var setterInstantiated = false
|
||||
|
||||
override val type: KotlinType? get() = descriptor.returnType
|
||||
|
||||
override fun load(): IrExpression {
|
||||
if (getterCall == null) throw AssertionError("No getter call for $descriptor")
|
||||
if (getterInstantiated) throw AssertionError("Getter for $descriptor has already been instantiated")
|
||||
getterInstantiated = true
|
||||
return callGenerator.generateCall(startOffset, endOffset, getterCall, operator)
|
||||
}
|
||||
|
||||
override fun store(irExpression: IrExpression): IrExpression {
|
||||
if (setterCall == null) throw AssertionError("No setter call for $descriptor")
|
||||
if (setterInstantiated) throw AssertionError("Setter for $descriptor has already been instantiated")
|
||||
setterInstantiated = true
|
||||
setterCall.irValueArgumentsByIndex[setterCall.argumentsCount - 1] = irExpression
|
||||
return callGenerator.generateCall(startOffset, endOffset, setterCall, operator)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.StatementGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.PregeneratedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class OnceCallValue(
|
||||
val statementGenerator: StatementGenerator,
|
||||
val call: PregeneratedCall,
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val operator: IrOperator? = null
|
||||
): IntermediateValue {
|
||||
private var instantiated = false
|
||||
|
||||
override fun load(): IrExpression {
|
||||
if (instantiated) throw AssertionError("Value for call ${call.descriptor} has already been instantiated")
|
||||
instantiated = true
|
||||
return CallGenerator(statementGenerator).generateCall(startOffset, endOffset, call, operator)
|
||||
}
|
||||
|
||||
override val type: KotlinType? get() = call.descriptor.returnType
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.ir.assertDetached
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class OnceExpressionValue(val irExpression: IrExpression) : IntermediateValue {
|
||||
init {
|
||||
irExpression.assertDetached()
|
||||
}
|
||||
|
||||
private var instantiated = false
|
||||
|
||||
override fun load(): IrExpression {
|
||||
if (instantiated) throw AssertionError("Single expression value for ${irExpression.render()} is already instantiated")
|
||||
instantiated = true
|
||||
return irExpression
|
||||
}
|
||||
|
||||
override val type: KotlinType? get() = irExpression.type
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.psi2ir.isValueArgumentReorderingRequired
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class PregeneratedCall(val original: ResolvedCall<*>) {
|
||||
val descriptor: CallableDescriptor = original.resultingDescriptor
|
||||
|
||||
var superQualifier: ClassDescriptor? = null
|
||||
|
||||
lateinit var callReceiver: CallReceiver
|
||||
|
||||
val irValueArgumentsByIndex = arrayOfNulls<IrExpression>(descriptor.valueParameters.size)
|
||||
|
||||
fun getValueArgument(valueParameterDescriptor: ValueParameterDescriptor) =
|
||||
irValueArgumentsByIndex[valueParameterDescriptor.index]
|
||||
}
|
||||
|
||||
val PregeneratedCall.argumentsCount: Int get() =
|
||||
irValueArgumentsByIndex.size
|
||||
|
||||
fun PregeneratedCall.getValueArgumentsInParameterOrder(): List<IrExpression?> =
|
||||
descriptor.valueParameters.map { irValueArgumentsByIndex[it.index] }
|
||||
|
||||
fun PregeneratedCall.isValueArgumentReorderingRequired() =
|
||||
original.isValueArgumentReorderingRequired()
|
||||
|
||||
val PregeneratedCall.hasExtensionReceiver: Boolean get() =
|
||||
descriptor.extensionReceiverParameter != null
|
||||
|
||||
val PregeneratedCall.hasDispatchReceiver: Boolean get() =
|
||||
descriptor.dispatchReceiverParameter != null
|
||||
|
||||
val PregeneratedCall.extensionReceiverType: KotlinType? get() =
|
||||
descriptor.extensionReceiverParameter?.type
|
||||
|
||||
val PregeneratedCall.dispatchReceiverType: KotlinType? get() =
|
||||
descriptor.dispatchReceiverParameter?.type
|
||||
|
||||
val PregeneratedCall.explicitReceiverParameter: ReceiverParameterDescriptor? get() =
|
||||
descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter
|
||||
|
||||
val PregeneratedCall.explicitReceiverType: KotlinType? get() =
|
||||
explicitReceiverParameter?.type
|
||||
|
||||
fun PregeneratedCall.setExplicitReceiverValue(explicitReceiverValue: IntermediateValue) {
|
||||
val previousCallReceiver = callReceiver
|
||||
callReceiver = object : CallReceiver {
|
||||
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
|
||||
return previousCallReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val newDispatchReceiverValue = if (hasExtensionReceiver) dispatchReceiverValue else explicitReceiverValue
|
||||
val newExtensionReceiverValue = if (hasExtensionReceiver) explicitReceiverValue else null
|
||||
withDispatchAndExtensionReceivers(newDispatchReceiverValue, newExtensionReceiverValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi2ir.generators.Scope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class RematerializableValue(val irExpression: IrExpressionWithCopy) : IntermediateValue {
|
||||
override val type: KotlinType?
|
||||
get() = irExpression.type
|
||||
|
||||
override fun load(): IrExpression = irExpression.copy()
|
||||
}
|
||||
|
||||
fun createRematerializableValue(irExpression: IrExpression): IntermediateValue? =
|
||||
(irExpression as? IrExpressionWithCopy)?.let { RematerializableValue(it) }
|
||||
|
||||
inline fun createRematerializableOrTemporary(
|
||||
scope: Scope,
|
||||
irExpression: IrExpression,
|
||||
nameHint: String? = null,
|
||||
addVariable: (IrVariable) -> Unit
|
||||
): IntermediateValue {
|
||||
val rematerializable = createRematerializableValue(irExpression)
|
||||
if (rematerializable != null) {
|
||||
return rematerializable
|
||||
}
|
||||
|
||||
val temporaryVariable = scope.createTemporaryVariable(irExpression, nameHint)
|
||||
addVariable(temporaryVariable)
|
||||
return VariableLValue(temporaryVariable)
|
||||
}
|
||||
|
||||
fun createRematerializableOrTemporary(scope: Scope, irExpression: IrExpression, block: IrBlockImpl, nameHint: String? = null): IntermediateValue =
|
||||
createRematerializableOrTemporary(scope, irExpression, nameHint) {
|
||||
block.addStatement(it)
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrIfThenElseImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.BodyGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.constNull
|
||||
import org.jetbrains.kotlin.psi2ir.generators.equalsNull
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
|
||||
|
||||
class SafeCallReceiver(
|
||||
val generator: BodyGenerator,
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val explicitReceiver: IrExpression,
|
||||
val implicitDispatchReceiverValue: IntermediateValue?
|
||||
) : CallReceiver {
|
||||
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
|
||||
val irTmp = generator.scope.createTemporaryVariable(explicitReceiver, "safe_receiver")
|
||||
val safeReceiverValue = VariableLValue(irTmp)
|
||||
|
||||
val dispatchReceiverValue: IntermediateValue
|
||||
val extensionReceiverValue: IntermediateValue?
|
||||
if (implicitDispatchReceiverValue != null) {
|
||||
dispatchReceiverValue = implicitDispatchReceiverValue
|
||||
extensionReceiverValue = safeReceiverValue
|
||||
}
|
||||
else {
|
||||
dispatchReceiverValue = safeReceiverValue
|
||||
extensionReceiverValue = null
|
||||
}
|
||||
|
||||
val irResult = withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue)
|
||||
val resultType = irResult.type?.makeNullable()
|
||||
|
||||
val irBlock = IrBlockImpl(startOffset, endOffset, resultType, resultType != null, IrOperator.SAFE_CALL)
|
||||
|
||||
irBlock.addStatement(irTmp)
|
||||
|
||||
val irIfThenElse = IrIfThenElseImpl(startOffset, endOffset, resultType,
|
||||
generator.equalsNull(startOffset, endOffset, safeReceiverValue.load()),
|
||||
generator.constNull(startOffset, endOffset),
|
||||
irResult,
|
||||
IrOperator.SAFE_CALL)
|
||||
irBlock.addStatement(irIfThenElse)
|
||||
|
||||
return irBlock
|
||||
}
|
||||
}
|
||||
+10
-7
@@ -14,12 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir
|
||||
package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
|
||||
fun KtElement.deparenthesize(): KtElement =
|
||||
if (this is KtExpression) KtPsiUtil.safeDeparenthesize(this) else this
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
|
||||
class SimpleCallReceiver(
|
||||
val dispatchReceiverValue: IntermediateValue?,
|
||||
val extensionReceiverValue: IntermediateValue?
|
||||
) : CallReceiver {
|
||||
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
|
||||
return withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue)
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi2ir.generators.Scope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
class SimplePropertyLValue(
|
||||
val scope: Scope,
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val irOperator: IrOperator?,
|
||||
val descriptor: PropertyDescriptor,
|
||||
val callReceiver: CallReceiver
|
||||
) : IntermediateReference, AssignmentReceiver {
|
||||
override val type: KotlinType?
|
||||
get() = descriptor.type
|
||||
|
||||
override fun load(): IrExpression {
|
||||
val getter = descriptor.getter!!
|
||||
return callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
IrGetterCallImpl(startOffset, endOffset, getter,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
irOperator)
|
||||
}
|
||||
}
|
||||
|
||||
override fun store(irExpression: IrExpression): IrExpression {
|
||||
val setter = descriptor.setter!!
|
||||
return callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
IrSetterCallImpl(startOffset, endOffset, setter,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
irExpression, irOperator)
|
||||
}
|
||||
}
|
||||
|
||||
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression {
|
||||
return callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val variablesForReceivers = SmartList<IrVariable>()
|
||||
|
||||
val tmpDispatchReceiverValue = dispatchReceiverValue?.load()?.let {
|
||||
createRematerializableOrTemporary(scope, it, "this") {
|
||||
irVar -> variablesForReceivers.add(irVar)
|
||||
}
|
||||
}
|
||||
|
||||
val tmpExtensionReceiverValue = extensionReceiverValue?.load()?.let {
|
||||
createRematerializableOrTemporary(scope, it, "receiver") {
|
||||
irVar -> variablesForReceivers.add(irVar)
|
||||
}
|
||||
}
|
||||
|
||||
val irResultExpression = withLValue(
|
||||
SimplePropertyLValue(scope, startOffset, endOffset, irOperator, descriptor,
|
||||
SimpleCallReceiver(tmpDispatchReceiverValue, tmpExtensionReceiverValue))
|
||||
)
|
||||
|
||||
if (variablesForReceivers.isEmpty()) {
|
||||
irResultExpression
|
||||
}
|
||||
else {
|
||||
val irBlock = IrBlockImpl(startOffset, endOffset, irResultExpression.type, irResultExpression.type != null, irOperator)
|
||||
irBlock.addAll(variablesForReceivers)
|
||||
irBlock.addStatement(irResultExpression)
|
||||
irBlock
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface IntermediateValue {
|
||||
fun load(): IrExpression
|
||||
val type: KotlinType?
|
||||
}
|
||||
|
||||
interface IntermediateReference : IntermediateValue {
|
||||
fun store(irExpression: IrExpression): IrExpression
|
||||
}
|
||||
|
||||
interface AssignmentReceiver {
|
||||
fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression
|
||||
}
|
||||
|
||||
interface CallReceiver {
|
||||
fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression
|
||||
}
|
||||
+8
-12
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.generators.values
|
||||
package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
@@ -22,22 +22,16 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetVariableImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||
import org.jetbrains.kotlin.ir.expressions.IrSetVariableImpl
|
||||
import org.jetbrains.kotlin.psi2ir.generators.IrBodyGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.toExpectedType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class VariableLValue(
|
||||
val irBodyGenerator: IrBodyGenerator,
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val descriptor: VariableDescriptor,
|
||||
val irOperator: IrOperator? = null
|
||||
) : IrLValue {
|
||||
constructor(
|
||||
irBodyGenerator: IrBodyGenerator,
|
||||
irVariable: IrVariable,
|
||||
irOperator: IrOperator? = null
|
||||
) : this(irBodyGenerator, irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator)
|
||||
) : IntermediateReference, AssignmentReceiver {
|
||||
constructor(irVariable: IrVariable, irOperator: IrOperator? = null) :
|
||||
this(irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator)
|
||||
|
||||
override val type: KotlinType? get() = descriptor.type
|
||||
|
||||
@@ -45,6 +39,8 @@ class VariableLValue(
|
||||
IrGetVariableImpl(startOffset, endOffset, descriptor, irOperator)
|
||||
|
||||
override fun store(irExpression: IrExpression): IrExpression =
|
||||
IrSetVariableImpl(startOffset, endOffset, descriptor,
|
||||
irBodyGenerator.toExpectedType(irExpression, descriptor.type), irOperator)
|
||||
IrSetVariableImpl(startOffset, endOffset, descriptor, irExpression, irOperator)
|
||||
|
||||
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression =
|
||||
withLValue(this)
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.psi2ir.transformations
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.detach
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.replaceWith
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.psi2ir.containsNull
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.isNullabilityFlexible
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
import java.lang.AssertionError
|
||||
|
||||
fun insertImplicitCasts(builtIns: KotlinBuiltIns, element: IrElement) {
|
||||
element.accept(InsertImplicitCasts(builtIns), null)
|
||||
}
|
||||
|
||||
class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementVisitor<Unit, Nothing?> {
|
||||
override fun visitElement(element: IrElement, data: Nothing?) {
|
||||
element.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: Nothing?) {
|
||||
expression.acceptChildren(this, null)
|
||||
|
||||
with(expression) {
|
||||
dispatchReceiver?.replaceWithCast(descriptor.dispatchReceiverParameter?.type)
|
||||
extensionReceiver?.replaceWithCast(descriptor.extensionReceiverParameter?.type)
|
||||
for (index in descriptor.valueParameters.indices) {
|
||||
val parameterType = descriptor.valueParameters[index].type
|
||||
getArgument(index)?.replaceWithCast(parameterType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn, data: Nothing?) {
|
||||
expression.acceptChildren(this, null)
|
||||
|
||||
expression.value?.replaceWithCast(expression.returnTarget.returnType)
|
||||
}
|
||||
|
||||
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?) {
|
||||
expression.acceptChildren(this, null)
|
||||
|
||||
expression.value.replaceWithCast(expression.descriptor.type)
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, data: Nothing?) {
|
||||
declaration.acceptChildren(this, null)
|
||||
|
||||
declaration.initializer?.replaceWithCast(declaration.descriptor.type)
|
||||
}
|
||||
|
||||
override fun visitWhen(expression: IrWhen, data: Nothing?) {
|
||||
expression.acceptChildren(this, null)
|
||||
|
||||
for (branchIndex in expression.branchIndices) {
|
||||
expression.getNthCondition(branchIndex)!!.replaceWithCast(builtIns.booleanType)
|
||||
expression.getNthResult(branchIndex)!!.replaceWithCast(expression.type)
|
||||
}
|
||||
expression.elseBranch?.replaceWithCast(expression.type)
|
||||
}
|
||||
|
||||
override fun visitLoop(loop: IrLoop, data: Nothing?) {
|
||||
loop.acceptChildren(this, null)
|
||||
|
||||
loop.condition.replaceWithCast(builtIns.booleanType)
|
||||
}
|
||||
|
||||
private fun IrExpression.replaceWithCast(expectedType: KotlinType?) {
|
||||
replaceWith { it.wrapWithImplicitCast(expectedType) }
|
||||
}
|
||||
|
||||
private fun IrExpression.wrapWithImplicitCast(expectedType: KotlinType?): IrExpression {
|
||||
if (this is IrBlock && !this.hasResult) return this
|
||||
if (expectedType == null) return this
|
||||
if (expectedType.isError) return this
|
||||
if (KotlinBuiltIns.isUnit(expectedType)) return this // TODO expose coercion to Unit in IR?
|
||||
|
||||
val valueType = this.type ?: throw AssertionError("expectedType != null, valueType == null: $this")
|
||||
|
||||
if (valueType.isNullabilityFlexible() && valueType.containsNull() && !expectedType.containsNull()) {
|
||||
val nonNullValueType = valueType.upperIfFlexible().makeNotNullable();
|
||||
return IrTypeOperatorCallImpl(
|
||||
this.startOffset, this.endOffset, nonNullValueType,
|
||||
IrTypeOperator.IMPLICIT_NOTNULL, nonNullValueType, this.detach()
|
||||
).wrapWithImplicitCast(expectedType)
|
||||
}
|
||||
|
||||
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType.makeNotNullable(), expectedType)) {
|
||||
return IrTypeOperatorCallImpl(this.startOffset, this.endOffset, expectedType,
|
||||
IrTypeOperator.IMPLICIT_CAST, expectedType, this.detach())
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,15 @@ fun IrElement.replaceWith(otherElement: IrElement) {
|
||||
parent.replaceChild(slot, otherElement.detach())
|
||||
}
|
||||
|
||||
fun <T : IrElement> T.replaceWith(transformation: (T) -> IrElement) {
|
||||
val originalParent = this.parent ?: throw AssertionError("Can't replace a non-root element $this")
|
||||
val originalSlot = this.slot
|
||||
val transformed = transformation(this)
|
||||
if (transformed != this) {
|
||||
originalParent.replaceChild(originalSlot, transformed)
|
||||
}
|
||||
}
|
||||
|
||||
fun IrElement.assertChild(child: IrElement) {
|
||||
assert(getChild(child.slot) == child) { "$this: Invalid child: $child" }
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class IrVariableImpl(
|
||||
}
|
||||
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||
return visitor.visitLocalVariable(this, data)
|
||||
return visitor.visitVariable(this, data)
|
||||
}
|
||||
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
|
||||
@@ -48,6 +48,15 @@ class IrBlockImpl(
|
||||
statements.add(statement)
|
||||
}
|
||||
|
||||
fun addAll(statements: List<IrStatement>) {
|
||||
statements.forEach { it.assertDetached() }
|
||||
val originalSize = statements.size
|
||||
this.statements.addAll(statements)
|
||||
statements.forEachIndexed { i, irStatement ->
|
||||
irStatement.setTreeLocation(this, originalSize + i)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getChild(slot: Int): IrElement? =
|
||||
statements.getOrNull(slot)
|
||||
|
||||
@@ -66,4 +75,14 @@ class IrBlockImpl(
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
statements.forEach { it.accept(visitor, data) }
|
||||
}
|
||||
}
|
||||
|
||||
fun IrBlockImpl.inlineStatement(statement: IrStatement) {
|
||||
if (statement is IrBlock) {
|
||||
statement.statements.forEach { it.detach() }
|
||||
addAll(statement.statements)
|
||||
}
|
||||
else {
|
||||
addStatement(statement)
|
||||
}
|
||||
}
|
||||
@@ -37,10 +37,9 @@ class IrCallImpl(
|
||||
endOffset: Int,
|
||||
type: KotlinType?,
|
||||
override val descriptor: CallableDescriptor,
|
||||
isSafe: Boolean,
|
||||
override val operator: IrOperator? = null,
|
||||
override val superQualifier: ClassDescriptor? = null
|
||||
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrCall {
|
||||
) : IrMemberAccessExpressionBase(startOffset, endOffset, type), IrCall {
|
||||
private val argumentsByParameterIndex =
|
||||
arrayOfNulls<IrExpression>(descriptor.valueParameters.size)
|
||||
|
||||
@@ -87,12 +86,10 @@ class IrCallImpl(
|
||||
abstract class IrPropertyAccessorCallBase(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType?,
|
||||
override val descriptor: CallableDescriptor,
|
||||
isSafe: Boolean,
|
||||
override val operator: IrOperator? = null,
|
||||
override val superQualifier: ClassDescriptor? = null
|
||||
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrCall {
|
||||
) : IrMemberAccessExpressionBase(startOffset, endOffset, descriptor.returnType), IrCall {
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||
return visitor.visitCall(this, data)
|
||||
}
|
||||
@@ -101,23 +98,19 @@ abstract class IrPropertyAccessorCallBase(
|
||||
class IrGetterCallImpl(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType?,
|
||||
descriptor: CallableDescriptor,
|
||||
isSafe: Boolean,
|
||||
operator: IrOperator? = null,
|
||||
superQualifier: ClassDescriptor? = null
|
||||
) : IrPropertyAccessorCallBase(startOffset, endOffset, type, descriptor, isSafe, operator, superQualifier), IrCall {
|
||||
) : IrPropertyAccessorCallBase(startOffset, endOffset, descriptor, operator, superQualifier), IrCall {
|
||||
constructor(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType?,
|
||||
descriptor: CallableDescriptor,
|
||||
isSafe: Boolean,
|
||||
dispatchReceiver: IrExpression?,
|
||||
extensionReceiver: IrExpression?,
|
||||
operator: IrOperator? = null,
|
||||
superQualifier: ClassDescriptor? = null
|
||||
) : this(startOffset, endOffset, type, descriptor, isSafe, operator, superQualifier) {
|
||||
) : this(startOffset, endOffset, descriptor, operator, superQualifier) {
|
||||
this.dispatchReceiver = dispatchReceiver
|
||||
this.extensionReceiver = extensionReceiver
|
||||
}
|
||||
@@ -136,24 +129,20 @@ class IrGetterCallImpl(
|
||||
class IrSetterCallImpl(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType?,
|
||||
descriptor: CallableDescriptor,
|
||||
isSafe: Boolean,
|
||||
operator: IrOperator? = null,
|
||||
superQualifier: ClassDescriptor? = null
|
||||
) : IrPropertyAccessorCallBase(startOffset, endOffset, type, descriptor, isSafe, operator, superQualifier), IrCall {
|
||||
) : IrPropertyAccessorCallBase(startOffset, endOffset, descriptor, operator, superQualifier), IrCall {
|
||||
constructor(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType?,
|
||||
descriptor: CallableDescriptor,
|
||||
isSafe: Boolean,
|
||||
dispatchReceiver: IrExpression?,
|
||||
extensionReceiver: IrExpression?,
|
||||
argument: IrExpression,
|
||||
operator: IrOperator? = null,
|
||||
superQualifier: ClassDescriptor? = null
|
||||
) : this(startOffset, endOffset, type, descriptor, isSafe, operator, superQualifier) {
|
||||
) : this(startOffset, endOffset, descriptor, operator, superQualifier) {
|
||||
this.dispatchReceiver = dispatchReceiver
|
||||
this.extensionReceiver = extensionReceiver
|
||||
putArgument(SETTER_ARGUMENT_INDEX, argument)
|
||||
|
||||
@@ -19,9 +19,11 @@ package org.jetbrains.kotlin.ir.expressions
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface IrConst<out T> : IrExpression {
|
||||
interface IrConst<out T> : IrExpression, IrExpressionWithCopy {
|
||||
val kind: IrConstKind<T>
|
||||
val value: T
|
||||
|
||||
override fun copy(): IrConst<T>
|
||||
}
|
||||
|
||||
sealed class IrConstKind<out T>(val asString: kotlin.String) {
|
||||
@@ -52,6 +54,9 @@ class IrConstImpl<out T> (
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitConst(this, data)
|
||||
|
||||
override fun copy(): IrConst<T> =
|
||||
IrConstImpl(startOffset, endOffset, type, kind, value)
|
||||
|
||||
companion object {
|
||||
fun string(startOffset: Int, endOffset: Int, type: KotlinType, value: String): IrConstImpl<String> =
|
||||
IrConstImpl(startOffset, endOffset, type, IrConstKind.String, value)
|
||||
|
||||
@@ -24,11 +24,14 @@ class IrDummyExpression(
|
||||
endOffset: Int,
|
||||
type: KotlinType?,
|
||||
val description: String
|
||||
) : IrTerminalExpressionBase(startOffset, endOffset, type) {
|
||||
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrExpressionWithCopy {
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitDummyExpression(this, data)
|
||||
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
// No children
|
||||
}
|
||||
|
||||
override fun copy(): IrDummyExpression =
|
||||
IrDummyExpression(startOffset, endOffset, type, description)
|
||||
}
|
||||
@@ -27,6 +27,10 @@ interface IrExpression : IrStatement {
|
||||
val type: KotlinType?
|
||||
}
|
||||
|
||||
interface IrExpressionWithCopy : IrExpression {
|
||||
fun copy(): IrExpression
|
||||
}
|
||||
|
||||
abstract class IrExpressionBase(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
|
||||
+6
-1
@@ -20,8 +20,10 @@ import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface IrGetExtensionReceiver : IrDeclarationReference {
|
||||
interface IrGetExtensionReceiver : IrDeclarationReference, IrExpressionWithCopy {
|
||||
override val descriptor: ReceiverParameterDescriptor
|
||||
|
||||
override fun copy(): IrGetExtensionReceiver
|
||||
}
|
||||
|
||||
class IrGetExtensionReceiverImpl(
|
||||
@@ -32,4 +34,7 @@ class IrGetExtensionReceiverImpl(
|
||||
) : IrTerminalDeclarationReferenceBase<ReceiverParameterDescriptor>(startOffset, endOffset, type, descriptor), IrGetExtensionReceiver {
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitGetExtensionReceiver(this, data)
|
||||
|
||||
override fun copy(): IrGetExtensionReceiver =
|
||||
IrGetExtensionReceiverImpl(startOffset, endOffset, type, descriptor)
|
||||
}
|
||||
|
||||
@@ -21,22 +21,17 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
interface IrLoop : IrExpression {
|
||||
var body: IrExpression
|
||||
}
|
||||
|
||||
interface IrConditionalLoop : IrLoop {
|
||||
var condition: IrExpression
|
||||
}
|
||||
|
||||
interface IrWhileLoop : IrConditionalLoop
|
||||
interface IrWhileLoop : IrLoop
|
||||
|
||||
interface IrDoWhileLoop : IrConditionalLoop
|
||||
interface IrDoWhileLoop : IrLoop
|
||||
|
||||
abstract class IrLoopBase(
|
||||
startOffset: Int,
|
||||
endOffset: Int
|
||||
) : IrExpressionBase(startOffset, endOffset, null), IrLoop {
|
||||
|
||||
|
||||
private var bodyImpl: IrExpression? = null
|
||||
override var body: IrExpression
|
||||
get() = bodyImpl!!
|
||||
@@ -63,7 +58,7 @@ abstract class IrLoopBase(
|
||||
abstract class IrConditionalLoopBase(
|
||||
startOffset: Int,
|
||||
endOffset: Int
|
||||
) : IrLoopBase(startOffset, endOffset), IrConditionalLoop {
|
||||
) : IrLoopBase(startOffset, endOffset) {
|
||||
private var conditionImpl: IrExpression? = null
|
||||
override var condition: IrExpression
|
||||
get() = conditionImpl!!
|
||||
|
||||
+1
-3
@@ -23,14 +23,12 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
interface IrMemberAccessExpression : IrDeclarationReference {
|
||||
var dispatchReceiver: IrExpression?
|
||||
var extensionReceiver: IrExpression?
|
||||
val isSafe: Boolean
|
||||
}
|
||||
|
||||
abstract class IrMemberAccessExpressionBase(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType?,
|
||||
override val isSafe: Boolean
|
||||
type: KotlinType?
|
||||
) : IrExpressionBase(startOffset, endOffset, type), IrMemberAccessExpression {
|
||||
override var dispatchReceiver: IrExpression? = null
|
||||
set(newReceiver) {
|
||||
|
||||
@@ -20,6 +20,8 @@ interface IrOperator {
|
||||
abstract class IrOperatorImpl(val debugName: String): IrOperator {
|
||||
override fun toString(): String = debugName
|
||||
}
|
||||
|
||||
object SAFE_CALL : IrOperatorImpl("SAFE_CALL")
|
||||
|
||||
object UMINUS : IrOperatorImpl("UMINUS")
|
||||
object UPLUS : IrOperatorImpl("UPLUS")
|
||||
@@ -88,3 +90,12 @@ interface IrOperator {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun IrOperator.isAssignmentOperatorWithResult() =
|
||||
when (this) {
|
||||
IrOperator.PREFIX_INCR, IrOperator.PREFIX_DECR,
|
||||
IrOperator.POSTFIX_INCR, IrOperator.POSTFIX_DECR ->
|
||||
true
|
||||
else ->
|
||||
false
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ abstract class IrOperatorCallBase(
|
||||
get() = null
|
||||
set(value) = throw UnsupportedOperationException("Operator call expression can't have a receiver")
|
||||
|
||||
override val isSafe: Boolean get() = false
|
||||
|
||||
override var extensionReceiver: IrExpression?
|
||||
get() = null
|
||||
set(value) = throw UnsupportedOperationException("Operator call expression can't have a receiver")
|
||||
|
||||
@@ -20,8 +20,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface IrThisReference : IrExpression {
|
||||
interface IrThisReference : IrExpression, IrExpressionWithCopy {
|
||||
val classDescriptor: ClassDescriptor
|
||||
override fun copy(): IrThisReference
|
||||
}
|
||||
|
||||
class IrThisReferenceImpl(
|
||||
@@ -32,4 +33,8 @@ class IrThisReferenceImpl(
|
||||
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrThisReference {
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitThisReference(this, data)
|
||||
|
||||
override fun copy(): IrThisReference =
|
||||
IrThisReferenceImpl(startOffset, endOffset, type, classDescriptor)
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
enum class IrTypeOperator {
|
||||
CAST,
|
||||
IMPLICIT_CAST,
|
||||
IMPLICIT_NOTNULL,
|
||||
SAFE_CAST,
|
||||
INSTANCEOF,
|
||||
NOT_INSTANCEOF;
|
||||
|
||||
+7
-3
@@ -26,11 +26,12 @@ interface IrVariableAccessExpression : IrDeclarationReference {
|
||||
val operator: IrOperator?
|
||||
}
|
||||
|
||||
interface IrGetVariable : IrVariableAccessExpression
|
||||
interface IrGetVariable : IrVariableAccessExpression, IrExpressionWithCopy {
|
||||
override fun copy(): IrGetVariable
|
||||
}
|
||||
|
||||
interface IrSetVariable : IrVariableAccessExpression {
|
||||
val value: IrExpression
|
||||
|
||||
var value: IrExpression
|
||||
}
|
||||
|
||||
class IrGetVariableImpl(
|
||||
@@ -41,6 +42,9 @@ class IrGetVariableImpl(
|
||||
) : IrTerminalDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, descriptor.type, descriptor), IrGetVariable {
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitGetVariable(this, data)
|
||||
|
||||
override fun copy(): IrGetVariable =
|
||||
IrGetVariableImpl(startOffset, endOffset, descriptor, operator)
|
||||
}
|
||||
|
||||
class IrSetVariableImpl(
|
||||
|
||||
@@ -31,6 +31,8 @@ interface IrWhen : IrExpression {
|
||||
var elseBranch: IrExpression?
|
||||
}
|
||||
|
||||
val IrWhen.branchIndices: IntRange get() = 0 ..branchesCount - 1
|
||||
|
||||
class IrWhenImpl(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
@@ -176,28 +178,4 @@ class IrIfThenElseImpl(
|
||||
thenBranch.accept(visitor, data)
|
||||
elseBranch?.accept(visitor, data)
|
||||
}
|
||||
|
||||
companion object {
|
||||
// a || b == if (a) true else b
|
||||
fun oror(startOffset: Int, endOffset: Int, a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.OROR): IrWhen =
|
||||
IrIfThenElseImpl(startOffset, endOffset, b.type!!,
|
||||
a, IrConstImpl.constTrue(b.startOffset, b.endOffset, b.type!!), b,
|
||||
operator)
|
||||
|
||||
fun oror(a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.OROR): IrWhen =
|
||||
oror(b.startOffset, b.endOffset, a, b, operator)
|
||||
|
||||
fun whenComma(a: IrExpression, b: IrExpression): IrWhen =
|
||||
oror(a, b, IrOperator.WHEN_COMMA)
|
||||
|
||||
// a && b == if (a) b else false
|
||||
fun andand(startOffset: Int, endOffset: Int, a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.ANDAND): IrWhen =
|
||||
IrIfThenElseImpl(startOffset, endOffset, b.type!!,
|
||||
a, b, IrConstImpl.constFalse(b.startOffset, b.endOffset, b.type!!),
|
||||
operator)
|
||||
|
||||
fun andand(a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.ANDAND): IrWhen =
|
||||
andand(b.startOffset, b.endOffset, a, b, operator)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
||||
override fun visitPropertySetter(declaration: IrPropertySetter, data: Nothing?): String =
|
||||
"IrPropertySetter ${declaration.descriptor.render()} property=${declaration.property?.name()}"
|
||||
|
||||
override fun visitLocalVariable(declaration: IrVariable, data: Nothing?): String =
|
||||
override fun visitVariable(declaration: IrVariable, data: Nothing?): String =
|
||||
"VAR ${declaration.descriptor.render()}"
|
||||
|
||||
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
|
||||
@@ -76,7 +76,7 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
||||
"THIS ${expression.classDescriptor.render()} type=${expression.renderType()}"
|
||||
|
||||
override fun visitCall(expression: IrCall, data: Nothing?): String =
|
||||
"CALL ${if (expression.isSafe) "?." else "."}${expression.descriptor.name} " +
|
||||
"CALL .${expression.descriptor.name} " +
|
||||
"type=${expression.renderType()} operator=${expression.operator}"
|
||||
|
||||
override fun visitGetVariable(expression: IrGetVariable, data: Nothing?): String =
|
||||
|
||||
@@ -33,7 +33,7 @@ interface IrElementVisitor<out R, in D> {
|
||||
fun visitProperty(declaration: IrProperty, data: D): R = visitDeclaration(declaration, data)
|
||||
fun visitSimpleProperty(declaration: IrSimpleProperty, data: D): R = visitProperty(declaration, data)
|
||||
fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D): R = visitProperty(declaration, data)
|
||||
fun visitLocalVariable(declaration: IrVariable, data: D) = visitDeclaration(declaration, data)
|
||||
fun visitVariable(declaration: IrVariable, data: D) = visitDeclaration(declaration, data)
|
||||
|
||||
fun visitBody(body: IrBody, data: D): R = visitElement(body, data)
|
||||
fun visitExpressionBody(body: IrExpressionBody, data: D): R = visitBody(body, data)
|
||||
|
||||
+18
-10
@@ -4,11 +4,13 @@ IrFile /arrayAssignment.kt
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
VAR val x: kotlin.IntArray
|
||||
CALL .intArrayOf type=kotlin.IntArray operator=null
|
||||
elements: DUMMY vararg type=kotlin.Int
|
||||
CALL .set type=kotlin.Unit operator=EQ
|
||||
$this: GET_VAR x type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='1'
|
||||
value: CONST Int type=kotlin.Int value='0'
|
||||
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
|
||||
DUMMY vararg type=kotlin.Int
|
||||
BLOCK type=kotlin.Unit hasResult=false operator=EQ
|
||||
CALL .set type=kotlin.Unit operator=EQ
|
||||
$this: GET_VAR x type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='1'
|
||||
value: CONST Int type=kotlin.Int value='0'
|
||||
IrFunction public fun foo(): kotlin.Int
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
@@ -17,8 +19,14 @@ IrFile /arrayAssignment.kt
|
||||
IrFunction public fun test2(): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
CALL .set type=kotlin.Unit operator=EQ
|
||||
$this: CALL .intArrayOf type=kotlin.IntArray operator=null
|
||||
elements: DUMMY vararg type=kotlin.Int
|
||||
index: CALL .foo type=kotlin.Int operator=null
|
||||
value: CONST Int type=kotlin.Int value='1'
|
||||
BLOCK type=kotlin.Unit hasResult=false operator=EQ
|
||||
VAR val tmp0_array: kotlin.IntArray
|
||||
CALL .intArrayOf type=kotlin.IntArray operator=null
|
||||
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
|
||||
DUMMY vararg type=kotlin.Int
|
||||
VAR val tmp1_index0: kotlin.Int
|
||||
CALL .foo type=kotlin.Int operator=null
|
||||
CALL .set type=kotlin.Unit operator=EQ
|
||||
$this: GET_VAR tmp0_array type=kotlin.IntArray operator=null
|
||||
index: GET_VAR tmp1_index0 type=kotlin.Int operator=null
|
||||
value: CONST Int type=kotlin.Int value='1'
|
||||
|
||||
+10
-2
@@ -1,9 +1,17 @@
|
||||
fun foo(): IntArray = intArrayOf(1, 2, 3)
|
||||
fun bar() = 42
|
||||
|
||||
class C(val x: IntArray)
|
||||
|
||||
fun testVariable() {
|
||||
var x = foo()
|
||||
x[0] += 1
|
||||
foo()[0] *= 2
|
||||
foo()[bar()] -= 1
|
||||
}
|
||||
|
||||
fun testCall() {
|
||||
foo()[bar()] *= 2
|
||||
}
|
||||
|
||||
fun testMember(c: C) {
|
||||
c.x[0]++
|
||||
}
|
||||
+27
-16
@@ -4,12 +4,14 @@ IrFile /arrayAugmentedAssignment1.kt
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
CALL .intArrayOf type=kotlin.IntArray operator=null
|
||||
elements: DUMMY vararg type=kotlin.Int
|
||||
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
|
||||
DUMMY vararg type=kotlin.Int
|
||||
IrFunction public fun bar(): kotlin.Int
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
CONST Int type=kotlin.Int value='42'
|
||||
DUMMY C
|
||||
IrFunction public fun testVariable(): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
@@ -24,27 +26,36 @@ IrFile /arrayAugmentedAssignment1.kt
|
||||
$this: GET_VAR x type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='0'
|
||||
other: CONST Int type=kotlin.Int value='1'
|
||||
IrFunction public fun testCall(): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
BLOCK type=kotlin.Unit hasResult=false operator=MULTEQ
|
||||
VAR val tmp0_array: kotlin.IntArray
|
||||
CALL .foo type=kotlin.IntArray operator=null
|
||||
VAR val tmp1_index0: kotlin.Int
|
||||
CALL .bar type=kotlin.Int operator=null
|
||||
CALL .set type=kotlin.Unit operator=MULTEQ
|
||||
$this: GET_VAR tmp0_array type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='0'
|
||||
index: GET_VAR tmp1_index0 type=kotlin.Int operator=null
|
||||
value: CALL .times type=kotlin.Int operator=MULTEQ
|
||||
$this: CALL .get type=kotlin.Int operator=MULTEQ
|
||||
$this: GET_VAR tmp0_array type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='0'
|
||||
index: GET_VAR tmp1_index0 type=kotlin.Int operator=null
|
||||
other: CONST Int type=kotlin.Int value='2'
|
||||
BLOCK type=kotlin.Unit hasResult=false operator=MINUSEQ
|
||||
VAR val tmp1_array: kotlin.IntArray
|
||||
CALL .foo type=kotlin.IntArray operator=null
|
||||
VAR val tmp2_index0: kotlin.Int
|
||||
CALL .bar type=kotlin.Int operator=null
|
||||
CALL .set type=kotlin.Unit operator=MINUSEQ
|
||||
$this: GET_VAR tmp1_array type=kotlin.IntArray operator=null
|
||||
index: GET_VAR tmp2_index0 type=kotlin.Int operator=null
|
||||
value: CALL .minus type=kotlin.Int operator=MINUSEQ
|
||||
$this: CALL .get type=kotlin.Int operator=MINUSEQ
|
||||
$this: GET_VAR tmp1_array type=kotlin.IntArray operator=null
|
||||
index: GET_VAR tmp2_index0 type=kotlin.Int operator=null
|
||||
other: CONST Int type=kotlin.Int value='1'
|
||||
IrFunction public fun testMember(/*0*/ c: C): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=kotlin.Int hasResult=true operator=null
|
||||
BLOCK type=kotlin.Int hasResult=true operator=POSTFIX_INCR
|
||||
VAR val tmp0_array: kotlin.IntArray
|
||||
CALL .<get-x> type=kotlin.IntArray operator=GET_PROPERTY
|
||||
$this: GET_VAR c type=C operator=null
|
||||
VAR val tmp1: kotlin.Int
|
||||
CALL .get type=kotlin.Int operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp0_array type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='0'
|
||||
CALL .set type=kotlin.Unit operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp0_array type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='0'
|
||||
value: CALL .inc type=kotlin.Int operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
|
||||
+5
-5
@@ -32,21 +32,21 @@ IrFile /augmentedAssignment1.kt
|
||||
BLOCK type=kotlin.Int hasResult=true operator=null
|
||||
CALL .<set-p> type=kotlin.Unit operator=PLUSEQ
|
||||
<set-?>: CALL .plus type=kotlin.Int operator=PLUSEQ
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=PLUSEQ
|
||||
other: CONST Int type=kotlin.Int value='1'
|
||||
CALL .<set-p> type=kotlin.Unit operator=MINUSEQ
|
||||
<set-?>: CALL .minus type=kotlin.Int operator=MINUSEQ
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=MINUSEQ
|
||||
other: CONST Int type=kotlin.Int value='2'
|
||||
CALL .<set-p> type=kotlin.Unit operator=MULTEQ
|
||||
<set-?>: CALL .times type=kotlin.Int operator=MULTEQ
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=MULTEQ
|
||||
other: CONST Int type=kotlin.Int value='3'
|
||||
CALL .<set-p> type=kotlin.Unit operator=DIVEQ
|
||||
<set-?>: CALL .div type=kotlin.Int operator=DIVEQ
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=DIVEQ
|
||||
other: CONST Int type=kotlin.Int value='4'
|
||||
CALL .<set-p> type=kotlin.Unit operator=PERCEQ
|
||||
<set-?>: CALL .mod type=kotlin.Int operator=PERCEQ
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=PERCEQ
|
||||
other: CONST Int type=kotlin.Int value='5'
|
||||
|
||||
+5
-5
@@ -42,17 +42,17 @@ IrFile /augmentedAssignment2.kt
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
CALL .plusAssign type=kotlin.Unit operator=PLUSEQ
|
||||
$receiver: CALL .<get-p> type=A operator=GET_PROPERTY
|
||||
$receiver: CALL .<get-p> type=A operator=PLUSEQ
|
||||
s: CONST String type=kotlin.String value='+='
|
||||
CALL .minusAssign type=kotlin.Unit operator=MINUSEQ
|
||||
$receiver: CALL .<get-p> type=A operator=GET_PROPERTY
|
||||
$receiver: CALL .<get-p> type=A operator=MINUSEQ
|
||||
s: CONST String type=kotlin.String value='-='
|
||||
CALL .timesAssign type=kotlin.Unit operator=MULTEQ
|
||||
$receiver: CALL .<get-p> type=A operator=GET_PROPERTY
|
||||
$receiver: CALL .<get-p> type=A operator=MULTEQ
|
||||
s: CONST String type=kotlin.String value='*='
|
||||
CALL .divAssign type=kotlin.Unit operator=DIVEQ
|
||||
$receiver: CALL .<get-p> type=A operator=GET_PROPERTY
|
||||
$receiver: CALL .<get-p> type=A operator=DIVEQ
|
||||
s: CONST String type=kotlin.String value='/='
|
||||
CALL .modAssign type=kotlin.Unit operator=PERCEQ
|
||||
$receiver: CALL .<get-p> type=A operator=GET_PROPERTY
|
||||
$receiver: CALL .<get-p> type=A operator=PERCEQ
|
||||
s: CONST String type=kotlin.String value='%='
|
||||
|
||||
@@ -28,7 +28,7 @@ IrFile /callWithReorderedArguments.kt
|
||||
CALL .foo type=kotlin.Unit operator=null
|
||||
a: CALL .noReorder1 type=kotlin.Int operator=null
|
||||
b: CALL .noReorder2 type=kotlin.Int operator=null
|
||||
BLOCK type=kotlin.Unit hasResult=false operator=SYNTHETIC_BLOCK
|
||||
BLOCK type=kotlin.Unit hasResult=true operator=SYNTHETIC_BLOCK
|
||||
VAR val tmp0_b: kotlin.Int
|
||||
CALL .reordered1 type=kotlin.Int operator=null
|
||||
VAR val tmp1_a: kotlin.Int
|
||||
@@ -36,7 +36,7 @@ IrFile /callWithReorderedArguments.kt
|
||||
CALL .foo type=kotlin.Unit operator=null
|
||||
a: GET_VAR tmp1_a type=kotlin.Int operator=null
|
||||
b: GET_VAR tmp0_b type=kotlin.Int operator=null
|
||||
BLOCK type=kotlin.Unit hasResult=false operator=SYNTHETIC_BLOCK
|
||||
BLOCK type=kotlin.Unit hasResult=true operator=SYNTHETIC_BLOCK
|
||||
VAR val tmp2_a: kotlin.Int
|
||||
CALL .reordered2 type=kotlin.Int operator=null
|
||||
CALL .foo type=kotlin.Unit operator=null
|
||||
|
||||
+3
-3
@@ -2,13 +2,13 @@ IrFunction public fun B.test(): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
BLOCK type=<no-type> hasResult=false operator=SYNTHETIC_BLOCK
|
||||
VAR val tmp0: A
|
||||
VAR val tmp0_container: A
|
||||
GET_OBJECT A type=A
|
||||
VAR val x: kotlin.Int
|
||||
CALL .component1 type=kotlin.Int operator=COMPONENT_N(index=1)
|
||||
$this: $RECEIVER of: test type=B
|
||||
$receiver: GET_VAR tmp0 type=A operator=null
|
||||
$receiver: GET_VAR tmp0_container type=A operator=null
|
||||
VAR val y: kotlin.Int
|
||||
CALL .component2 type=kotlin.Int operator=COMPONENT_N(index=2)
|
||||
$this: $RECEIVER of: test type=B
|
||||
$receiver: GET_VAR tmp0 type=A operator=null
|
||||
$receiver: GET_VAR tmp0_container type=A operator=null
|
||||
|
||||
+9
-2
@@ -9,6 +9,13 @@ IrFile /dotQualified.kt
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
CALL ?.<get-length> type=kotlin.Int? operator=GET_PROPERTY
|
||||
$this: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
|
||||
BLOCK type=kotlin.Int? hasResult=true operator=SAFE_CALL
|
||||
VAR val tmp0_safe_receiver: kotlin.String?
|
||||
GET_VAR s type=kotlin.String? operator=null
|
||||
WHEN type=kotlin.Int? operator=SAFE_CALL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CONST Null type=kotlin.Nothing? value='null'
|
||||
else: CALL .<get-length> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
|
||||
+29
-29
@@ -11,22 +11,24 @@ IrFile /elvis.kt
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
WHEN type=kotlin.Any operator=ELVIS
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=ELVIS
|
||||
arg0: GET_VAR a type=kotlin.Any? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: GET_VAR b type=kotlin.Any operator=null
|
||||
else: GET_VAR a type=kotlin.Any? operator=null
|
||||
BLOCK type=kotlin.Any hasResult=true operator=ELVIS
|
||||
WHEN type=kotlin.Any operator=null
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR a type=kotlin.Any? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: GET_VAR b type=kotlin.Any operator=null
|
||||
else: GET_VAR a type=kotlin.Any? operator=null
|
||||
IrFunction public fun test2(/*0*/ a: kotlin.String?, /*1*/ b: kotlin.Any): kotlin.Any
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
WHEN type=kotlin.Any operator=ELVIS
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=ELVIS
|
||||
arg0: GET_VAR a type=kotlin.String? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: GET_VAR b type=kotlin.Any operator=null
|
||||
else: GET_VAR a type=kotlin.String? operator=null
|
||||
BLOCK type=kotlin.Any hasResult=true operator=ELVIS
|
||||
WHEN type=kotlin.Any operator=null
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR a type=kotlin.String? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: GET_VAR b type=kotlin.Any operator=null
|
||||
else: GET_VAR a type=kotlin.String? operator=null
|
||||
IrFunction public fun test3(/*0*/ a: kotlin.Any?, /*1*/ b: kotlin.Any?): kotlin.String
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
@@ -42,39 +44,37 @@ IrFile /elvis.kt
|
||||
CONST String type=kotlin.String value=''
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.String hasResult=true operator=ELVIS
|
||||
VAR val tmp0: kotlin.String?
|
||||
TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String?
|
||||
GET_VAR a type=kotlin.Any? operator=null
|
||||
WHEN type=kotlin.String operator=ELVIS
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=ELVIS
|
||||
arg0: GET_VAR tmp0 type=kotlin.String? operator=null
|
||||
WHEN type=kotlin.String operator=null
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR a type=kotlin.Any? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
|
||||
GET_VAR b type=kotlin.Any? operator=null
|
||||
else: GET_VAR tmp0 type=kotlin.String? operator=null
|
||||
else: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
|
||||
GET_VAR a type=kotlin.Any? operator=null
|
||||
IrFunction public fun test4(/*0*/ x: kotlin.Any): kotlin.Any
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.Any hasResult=true operator=ELVIS
|
||||
VAR val tmp0: kotlin.Any?
|
||||
VAR val tmp0_elvis_lhs: kotlin.Any?
|
||||
CALL .<get-p> type=kotlin.Any? operator=GET_PROPERTY
|
||||
WHEN type=kotlin.Any operator=ELVIS
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=ELVIS
|
||||
arg0: GET_VAR tmp0 type=kotlin.Any? operator=null
|
||||
WHEN type=kotlin.Any operator=null
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_elvis_lhs type=kotlin.Any? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: GET_VAR x type=kotlin.Any operator=null
|
||||
else: GET_VAR tmp0 type=kotlin.Any? operator=null
|
||||
else: GET_VAR tmp0_elvis_lhs type=kotlin.Any? operator=null
|
||||
IrFunction public fun test5(/*0*/ x: kotlin.Any): kotlin.Any
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.Any hasResult=true operator=ELVIS
|
||||
VAR val tmp0: kotlin.Any?
|
||||
VAR val tmp0_elvis_lhs: kotlin.Any?
|
||||
CALL .foo type=kotlin.Any? operator=null
|
||||
WHEN type=kotlin.Any operator=ELVIS
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=ELVIS
|
||||
arg0: GET_VAR tmp0 type=kotlin.Any? operator=null
|
||||
WHEN type=kotlin.Any operator=null
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_elvis_lhs type=kotlin.Any? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: GET_VAR x type=kotlin.Any operator=null
|
||||
else: GET_VAR tmp0 type=kotlin.Any? operator=null
|
||||
else: GET_VAR tmp0_elvis_lhs type=kotlin.Any? operator=null
|
||||
|
||||
+3
-10
@@ -3,13 +3,6 @@ IrFile /implicitCastOnPlatformType.kt
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.String hasResult=true operator=IMPLICIT_NOTNULL
|
||||
VAR val tmp0: kotlin.String!
|
||||
CALL .getProperty type=kotlin.String! operator=null
|
||||
p0: CONST String type=kotlin.String value='test'
|
||||
WHEN type=kotlin.String operator=IMPLICIT_NOTNULL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=IMPLICIT_NOTNULL
|
||||
arg0: GET_VAR tmp0 type=kotlin.String! operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CALL .THROW_NPE type=kotlin.Nothing operator=IMPLICIT_NOTNULL
|
||||
else: GET_VAR tmp0 type=kotlin.String! operator=null
|
||||
TYPE_OP operator=IMPLICIT_NOTNULL typeOperand=kotlin.String
|
||||
CALL .getProperty type=kotlin.String! operator=null
|
||||
p0: CONST String type=kotlin.String value='test'
|
||||
|
||||
+9
-8
@@ -5,7 +5,8 @@ IrFile /incrementDecrement.kt
|
||||
IrProperty public val arr: kotlin.IntArray getter=null setter=null
|
||||
IrExpressionBody
|
||||
CALL .intArrayOf type=kotlin.IntArray operator=null
|
||||
elements: DUMMY vararg type=kotlin.Int
|
||||
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
|
||||
DUMMY vararg type=kotlin.Int
|
||||
IrFunction public fun testVarPrefix(): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
@@ -38,7 +39,7 @@ IrFile /incrementDecrement.kt
|
||||
GET_VAR x type=kotlin.Int operator=POSTFIX_INCR
|
||||
SET_VAR x type=<no-type> operator=POSTFIX_INCR
|
||||
CALL .inc type=kotlin.Int operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp0 type=kotlin.Int operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp0 type=kotlin.Int operator=null
|
||||
GET_VAR tmp0 type=kotlin.Int operator=null
|
||||
VAR val x2: kotlin.Int
|
||||
BLOCK type=kotlin.Int hasResult=true operator=POSTFIX_DECR
|
||||
@@ -46,7 +47,7 @@ IrFile /incrementDecrement.kt
|
||||
GET_VAR x type=kotlin.Int operator=POSTFIX_DECR
|
||||
SET_VAR x type=<no-type> operator=POSTFIX_DECR
|
||||
CALL .dec type=kotlin.Int operator=POSTFIX_DECR
|
||||
$this: GET_VAR tmp1 type=kotlin.Int operator=POSTFIX_DECR
|
||||
$this: GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
IrFunction public fun testPropPrefix(): kotlin.Unit
|
||||
IrExpressionBody
|
||||
@@ -55,7 +56,7 @@ IrFile /incrementDecrement.kt
|
||||
BLOCK type=kotlin.Int hasResult=true operator=PREFIX_INCR
|
||||
VAR val tmp0: kotlin.Int
|
||||
CALL .inc type=kotlin.Int operator=PREFIX_INCR
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=PREFIX_INCR
|
||||
CALL .<set-p> type=kotlin.Unit operator=PREFIX_INCR
|
||||
<set-?>: GET_VAR tmp0 type=kotlin.Int operator=null
|
||||
GET_VAR tmp0 type=kotlin.Int operator=null
|
||||
@@ -63,7 +64,7 @@ IrFile /incrementDecrement.kt
|
||||
BLOCK type=kotlin.Int hasResult=true operator=PREFIX_DECR
|
||||
VAR val tmp1: kotlin.Int
|
||||
CALL .dec type=kotlin.Int operator=PREFIX_DECR
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=PREFIX_DECR
|
||||
CALL .<set-p> type=kotlin.Unit operator=PREFIX_DECR
|
||||
<set-?>: GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
@@ -73,16 +74,16 @@ IrFile /incrementDecrement.kt
|
||||
VAR val p1: kotlin.Int
|
||||
BLOCK type=kotlin.Int hasResult=true operator=POSTFIX_INCR
|
||||
VAR val tmp0: kotlin.Int
|
||||
CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
CALL .<get-p> type=kotlin.Int operator=POSTFIX_INCR
|
||||
CALL .<set-p> type=kotlin.Unit operator=POSTFIX_INCR
|
||||
<set-?>: CALL .inc type=kotlin.Int operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp0 type=kotlin.Int operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp0 type=kotlin.Int operator=null
|
||||
GET_VAR tmp0 type=kotlin.Int operator=null
|
||||
VAR val p2: kotlin.Int
|
||||
BLOCK type=kotlin.Int hasResult=true operator=PREFIX_DECR
|
||||
VAR val tmp1: kotlin.Int
|
||||
CALL .dec type=kotlin.Int operator=PREFIX_DECR
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: CALL .<get-p> type=kotlin.Int operator=PREFIX_DECR
|
||||
CALL .<set-p> type=kotlin.Unit operator=PREFIX_DECR
|
||||
<set-?>: GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package test
|
||||
|
||||
class C
|
||||
|
||||
var C?.p: Int
|
||||
get() = 42
|
||||
set(value) {}
|
||||
|
||||
operator fun Int?.inc(): Int? = this?.inc()
|
||||
|
||||
operator fun Int?.get(index: Int): Int = 42
|
||||
operator fun Int?.set(index: Int, value: Int) {}
|
||||
|
||||
fun testProperty(nc: C?) {
|
||||
nc?.p++
|
||||
}
|
||||
|
||||
fun testArrayAccess(nc: C?) {
|
||||
nc?.p[0]++
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
IrFile /safeCallWithIncrementDecrement.kt
|
||||
DUMMY C
|
||||
IrProperty public var test.C?.p: kotlin.Int getter=<get-p> setter=<set-p>
|
||||
IrPropertyGetter public fun test.C?.<get-p>(): kotlin.Int property=p
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
CONST Int type=kotlin.Int value='42'
|
||||
IrPropertySetter public fun test.C?.<set-p>(/*0*/ value: kotlin.Int): kotlin.Unit property=p
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
IrFunction public operator fun kotlin.Int?.inc(): kotlin.Int?
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.Int? hasResult=true operator=SAFE_CALL
|
||||
VAR val tmp0_safe_receiver: kotlin.Int?
|
||||
$RECEIVER of: inc type=kotlin.Int?
|
||||
WHEN type=kotlin.Int? operator=SAFE_CALL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_safe_receiver type=kotlin.Int? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CONST Null type=kotlin.Nothing? value='null'
|
||||
else: CALL .inc type=kotlin.Int operator=null
|
||||
$this: GET_VAR tmp0_safe_receiver type=kotlin.Int? operator=null
|
||||
IrFunction public operator fun kotlin.Int?.get(/*0*/ index: kotlin.Int): kotlin.Int
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
CONST Int type=kotlin.Int value='42'
|
||||
IrFunction public operator fun kotlin.Int?.set(/*0*/ index: kotlin.Int, /*1*/ value: kotlin.Int): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
IrFunction public fun testProperty(/*0*/ nc: test.C?): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=kotlin.Int? hasResult=true operator=null
|
||||
BLOCK type=kotlin.Int? hasResult=true operator=SAFE_CALL
|
||||
VAR val tmp0_safe_receiver: test.C?
|
||||
GET_VAR nc type=test.C? operator=null
|
||||
WHEN type=kotlin.Int? operator=SAFE_CALL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_safe_receiver type=test.C? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CONST Null type=kotlin.Nothing? value='null'
|
||||
else: BLOCK type=kotlin.Int hasResult=true operator=POSTFIX_INCR
|
||||
VAR val tmp1: kotlin.Int
|
||||
CALL .<get-p> type=kotlin.Int operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp0_safe_receiver type=test.C? operator=null
|
||||
CALL .<set-p> type=kotlin.Unit operator=POSTFIX_INCR
|
||||
$this: GET_VAR tmp0_safe_receiver type=test.C? operator=null
|
||||
value: CALL .inc type=kotlin.Int? operator=POSTFIX_INCR
|
||||
$receiver: GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
GET_VAR tmp1 type=kotlin.Int operator=null
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
class Ref(var value: Int)
|
||||
|
||||
interface IHost {
|
||||
fun String.extLength() = length
|
||||
}
|
||||
|
||||
fun test1(x: String?) = x?.length
|
||||
fun test2(x: String?) = x?.hashCode()
|
||||
fun test3(x: String?, y: Any?) = x?.equals(y)
|
||||
|
||||
fun test4(x: Ref?) {
|
||||
x?.value = 0
|
||||
}
|
||||
|
||||
fun IHost.test5(s: String?) = s?.extLength()
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
IrFile /safeCalls.kt
|
||||
DUMMY Ref
|
||||
DUMMY IHost
|
||||
IrFunction public fun test1(/*0*/ x: kotlin.String?): kotlin.Int?
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.Int? hasResult=true operator=SAFE_CALL
|
||||
VAR val tmp0_safe_receiver: kotlin.String?
|
||||
GET_VAR x type=kotlin.String? operator=null
|
||||
WHEN type=kotlin.Int? operator=SAFE_CALL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CONST Null type=kotlin.Nothing? value='null'
|
||||
else: CALL .<get-length> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
IrFunction public fun test2(/*0*/ x: kotlin.String?): kotlin.Int?
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.Int? hasResult=true operator=SAFE_CALL
|
||||
VAR val tmp0_safe_receiver: kotlin.String?
|
||||
GET_VAR x type=kotlin.String? operator=null
|
||||
WHEN type=kotlin.Int? operator=SAFE_CALL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CONST Null type=kotlin.Nothing? value='null'
|
||||
else: CALL .hashCode type=kotlin.Int operator=null
|
||||
$this: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
IrFunction public fun test3(/*0*/ x: kotlin.String?, /*1*/ y: kotlin.Any?): kotlin.Boolean?
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.Boolean? hasResult=true operator=SAFE_CALL
|
||||
VAR val tmp0_safe_receiver: kotlin.String?
|
||||
GET_VAR x type=kotlin.String? operator=null
|
||||
WHEN type=kotlin.Boolean? operator=SAFE_CALL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CONST Null type=kotlin.Nothing? value='null'
|
||||
else: CALL .equals type=kotlin.Boolean operator=null
|
||||
$this: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
other: GET_VAR y type=kotlin.Any? operator=null
|
||||
IrFunction public fun test4(/*0*/ x: Ref?): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
BLOCK type=kotlin.Unit? hasResult=true operator=SAFE_CALL
|
||||
VAR val tmp0_safe_receiver: Ref?
|
||||
GET_VAR x type=Ref? operator=null
|
||||
WHEN type=kotlin.Unit? operator=SAFE_CALL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_safe_receiver type=Ref? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CONST Null type=kotlin.Nothing? value='null'
|
||||
else: CALL .<set-value> type=kotlin.Unit operator=EQ
|
||||
$this: GET_VAR tmp0_safe_receiver type=Ref? operator=null
|
||||
<set-?>: CONST Int type=kotlin.Int value='0'
|
||||
IrFunction public fun IHost.test5(/*0*/ s: kotlin.String?): kotlin.Int?
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
BLOCK type=kotlin.Int? hasResult=true operator=SAFE_CALL
|
||||
VAR val tmp0_safe_receiver: kotlin.String?
|
||||
GET_VAR s type=kotlin.String? operator=null
|
||||
WHEN type=kotlin.Int? operator=SAFE_CALL
|
||||
if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ
|
||||
arg0: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value='null'
|
||||
then: CONST Null type=kotlin.Nothing? value='null'
|
||||
else: CALL .extLength type=kotlin.Int operator=null
|
||||
$this: $RECEIVER of: test5 type=IHost
|
||||
$receiver: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null
|
||||
@@ -19,12 +19,10 @@ IrFile /smartCastsWithDestructuring.kt
|
||||
GET_VAR x type=I1 operator=null
|
||||
then: RETURN type=<no-type>
|
||||
BLOCK type=<no-type> hasResult=false operator=SYNTHETIC_BLOCK
|
||||
VAR val tmp0: I1
|
||||
GET_VAR x type=I1 operator=null
|
||||
VAR val c1: kotlin.Int
|
||||
CALL .component1 type=kotlin.Int operator=COMPONENT_N(index=1)
|
||||
$receiver: GET_VAR tmp0 type=I1 operator=null
|
||||
$receiver: GET_VAR x type=I1 operator=null
|
||||
VAR val c2: kotlin.String
|
||||
CALL .component2 type=kotlin.String operator=COMPONENT_N(index=2)
|
||||
$receiver: TYPE_OP operator=IMPLICIT_CAST typeOperand=I2
|
||||
GET_VAR tmp0 type=I1 operator=null
|
||||
GET_VAR x type=I1 operator=null
|
||||
|
||||
Vendored
+2
-4
@@ -21,8 +21,7 @@ IrFile /when.kt
|
||||
then: CONST String type=kotlin.String value='String'
|
||||
if: CALL .contains type=kotlin.Boolean operator=IN
|
||||
$receiver: CALL .setOf type=kotlin.collections.Set<kotlin.Nothing> operator=null
|
||||
element: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
||||
element: GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
||||
then: CONST String type=kotlin.String value='nothingness?'
|
||||
else: CONST String type=kotlin.String value='something'
|
||||
IrFunction public fun test(/*0*/ x: kotlin.Any?): kotlin.String
|
||||
@@ -43,8 +42,7 @@ IrFile /when.kt
|
||||
then: CONST String type=kotlin.String value='String'
|
||||
if: CALL .contains type=kotlin.Boolean operator=IN
|
||||
$receiver: CALL .setOf type=kotlin.collections.Set<kotlin.Nothing> operator=null
|
||||
element: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||
GET_VAR x type=kotlin.Any? operator=null
|
||||
element: GET_VAR x type=kotlin.Any? operator=null
|
||||
then: CONST String type=kotlin.String value='nothingness?'
|
||||
else: CONST String type=kotlin.String value='something'
|
||||
IrFunction public fun testComma(/*0*/ x: kotlin.Int): kotlin.String
|
||||
|
||||
@@ -179,6 +179,18 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallWithIncrementDecrement.kt")
|
||||
public void testSafeCallWithIncrementDecrement() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/safeCallWithIncrementDecrement.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("safeCalls.kt")
|
||||
public void testSafeCalls() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/safeCalls.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleOperators.kt")
|
||||
public void testSimpleOperators() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/simpleOperators.kt");
|
||||
|
||||
Reference in New Issue
Block a user