- 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.psiUtil.endOffset
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.model.*
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.newHashMapWithExpectedSize
import java.util.*
class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenerator {
class IrCallGenerator(
private val irStatementGenerator: IrStatementGenerator
) : IrGenerator {
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) {
temporaries[ktExpression] = temporaryVariableDescriptor
fun putValue(ktExpression: KtExpression, irValue: IrValue) {
expressionValues[ktExpression] = irValue
}
private fun generateExpressionOrTemporary(ktExpression: KtExpression, expectedType: KotlinType?): IrExpression {
val temporary = temporaries[ktExpression]
return if (temporary != null)
irStatementGenerator.smartCastTo(
IrGetVariableExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, temporary.type, temporary),
expectedType
)
else
irStatementGenerator.generateExpression(ktExpression, expectedType)
fun putValue(receiver: ReceiverValue, irValue: IrValue) {
receiverValues[receiver] = irValue
}
fun putValue(valueArgument: ResolvedValueArgument, irValue: IrValue) {
valueArgumentValues[valueArgument] = irValue
}
fun generateCall(
@@ -64,10 +65,8 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
returnType,
resolvedCall.call.isSafeCall(), descriptor
).apply {
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver,
descriptor.dispatchReceiverParameter?.type)
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver,
descriptor.extensionReceiverParameter?.type)
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter)
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter)
}
is FunctionDescriptor ->
generateFunctionCall(descriptor, ktExpression, returnType, operator, resolvedCall, superQualifier)
@@ -102,10 +101,8 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
ktExpression.startOffset, ktExpression.endOffset, resultType,
descriptor, resolvedCall.call.isSafeCall(), operator, superQualifier
)
irCall.dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver,
descriptor.dispatchReceiverParameter?.type)
irCall.extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver,
descriptor.extensionReceiverParameter?.type)
irCall.dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter)
irCall.extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter)
return if (resolvedCall.requiresArgumentReordering()) {
generateCallWithArgumentReordering(irCall, ktExpression, resolvedCall, resultType)
@@ -116,10 +113,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
for (index in valueArguments!!.indices) {
val valueArgument = valueArguments[index]
val valueParameter = descriptor.valueParameters[index]
val irArgument = generateValueArgument(
valueArgument,
valueParameter.varargElementType ?: valueParameter.type
) ?: continue
val irArgument = generateValueArgument(valueArgument, valueParameter) ?: continue
irCall.putArgument(index, irArgument)
}
}
@@ -140,21 +134,19 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
hasResult = isUsedAsExpression(ktExpression),
isDesugared = true)
val temporaryVariablesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
val temporariesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
for (valueArgument in valueArgumentsInEvaluationOrder) {
val irArgument = generateValueArgument(valueArgument, null) ?: continue
val irArgument = generateValueArgument(valueArgument) ?: continue
val irTemporary = irStatementGenerator.declarationFactory.createTemporaryVariable(irArgument)
temporariesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
irBlock.addStatement(irTemporary)
temporaryVariablesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
}
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
val (temporaryDescriptor, irArgument) = temporaryVariablesForValueArguments[valueArgument]!!
val (temporaryDescriptor, irArgument) = temporariesForValueArguments[valueArgument]!!
val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index]
val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset, irArgument.type,
temporaryDescriptor)
irCall.putArgument(index, irStatementGenerator.smartCastTo(irGetTemporary, valueParameter.type))
val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset, temporaryDescriptor)
irCall.putArgument(index, irGetTemporary.toExpectedType(valueParameter.type))
}
irBlock.addStatement(irCall)
@@ -162,8 +154,16 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
return irBlock
}
// TODO smart casts on implicit receivers
fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?, expectedType: KotlinType?): IrExpression? =
fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?, receiverParameterDescriptor: ReceiverParameterDescriptor?) =
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) {
is ImplicitClassReceiver ->
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)
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
is ExpressionReceiver ->
generateExpressionOrTemporary(receiver.expression, expectedType)
generateExpression(receiver.expression)
is ClassValueReceiver ->
IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
receiver.classQualifier.descriptor)
@@ -185,15 +185,32 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
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) {
is DefaultValueArgument ->
null
is ExpressionValueArgument ->
generateExpressionOrTemporary(valueArgument.valueArgument!!.getArgumentExpression()!!, expectedType)
generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
is VarargValueArgument ->
TODO("vararg")
else ->
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 =
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 =
IrVariableImpl(irExpression.startOffset, irExpression.endOffset, IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable(
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.resolve.BindingContext
interface IrDeclarationGenerator : IrGenerator
@@ -94,7 +95,8 @@ abstract class IrDeclarationGeneratorBase(
private fun generateExpressionWithinContext(ktExpression: KtExpression, scopeOwner: DeclarationDescriptor): IrExpression =
IrStatementGenerator(context, scopeOwner, IrLocalDeclarationsFactory(scopeOwner))
.generateExpression(ktExpression, getExpectedTypeForLastInferredCall(ktExpression))
.generateExpression(ktExpression)
.toExpectedType(getExpectedTypeForLastInferredCall(ktExpression))
private fun generateFunctionBody(scopeOwner: CallableDescriptor, ktBody: KtExpression): IrBody {
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 =
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? =
context.bindingContext.getType(key)
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.psi2ir.generators
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
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.psi.KtBinaryExpression
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.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 {
override val context: IrGeneratorContext get() = irStatementGenerator.context
@@ -33,18 +45,46 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
return when (ktOperator) {
KtTokens.EQ -> generateAssignment(expression)
in KtTokens.AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, ktOperator)
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 {
val ktLeft = expression.left!!
val ktRight = expression.right!!
val lhs = generateAssignmentLHS(ktLeft)
return lhs.generateAssignment(expression, IrOperator.EQ, irStatementGenerator.generateExpression(ktRight, lhs.type))
val lhsReference = generateReferenceForAssignmentLhs(ktLeft, IrOperator.EQ)
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 descriptor = resolvedCall.candidateDescriptor
@@ -53,15 +93,13 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
if (descriptor.isDelegated)
TODO("Delegated local variable")
else
VariableLHS(descriptor)
IrVariableReferenceValue(ktLeft, irOperator, descriptor)
is PropertyDescriptor ->
IrCallGenerator(irStatementGenerator).run {
PropertyLHS(
descriptor,
generateReceiver(ktLeft, resolvedCall.dispatchReceiver,
descriptor.dispatchReceiverParameter?.type),
generateReceiver(ktLeft, resolvedCall.extensionReceiver,
descriptor.extensionReceiverParameter?.type),
IrPropertyReferenceValue(
ktLeft, irOperator, descriptor,
generateReceiver(ktLeft, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter),
generateReceiver(ktLeft, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter),
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.startOffset
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.BindingContextUtils
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.evaluate.ConstantExpressionEvaluator
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
class IrStatementGenerator(
@@ -42,32 +42,14 @@ class IrStatementGenerator(
val declarationFactory: IrLocalDeclarationsFactory
) : KtVisitor<IrStatement, Nothing?>(), IrGenerator {
fun generateExpression(ktExpression: KtExpression, expectedType: KotlinType?): IrExpression =
ktExpression.genExpr(expectedType)
fun generateExpression(ktExpression: KtExpression): IrExpression =
ktExpression.genExpr()
private fun KtElement.genStmt(expectedType: KotlinType?): IrStatement {
val irStatement = 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.genStmt(): IrStatement =
deparenthesize().accept(this@IrStatementGenerator, null)
private fun KtElement.genExpr(): IrExpression =
genStmt().assertCast()
override fun visitExpression(expression: KtExpression, data: Nothing?): IrStatement =
createDummyExpression(expression, expression.javaClass.simpleName)
@@ -78,7 +60,9 @@ class IrStatementGenerator(
val variableDescriptor = getOrFail(BindingContext.VARIABLE, property)
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
}
@@ -89,10 +73,11 @@ class IrStatementGenerator(
val irBlock = IrBlockExpressionImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, null,
hasResult = false, isDesugared = true)
val ktInitializer = multiDeclaration.initializer!!
val irInitializer = declarationFactory.createTemporaryVariable(ktInitializer.genExpr(null))
irBlock.addStatement(irInitializer)
val irInitializerVal = declarationFactory.createTemporaryVariable(ktInitializer.genExpr())
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()) {
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
@@ -108,7 +93,7 @@ class IrStatementGenerator(
override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrStatement {
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, getReturnType(expression),
hasResult = isUsedAsExpression(expression), isDesugared = false)
expression.statements.forEach { irBlock.addStatement(it.genStmt(null)) }
expression.statements.forEach { irBlock.addStatement(it.genStmt()) }
return irBlock
}
@@ -117,7 +102,7 @@ class IrStatementGenerator(
return IrReturnExpressionImpl(
expression.startOffset, expression.endOffset,
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) {
val entry0 = expression.entries[0]
if (entry0 is KtLiteralStringTemplateEntry) {
return entry0.genExpr(null)
return entry0.genExpr()
}
}
@@ -200,7 +185,7 @@ class IrStatementGenerator(
IrCallGenerator(this).generateCall(expression, resolvedCall)
}
is VariableDescriptor ->
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor.type, descriptor)
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor)
else ->
IrDummyExpression(
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
sealed class IrOperator {
object INVOKE : IrOperator()
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()
sealed class IrOperator(val debugName: String) {
override fun toString(): String = debugName
object INVOKE : IrOperator("INVOKE")
object PREFIX_INCR : IrOperator("PREFIX_INCR")
object PREFIX_DECR : IrOperator("PREFIX_DECR")
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 LT : IrOperator()
object GT : IrOperator()
object LTEQ : IrOperator()
object GTEQ : IrOperator()
object LT : IrOperator("LT")
object GT : IrOperator("GT")
object LTEQ : IrOperator("LTEQ")
object GTEQ : IrOperator("GTEQ")
object EQEQ : IrOperator()
object EQEQEQ : IrOperator()
object EXCLEQ : IrOperator()
object EXCLEQEQ : IrOperator()
object IN : IrOperator()
object NOT_IN : IrOperator()
object ANDAND : IrOperator()
object OROR : IrOperator()
object RANGE : IrOperator()
object EQEQ : IrOperator("EQEQ")
object EQEQEQ : IrOperator("EQEQEQ")
object EXCLEQ : IrOperator("EXCLEQ")
object EXCLEQEQ : IrOperator("EXCLEQEQ")
object IN : IrOperator("IN")
object NOT_IN : IrOperator("NOT_IN")
object ANDAND : IrOperator("ANDAND")
object OROR : IrOperator("OROR")
object RANGE : IrOperator("RANGE")
object PLUS : IrOperator()
object MINUS : IrOperator()
object MUL : IrOperator()
object DIV : IrOperator()
object MOD : IrOperator()
object PLUS : IrOperator("PLUS")
object MINUS : IrOperator("MINUS")
object MUL : IrOperator("MUL")
object DIV : IrOperator("DIV")
object MOD : IrOperator("MOD")
object EQ : IrOperator()
object PLUSEQ : IrOperator()
object MINUSEQ : IrOperator()
object MULEQ : IrOperator()
object DIVEQ : IrOperator()
object MODEQ : 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() {
data class COMPONENT_N private constructor(val index: Int) : IrOperator("COMPONENT_$index") {
companion object {
private val precreatedComponents = Array(32, ::COMPONENT_N)
private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) }
fun withIndex(index: Int) =
if (index < precreatedComponents.size)
precreatedComponents[index]
precreatedComponents[index - 1]
else
COMPONENT_N(index)
}
@@ -23,13 +23,13 @@ import org.jetbrains.kotlin.types.KotlinType
interface IrPropertyAccessExpression : IrMemberAccessExpression {
override val descriptor: PropertyDescriptor
val operator: IrOperator?
}
interface IrGetPropertyExpression : IrPropertyAccessExpression
interface IrSetPropertyExpression : IrPropertyAccessExpression {
var value: IrExpression
val operator: IrOperator
}
class IrGetPropertyExpressionImpl(
@@ -37,7 +37,8 @@ class IrGetPropertyExpressionImpl(
endOffset: Int,
type: KotlinType?,
isSafe: Boolean,
override val descriptor: PropertyDescriptor
override val descriptor: PropertyDescriptor,
override val operator: IrOperator? = null
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrGetPropertyExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetProperty(this, data)
@@ -48,7 +49,7 @@ class IrSetPropertyExpressionImpl(
endOffset: Int,
isSafe: Boolean,
override val descriptor: PropertyDescriptor,
override val operator: IrOperator = IrOperator.EQ
override val operator: IrOperator? = null
) : IrMemberAccessExpressionBase(startOffset, endOffset, null, isSafe), IrSetPropertyExpression {
constructor(
startOffset: Int,
@@ -56,7 +57,7 @@ class IrSetPropertyExpressionImpl(
isSafe: Boolean,
descriptor: PropertyDescriptor,
value: IrExpression,
operator: IrOperator = IrOperator.EQ
operator: IrOperator? = null
) : this(startOffset, endOffset, isSafe, descriptor, operator) {
this.value = value
}
@@ -21,11 +21,11 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
enum class IrTypeOperator {
AS,
SMART_AS,
SAFE_AS,
IS,
NOT_IS;
CAST,
IMPLICIT_CAST,
SAFE_CAST,
INSTANCEOF,
NOT_INSTANCEOF;
}
interface IrTypeOperatorExpression : IrExpression {
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -24,21 +23,22 @@ import org.jetbrains.kotlin.types.KotlinType
interface IrVariableAccessExpression : IrDeclarationReference {
override val descriptor: VariableDescriptor
val operator: IrOperator?
}
interface IrGetVariableExpression : IrVariableAccessExpression
interface IrSetVariableExpression : IrVariableAccessExpression {
val value: IrExpression
val operator: IrOperator?
}
class IrGetVariableExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
descriptor: VariableDescriptor
) : IrTerminalDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, type, descriptor), IrGetVariableExpression {
descriptor: VariableDescriptor,
override val operator: IrOperator? = null
) : IrTerminalDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, descriptor.type, descriptor), IrGetVariableExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetVariable(this, data)
}
@@ -47,14 +47,14 @@ class IrSetVariableExpressionImpl(
startOffset: Int,
endOffset: Int,
override val descriptor: VariableDescriptor,
override val operator: IrOperator = IrOperator.EQ
override val operator: IrOperator?
) : IrExpressionBase(startOffset, endOffset, null), IrSetVariableExpression {
constructor(
startOffset: Int,
endOffset: Int,
descriptor: VariableDescriptor,
value: IrExpression,
operator: IrOperator = IrOperator.EQ
operator: IrOperator?
) : this(startOffset, endOffset, descriptor, operator) {
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
RETURN type=<no-type>
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?
+6 -6
View File
@@ -21,18 +21,18 @@ IrFile /smartCasts.kt
DUMMY KtIfExpression type=kotlin.Unit
CALL .println type=kotlin.Unit operator=
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
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
CALL .expectsInt type=kotlin.Unit operator=
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
CALL .expectsString type=kotlin.Unit 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
IrFunction public fun test2(/*0*/ x: kotlin.Any): kotlin.String
IrExpressionBody
@@ -40,12 +40,12 @@ IrFile /smartCasts.kt
DUMMY KtIfExpression type=kotlin.Unit
RETURN type=<no-type>
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
IrFunction public fun test3(/*0*/ x: kotlin.Any): kotlin.String
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=false
DUMMY KtIfExpression type=kotlin.Unit
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
@@ -22,5 +22,5 @@ IrFile /smartCastsWithDestructuring.kt
$receiver: GET_VAR tmp0 type=I1
VAR val c2: kotlin.String
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
@@ -41,6 +41,18 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
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")
public void testBoxOk() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/boxOk.kt");