- smart casts handling separated from expression generation
- improved infrastructure for desugaring
This commit is contained in:
Dmitry Petrov
2016-08-16 15:43:23 +03:00
committed by Dmitry Petrov
parent ecf6ab9e25
commit 0a57eb8ea4
21 changed files with 363 additions and 215 deletions
@@ -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
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetVariableExpressionImpl
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorExpressionImpl
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
fun IrExpression.toExpectedType(expectedType: KotlinType?): IrExpression {
if (expectedType == null) return this
val valueType = type ?: throw AssertionError("expectedType != null, valueType == null: $this")
if (KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) {
return this
}
return IrTypeOperatorExpressionImpl(
startOffset, endOffset, expectedType,
IrTypeOperator.IMPLICIT_CAST, expectedType,
this
)
}
fun IrVariable.implicitGetExpression(): IrExpression =
IrGetVariableExpressionImpl(startOffset, endOffset, descriptor)
@@ -1,61 +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.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrOperator
import org.jetbrains.kotlin.ir.expressions.IrSetPropertyExpressionImpl
import org.jetbrains.kotlin.ir.expressions.IrSetVariableExpressionImpl
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.types.KotlinType
interface AssignmentLHS {
val type: KotlinType?
fun generateAssignment(ktOperation: KtBinaryExpression, irOperator: IrOperator, irRight: IrExpression): IrExpression
}
class VariableLHS(
val descriptor: VariableDescriptor
) : AssignmentLHS {
override val type: KotlinType? = descriptor.type
override fun generateAssignment(ktOperation: KtBinaryExpression, irOperator: IrOperator, irRight: IrExpression) =
IrSetVariableExpressionImpl(ktOperation.startOffset, ktOperation.endOffset, descriptor, irRight, irOperator)
}
class PropertyLHS(
val descriptor: PropertyDescriptor,
val dispatchReceiver: IrExpression?,
val extensionReceiver: IrExpression?,
val isSafe: Boolean
) : AssignmentLHS {
override val type: KotlinType? = descriptor.type
override fun generateAssignment(ktOperation: KtBinaryExpression, irOperator: IrOperator, irRight: IrExpression): IrExpression =
IrSetPropertyExpressionImpl(ktOperation.startOffset, ktOperation.endOffset, isSafe, descriptor, irOperator).apply {
dispatchReceiver = this@PropertyLHS.dispatchReceiver
extensionReceiver = this@PropertyLHS.extensionReceiver
value = irRight
}
}
@@ -21,31 +21,32 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.newHashMapWithExpectedSize
import java.util.* import java.util.*
class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenerator { class IrCallGenerator(
private val irStatementGenerator: IrStatementGenerator
) : IrGenerator {
override val context: IrGeneratorContext get() = irStatementGenerator.context override val context: IrGeneratorContext get() = irStatementGenerator.context
private val temporaries = newHashMapWithExpectedSize<KtExpression, VariableDescriptor>(3) private val expressionValues = HashMap<KtExpression, IrValue>()
private val receiverValues = HashMap<ReceiverValue, IrValue>()
private val valueArgumentValues = HashMap<ResolvedValueArgument, IrValue>()
fun putTemporary(ktExpression: KtExpression, temporaryVariableDescriptor: VariableDescriptor) { fun putValue(ktExpression: KtExpression, irValue: IrValue) {
temporaries[ktExpression] = temporaryVariableDescriptor expressionValues[ktExpression] = irValue
} }
private fun generateExpressionOrTemporary(ktExpression: KtExpression, expectedType: KotlinType?): IrExpression { fun putValue(receiver: ReceiverValue, irValue: IrValue) {
val temporary = temporaries[ktExpression] receiverValues[receiver] = irValue
return if (temporary != null) }
irStatementGenerator.smartCastTo(
IrGetVariableExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, temporary.type, temporary), fun putValue(valueArgument: ResolvedValueArgument, irValue: IrValue) {
expectedType valueArgumentValues[valueArgument] = irValue
)
else
irStatementGenerator.generateExpression(ktExpression, expectedType)
} }
fun generateCall( fun generateCall(
@@ -64,10 +65,8 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
returnType, returnType,
resolvedCall.call.isSafeCall(), descriptor resolvedCall.call.isSafeCall(), descriptor
).apply { ).apply {
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver, dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter)
descriptor.dispatchReceiverParameter?.type) extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter)
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver,
descriptor.extensionReceiverParameter?.type)
} }
is FunctionDescriptor -> is FunctionDescriptor ->
generateFunctionCall(descriptor, ktExpression, returnType, operator, resolvedCall, superQualifier) generateFunctionCall(descriptor, ktExpression, returnType, operator, resolvedCall, superQualifier)
@@ -102,10 +101,8 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
ktExpression.startOffset, ktExpression.endOffset, resultType, ktExpression.startOffset, ktExpression.endOffset, resultType,
descriptor, resolvedCall.call.isSafeCall(), operator, superQualifier descriptor, resolvedCall.call.isSafeCall(), operator, superQualifier
) )
irCall.dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver, irCall.dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter)
descriptor.dispatchReceiverParameter?.type) irCall.extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter)
irCall.extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver,
descriptor.extensionReceiverParameter?.type)
return if (resolvedCall.requiresArgumentReordering()) { return if (resolvedCall.requiresArgumentReordering()) {
generateCallWithArgumentReordering(irCall, ktExpression, resolvedCall, resultType) generateCallWithArgumentReordering(irCall, ktExpression, resolvedCall, resultType)
@@ -116,10 +113,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
for (index in valueArguments!!.indices) { for (index in valueArguments!!.indices) {
val valueArgument = valueArguments[index] val valueArgument = valueArguments[index]
val valueParameter = descriptor.valueParameters[index] val valueParameter = descriptor.valueParameters[index]
val irArgument = generateValueArgument( val irArgument = generateValueArgument(valueArgument, valueParameter) ?: continue
valueArgument,
valueParameter.varargElementType ?: valueParameter.type
) ?: continue
irCall.putArgument(index, irArgument) irCall.putArgument(index, irArgument)
} }
} }
@@ -140,21 +134,19 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
hasResult = isUsedAsExpression(ktExpression), hasResult = isUsedAsExpression(ktExpression),
isDesugared = true) isDesugared = true)
val temporaryVariablesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>() val temporariesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
for (valueArgument in valueArgumentsInEvaluationOrder) { for (valueArgument in valueArgumentsInEvaluationOrder) {
val irArgument = generateValueArgument(valueArgument, null) ?: continue val irArgument = generateValueArgument(valueArgument) ?: continue
val irTemporary = irStatementGenerator.declarationFactory.createTemporaryVariable(irArgument) val irTemporary = irStatementGenerator.declarationFactory.createTemporaryVariable(irArgument)
temporariesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
irBlock.addStatement(irTemporary) irBlock.addStatement(irTemporary)
temporaryVariablesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
} }
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) { for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
val (temporaryDescriptor, irArgument) = temporaryVariablesForValueArguments[valueArgument]!! val (temporaryDescriptor, irArgument) = temporariesForValueArguments[valueArgument]!!
val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index] val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index]
val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset, irArgument.type, val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset, temporaryDescriptor)
temporaryDescriptor) irCall.putArgument(index, irGetTemporary.toExpectedType(valueParameter.type))
irCall.putArgument(index, irStatementGenerator.smartCastTo(irGetTemporary, valueParameter.type))
} }
irBlock.addStatement(irCall) irBlock.addStatement(irCall)
@@ -162,8 +154,16 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
return irBlock return irBlock
} }
// TODO smart casts on implicit receivers fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?, receiverParameterDescriptor: ReceiverParameterDescriptor?) =
fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?, expectedType: KotlinType?): IrExpression? = generateReceiver(ktExpression, receiver)?.toExpectedType(receiverParameterDescriptor?.type)
fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? =
if (receiver == null)
null
else
receiverValues[receiver]?.load() ?: doGenerateReceiver(ktExpression, receiver)
fun doGenerateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? =
when (receiver) { when (receiver) {
is ImplicitClassReceiver -> is ImplicitClassReceiver ->
IrThisExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type, receiver.classDescriptor) IrThisExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type, receiver.classDescriptor)
@@ -172,7 +172,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
IrThisExpressionImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor) IrThisExpressionImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor)
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver") } ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
is ExpressionReceiver -> is ExpressionReceiver ->
generateExpressionOrTemporary(receiver.expression, expectedType) generateExpression(receiver.expression)
is ClassValueReceiver -> is ClassValueReceiver ->
IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type, IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
receiver.classQualifier.descriptor) receiver.classQualifier.descriptor)
@@ -185,15 +185,32 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
TODO("Receiver: ${receiver.javaClass.simpleName}") TODO("Receiver: ${receiver.javaClass.simpleName}")
} }
fun generateValueArgument(valueArgument: ResolvedValueArgument, expectedType: KotlinType?) = fun generateValueArgument(valueArgument: ResolvedValueArgument, valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
if (valueParameterDescriptor.varargElementType != null) {
generateValueArgument(valueArgument)
}
else {
generateValueArgument(valueArgument)?.toExpectedType(valueParameterDescriptor.type)
}
fun generateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? =
if (valueArgument is DefaultValueArgument)
null
else
valueArgumentValues[valueArgument]?.load() ?: doGenerateValueArgument(valueArgument)
private fun doGenerateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? =
when (valueArgument) { when (valueArgument) {
is DefaultValueArgument ->
null
is ExpressionValueArgument -> is ExpressionValueArgument ->
generateExpressionOrTemporary(valueArgument.valueArgument!!.getArgumentExpression()!!, expectedType) generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
is VarargValueArgument -> is VarargValueArgument ->
TODO("vararg") TODO("vararg")
else -> else ->
TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}") TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}")
} }
private fun generateExpression(ktExpression: KtExpression): IrExpression =
expressionValues[ktExpression]?.load() ?: irStatementGenerator.generateExpression(ktExpression)
} }
@@ -70,10 +70,6 @@ class IrLocalDeclarationsFactory(val scopeOwner: DeclarationDescriptor) : IrDecl
fun createDescriptorForTemporaryVariable(type: KotlinType): IrTemporaryVariableDescriptor = fun createDescriptorForTemporaryVariable(type: KotlinType): IrTemporaryVariableDescriptor =
IrTemporaryVariableDescriptorImpl(scopeOwner, Name.identifier("tmp${nextTemporaryIndex()}"), type) IrTemporaryVariableDescriptorImpl(scopeOwner, Name.identifier("tmp${nextTemporaryIndex()}"), type)
fun createTemporaryVariable(ktElement: KtElement, type: KotlinType): IrVariable =
IrVariableImpl(ktElement.startOffset, ktElement.endOffset, IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable(type))
fun createTemporaryVariable(irExpression: IrExpression): IrVariable = fun createTemporaryVariable(irExpression: IrExpression): IrVariable =
IrVariableImpl(irExpression.startOffset, irExpression.endOffset, IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE, IrVariableImpl(irExpression.startOffset, irExpression.endOffset, IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable( createDescriptorForTemporaryVariable(
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
interface IrDeclarationGenerator : IrGenerator interface IrDeclarationGenerator : IrGenerator
@@ -94,7 +95,8 @@ abstract class IrDeclarationGeneratorBase(
private fun generateExpressionWithinContext(ktExpression: KtExpression, scopeOwner: DeclarationDescriptor): IrExpression = private fun generateExpressionWithinContext(ktExpression: KtExpression, scopeOwner: DeclarationDescriptor): IrExpression =
IrStatementGenerator(context, scopeOwner, IrLocalDeclarationsFactory(scopeOwner)) IrStatementGenerator(context, scopeOwner, IrLocalDeclarationsFactory(scopeOwner))
.generateExpression(ktExpression, getExpectedTypeForLastInferredCall(ktExpression)) .generateExpression(ktExpression)
.toExpectedType(getExpectedTypeForLastInferredCall(ktExpression))
private fun generateFunctionBody(scopeOwner: CallableDescriptor, ktBody: KtExpression): IrBody { private fun generateFunctionBody(scopeOwner: CallableDescriptor, ktBody: KtExpression): IrBody {
val irRhs = generateExpressionWithinContext(ktBody, scopeOwner) val irRhs = generateExpressionWithinContext(ktBody, scopeOwner)
@@ -45,9 +45,6 @@ fun <K, V : Any> IrGenerator.getOrFail(slice: ReadOnlySlice<K, V>, key: K): V =
inline fun <K, V : Any> IrGenerator.getOrFail(slice: ReadOnlySlice<K, V>, key: K, message: (K) -> String): V = inline fun <K, V : Any> IrGenerator.getOrFail(slice: ReadOnlySlice<K, V>, key: K, message: (K) -> String): V =
context.bindingContext[slice, key] ?: throw RuntimeException(message(key)) context.bindingContext[slice, key] ?: throw RuntimeException(message(key))
inline fun <K, V : Any> IrGenerator.getOrElse(slice: ReadOnlySlice<K, V>, key: K, otherwise: (K) -> V): V =
context.bindingContext[slice, key] ?: otherwise(key)
fun IrGenerator.getInferredTypeWithSmartcasts(key: KtExpression): KotlinType? = fun IrGenerator.getInferredTypeWithSmartcasts(key: KtExpression): KotlinType? =
context.bindingContext.getType(key) context.bindingContext.getType(key)
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.psi2ir.generators package org.jetbrains.kotlin.psi2ir.generators
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -23,7 +24,18 @@ import org.jetbrains.kotlin.ir.expressions.IrOperator
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
val KT_OPERATOR_TO_IR_OPERATOR = hashMapOf(
KtTokens.PLUSEQ to IrOperator.PLUSEQ,
KtTokens.MINUSEQ to IrOperator.MINUSEQ,
KtTokens.MULTEQ to IrOperator.MULTEQ,
KtTokens.DIVEQ to IrOperator.DIVEQ,
KtTokens.PERCEQ to IrOperator.PERCEQ
)
class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator { class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator {
override val context: IrGeneratorContext get() = irStatementGenerator.context override val context: IrGeneratorContext get() = irStatementGenerator.context
@@ -33,18 +45,46 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
return when (ktOperator) { return when (ktOperator) {
KtTokens.EQ -> generateAssignment(expression) KtTokens.EQ -> generateAssignment(expression)
in KtTokens.AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, ktOperator)
else -> createDummyExpression(expression, ktOperator.toString()) else -> createDummyExpression(expression, ktOperator.toString())
} }
} }
private fun generateAugmentedAssignment(expression: KtBinaryExpression, ktOperator: IElementType): IrExpression {
val ktLeft = expression.left!!
val irOperator = getIrOperator(ktOperator)
val lhs = generateReferenceForAssignmentLhs(ktLeft, irOperator)
val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false
val operatorCall = getResolvedCall(expression)!!
val opCallGenerator = IrCallGenerator(irStatementGenerator).apply { putValue(ktLeft, lhs) }
val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator)
return if (isSimpleAssignment) {
// Set( Op( Get(), RHS ) )
lhs.store(irOpCall)
}
else {
// Op( Get(), RHS )
irOpCall
}
}
private fun getIrOperator(ktOperator: IElementType): IrOperator {
return KT_OPERATOR_TO_IR_OPERATOR[ktOperator] ?: TODO("Operator: $ktOperator")
}
private fun generateAssignment(expression: KtBinaryExpression): IrExpression { private fun generateAssignment(expression: KtBinaryExpression): IrExpression {
val ktLeft = expression.left!! val ktLeft = expression.left!!
val ktRight = expression.right!! val ktRight = expression.right!!
val lhs = generateAssignmentLHS(ktLeft) val lhsReference = generateReferenceForAssignmentLhs(ktLeft, IrOperator.EQ)
return lhs.generateAssignment(expression, IrOperator.EQ, irStatementGenerator.generateExpression(ktRight, lhs.type)) return lhsReference.store(irStatementGenerator.generateExpression(ktRight))
} }
private fun generateAssignmentLHS(ktLeft: KtExpression): AssignmentLHS { private fun generateReferenceForAssignmentLhs(ktLeft: KtExpression, irOperator: IrOperator?): IrReference {
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS") val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
val descriptor = resolvedCall.candidateDescriptor val descriptor = resolvedCall.candidateDescriptor
@@ -53,15 +93,13 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
if (descriptor.isDelegated) if (descriptor.isDelegated)
TODO("Delegated local variable") TODO("Delegated local variable")
else else
VariableLHS(descriptor) IrVariableReferenceValue(ktLeft, irOperator, descriptor)
is PropertyDescriptor -> is PropertyDescriptor ->
IrCallGenerator(irStatementGenerator).run { IrCallGenerator(irStatementGenerator).run {
PropertyLHS( IrPropertyReferenceValue(
descriptor, ktLeft, irOperator, descriptor,
generateReceiver(ktLeft, resolvedCall.dispatchReceiver, generateReceiver(ktLeft, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter),
descriptor.dispatchReceiverParameter?.type), generateReceiver(ktLeft, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter),
generateReceiver(ktLeft, resolvedCall.extensionReceiver,
descriptor.extensionReceiverParameter?.type),
resolvedCall.call.isSafeCall() resolvedCall.call.isSafeCall()
) )
} }
@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.deparenthesize import org.jetbrains.kotlin.psi2ir.deparenthesize
import org.jetbrains.kotlin.psi2ir.implicitGetExpression
import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -32,8 +34,6 @@ import org.jetbrains.kotlin.resolve.constants.IntValue
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
class IrStatementGenerator( class IrStatementGenerator(
@@ -42,32 +42,14 @@ class IrStatementGenerator(
val declarationFactory: IrLocalDeclarationsFactory val declarationFactory: IrLocalDeclarationsFactory
) : KtVisitor<IrStatement, Nothing?>(), IrGenerator { ) : KtVisitor<IrStatement, Nothing?>(), IrGenerator {
fun generateExpression(ktExpression: KtExpression, expectedType: KotlinType?): IrExpression = fun generateExpression(ktExpression: KtExpression): IrExpression =
ktExpression.genExpr(expectedType) ktExpression.genExpr()
private fun KtElement.genStmt(expectedType: KotlinType?): IrStatement { private fun KtElement.genStmt(): IrStatement =
val irStatement = deparenthesize().accept(this@IrStatementGenerator, null) deparenthesize().accept(this@IrStatementGenerator, null)
if (irStatement is IrExpression) {
return smartCastTo(irStatement, expectedType)
}
return irStatement
}
private fun KtElement.genExpr(expectedType: KotlinType?): IrExpression =
genStmt(expectedType).assertCast()
fun smartCastTo(irExpression: IrExpression, expectedType: KotlinType?): IrExpression {
val actualType = irExpression.type
if (expectedType != null && actualType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(actualType, expectedType)) {
return IrTypeOperatorExpressionImpl(
irExpression.startOffset, irExpression.endOffset, expectedType,
IrTypeOperator.SMART_AS, expectedType,
irExpression
)
}
return irExpression
}
private fun KtElement.genExpr(): IrExpression =
genStmt().assertCast()
override fun visitExpression(expression: KtExpression, data: Nothing?): IrStatement = override fun visitExpression(expression: KtExpression, data: Nothing?): IrStatement =
createDummyExpression(expression, expression.javaClass.simpleName) createDummyExpression(expression, expression.javaClass.simpleName)
@@ -78,7 +60,9 @@ class IrStatementGenerator(
val variableDescriptor = getOrFail(BindingContext.VARIABLE, property) val variableDescriptor = getOrFail(BindingContext.VARIABLE, property)
val irLocalVariable = declarationFactory.createLocalVariable(property, variableDescriptor) val irLocalVariable = declarationFactory.createLocalVariable(property, variableDescriptor)
irLocalVariable.initializer = property.initializer?.genExpr(variableDescriptor.type) irLocalVariable.initializer = property.initializer?.let {
it.genExpr().toExpectedType(variableDescriptor.type)
}
return irLocalVariable return irLocalVariable
} }
@@ -89,10 +73,11 @@ class IrStatementGenerator(
val irBlock = IrBlockExpressionImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, null, val irBlock = IrBlockExpressionImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, null,
hasResult = false, isDesugared = true) hasResult = false, isDesugared = true)
val ktInitializer = multiDeclaration.initializer!! val ktInitializer = multiDeclaration.initializer!!
val irInitializer = declarationFactory.createTemporaryVariable(ktInitializer.genExpr(null)) val irInitializerVal = declarationFactory.createTemporaryVariable(ktInitializer.genExpr())
irBlock.addStatement(irInitializer) irBlock.addStatement(irInitializerVal)
val irCallGenerator = IrCallGenerator(this).apply { putTemporary(ktInitializer, irInitializer.descriptor) } val irCallGenerator = IrCallGenerator(this)
irCallGenerator.putValue(ktInitializer, justExpressionValue { irInitializerVal.implicitGetExpression() })
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) { for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry) val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
@@ -108,7 +93,7 @@ class IrStatementGenerator(
override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrStatement { override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrStatement {
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, getReturnType(expression), val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, getReturnType(expression),
hasResult = isUsedAsExpression(expression), isDesugared = false) hasResult = isUsedAsExpression(expression), isDesugared = false)
expression.statements.forEach { irBlock.addStatement(it.genStmt(null)) } expression.statements.forEach { irBlock.addStatement(it.genStmt()) }
return irBlock return irBlock
} }
@@ -117,7 +102,7 @@ class IrStatementGenerator(
return IrReturnExpressionImpl( return IrReturnExpressionImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
returnTarget, returnTarget,
expression.returnedExpression?.let { it.genExpr(returnTarget.returnType) } expression.returnedExpression?.let { it.genExpr().toExpectedType(returnTarget.returnType) }
) )
} }
@@ -160,7 +145,7 @@ class IrStatementGenerator(
if (expression.entries.size == 1) { if (expression.entries.size == 1) {
val entry0 = expression.entries[0] val entry0 = expression.entries[0]
if (entry0 is KtLiteralStringTemplateEntry) { if (entry0 is KtLiteralStringTemplateEntry) {
return entry0.genExpr(null) return entry0.genExpr()
} }
} }
@@ -200,7 +185,7 @@ class IrStatementGenerator(
IrCallGenerator(this).generateCall(expression, resolvedCall) IrCallGenerator(this).generateCall(expression, resolvedCall)
} }
is VariableDescriptor -> is VariableDescriptor ->
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor.type, descriptor) IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor)
else -> else ->
IrDummyExpression( IrDummyExpression(
expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression), expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression),
@@ -0,0 +1,83 @@
/*
* 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.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
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.toExpectedType
interface IrValue {
fun load(): IrExpression
}
inline fun justExpressionValue(crossinline makeExpression: () -> IrExpression) =
object : IrValue {
override fun load() = makeExpression()
}
interface IrReference : IrValue {
fun store(value: IrExpression): IrExpression
}
class IrVariableReferenceValue(
val ktElement: KtElement,
val irOperator: IrOperator?,
val descriptor: VariableDescriptor
) : IrReference {
override fun load(): IrExpression =
IrGetVariableExpressionImpl(
ktElement.startOffset, ktElement.endOffset,
descriptor, irOperator
)
override fun store(value: IrExpression): IrExpression =
IrSetVariableExpressionImpl(
ktElement.startOffset, ktElement.endOffset,
descriptor, value.toExpectedType(descriptor.type), irOperator
)
}
class IrPropertyReferenceValue(
val ktElement: KtElement,
val irOperator: IrOperator?,
val descriptor: PropertyDescriptor,
val dispatchReceiver: IrExpression?,
val extensionReceiver: IrExpression?,
val isSafe: Boolean
) : IrReference {
private fun IrPropertyAccessExpression.setReceivers() =
apply {
dispatchReceiver = this@IrPropertyReferenceValue.dispatchReceiver
extensionReceiver = this@IrPropertyReferenceValue.extensionReceiver
}
override fun load(): IrExpression =
IrGetPropertyExpressionImpl(
ktElement.startOffset, ktElement.endOffset,
descriptor.type, isSafe, descriptor, irOperator
).setReceivers()
override fun store(value: IrExpression): IrExpression =
IrSetPropertyExpressionImpl(
ktElement.startOffset, ktElement.endOffset,
isSafe, descriptor, value.toExpectedType(descriptor.type), irOperator
).setReceivers()
}
@@ -16,52 +16,54 @@
package org.jetbrains.kotlin.ir.expressions package org.jetbrains.kotlin.ir.expressions
sealed class IrOperator { sealed class IrOperator(val debugName: String) {
object INVOKE : IrOperator() override fun toString(): String = debugName
object PREFIX_INCR : IrOperator()
object PREFIX_DECR : IrOperator()
object POSTFIX_INCR : IrOperator()
object POSTFIX_DECR : IrOperator()
object UMINUS : IrOperator()
object EXCL : IrOperator()
object EXCLEXCL : IrOperator()
object ELVIS : IrOperator()
object LT : IrOperator() object INVOKE : IrOperator("INVOKE")
object GT : IrOperator() object PREFIX_INCR : IrOperator("PREFIX_INCR")
object LTEQ : IrOperator() object PREFIX_DECR : IrOperator("PREFIX_DECR")
object GTEQ : IrOperator() object POSTFIX_INCR : IrOperator("POSTFIX_INCR")
object POSTFIX_DECR : IrOperator("POSTFIX_DECR")
object UMINUS : IrOperator("UMINUS")
object EXCL : IrOperator("EXCL")
object EXCLEXCL : IrOperator("EXCLEXCL")
object ELVIS : IrOperator("ELVIS")
object EQEQ : IrOperator() object LT : IrOperator("LT")
object EQEQEQ : IrOperator() object GT : IrOperator("GT")
object EXCLEQ : IrOperator() object LTEQ : IrOperator("LTEQ")
object EXCLEQEQ : IrOperator() object GTEQ : IrOperator("GTEQ")
object IN : IrOperator()
object NOT_IN : IrOperator()
object ANDAND : IrOperator()
object OROR : IrOperator()
object RANGE : IrOperator()
object PLUS : IrOperator() object EQEQ : IrOperator("EQEQ")
object MINUS : IrOperator() object EQEQEQ : IrOperator("EQEQEQ")
object MUL : IrOperator() object EXCLEQ : IrOperator("EXCLEQ")
object DIV : IrOperator() object EXCLEQEQ : IrOperator("EXCLEQEQ")
object MOD : IrOperator() object IN : IrOperator("IN")
object NOT_IN : IrOperator("NOT_IN")
object ANDAND : IrOperator("ANDAND")
object OROR : IrOperator("OROR")
object RANGE : IrOperator("RANGE")
object EQ : IrOperator() object PLUS : IrOperator("PLUS")
object PLUSEQ : IrOperator() object MINUS : IrOperator("MINUS")
object MINUSEQ : IrOperator() object MUL : IrOperator("MUL")
object MULEQ : IrOperator() object DIV : IrOperator("DIV")
object DIVEQ : IrOperator() object MOD : IrOperator("MOD")
object MODEQ : IrOperator()
data class COMPONENT_N private constructor(val index: Int) : IrOperator() { object EQ : IrOperator("EQ")
object PLUSEQ : IrOperator("PLUSEQ")
object MINUSEQ : IrOperator("MINUSEQ")
object MULTEQ : IrOperator("MULTEQ")
object DIVEQ : IrOperator("DIVEQ")
object PERCEQ : IrOperator("PERCEQ")
data class COMPONENT_N private constructor(val index: Int) : IrOperator("COMPONENT_$index") {
companion object { companion object {
private val precreatedComponents = Array(32, ::COMPONENT_N) private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) }
fun withIndex(index: Int) = fun withIndex(index: Int) =
if (index < precreatedComponents.size) if (index < precreatedComponents.size)
precreatedComponents[index] precreatedComponents[index - 1]
else else
COMPONENT_N(index) COMPONENT_N(index)
} }
@@ -23,13 +23,13 @@ import org.jetbrains.kotlin.types.KotlinType
interface IrPropertyAccessExpression : IrMemberAccessExpression { interface IrPropertyAccessExpression : IrMemberAccessExpression {
override val descriptor: PropertyDescriptor override val descriptor: PropertyDescriptor
val operator: IrOperator?
} }
interface IrGetPropertyExpression : IrPropertyAccessExpression interface IrGetPropertyExpression : IrPropertyAccessExpression
interface IrSetPropertyExpression : IrPropertyAccessExpression { interface IrSetPropertyExpression : IrPropertyAccessExpression {
var value: IrExpression var value: IrExpression
val operator: IrOperator
} }
class IrGetPropertyExpressionImpl( class IrGetPropertyExpressionImpl(
@@ -37,7 +37,8 @@ class IrGetPropertyExpressionImpl(
endOffset: Int, endOffset: Int,
type: KotlinType?, type: KotlinType?,
isSafe: Boolean, isSafe: Boolean,
override val descriptor: PropertyDescriptor override val descriptor: PropertyDescriptor,
override val operator: IrOperator? = null
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrGetPropertyExpression { ) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrGetPropertyExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetProperty(this, data) visitor.visitGetProperty(this, data)
@@ -48,7 +49,7 @@ class IrSetPropertyExpressionImpl(
endOffset: Int, endOffset: Int,
isSafe: Boolean, isSafe: Boolean,
override val descriptor: PropertyDescriptor, override val descriptor: PropertyDescriptor,
override val operator: IrOperator = IrOperator.EQ override val operator: IrOperator? = null
) : IrMemberAccessExpressionBase(startOffset, endOffset, null, isSafe), IrSetPropertyExpression { ) : IrMemberAccessExpressionBase(startOffset, endOffset, null, isSafe), IrSetPropertyExpression {
constructor( constructor(
startOffset: Int, startOffset: Int,
@@ -56,7 +57,7 @@ class IrSetPropertyExpressionImpl(
isSafe: Boolean, isSafe: Boolean,
descriptor: PropertyDescriptor, descriptor: PropertyDescriptor,
value: IrExpression, value: IrExpression,
operator: IrOperator = IrOperator.EQ operator: IrOperator? = null
) : this(startOffset, endOffset, isSafe, descriptor, operator) { ) : this(startOffset, endOffset, isSafe, descriptor, operator) {
this.value = value this.value = value
} }
@@ -21,11 +21,11 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
enum class IrTypeOperator { enum class IrTypeOperator {
AS, CAST,
SMART_AS, IMPLICIT_CAST,
SAFE_AS, SAFE_CAST,
IS, INSTANCEOF,
NOT_IS; NOT_INSTANCEOF;
} }
interface IrTypeOperatorExpression : IrExpression { interface IrTypeOperatorExpression : IrExpression {
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.ir.expressions package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.* import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -24,21 +23,22 @@ import org.jetbrains.kotlin.types.KotlinType
interface IrVariableAccessExpression : IrDeclarationReference { interface IrVariableAccessExpression : IrDeclarationReference {
override val descriptor: VariableDescriptor override val descriptor: VariableDescriptor
val operator: IrOperator?
} }
interface IrGetVariableExpression : IrVariableAccessExpression interface IrGetVariableExpression : IrVariableAccessExpression
interface IrSetVariableExpression : IrVariableAccessExpression { interface IrSetVariableExpression : IrVariableAccessExpression {
val value: IrExpression val value: IrExpression
val operator: IrOperator?
} }
class IrGetVariableExpressionImpl( class IrGetVariableExpressionImpl(
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
type: KotlinType?, descriptor: VariableDescriptor,
descriptor: VariableDescriptor override val operator: IrOperator? = null
) : IrTerminalDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, type, descriptor), IrGetVariableExpression { ) : IrTerminalDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, descriptor.type, descriptor), IrGetVariableExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetVariable(this, data) visitor.visitGetVariable(this, data)
} }
@@ -47,14 +47,14 @@ class IrSetVariableExpressionImpl(
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
override val descriptor: VariableDescriptor, override val descriptor: VariableDescriptor,
override val operator: IrOperator = IrOperator.EQ override val operator: IrOperator?
) : IrExpressionBase(startOffset, endOffset, null), IrSetVariableExpression { ) : IrExpressionBase(startOffset, endOffset, null), IrSetVariableExpression {
constructor( constructor(
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
descriptor: VariableDescriptor, descriptor: VariableDescriptor,
value: IrExpression, value: IrExpression,
operator: IrOperator = IrOperator.EQ operator: IrOperator?
) : this(startOffset, endOffset, descriptor, operator) { ) : this(startOffset, endOffset, descriptor, operator) {
this.value = value this.value = value
} }
+6
View File
@@ -0,0 +1,6 @@
// <<< augmentedAssignment1.txt
fun test(): Int {
var x = 0
x += 10
return x
}
+12
View File
@@ -0,0 +1,12 @@
IrFile /augmentedAssignment1.kt
IrFunction public fun test(): kotlin.Int
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=false
VAR var x: kotlin.Int
LITERAL Int type=kotlin.Int value='0'
SET_VAR x type=<no-type>
CALL .plus type=kotlin.Int operator=PLUSEQ
$this: GET_VAR x type=kotlin.Int
other: LITERAL Int type=kotlin.Int value='10'
RETURN type=<no-type>
GET_VAR x type=kotlin.Int
+8
View File
@@ -0,0 +1,8 @@
class A
operator fun A.plusAssign(s: String) {}
fun test() { // <<< augmentedAssignment2.txt
val a = A()
a += ""
}
+8
View File
@@ -0,0 +1,8 @@
IrFunction public fun test(): kotlin.Unit
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=false
VAR val a: A
CALL .<init> type=A operator=
CALL .plusAssign type=kotlin.Unit operator=PLUSEQ
$receiver: GET_VAR a type=A
s: ? IrStringConcatenationExpressionImpl type=kotlin.String
+1 -1
View File
@@ -10,5 +10,5 @@ IrFile /dotQualified.kt
BLOCK type=<no-type> hasResult=false isDesugared=true BLOCK type=<no-type> hasResult=false isDesugared=true
RETURN type=<no-type> RETURN type=<no-type>
GET_PROPERTY ?.length type=kotlin.Int? GET_PROPERTY ?.length type=kotlin.Int?
$this: TYPE_OP operator=SMART_AS typeOperand=kotlin.String $this: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR s type=kotlin.String? GET_VAR s type=kotlin.String?
+6 -6
View File
@@ -21,18 +21,18 @@ IrFile /smartCasts.kt
DUMMY KtIfExpression type=kotlin.Unit DUMMY KtIfExpression type=kotlin.Unit
CALL .println type=kotlin.Unit operator= CALL .println type=kotlin.Unit operator=
message: GET_PROPERTY .length type=kotlin.Int message: GET_PROPERTY .length type=kotlin.Int
$this: TYPE_OP operator=SMART_AS typeOperand=kotlin.String $this: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR x type=kotlin.Any GET_VAR x type=kotlin.Any
CALL .expectsString type=kotlin.Unit operator= CALL .expectsString type=kotlin.Unit operator=
s: TYPE_OP operator=SMART_AS typeOperand=kotlin.String s: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR x type=kotlin.Any GET_VAR x type=kotlin.Any
CALL .expectsInt type=kotlin.Unit operator= CALL .expectsInt type=kotlin.Unit operator=
i: GET_PROPERTY .length type=kotlin.Int i: GET_PROPERTY .length type=kotlin.Int
$this: TYPE_OP operator=SMART_AS typeOperand=kotlin.String $this: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR x type=kotlin.Any GET_VAR x type=kotlin.Any
CALL .expectsString type=kotlin.Unit operator= CALL .expectsString type=kotlin.Unit operator=
s: CALL .overloaded type=kotlin.String operator= s: CALL .overloaded type=kotlin.String operator=
s: TYPE_OP operator=SMART_AS typeOperand=kotlin.String s: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR x type=kotlin.Any GET_VAR x type=kotlin.Any
IrFunction public fun test2(/*0*/ x: kotlin.Any): kotlin.String IrFunction public fun test2(/*0*/ x: kotlin.Any): kotlin.String
IrExpressionBody IrExpressionBody
@@ -40,12 +40,12 @@ IrFile /smartCasts.kt
DUMMY KtIfExpression type=kotlin.Unit DUMMY KtIfExpression type=kotlin.Unit
RETURN type=<no-type> RETURN type=<no-type>
CALL .overloaded type=kotlin.String operator= CALL .overloaded type=kotlin.String operator=
s: TYPE_OP operator=SMART_AS typeOperand=kotlin.String s: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR x type=kotlin.Any GET_VAR x type=kotlin.Any
IrFunction public fun test3(/*0*/ x: kotlin.Any): kotlin.String IrFunction public fun test3(/*0*/ x: kotlin.Any): kotlin.String
IrExpressionBody IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=false BLOCK type=<no-type> hasResult=false isDesugared=false
DUMMY KtIfExpression type=kotlin.Unit DUMMY KtIfExpression type=kotlin.Unit
RETURN type=<no-type> RETURN type=<no-type>
TYPE_OP operator=SMART_AS typeOperand=kotlin.String TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR x type=kotlin.Any GET_VAR x type=kotlin.Any
@@ -22,5 +22,5 @@ IrFile /smartCastsWithDestructuring.kt
$receiver: GET_VAR tmp0 type=I1 $receiver: GET_VAR tmp0 type=I1
VAR val c2: kotlin.String VAR val c2: kotlin.String
CALL .component2 type=kotlin.String operator=COMPONENT_N(index=2) CALL .component2 type=kotlin.String operator=COMPONENT_N(index=2)
$receiver: TYPE_OP operator=SMART_AS typeOperand=I2 $receiver: TYPE_OP operator=IMPLICIT_CAST typeOperand=I2
GET_VAR tmp0 type=I1 GET_VAR tmp0 type=I1
@@ -41,6 +41,18 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("augmentedAssignment1.kt")
public void testAugmentedAssignment1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/augmentedAssignment1.kt");
doTest(fileName);
}
@TestMetadata("augmentedAssignment2.kt")
public void testAugmentedAssignment2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/augmentedAssignment2.kt");
doTest(fileName);
}
@TestMetadata("boxOk.kt") @TestMetadata("boxOk.kt")
public void testBoxOk() throws Exception { public void testBoxOk() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/boxOk.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/boxOk.kt");