IR:
- Redo smart casts handling (yet again). Front-end typing information can't be used for expressions in IR, since it provides inferred type for PSI expressions for the last corresponding resoled call. - Assignments handling, initial implementation.
This commit is contained in:
committed by
Dmitry Petrov
parent
c4bbcadb34
commit
ecf6ab9e25
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+42
-36
@@ -37,12 +37,15 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
|
|||||||
temporaries[ktExpression] = temporaryVariableDescriptor
|
temporaries[ktExpression] = temporaryVariableDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateExpressionOrTemporary(ktExpression: KtExpression): IrExpression {
|
private fun generateExpressionOrTemporary(ktExpression: KtExpression, expectedType: KotlinType?): IrExpression {
|
||||||
val temporary = temporaries[ktExpression]
|
val temporary = temporaries[ktExpression]
|
||||||
return if (temporary != null)
|
return if (temporary != null)
|
||||||
IrGetVariableExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, getType(ktExpression), temporary)
|
irStatementGenerator.smartCastTo(
|
||||||
|
IrGetVariableExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, temporary.type, temporary),
|
||||||
|
expectedType
|
||||||
|
)
|
||||||
else
|
else
|
||||||
irStatementGenerator.generateExpression(ktExpression)
|
irStatementGenerator.generateExpression(ktExpression, expectedType)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateCall(
|
fun generateCall(
|
||||||
@@ -50,27 +53,24 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
|
|||||||
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
||||||
operator: IrOperator? = null,
|
operator: IrOperator? = null,
|
||||||
superQualifier: ClassDescriptor? = null
|
superQualifier: ClassDescriptor? = null
|
||||||
) = generateCall(ktExpression, getTypeOrFail(ktExpression), resolvedCall, operator, superQualifier)
|
|
||||||
|
|
||||||
fun generateCall(
|
|
||||||
ktExpression: KtExpression,
|
|
||||||
resultType: KotlinType?,
|
|
||||||
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
|
||||||
operator: IrOperator? = null,
|
|
||||||
superQualifier: ClassDescriptor? = null
|
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
val descriptor = resolvedCall.resultingDescriptor
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
|
val returnType = getReturnType(resolvedCall)
|
||||||
|
|
||||||
return when (descriptor) {
|
return when (descriptor) {
|
||||||
is PropertyDescriptor ->
|
is PropertyDescriptor ->
|
||||||
IrGetPropertyExpressionImpl(
|
IrGetPropertyExpressionImpl(
|
||||||
ktExpression.startOffset, ktExpression.endOffset, resultType,
|
ktExpression.startOffset, ktExpression.endOffset,
|
||||||
|
returnType,
|
||||||
resolvedCall.call.isSafeCall(), descriptor
|
resolvedCall.call.isSafeCall(), descriptor
|
||||||
).apply {
|
).apply {
|
||||||
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver)
|
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver,
|
||||||
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver)
|
descriptor.dispatchReceiverParameter?.type)
|
||||||
|
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver,
|
||||||
|
descriptor.extensionReceiverParameter?.type)
|
||||||
}
|
}
|
||||||
is FunctionDescriptor ->
|
is FunctionDescriptor ->
|
||||||
generateFunctionCall(descriptor, ktExpression, resultType, operator, resolvedCall, superQualifier)
|
generateFunctionCall(descriptor, ktExpression, returnType, operator, resolvedCall, superQualifier)
|
||||||
else ->
|
else ->
|
||||||
TODO("Unexpected callable descriptor: $descriptor ${descriptor.javaClass.simpleName}")
|
TODO("Unexpected callable descriptor: $descriptor ${descriptor.javaClass.simpleName}")
|
||||||
}
|
}
|
||||||
@@ -102,8 +102,10 @@ 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,
|
||||||
irCall.extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver)
|
descriptor.dispatchReceiverParameter?.type)
|
||||||
|
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)
|
||||||
@@ -113,7 +115,11 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
|
|||||||
val valueArguments = resolvedCall.valueArgumentsByIndex
|
val valueArguments = resolvedCall.valueArgumentsByIndex
|
||||||
for (index in valueArguments!!.indices) {
|
for (index in valueArguments!!.indices) {
|
||||||
val valueArgument = valueArguments[index]
|
val valueArgument = valueArguments[index]
|
||||||
val irArgument = generateValueArgument(valueArgument) ?: continue
|
val valueParameter = descriptor.valueParameters[index]
|
||||||
|
val irArgument = generateValueArgument(
|
||||||
|
valueArgument,
|
||||||
|
valueParameter.varargElementType ?: valueParameter.type
|
||||||
|
) ?: continue
|
||||||
irCall.putArgument(index, irArgument)
|
irCall.putArgument(index, irArgument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +142,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
|
|||||||
|
|
||||||
val temporaryVariablesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
|
val temporaryVariablesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
|
||||||
for (valueArgument in valueArgumentsInEvaluationOrder) {
|
for (valueArgument in valueArgumentsInEvaluationOrder) {
|
||||||
val irArgument = generateValueArgument(valueArgument) ?: continue
|
val irArgument = generateValueArgument(valueArgument, null) ?: continue
|
||||||
val irTemporary = irStatementGenerator.declarationFactory.createTemporaryVariable(irArgument)
|
val irTemporary = irStatementGenerator.declarationFactory.createTemporaryVariable(irArgument)
|
||||||
irBlock.addStatement(irTemporary)
|
irBlock.addStatement(irTemporary)
|
||||||
|
|
||||||
@@ -145,9 +151,10 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
|
|||||||
|
|
||||||
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
|
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
|
||||||
val (temporaryDescriptor, irArgument) = temporaryVariablesForValueArguments[valueArgument]!!
|
val (temporaryDescriptor, irArgument) = temporaryVariablesForValueArguments[valueArgument]!!
|
||||||
val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset,
|
val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index]
|
||||||
irArgument.type, temporaryDescriptor)
|
val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset, irArgument.type,
|
||||||
irCall.putArgument(index, irGetTemporary)
|
temporaryDescriptor)
|
||||||
|
irCall.putArgument(index, irStatementGenerator.smartCastTo(irGetTemporary, valueParameter.type))
|
||||||
}
|
}
|
||||||
|
|
||||||
irBlock.addStatement(irCall)
|
irBlock.addStatement(irCall)
|
||||||
@@ -156,7 +163,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO smart casts on implicit receivers
|
// TODO smart casts on implicit receivers
|
||||||
fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? =
|
fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?, expectedType: KotlinType?): 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)
|
||||||
@@ -165,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)
|
generateExpressionOrTemporary(receiver.expression, expectedType)
|
||||||
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)
|
||||||
@@ -178,16 +185,15 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
|
|||||||
TODO("Receiver: ${receiver.javaClass.simpleName}")
|
TODO("Receiver: ${receiver.javaClass.simpleName}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? {
|
fun generateValueArgument(valueArgument: ResolvedValueArgument, expectedType: KotlinType?) =
|
||||||
when (valueArgument) {
|
when (valueArgument) {
|
||||||
is DefaultValueArgument ->
|
is DefaultValueArgument ->
|
||||||
return null
|
null
|
||||||
is ExpressionValueArgument ->
|
is ExpressionValueArgument ->
|
||||||
return generateExpressionOrTemporary(valueArgument.valueArgument!!.getArgumentExpression()!!)
|
generateExpressionOrTemporary(valueArgument.valueArgument!!.getArgumentExpression()!!, expectedType)
|
||||||
is VarargValueArgument ->
|
is VarargValueArgument ->
|
||||||
TODO("vararg")
|
TODO("vararg")
|
||||||
else ->
|
else ->
|
||||||
TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}")
|
TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-11
@@ -16,10 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.psi2ir.generators
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDummyDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDummyDeclaration
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
@@ -51,13 +48,17 @@ abstract class IrDeclarationGeneratorBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateClassOrObjectDeclaration(ktDeclaration: KtClassOrObject) {
|
private fun generateClassOrObjectDeclaration(ktDeclaration: KtClassOrObject) {
|
||||||
IrDummyDeclaration(ktDeclaration.startOffset, ktDeclaration.endOffset, getOrFail(BindingContext.CLASS, ktDeclaration))
|
IrDummyDeclaration(
|
||||||
.register()
|
ktDeclaration.startOffset, ktDeclaration.endOffset,
|
||||||
|
getOrFail(BindingContext.CLASS, ktDeclaration)
|
||||||
|
).register()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateTypeAliasDeclaration(ktDeclaration: KtTypeAlias) {
|
private fun generateTypeAliasDeclaration(ktDeclaration: KtTypeAlias) {
|
||||||
IrDummyDeclaration(ktDeclaration.startOffset, ktDeclaration.endOffset, getOrFail(BindingContext.TYPE_ALIAS, ktDeclaration))
|
IrDummyDeclaration(
|
||||||
.register()
|
ktDeclaration.startOffset, ktDeclaration.endOffset,
|
||||||
|
getOrFail(BindingContext.TYPE_ALIAS, ktDeclaration)
|
||||||
|
).register()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateFunctionDeclaration(ktNamedFunction: KtNamedFunction) {
|
fun generateFunctionDeclaration(ktNamedFunction: KtNamedFunction) {
|
||||||
@@ -92,16 +93,17 @@ abstract class IrDeclarationGeneratorBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateExpressionWithinContext(ktExpression: KtExpression, scopeOwner: DeclarationDescriptor): IrExpression =
|
private fun generateExpressionWithinContext(ktExpression: KtExpression, scopeOwner: DeclarationDescriptor): IrExpression =
|
||||||
IrStatementGenerator(context, IrLocalDeclarationsFactory(scopeOwner)).generateExpression(ktExpression)
|
IrStatementGenerator(context, scopeOwner, IrLocalDeclarationsFactory(scopeOwner))
|
||||||
|
.generateExpression(ktExpression, getExpectedTypeForLastInferredCall(ktExpression))
|
||||||
|
|
||||||
private fun generateFunctionBody(scopeOwner: DeclarationDescriptor, ktBody: KtExpression): IrBody {
|
private fun generateFunctionBody(scopeOwner: CallableDescriptor, ktBody: KtExpression): IrBody {
|
||||||
val irRhs = generateExpressionWithinContext(ktBody, scopeOwner)
|
val irRhs = generateExpressionWithinContext(ktBody, scopeOwner)
|
||||||
val irExpressionBody =
|
val irExpressionBody =
|
||||||
if (ktBody is KtBlockExpression)
|
if (ktBody is KtBlockExpression)
|
||||||
irRhs
|
irRhs
|
||||||
else
|
else
|
||||||
IrBlockExpressionImpl(ktBody.startOffset, ktBody.endOffset, null, hasResult = false, isDesugared = true).apply {
|
IrBlockExpressionImpl(ktBody.startOffset, ktBody.endOffset, null, hasResult = false, isDesugared = true).apply {
|
||||||
addStatement(IrReturnExpressionImpl(ktBody.startOffset, ktBody.endOffset, null, irRhs))
|
addStatement(IrReturnExpressionImpl(ktBody.startOffset, ktBody.endOffset, scopeOwner, irRhs))
|
||||||
}
|
}
|
||||||
return IrExpressionBodyImpl(ktBody.startOffset, ktBody.endOffset, irExpressionBody)
|
return IrExpressionBodyImpl(ktBody.startOffset, ktBody.endOffset, irExpressionBody)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,23 +17,25 @@
|
|||||||
package org.jetbrains.kotlin.psi2ir.generators
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrDummyExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtBlockExpression
|
||||||
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.startOffset
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
|
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
|
||||||
|
|
||||||
interface IrGenerator {
|
interface IrGenerator {
|
||||||
val context: IrGeneratorContext
|
val context: IrGeneratorContext
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrGenerator.getType(key: KtExpression): KotlinType? =
|
|
||||||
context.bindingContext.getType(key)
|
|
||||||
|
|
||||||
fun IrGenerator.getTypeOrFail(key: KtExpression): KotlinType =
|
|
||||||
getType(key) ?: TODO("No type for expression: ${key.text}")
|
|
||||||
|
|
||||||
fun <K, V : Any> IrGenerator.get(slice: ReadOnlySlice<K, V>, key: K): V? =
|
fun <K, V : Any> IrGenerator.get(slice: ReadOnlySlice<K, V>, key: K): V? =
|
||||||
context.bindingContext[slice, key]
|
context.bindingContext[slice, key]
|
||||||
|
|
||||||
@@ -43,11 +45,54 @@ 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))
|
||||||
|
|
||||||
fun IrGenerator.isUsedAsExpression(ktExpression: KtExpression) =
|
|
||||||
get(BindingContext.USED_AS_EXPRESSION, ktExpression) ?: false
|
|
||||||
|
|
||||||
inline fun <K, V : Any> IrGenerator.getOrElse(slice: ReadOnlySlice<K, V>, key: K, otherwise: (K) -> V): V =
|
inline fun <K, V : Any> IrGenerator.getOrElse(slice: ReadOnlySlice<K, V>, key: K, otherwise: (K) -> V): V =
|
||||||
context.bindingContext[slice, key] ?: otherwise(key)
|
context.bindingContext[slice, key] ?: otherwise(key)
|
||||||
|
|
||||||
|
fun IrGenerator.getInferredTypeWithSmartcasts(key: KtExpression): KotlinType? =
|
||||||
|
context.bindingContext.getType(key)
|
||||||
|
|
||||||
|
fun IrGenerator.getExpectedTypeForLastInferredCall(key: KtExpression): KotlinType? =
|
||||||
|
get(BindingContext.EXPECTED_EXPRESSION_TYPE, key)
|
||||||
|
|
||||||
|
fun IrGenerator.getInferredTypeWithSmarcastsOrFail(key: KtExpression): KotlinType =
|
||||||
|
getInferredTypeWithSmartcasts(key) ?: TODO("No type for expression: ${key.text}")
|
||||||
|
|
||||||
|
fun IrGenerator.isUsedAsExpression(ktExpression: KtExpression) =
|
||||||
|
get(BindingContext.USED_AS_EXPRESSION, ktExpression) ?: false
|
||||||
|
|
||||||
fun IrGenerator.getResolvedCall(key: KtExpression): ResolvedCall<out CallableDescriptor>? =
|
fun IrGenerator.getResolvedCall(key: KtExpression): ResolvedCall<out CallableDescriptor>? =
|
||||||
key.getResolvedCall(context.bindingContext)
|
key.getResolvedCall(context.bindingContext)
|
||||||
|
|
||||||
|
fun IrGenerator.getReturnType(key: KtExpression): KotlinType? {
|
||||||
|
val resolvedCall = getResolvedCall(key)
|
||||||
|
if (resolvedCall != null) {
|
||||||
|
return getReturnType(resolvedCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key is KtBlockExpression) {
|
||||||
|
if (!isUsedAsExpression(key)) return null
|
||||||
|
return getReturnType(key.statements.last())
|
||||||
|
}
|
||||||
|
|
||||||
|
throw AssertionError("Unexpected expression: $key")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getReturnType(resolvedCall: ResolvedCall<*>): KotlinType {
|
||||||
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
|
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
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
throw AssertionError("Unexpected desciptor in resolved call: $descriptor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrGenerator.createDummyExpression(ktExpression: KtExpression, description: String): IrDummyExpression =
|
||||||
|
IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, getInferredTypeWithSmartcasts(ktExpression), description)
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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.impl.LocalVariableDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
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.calls.callUtil.isSafeCall
|
||||||
|
|
||||||
|
class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator {
|
||||||
|
override val context: IrGeneratorContext get() = irStatementGenerator.context
|
||||||
|
|
||||||
|
fun generateBinaryExpression(expression: KtBinaryExpression): IrExpression {
|
||||||
|
val ktOperator = expression.operationReference.getReferencedNameElementType()
|
||||||
|
|
||||||
|
return when (ktOperator) {
|
||||||
|
KtTokens.EQ -> generateAssignment(expression)
|
||||||
|
else -> createDummyExpression(expression, ktOperator.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateAssignmentLHS(ktLeft: KtExpression): AssignmentLHS {
|
||||||
|
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
|
||||||
|
val descriptor = resolvedCall.candidateDescriptor
|
||||||
|
|
||||||
|
return when (descriptor) {
|
||||||
|
is LocalVariableDescriptor ->
|
||||||
|
if (descriptor.isDelegated)
|
||||||
|
TODO("Delegated local variable")
|
||||||
|
else
|
||||||
|
VariableLHS(descriptor)
|
||||||
|
is PropertyDescriptor ->
|
||||||
|
IrCallGenerator(irStatementGenerator).run {
|
||||||
|
PropertyLHS(
|
||||||
|
descriptor,
|
||||||
|
generateReceiver(ktLeft, resolvedCall.dispatchReceiver,
|
||||||
|
descriptor.dispatchReceiverParameter?.type),
|
||||||
|
generateReceiver(ktLeft, resolvedCall.extensionReceiver,
|
||||||
|
descriptor.extensionReceiverParameter?.type),
|
||||||
|
resolvedCall.call.isSafeCall()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
TODO("Other cases of LHS")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+103
-54
@@ -16,10 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.psi2ir.generators
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.assertCast
|
import org.jetbrains.kotlin.ir.assertCast
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
@@ -28,43 +25,52 @@ 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.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntValue
|
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.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||||
|
|
||||||
class IrStatementGenerator(
|
class IrStatementGenerator(
|
||||||
override val context: IrGeneratorContext,
|
override val context: IrGeneratorContext,
|
||||||
|
val scopeOwner: DeclarationDescriptor,
|
||||||
val declarationFactory: IrLocalDeclarationsFactory
|
val declarationFactory: IrLocalDeclarationsFactory
|
||||||
) : KtVisitor<IrStatement, Nothing?>(), IrGenerator {
|
) : KtVisitor<IrStatement, Nothing?>(), IrGenerator {
|
||||||
|
|
||||||
fun generateStatement(ktExpression: KtExpression) = ktExpression.generate()
|
fun generateExpression(ktExpression: KtExpression, expectedType: KotlinType?): IrExpression =
|
||||||
fun generateExpression(ktExpression: KtExpression) = ktExpression.generateExpression()
|
ktExpression.genExpr(expectedType)
|
||||||
|
|
||||||
private fun KtElement.generate(): IrStatement =
|
private fun KtElement.genStmt(expectedType: KotlinType?): IrStatement {
|
||||||
deparenthesize()
|
val irStatement = deparenthesize().accept(this@IrStatementGenerator, null)
|
||||||
.accept(this@IrStatementGenerator, null)
|
if (irStatement is IrExpression) {
|
||||||
.applySmartCastIfNeeded(this)
|
return smartCastTo(irStatement, expectedType)
|
||||||
|
|
||||||
private fun KtElement.generateExpression(): IrExpression =
|
|
||||||
generate().assertCast()
|
|
||||||
|
|
||||||
private fun IrStatement.applySmartCastIfNeeded(ktElement: KtElement): IrStatement {
|
|
||||||
if (this is IrExpression && ktElement is KtExpression) {
|
|
||||||
val smartCastType = get(BindingContext.SMARTCAST, ktElement)
|
|
||||||
if (smartCastType != null) {
|
|
||||||
return IrTypeOperatorExpressionImpl(
|
|
||||||
ktElement.startOffset, ktElement.endOffset, smartCastType,
|
|
||||||
IrTypeOperator.SMART_AS, this@applySmartCastIfNeeded, smartCastType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun visitExpression(expression: KtExpression, data: Nothing?): IrStatement =
|
override fun visitExpression(expression: KtExpression, data: Nothing?): IrStatement =
|
||||||
IrDummyExpression(expression.startOffset, expression.endOffset, getType(expression), expression.javaClass.simpleName)
|
createDummyExpression(expression, expression.javaClass.simpleName)
|
||||||
|
|
||||||
override fun visitProperty(property: KtProperty, data: Nothing?): IrStatement {
|
override fun visitProperty(property: KtProperty, data: Nothing?): IrStatement {
|
||||||
if (property.delegateExpression != null) TODO("Local delegated property")
|
if (property.delegateExpression != null) TODO("Local delegated property")
|
||||||
@@ -72,7 +78,7 @@ 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?.generateExpression()
|
irLocalVariable.initializer = property.initializer?.genExpr(variableDescriptor.type)
|
||||||
|
|
||||||
return irLocalVariable
|
return irLocalVariable
|
||||||
}
|
}
|
||||||
@@ -80,10 +86,10 @@ class IrStatementGenerator(
|
|||||||
override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Nothing?): IrStatement {
|
override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Nothing?): IrStatement {
|
||||||
// TODO use some special form that introduces multiple declarations into surrounding scope?
|
// TODO use some special form that introduces multiple declarations into surrounding scope?
|
||||||
|
|
||||||
val irBlock = IrBlockExpressionImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, getType(multiDeclaration),
|
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.generateExpression())
|
val irInitializer = declarationFactory.createTemporaryVariable(ktInitializer.genExpr(null))
|
||||||
irBlock.addStatement(irInitializer)
|
irBlock.addStatement(irInitializer)
|
||||||
|
|
||||||
val irCallGenerator = IrCallGenerator(this).apply { putTemporary(ktInitializer, irInitializer.descriptor) }
|
val irCallGenerator = IrCallGenerator(this).apply { putTemporary(ktInitializer, irInitializer.descriptor) }
|
||||||
@@ -91,8 +97,7 @@ class IrStatementGenerator(
|
|||||||
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)
|
||||||
val componentVariable = getOrFail(BindingContext.VARIABLE, ktEntry)
|
val componentVariable = getOrFail(BindingContext.VARIABLE, ktEntry)
|
||||||
val irComponentCall = irCallGenerator.generateCall(ktEntry, componentVariable.type, componentResolvedCall,
|
val irComponentCall = irCallGenerator.generateCall(ktEntry, componentResolvedCall, IrOperator.COMPONENT_N.withIndex(index + 1))
|
||||||
IrOperator.COMPONENT_N.withIndex(index + 1))
|
|
||||||
val irComponentVar = declarationFactory.createLocalVariable(ktEntry, componentVariable, irComponentCall)
|
val irComponentVar = declarationFactory.createLocalVariable(ktEntry, componentVariable, irComponentCall)
|
||||||
irBlock.addStatement(irComponentVar)
|
irBlock.addStatement(irComponentVar)
|
||||||
}
|
}
|
||||||
@@ -101,20 +106,44 @@ 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, getType(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.generate()) }
|
expression.statements.forEach { irBlock.addStatement(it.genStmt(null)) }
|
||||||
return irBlock
|
return irBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrStatement =
|
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrStatement {
|
||||||
IrReturnExpressionImpl(expression.startOffset, expression.endOffset, getType(expression),
|
val returnTarget = getReturnExpressionTarget(expression)
|
||||||
expression.returnedExpression?.generateExpression())
|
return IrReturnExpressionImpl(
|
||||||
|
expression.startOffset, expression.endOffset,
|
||||||
|
returnTarget,
|
||||||
|
expression.returnedExpression?.let { it.genExpr(returnTarget.returnType) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getReturnExpressionTarget(expression: KtReturnExpression): CallableDescriptor =
|
||||||
|
if (!ExpressionTypingUtils.isFunctionLiteral(scopeOwner) && !ExpressionTypingUtils.isFunctionExpression(scopeOwner)) {
|
||||||
|
scopeOwner as? CallableDescriptor ?: throw AssertionError("Return not in a callable: $scopeOwner")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val label = expression.getTargetLabel()
|
||||||
|
if (label != null) {
|
||||||
|
val labelTarget = getOrFail(BindingContext.LABEL_TARGET, label)
|
||||||
|
val labelTargetDescriptor = getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, labelTarget)
|
||||||
|
labelTargetDescriptor as CallableDescriptor
|
||||||
|
}
|
||||||
|
else if (ExpressionTypingUtils.isFunctionLiteral(scopeOwner)) {
|
||||||
|
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(scopeOwner, true).first
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scopeOwner as? CallableDescriptor ?: throw AssertionError("Return not in a callable: $scopeOwner")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression {
|
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression {
|
||||||
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
|
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
|
||||||
?: error("KtConstantExpression was not evaluated: ${expression.text}")
|
?: error("KtConstantExpression was not evaluated: ${expression.text}")
|
||||||
val constantValue = compileTimeConstant.toConstantValue(getTypeOrFail(expression))
|
val constantValue = compileTimeConstant.toConstantValue(getInferredTypeWithSmarcastsOrFail(expression))
|
||||||
val constantType = constantValue.type
|
val constantType = constantValue.type
|
||||||
|
|
||||||
return when (constantValue) {
|
return when (constantValue) {
|
||||||
@@ -128,12 +157,17 @@ class IrStatementGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Nothing?): IrStatement {
|
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Nothing?): IrStatement {
|
||||||
if (expression.entries.size == 1 && expression.entries[0] is KtLiteralStringTemplateEntry) {
|
if (expression.entries.size == 1) {
|
||||||
return expression.entries[0].generate()
|
val entry0 = expression.entries[0]
|
||||||
|
if (entry0 is KtLiteralStringTemplateEntry) {
|
||||||
|
return entry0.genExpr(null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, getType(expression))
|
val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression))
|
||||||
expression.entries.forEach { irStringTemplate.addArgument(it.generateExpression()) }
|
expression.entries.forEach { it.expression!!.let {
|
||||||
|
irStringTemplate.addArgument(TODO())
|
||||||
|
} }
|
||||||
return irStringTemplate
|
return irStringTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,21 +186,26 @@ class IrStatementGenerator(
|
|||||||
return when (descriptor) {
|
return when (descriptor) {
|
||||||
is ClassDescriptor ->
|
is ClassDescriptor ->
|
||||||
if (DescriptorUtils.isObject(descriptor))
|
if (DescriptorUtils.isObject(descriptor))
|
||||||
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), descriptor)
|
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor)
|
||||||
else if (DescriptorUtils.isEnumEntry(descriptor))
|
else if (DescriptorUtils.isEnumEntry(descriptor))
|
||||||
IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), descriptor)
|
IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor)
|
||||||
else
|
else {
|
||||||
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getType(expression),
|
val companionObjectDescriptor = descriptor.companionObjectDescriptor
|
||||||
descriptor.companionObjectDescriptor ?: error("Class value without companion object: $descriptor"))
|
?: error("Class value without companion object: $descriptor")
|
||||||
|
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset,
|
||||||
|
descriptor.classValueType,
|
||||||
|
companionObjectDescriptor)
|
||||||
|
}
|
||||||
is PropertyDescriptor -> {
|
is PropertyDescriptor -> {
|
||||||
IrCallGenerator(this).generateCall(expression, resolvedCall)
|
IrCallGenerator(this).generateCall(expression, resolvedCall)
|
||||||
}
|
}
|
||||||
is VariableDescriptor ->
|
is VariableDescriptor ->
|
||||||
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), descriptor)
|
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor.type, descriptor)
|
||||||
else ->
|
else ->
|
||||||
IrDummyExpression(expression.startOffset, expression.endOffset, getType(expression),
|
IrDummyExpression(
|
||||||
expression.getReferencedName() +
|
expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression),
|
||||||
": ${descriptor?.name} ${descriptor?.javaClass?.simpleName}")
|
expression.getReferencedName() + ": ${descriptor?.name} ${descriptor?.javaClass?.simpleName}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,14 +229,24 @@ class IrStatementGenerator(
|
|||||||
val referenceTarget = getOrFail(BindingContext.REFERENCE_TARGET, expression.instanceReference) { "No reference target for this" }
|
val referenceTarget = getOrFail(BindingContext.REFERENCE_TARGET, expression.instanceReference) { "No reference target for this" }
|
||||||
return when (referenceTarget) {
|
return when (referenceTarget) {
|
||||||
is ClassDescriptor ->
|
is ClassDescriptor ->
|
||||||
IrThisExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), referenceTarget)
|
IrThisExpressionImpl(
|
||||||
is CallableDescriptor ->
|
expression.startOffset, expression.endOffset,
|
||||||
IrGetExtensionReceiverExpressionImpl(
|
referenceTarget.defaultType, // TODO substituted type for 'this'?
|
||||||
expression.startOffset, expression.endOffset, getType(expression),
|
referenceTarget
|
||||||
referenceTarget.extensionReceiverParameter!!
|
|
||||||
)
|
)
|
||||||
|
is CallableDescriptor -> {
|
||||||
|
val extensionReceiver = referenceTarget.extensionReceiverParameter ?: TODO("No extension receiver: $referenceTarget")
|
||||||
|
IrGetExtensionReceiverExpressionImpl(
|
||||||
|
expression.startOffset, expression.endOffset,
|
||||||
|
extensionReceiver.type,
|
||||||
|
extensionReceiver
|
||||||
|
)
|
||||||
|
}
|
||||||
else ->
|
else ->
|
||||||
error("Expected this or receiver: $referenceTarget")
|
error("Expected this or receiver: $referenceTarget")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Nothing?): IrStatement =
|
||||||
|
IrOperatorExpressionGenerator(this).generateBinaryExpression(expression)
|
||||||
}
|
}
|
||||||
|
|||||||
-15
@@ -17,28 +17,13 @@
|
|||||||
package org.jetbrains.kotlin.ir.expressions
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
interface IrGetVariableExpression : IrDeclarationReference {
|
|
||||||
override val descriptor: VariableDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IrGetExtensionReceiverExpression : IrDeclarationReference {
|
interface IrGetExtensionReceiverExpression : IrDeclarationReference {
|
||||||
override val descriptor: CallableDescriptor
|
override val descriptor: CallableDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrGetVariableExpressionImpl(
|
|
||||||
startOffset: Int,
|
|
||||||
endOffset: Int,
|
|
||||||
type: KotlinType?,
|
|
||||||
descriptor: VariableDescriptor
|
|
||||||
) : IrTerminalDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, type, descriptor), IrGetVariableExpression {
|
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
|
||||||
visitor.visitGetVariable(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
class IrGetExtensionReceiverExpressionImpl(
|
class IrGetExtensionReceiverExpressionImpl(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
+16
-15
@@ -29,6 +29,7 @@ interface IrGetPropertyExpression : IrPropertyAccessExpression
|
|||||||
|
|
||||||
interface IrSetPropertyExpression : IrPropertyAccessExpression {
|
interface IrSetPropertyExpression : IrPropertyAccessExpression {
|
||||||
var value: IrExpression
|
var value: IrExpression
|
||||||
|
val operator: IrOperator
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrGetPropertyExpressionImpl(
|
class IrGetPropertyExpressionImpl(
|
||||||
@@ -45,18 +46,18 @@ class IrGetPropertyExpressionImpl(
|
|||||||
class IrSetPropertyExpressionImpl(
|
class IrSetPropertyExpressionImpl(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
type: KotlinType?,
|
|
||||||
isSafe: Boolean,
|
isSafe: Boolean,
|
||||||
override val descriptor: PropertyDescriptor
|
override val descriptor: PropertyDescriptor,
|
||||||
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrSetPropertyExpression {
|
override val operator: IrOperator = IrOperator.EQ
|
||||||
|
) : IrMemberAccessExpressionBase(startOffset, endOffset, null, isSafe), IrSetPropertyExpression {
|
||||||
constructor(
|
constructor(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
type: KotlinType?,
|
|
||||||
isSafe: Boolean,
|
isSafe: Boolean,
|
||||||
descriptor: PropertyDescriptor,
|
descriptor: PropertyDescriptor,
|
||||||
value: IrExpression
|
value: IrExpression,
|
||||||
) : this(startOffset, endOffset, type, isSafe, descriptor) {
|
operator: IrOperator = IrOperator.EQ
|
||||||
|
) : this(startOffset, endOffset, isSafe, descriptor, operator) {
|
||||||
this.value = value
|
this.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,15 +71,6 @@ class IrSetPropertyExpressionImpl(
|
|||||||
value.setTreeLocation(this, ARGUMENT0_SLOT)
|
value.setTreeLocation(this, ARGUMENT0_SLOT)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
|
||||||
return visitor.visitSetProperty(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
|
||||||
super.acceptChildren(visitor, data)
|
|
||||||
value.accept(visitor, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getChild(slot: Int): IrElement? =
|
override fun getChild(slot: Int): IrElement? =
|
||||||
when (slot) {
|
when (slot) {
|
||||||
ARGUMENT0_SLOT -> value
|
ARGUMENT0_SLOT -> value
|
||||||
@@ -91,4 +83,13 @@ class IrSetPropertyExpressionImpl(
|
|||||||
else -> super.replaceChild(slot, newChild)
|
else -> super.replaceChild(slot, newChild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||||
|
return visitor.visitSetProperty(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
|
super.acceptChildren(visitor, data)
|
||||||
|
value.accept(visitor, data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.expressions
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.ir.*
|
import org.jetbrains.kotlin.ir.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -23,19 +24,20 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
|
|
||||||
interface IrReturnExpression : IrExpression {
|
interface IrReturnExpression : IrExpression {
|
||||||
var value: IrExpression?
|
var value: IrExpression?
|
||||||
|
val returnTarget: CallableDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrReturnExpressionImpl(
|
class IrReturnExpressionImpl(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
type: KotlinType?
|
override val returnTarget: CallableDescriptor
|
||||||
) : IrExpressionBase(startOffset, endOffset, type), IrReturnExpression {
|
) : IrExpressionBase(startOffset, endOffset, null), IrReturnExpression {
|
||||||
constructor(
|
constructor(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
type: KotlinType?,
|
returnTarget: CallableDescriptor,
|
||||||
value: IrExpression?
|
value: IrExpression?
|
||||||
) : this(startOffset, endOffset, type) {
|
) : this(startOffset, endOffset, returnTarget) {
|
||||||
this.value = value
|
this.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -46,8 +46,8 @@ class IrTypeOperatorExpressionImpl(
|
|||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
type: KotlinType?,
|
type: KotlinType?,
|
||||||
operator: IrTypeOperator,
|
operator: IrTypeOperator,
|
||||||
argument: IrExpression,
|
typeOperand: KotlinType,
|
||||||
typeOperand: KotlinType
|
argument: IrExpression
|
||||||
) : this(startOffset, endOffset, type, operator, typeOperand) {
|
) : this(startOffset, endOffset, type, operator, typeOperand) {
|
||||||
this.argument = argument
|
this.argument = argument
|
||||||
}
|
}
|
||||||
|
|||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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.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
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
interface IrVariableAccessExpression : IrDeclarationReference {
|
||||||
|
override val descriptor: VariableDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
|
visitor.visitGetVariable(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrSetVariableExpressionImpl(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
override val descriptor: VariableDescriptor,
|
||||||
|
override val operator: IrOperator = IrOperator.EQ
|
||||||
|
) : IrExpressionBase(startOffset, endOffset, null), IrSetVariableExpression {
|
||||||
|
constructor(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
descriptor: VariableDescriptor,
|
||||||
|
value: IrExpression,
|
||||||
|
operator: IrOperator = IrOperator.EQ
|
||||||
|
) : this(startOffset, endOffset, descriptor, operator) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
private var valueImpl: IrExpression? = null
|
||||||
|
override var value: IrExpression
|
||||||
|
get() = valueImpl!!
|
||||||
|
set(value) {
|
||||||
|
value.assertDetached()
|
||||||
|
valueImpl?.detach()
|
||||||
|
valueImpl = value
|
||||||
|
value.setTreeLocation(this, ARGUMENT0_SLOT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getChild(slot: Int): IrElement? =
|
||||||
|
when (slot) {
|
||||||
|
ARGUMENT0_SLOT -> value
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun replaceChild(slot: Int, newChild: IrElement) {
|
||||||
|
when (slot) {
|
||||||
|
ARGUMENT0_SLOT -> value = newChild.assertCast()
|
||||||
|
else -> throwNoSuchSlot(slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||||
|
return visitor.visitSetVariable(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
|
value.accept(visitor, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
|||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
|
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
|
||||||
import org.jetbrains.kotlin.renderer.OverrideRenderingPolicy
|
import org.jetbrains.kotlin.renderer.OverrideRenderingPolicy
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
||||||
override fun visitElement(element: IrElement, data: Nothing?): String =
|
override fun visitElement(element: IrElement, data: Nothing?): String =
|
||||||
@@ -83,6 +84,9 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
|||||||
override fun visitGetVariable(expression: IrGetVariableExpression, data: Nothing?): String =
|
override fun visitGetVariable(expression: IrGetVariableExpression, data: Nothing?): String =
|
||||||
"GET_VAR ${expression.descriptor.name} type=${expression.renderType()}"
|
"GET_VAR ${expression.descriptor.name} type=${expression.renderType()}"
|
||||||
|
|
||||||
|
override fun visitSetVariable(expression: IrSetVariableExpression, data: Nothing?): String =
|
||||||
|
"SET_VAR ${expression.descriptor.name} type=${expression.renderType()}"
|
||||||
|
|
||||||
override fun visitGetObjectValue(expression: IrGetObjectValueExpression, data: Nothing?): String =
|
override fun visitGetObjectValue(expression: IrGetObjectValueExpression, data: Nothing?): String =
|
||||||
"GET_OBJECT ${expression.descriptor.name} type=${expression.renderType()}"
|
"GET_OBJECT ${expression.descriptor.name} type=${expression.renderType()}"
|
||||||
|
|
||||||
@@ -93,6 +97,10 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
|||||||
"SET_PROPERTY ${if (expression.isSafe) "?." else "."}${expression.descriptor.name}" +
|
"SET_PROPERTY ${if (expression.isSafe) "?." else "."}${expression.descriptor.name}" +
|
||||||
"type=${expression.renderType()}"
|
"type=${expression.renderType()}"
|
||||||
|
|
||||||
|
override fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: Nothing?): String {
|
||||||
|
return "TYPE_OP operator=${expression.operator} typeOperand=${expression.typeOperand.render()}"
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: Nothing?): String =
|
override fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: Nothing?): String =
|
||||||
"DUMMY ${declaration.descriptor.name}"
|
"DUMMY ${declaration.descriptor.name}"
|
||||||
|
|
||||||
@@ -116,6 +124,9 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
|||||||
DESCRIPTOR_RENDERER.render(this)
|
DESCRIPTOR_RENDERER.render(this)
|
||||||
|
|
||||||
internal fun IrExpression.renderType(): String =
|
internal fun IrExpression.renderType(): String =
|
||||||
type?.let { DESCRIPTOR_RENDERER.renderType(it) } ?: "<no-type>"
|
type.render()
|
||||||
|
|
||||||
|
internal fun KotlinType?.render(): String =
|
||||||
|
this?.let { DESCRIPTOR_RENDERER.renderType(it) } ?: "<no-type>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,7 @@ interface IrElementVisitor<out R, in D> {
|
|||||||
fun visitGetObjectValue(expression: IrGetObjectValueExpression, data: D) = visitDeclarationReference(expression, data)
|
fun visitGetObjectValue(expression: IrGetObjectValueExpression, data: D) = visitDeclarationReference(expression, data)
|
||||||
fun visitGetEnumValue(expression: IrGetEnumValueExpression, data: D) = visitDeclarationReference(expression, data)
|
fun visitGetEnumValue(expression: IrGetEnumValueExpression, data: D) = visitDeclarationReference(expression, data)
|
||||||
fun visitGetVariable(expression: IrGetVariableExpression, data: D) = visitDeclarationReference(expression, data)
|
fun visitGetVariable(expression: IrGetVariableExpression, data: D) = visitDeclarationReference(expression, data)
|
||||||
|
fun visitSetVariable(expression: IrSetVariableExpression, data: D) = visitDeclarationReference(expression, data)
|
||||||
fun visitGetExtensionReceiver(expression: IrGetExtensionReceiverExpression, data: D) = visitDeclarationReference(expression, data)
|
fun visitGetExtensionReceiver(expression: IrGetExtensionReceiverExpression, data: D) = visitDeclarationReference(expression, data)
|
||||||
fun visitMemberAccess(expression: IrMemberAccessExpression, data: D) = visitDeclarationReference(expression, data)
|
fun visitMemberAccess(expression: IrMemberAccessExpression, data: D) = visitDeclarationReference(expression, data)
|
||||||
fun visitCallExpression(expression: IrCallExpression, data: D) = visitMemberAccess(expression, data)
|
fun visitCallExpression(expression: IrCallExpression, data: D) = visitMemberAccess(expression, data)
|
||||||
@@ -65,4 +66,5 @@ interface IrElementVisitor<out R, in D> {
|
|||||||
// NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered
|
// NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered
|
||||||
fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: D) = visitDeclaration(declaration, data)
|
fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: D) = visitDeclaration(declaration, data)
|
||||||
fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data)
|
fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// <<< assignments.txt
|
||||||
|
class Ref(var x: Int)
|
||||||
|
|
||||||
|
fun test1() {
|
||||||
|
var x = 0
|
||||||
|
x = 1
|
||||||
|
x = x + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2(r: Ref) {
|
||||||
|
r.x = 0
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
IrFile /assignments.kt
|
||||||
|
DUMMY Ref
|
||||||
|
IrFunction public fun test1(): kotlin.Unit
|
||||||
|
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>
|
||||||
|
LITERAL Int type=kotlin.Int value='1'
|
||||||
|
SET_VAR x type=<no-type>
|
||||||
|
DUMMY PLUS type=kotlin.Int
|
||||||
|
IrFunction public fun test2(/*0*/ r: Ref): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
SET_PROPERTY .xtype=<no-type>
|
||||||
|
$this: GET_VAR r type=Ref
|
||||||
|
$value: LITERAL Int type=kotlin.Int value='0'
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
IrFile /callWithReorderedArguments.kt
|
IrFile /callWithReorderedArguments.kt
|
||||||
IrFunction public fun foo(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Unit
|
IrFunction public fun foo(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Unit
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
IrFunction public fun noReorder1(): kotlin.Int
|
IrFunction public fun noReorder1(): kotlin.Int
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false isDesugared=true
|
BLOCK type=<no-type> hasResult=false isDesugared=true
|
||||||
@@ -24,7 +24,7 @@ IrFile /callWithReorderedArguments.kt
|
|||||||
LITERAL Int type=kotlin.Int value='2'
|
LITERAL Int type=kotlin.Int value='2'
|
||||||
IrFunction public fun test(): kotlin.Unit
|
IrFunction public fun test(): kotlin.Unit
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
CALL .foo type=kotlin.Unit operator=
|
CALL .foo type=kotlin.Unit operator=
|
||||||
a: CALL .noReorder1 type=kotlin.Int operator=
|
a: CALL .noReorder1 type=kotlin.Int operator=
|
||||||
b: CALL .noReorder2 type=kotlin.Int operator=
|
b: CALL .noReorder2 type=kotlin.Int operator=
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
IrFunction public fun B.test(): kotlin.Unit
|
IrFunction public fun B.test(): kotlin.Unit
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
VAR val tmp0: A
|
VAR val tmp0: A
|
||||||
GET_VAR A type=A
|
GET_VAR A type=A
|
||||||
VAR val x: kotlin.Int
|
VAR val x: kotlin.Int
|
||||||
|
|||||||
+2
-1
@@ -10,4 +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: GET_VAR s type=kotlin.String?
|
$this: TYPE_OP operator=SMART_AS typeOperand=kotlin.String
|
||||||
|
GET_VAR s type=kotlin.String?
|
||||||
|
|||||||
+2
-2
@@ -23,10 +23,10 @@ IrFile /references.kt
|
|||||||
GET_VAR x type=kotlin.String
|
GET_VAR x type=kotlin.String
|
||||||
IrFunction public fun test3(): kotlin.String
|
IrFunction public fun test3(): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=kotlin.Nothing hasResult=false isDesugared=false
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
VAR val x: kotlin.String = "OK"
|
VAR val x: kotlin.String = "OK"
|
||||||
LITERAL String type=kotlin.String value='OK'
|
LITERAL String type=kotlin.String value='OK'
|
||||||
RETURN type=kotlin.Nothing
|
RETURN type=<no-type>
|
||||||
GET_VAR x type=kotlin.String
|
GET_VAR x type=kotlin.String
|
||||||
IrFunction public fun test4(): kotlin.String
|
IrFunction public fun test4(): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// <<< smartCasts.txt
|
||||||
|
fun expectsString(s: String) {}
|
||||||
|
fun expectsInt(i: Int) {}
|
||||||
|
|
||||||
|
fun overloaded(s: String) = s
|
||||||
|
fun overloaded(x: Any) = x
|
||||||
|
|
||||||
|
fun test1(x: Any) {
|
||||||
|
if (x !is String) return
|
||||||
|
println(x.length)
|
||||||
|
expectsString(x)
|
||||||
|
expectsInt(x.length)
|
||||||
|
expectsString(overloaded(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2(x: Any): String {
|
||||||
|
if (x !is String) return ""
|
||||||
|
return overloaded(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test3(x: Any): String {
|
||||||
|
if (x !is String) return ""
|
||||||
|
return x
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
IrFile /smartCasts.kt
|
||||||
|
IrFunction public fun expectsString(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
IrFunction public fun expectsInt(/*0*/ i: kotlin.Int): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
IrFunction public fun overloaded(/*0*/ s: kotlin.String): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=true
|
||||||
|
RETURN type=<no-type>
|
||||||
|
GET_VAR s type=kotlin.String
|
||||||
|
IrFunction public fun overloaded(/*0*/ x: kotlin.Any): kotlin.Any
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=true
|
||||||
|
RETURN type=<no-type>
|
||||||
|
GET_VAR x type=kotlin.Any
|
||||||
|
IrFunction public fun test1(/*0*/ x: kotlin.Any): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
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
|
||||||
|
GET_VAR x type=kotlin.Any
|
||||||
|
CALL .expectsString type=kotlin.Unit operator=
|
||||||
|
s: TYPE_OP operator=SMART_AS 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
|
||||||
|
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
|
||||||
|
GET_VAR x type=kotlin.Any
|
||||||
|
IrFunction public fun test2(/*0*/ x: kotlin.Any): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
DUMMY KtIfExpression type=kotlin.Unit
|
||||||
|
RETURN type=<no-type>
|
||||||
|
CALL .overloaded type=kotlin.String operator=
|
||||||
|
s: TYPE_OP operator=SMART_AS 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
|
||||||
|
GET_VAR x type=kotlin.Any
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// <<< smartCastsWithDestructuring.txt
|
||||||
|
interface I1
|
||||||
|
interface I2
|
||||||
|
|
||||||
|
operator fun I1.component1() = 1
|
||||||
|
operator fun I2.component2() = ""
|
||||||
|
|
||||||
|
fun test(x: I1) {
|
||||||
|
if (x !is I2) return
|
||||||
|
val (c1, c2) = x
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
IrFile /smartCastsWithDestructuring.kt
|
||||||
|
DUMMY I1
|
||||||
|
DUMMY I2
|
||||||
|
IrFunction public operator fun I1.component1(): kotlin.Int
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=true
|
||||||
|
RETURN type=<no-type>
|
||||||
|
LITERAL Int type=kotlin.Int value='1'
|
||||||
|
IrFunction public operator fun I2.component2(): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=true
|
||||||
|
RETURN type=<no-type>
|
||||||
|
? IrStringConcatenationExpressionImpl type=kotlin.String
|
||||||
|
IrFunction public fun test(/*0*/ x: I1): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
DUMMY KtIfExpression type=kotlin.Unit
|
||||||
|
VAR val tmp0: I1
|
||||||
|
GET_VAR x type=I1
|
||||||
|
VAR val c1: kotlin.Int
|
||||||
|
CALL .component1 type=kotlin.Int operator=COMPONENT_N(index=1)
|
||||||
|
$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
|
||||||
|
GET_VAR tmp0 type=I1
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
IrFile /smoke.kt
|
IrFile /smoke.kt
|
||||||
IrFunction public fun testFun(): kotlin.String
|
IrFunction public fun testFun(): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=kotlin.Nothing hasResult=false isDesugared=false
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
RETURN type=kotlin.Nothing
|
RETURN type=<no-type>
|
||||||
LITERAL String type=kotlin.String value='OK'
|
LITERAL String type=kotlin.String value='OK'
|
||||||
IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null
|
IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
@@ -24,4 +24,4 @@ IrFile /smoke.kt
|
|||||||
LITERAL Int type=kotlin.Int value='42'
|
LITERAL Int type=kotlin.Int value='42'
|
||||||
IrPropertySetter public fun <set-testVarWithAccessors>(/*0*/ v: kotlin.Int): kotlin.Unit property=testVarWithAccessors
|
IrPropertySetter public fun <set-testVarWithAccessors>(/*0*/ v: kotlin.Int): kotlin.Unit property=testVarWithAccessors
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("assignments.kt")
|
||||||
|
public void testAssignments() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/assignments.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");
|
||||||
@@ -77,6 +83,18 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("smartCasts.kt")
|
||||||
|
public void testSmartCasts() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/smartCasts.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("smartCastsWithDestructuring.kt")
|
||||||
|
public void testSmartCastsWithDestructuring() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/smartCastsWithDestructuring.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("smoke.kt")
|
@TestMetadata("smoke.kt")
|
||||||
public void testSmoke() throws Exception {
|
public void testSmoke() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/smoke.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/smoke.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user