Copy common utils from Native
This commit is contained in:
@@ -10,5 +10,7 @@
|
|||||||
<orderEntry type="module" module-name="util" />
|
<orderEntry type="module" module-name="util" />
|
||||||
<orderEntry type="module" module-name="ir.tree" />
|
<orderEntry type="module" module-name="ir.tree" />
|
||||||
<orderEntry type="module" module-name="descriptors" />
|
<orderEntry type="module" module-name="descriptors" />
|
||||||
|
<orderEntry type="module" module-name="frontend" />
|
||||||
|
<orderEntry type="module" module-name="cli-common" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
+253
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
|
|
||||||
|
typealias ReportError = (element: IrElement, message: String) -> Unit
|
||||||
|
|
||||||
|
class CheckIrElementVisitor(val builtIns: KotlinBuiltIns, val reportError: ReportError, val ensureAllNodesAreDifferent: Boolean) : IrElementVisitorVoid {
|
||||||
|
|
||||||
|
val set = mutableSetOf<IrElement>()
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
if (ensureAllNodesAreDifferent) {
|
||||||
|
if (set.contains(element))
|
||||||
|
reportError(element, "Duplicate IR node")
|
||||||
|
set.add(element)
|
||||||
|
}
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrExpression.ensureTypeIs(expectedType: KotlinType) {
|
||||||
|
if (expectedType != type) {
|
||||||
|
reportError(this, "unexpected expression.type: expected $expectedType, got ${type}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrSymbol.ensureBound(expression: IrExpression) {
|
||||||
|
if (!this.isBound) {
|
||||||
|
reportError(expression, "Unbound symbol ${this}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T> visitConst(expression: IrConst<T>) {
|
||||||
|
super.visitConst(expression)
|
||||||
|
|
||||||
|
val naturalType = when (expression.kind) {
|
||||||
|
IrConstKind.Null -> builtIns.nullableNothingType
|
||||||
|
IrConstKind.Boolean -> builtIns.booleanType
|
||||||
|
IrConstKind.Char -> builtIns.charType
|
||||||
|
IrConstKind.Byte -> builtIns.byteType
|
||||||
|
IrConstKind.Short -> builtIns.shortType
|
||||||
|
IrConstKind.Int -> builtIns.intType
|
||||||
|
IrConstKind.Long -> builtIns.longType
|
||||||
|
IrConstKind.String -> builtIns.stringType
|
||||||
|
IrConstKind.Float -> builtIns.floatType
|
||||||
|
IrConstKind.Double -> builtIns.doubleType
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.ensureTypeIs(naturalType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitStringConcatenation(expression: IrStringConcatenation) {
|
||||||
|
super.visitStringConcatenation(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(builtIns.stringType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetObjectValue(expression: IrGetObjectValue) {
|
||||||
|
super.visitGetObjectValue(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(expression.descriptor.defaultType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: visitGetEnumValue
|
||||||
|
|
||||||
|
override fun visitGetValue(expression: IrGetValue) {
|
||||||
|
super.visitGetValue(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(expression.descriptor.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetVariable(expression: IrSetVariable) {
|
||||||
|
super.visitSetVariable(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(builtIns.unitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetField(expression: IrGetField) {
|
||||||
|
super.visitGetField(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(expression.descriptor.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetField(expression: IrSetField) {
|
||||||
|
super.visitSetField(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(builtIns.unitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall) {
|
||||||
|
super.visitCall(expression)
|
||||||
|
|
||||||
|
val returnType = expression.descriptor.returnType
|
||||||
|
if (returnType == null) {
|
||||||
|
reportError(expression, "${expression.descriptor} return type is null")
|
||||||
|
} else {
|
||||||
|
expression.ensureTypeIs(returnType)
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.superQualifierSymbol?.ensureBound(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
||||||
|
super.visitDelegatingConstructorCall(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(builtIns.unitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) {
|
||||||
|
super.visitEnumConstructorCall(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(builtIns.unitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) {
|
||||||
|
super.visitInstanceInitializerCall(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(builtIns.unitType)
|
||||||
|
expression.classSymbol.ensureBound(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall) {
|
||||||
|
super.visitTypeOperator(expression)
|
||||||
|
|
||||||
|
val operator = expression.operator
|
||||||
|
val typeOperand = expression.typeOperand
|
||||||
|
|
||||||
|
val naturalType = when (operator) {
|
||||||
|
IrTypeOperator.CAST,
|
||||||
|
IrTypeOperator.IMPLICIT_CAST,
|
||||||
|
IrTypeOperator.IMPLICIT_NOTNULL,
|
||||||
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
||||||
|
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> typeOperand
|
||||||
|
|
||||||
|
IrTypeOperator.SAFE_CAST -> typeOperand.makeNullable()
|
||||||
|
|
||||||
|
IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> builtIns.booleanType
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT && typeOperand != builtIns.unitType) {
|
||||||
|
reportError(expression, "typeOperand is $typeOperand")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check IMPLICIT_NOTNULL's argument type.
|
||||||
|
|
||||||
|
expression.ensureTypeIs(naturalType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLoop(loop: IrLoop) {
|
||||||
|
super.visitLoop(loop)
|
||||||
|
|
||||||
|
loop.ensureTypeIs(builtIns.unitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBreakContinue(jump: IrBreakContinue) {
|
||||||
|
super.visitBreakContinue(jump)
|
||||||
|
|
||||||
|
jump.ensureTypeIs(builtIns.nothingType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn) {
|
||||||
|
super.visitReturn(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(builtIns.nothingType)
|
||||||
|
expression.returnTargetSymbol.ensureBound(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitThrow(expression: IrThrow) {
|
||||||
|
super.visitThrow(expression)
|
||||||
|
|
||||||
|
expression.ensureTypeIs(builtIns.nothingType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
super.visitClass(declaration)
|
||||||
|
|
||||||
|
if (declaration.descriptor.kind != ClassKind.ANNOTATION_CLASS) {
|
||||||
|
// Check that all functions and properties from memberScope are present in IR
|
||||||
|
// (including FAKE_OVERRIDE ones).
|
||||||
|
|
||||||
|
val allDescriptors = declaration.descriptor.unsubstitutedMemberScope
|
||||||
|
.getContributedDescriptors().filterIsInstance<CallableMemberDescriptor>()
|
||||||
|
|
||||||
|
val presentDescriptors = declaration.declarations.map { it.descriptor }
|
||||||
|
|
||||||
|
val missingDescriptors = allDescriptors - presentDescriptors
|
||||||
|
|
||||||
|
if (missingDescriptors.isNotEmpty()) {
|
||||||
|
reportError(declaration, "Missing declarations for descriptors:\n" +
|
||||||
|
missingDescriptors.joinToString("\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclarationReference(expression: IrDeclarationReference) {
|
||||||
|
super.visitDeclarationReference(expression)
|
||||||
|
|
||||||
|
expression.symbol.ensureBound(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
|
||||||
|
super.visitFunctionAccess(expression)
|
||||||
|
|
||||||
|
expression.symbol.ensureBound(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||||
|
super.visitFunctionReference(expression)
|
||||||
|
|
||||||
|
expression.symbol.ensureBound(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPropertyReference(expression: IrPropertyReference) {
|
||||||
|
super.visitPropertyReference(expression)
|
||||||
|
|
||||||
|
expression.field?.ensureBound(expression)
|
||||||
|
expression.getter?.ensureBound(expression)
|
||||||
|
expression.setter?.ensureBound(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) {
|
||||||
|
super.visitLocalDelegatedPropertyReference(expression)
|
||||||
|
|
||||||
|
expression.delegate.ensureBound(expression)
|
||||||
|
expression.getter.ensureBound(expression)
|
||||||
|
expression.setter?.ensureBound(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
package org.jetbrains.kotlin.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||||
|
import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjection
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
|
||||||
|
interface CommonBackendContext : BackendContext {
|
||||||
|
|
||||||
|
val ir: Ir<CommonBackendContext>
|
||||||
|
|
||||||
|
//TODO move to builtins
|
||||||
|
fun getInternalClass(name: String): ClassDescriptor
|
||||||
|
|
||||||
|
//TODO move to builtins
|
||||||
|
fun getInternalFunctions(name: String): List<FunctionDescriptor>
|
||||||
|
|
||||||
|
val reflectionTypes: ReflectionTypes
|
||||||
|
|
||||||
|
fun log(message: () -> String)
|
||||||
|
|
||||||
|
val messageCollector: MessageCollector
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReflectionTypes(module: ModuleDescriptor, internalPackage: FqName) {
|
||||||
|
|
||||||
|
private val kotlinReflectScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
|
module.getPackage(KOTLIN_REFLECT_FQ_NAME).memberScope
|
||||||
|
}
|
||||||
|
|
||||||
|
private val internalScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
|
module.getPackage(internalPackage).memberScope
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun find(memberScope: MemberScope, className: String): ClassDescriptor {
|
||||||
|
val name = Name.identifier(className)
|
||||||
|
return memberScope.getContributedClassifier(name, NoLookupLocation.FROM_REFLECTION) as ClassDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ClassLookup(val memberScope: MemberScope) {
|
||||||
|
operator fun getValue(types: ReflectionTypes, property: KProperty<*>): ClassDescriptor {
|
||||||
|
return types.find(memberScope, property.name.capitalize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFunctionTypeArgumentProjections(
|
||||||
|
receiverType: KotlinType?,
|
||||||
|
parameterTypes: List<KotlinType>,
|
||||||
|
returnType: KotlinType
|
||||||
|
): List<TypeProjection> {
|
||||||
|
val arguments = ArrayList<TypeProjection>(parameterTypes.size + (if (receiverType != null) 1 else 0) + 1)
|
||||||
|
|
||||||
|
arguments.addIfNotNull(receiverType?.asTypeProjection())
|
||||||
|
|
||||||
|
parameterTypes.mapTo(arguments, KotlinType::asTypeProjection)
|
||||||
|
|
||||||
|
arguments.add(returnType.asTypeProjection())
|
||||||
|
|
||||||
|
return arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getKFunction(n: Int): ClassDescriptor = find(kotlinReflectScope, "KFunction$n")
|
||||||
|
|
||||||
|
val kClass: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
|
val kProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
|
val kProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
|
val kProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
|
val kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
|
val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
|
val kMutableProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
|
val kFunctionImpl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
val kProperty0Impl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
val kProperty1Impl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
val kProperty2Impl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
val kMutableProperty0Impl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
val kMutableProperty1Impl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
val kMutableProperty2Impl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
val kLocalDelegatedPropertyImpl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
val kLocalDelegatedMutablePropertyImpl: ClassDescriptor by ClassLookup(internalScope)
|
||||||
|
|
||||||
|
fun getKFunctionType(
|
||||||
|
annotations: Annotations,
|
||||||
|
receiverType: KotlinType?,
|
||||||
|
parameterTypes: List<KotlinType>,
|
||||||
|
returnType: KotlinType
|
||||||
|
): KotlinType {
|
||||||
|
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType)
|
||||||
|
val classDescriptor = getKFunction(arguments.size - 1 /* return type */)
|
||||||
|
return KotlinTypeFactory.simpleNotNullType(annotations, classDescriptor, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||||
|
import org.jetbrains.kotlin.ir.util.DeepCopySymbolsRemapper
|
||||||
|
import org.jetbrains.kotlin.ir.util.DescriptorsRemapper
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
|
|
||||||
|
fun IrElement.deepCopyWithVariablesImpl(): IrElement {
|
||||||
|
val descriptorsRemapper = object : DescriptorsRemapper {
|
||||||
|
override fun remapDeclaredVariable(descriptor: VariableDescriptor) = LocalVariableDescriptor(
|
||||||
|
/* containingDeclaration = */ descriptor.containingDeclaration,
|
||||||
|
/* annotations = */ descriptor.annotations,
|
||||||
|
/* name = */ descriptor.name,
|
||||||
|
/* type = */ descriptor.type,
|
||||||
|
/* mutable = */ descriptor.isVar,
|
||||||
|
/* isDelegated = */ false,
|
||||||
|
/* source = */ descriptor.source
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val symbolsRemapper = DeepCopySymbolsRemapper(descriptorsRemapper)
|
||||||
|
acceptVoid(symbolsRemapper)
|
||||||
|
|
||||||
|
return this.transform(
|
||||||
|
object : DeepCopyIrTreeWithReturnableBlockSymbols(symbolsRemapper) {
|
||||||
|
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
|
||||||
|
return irLoop
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : IrElement> T.deepCopyWithVariables(): T =
|
||||||
|
this.deepCopyWithVariablesImpl() as T
|
||||||
+618
@@ -0,0 +1,618 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
|
|
||||||
|
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
|
||||||
|
val context: CommonBackendContext) {
|
||||||
|
|
||||||
|
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
|
||||||
|
private var typeSubstitutor: TypeSubstitutor? = null
|
||||||
|
private var nameIndex = 0
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement {
|
||||||
|
this.typeSubstitutor = typeSubstitutor
|
||||||
|
irElement.acceptChildrenVoid(DescriptorCollector())
|
||||||
|
return irElement.accept(InlineCopyIr(), null)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
inner class DescriptorCollector: IrElementVisitorVoid {
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildren(this, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
val newDescriptor = copyClassDescriptor(oldDescriptor)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
descriptorSubstituteMap[oldDescriptor.thisAsReceiverParameter] = newDescriptor.thisAsReceiverParameter
|
||||||
|
|
||||||
|
super.visitClass(declaration)
|
||||||
|
|
||||||
|
val constructors = oldDescriptor.constructors.map { oldConstructorDescriptor ->
|
||||||
|
descriptorSubstituteMap[oldConstructorDescriptor] as ClassConstructorDescriptor
|
||||||
|
}.toSet()
|
||||||
|
|
||||||
|
val oldPrimaryConstructor = oldDescriptor.unsubstitutedPrimaryConstructor
|
||||||
|
val primaryConstructor = oldPrimaryConstructor?.let { descriptorSubstituteMap[it] as ClassConstructorDescriptor }
|
||||||
|
|
||||||
|
val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope
|
||||||
|
.getContributedDescriptors()
|
||||||
|
.map {
|
||||||
|
descriptorSubstituteMap[it]!!
|
||||||
|
}
|
||||||
|
newDescriptor.initialize(
|
||||||
|
SimpleMemberScope(contributedDescriptors),
|
||||||
|
constructors,
|
||||||
|
primaryConstructor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitProperty(declaration: IrProperty) {
|
||||||
|
|
||||||
|
copyPropertyOrField(declaration.descriptor)
|
||||||
|
super.visitProperty(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField) {
|
||||||
|
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
if (descriptorSubstituteMap[oldDescriptor] == null) {
|
||||||
|
copyPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
|
||||||
|
}
|
||||||
|
super.visitField(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
|
||||||
|
val newDescriptor = copyFunctionDescriptor(oldDescriptor)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
oldDescriptor.extensionReceiverParameter?.let{
|
||||||
|
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.visitFunction(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable) {
|
||||||
|
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
val newDescriptor = IrTemporaryVariableDescriptorImpl(
|
||||||
|
containingDeclaration = newContainingDeclaration,
|
||||||
|
name = generateCopyName(oldDescriptor.name),
|
||||||
|
outType = substituteType(oldDescriptor.type)!!,
|
||||||
|
isMutable = oldDescriptor.isVar)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
|
||||||
|
super.visitVariable(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitCatch(aCatch: IrCatch) {
|
||||||
|
val oldDescriptor = aCatch.parameter
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
val newDescriptor = IrTemporaryVariableDescriptorImpl(
|
||||||
|
containingDeclaration = newContainingDeclaration,
|
||||||
|
name = generateCopyName(oldDescriptor.name),
|
||||||
|
outType = substituteType(oldDescriptor.type)!!,
|
||||||
|
isMutable = oldDescriptor.isVar)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
|
||||||
|
super.visitCatch(aCatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- Copy descriptors ------------------------------------------------//
|
||||||
|
|
||||||
|
private fun generateCopyName(name: Name): Name {
|
||||||
|
|
||||||
|
val declarationName = name.toString() // Name of declaration
|
||||||
|
val indexStr = (nameIndex++).toString() // Unique for inline target index
|
||||||
|
return Name.identifier(declarationName + "_" + indexStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor {
|
||||||
|
|
||||||
|
return when (oldDescriptor) {
|
||||||
|
is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor)
|
||||||
|
is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor)
|
||||||
|
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor) : FunctionDescriptor {
|
||||||
|
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
return SimpleFunctionDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ newContainingDeclaration,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* name = */ generateCopyName(oldDescriptor.name),
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* source = */ oldDescriptor.source
|
||||||
|
).apply {
|
||||||
|
|
||||||
|
val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter
|
||||||
|
val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor }
|
||||||
|
val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types
|
||||||
|
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
|
||||||
|
val newReceiverParameterType = substituteType(oldDescriptor.extensionReceiverParameter?.type)
|
||||||
|
val newReturnType = substituteType(oldDescriptor.returnType)
|
||||||
|
|
||||||
|
initialize(
|
||||||
|
/* receiverParameterType = */ newReceiverParameterType,
|
||||||
|
/* dispatchReceiverParameter = */ newDispatchReceiverParameter,
|
||||||
|
/* typeParameters = */ newTypeParameters,
|
||||||
|
/* unsubstitutedValueParameters = */ newValueParameters,
|
||||||
|
/* unsubstitutedReturnType = */ newReturnType,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility
|
||||||
|
)
|
||||||
|
isTailrec = oldDescriptor.isTailrec
|
||||||
|
isSuspend = oldDescriptor.isSuspend
|
||||||
|
overriddenDescriptors += oldDescriptor.overriddenDescriptors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyConstructorDescriptor(oldDescriptor: ConstructorDescriptor) : FunctionDescriptor {
|
||||||
|
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
return ClassConstructorDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ newContainingDeclaration as ClassDescriptor,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* isPrimary = */ oldDescriptor.isPrimary,
|
||||||
|
/* source = */ oldDescriptor.source
|
||||||
|
).apply {
|
||||||
|
|
||||||
|
val newTypeParameters = oldDescriptor.typeParameters
|
||||||
|
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
|
||||||
|
val receiverParameterType = substituteType(oldDescriptor.dispatchReceiverParameter?.type)
|
||||||
|
val returnType = substituteType(oldDescriptor.returnType)
|
||||||
|
|
||||||
|
initialize(
|
||||||
|
/* receiverParameterType = */ receiverParameterType,
|
||||||
|
/* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver.
|
||||||
|
/* typeParameters = */ newTypeParameters,
|
||||||
|
/* unsubstitutedValueParameters = */ newValueParameters,
|
||||||
|
/* unsubstitutedReturnType = */ returnType,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyPropertyOrField(oldDescriptor: PropertyDescriptor) {
|
||||||
|
|
||||||
|
val newDescriptor = copyPropertyDescriptor(oldDescriptor)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
oldDescriptor.getter?.let {
|
||||||
|
descriptorSubstituteMap[it] = newDescriptor.getter!!
|
||||||
|
}
|
||||||
|
oldDescriptor.setter?.let {
|
||||||
|
descriptorSubstituteMap[it] = newDescriptor.setter!!
|
||||||
|
}
|
||||||
|
oldDescriptor.extensionReceiverParameter?.let{
|
||||||
|
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyPropertyDescriptor(oldDescriptor: PropertyDescriptor): PropertyDescriptor {
|
||||||
|
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor
|
||||||
|
return PropertyDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ newContainingDeclaration,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility,
|
||||||
|
/* isVar = */ oldDescriptor.isVar,
|
||||||
|
/* name = */ oldDescriptor.name,
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* source = */ oldDescriptor.source,
|
||||||
|
/* lateInit = */ oldDescriptor.isLateInit,
|
||||||
|
/* isConst = */ oldDescriptor.isConst,
|
||||||
|
/* isHeader = */ oldDescriptor.isHeader,
|
||||||
|
/* isImpl = */ oldDescriptor.isImpl,
|
||||||
|
/* isExternal = */ oldDescriptor.isExternal,
|
||||||
|
/* isDelegated = */ oldDescriptor.isDelegated
|
||||||
|
).apply {
|
||||||
|
|
||||||
|
setType(
|
||||||
|
/* outType = */ oldDescriptor.type,
|
||||||
|
/* typeParameters = */ oldDescriptor.typeParameters,
|
||||||
|
/* dispatchReceiverParameter = */ newContainingDeclaration.thisAsReceiverParameter,
|
||||||
|
/* receiverType = */ oldDescriptor.extensionReceiverParameter?.type)
|
||||||
|
|
||||||
|
initialize(
|
||||||
|
/* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) },
|
||||||
|
/* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) })
|
||||||
|
|
||||||
|
overriddenDescriptors += oldDescriptor.overriddenDescriptors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor)
|
||||||
|
: PropertyGetterDescriptorImpl {
|
||||||
|
|
||||||
|
return PropertyGetterDescriptorImpl(
|
||||||
|
/* correspondingProperty = */ newPropertyDescriptor,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility,
|
||||||
|
/* isDefault = */ oldDescriptor.isDefault,
|
||||||
|
/* isExternal = */ oldDescriptor.isExternal,
|
||||||
|
/* isInline = */ oldDescriptor.isInline,
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* original = */ null,
|
||||||
|
/* source = */ oldDescriptor.source).apply {
|
||||||
|
initialize(oldDescriptor.returnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor)
|
||||||
|
: PropertySetterDescriptorImpl {
|
||||||
|
|
||||||
|
return PropertySetterDescriptorImpl(
|
||||||
|
/* correspondingProperty = */ newPropertyDescriptor,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility,
|
||||||
|
/* isDefault = */ oldDescriptor.isDefault,
|
||||||
|
/* isExternal = */ oldDescriptor.isExternal,
|
||||||
|
/* isInline = */ oldDescriptor.isInline,
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* original = */ null,
|
||||||
|
/* source = */ oldDescriptor.source).apply {
|
||||||
|
initialize(copyValueParameters(oldDescriptor.valueParameters, this).single())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl {
|
||||||
|
|
||||||
|
val oldSuperClass = oldDescriptor.getSuperClassOrAny()
|
||||||
|
val newSuperClass = descriptorSubstituteMap.getOrDefault(oldSuperClass, oldSuperClass) as ClassDescriptor
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
val newName = if (DescriptorUtils.isAnonymousObject(oldDescriptor)) // Anonymous objects are identified by their name.
|
||||||
|
oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering.
|
||||||
|
else
|
||||||
|
generateCopyName(oldDescriptor.name)
|
||||||
|
return ClassDescriptorImpl(
|
||||||
|
/* containingDeclaration = */ newContainingDeclaration,
|
||||||
|
/* name = */ newName,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* supertypes = */ listOf(newSuperClass.defaultType),
|
||||||
|
/* source = */ oldDescriptor.source,
|
||||||
|
/* isExternal = */ oldDescriptor.isExternal
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
inner class InlineCopyIr : DeepCopyIrTree() {
|
||||||
|
|
||||||
|
override fun mapClassDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
||||||
|
override fun mapTypeAliasDeclaration (descriptor: TypeAliasDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as TypeAliasDescriptor
|
||||||
|
override fun mapFunctionDeclaration (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
||||||
|
override fun mapConstructorDeclaration (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
||||||
|
override fun mapPropertyDeclaration (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
|
||||||
|
override fun mapLocalPropertyDeclaration (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
|
||||||
|
override fun mapEnumEntryDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
||||||
|
override fun mapVariableDeclaration (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
|
||||||
|
override fun mapErrorDeclaration (descriptor: DeclarationDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor)
|
||||||
|
|
||||||
|
override fun mapClassReference (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
||||||
|
override fun mapValueReference (descriptor: ValueDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ValueDescriptor
|
||||||
|
override fun mapVariableReference (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
|
||||||
|
override fun mapPropertyReference (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
|
||||||
|
override fun mapCallee (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
||||||
|
override fun mapDelegatedConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
||||||
|
override fun mapEnumConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
||||||
|
override fun mapLocalPropertyReference (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
|
||||||
|
override fun mapClassifierReference (descriptor: ClassifierDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassifierDescriptor
|
||||||
|
override fun mapReturnTarget (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun mapSuperQualifier(qualifier: ClassDescriptor?): ClassDescriptor? {
|
||||||
|
if (qualifier == null) return null
|
||||||
|
return descriptorSubstituteMap.getOrDefault(qualifier, qualifier) as ClassDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- Visits ----------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrCall {
|
||||||
|
if (expression !is IrCallImpl) return super.visitCall(expression)
|
||||||
|
val newDescriptor = mapCallee(expression.descriptor)
|
||||||
|
return IrCallImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = newDescriptor.returnType!!,
|
||||||
|
calleeDescriptor = newDescriptor,
|
||||||
|
typeArguments = substituteTypeArguments(expression.transformTypeArguments(newDescriptor)),
|
||||||
|
origin = expression.origin,
|
||||||
|
superQualifierDescriptor = mapSuperQualifier(expression.superQualifier)
|
||||||
|
).transformValueArguments(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction): IrFunction =
|
||||||
|
IrFunctionImpl(
|
||||||
|
startOffset = declaration.startOffset,
|
||||||
|
endOffset = declaration.endOffset,
|
||||||
|
origin = mapDeclarationOrigin(declaration.origin),
|
||||||
|
descriptor = mapFunctionDeclaration(declaration.descriptor),
|
||||||
|
body = declaration.body?.transform(this, null)
|
||||||
|
).transformParameters(declaration)
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun <T : IrFunction> T.transformDefaults(original: T): T {
|
||||||
|
for (originalValueParameter in original.descriptor.valueParameters) {
|
||||||
|
val valueParameter = descriptor.valueParameters[originalValueParameter.index]
|
||||||
|
original.getDefault(originalValueParameter)?.let { irDefaultParameterValue ->
|
||||||
|
putDefault(valueParameter, irDefaultParameterValue.transform(this@InlineCopyIr, null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: KotlinType) : KotlinType {
|
||||||
|
return when (operator) {
|
||||||
|
IrTypeOperator.CAST,
|
||||||
|
IrTypeOperator.IMPLICIT_CAST,
|
||||||
|
IrTypeOperator.IMPLICIT_NOTNULL,
|
||||||
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
||||||
|
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type
|
||||||
|
IrTypeOperator.SAFE_CAST -> type.makeNullable()
|
||||||
|
IrTypeOperator.INSTANCEOF,
|
||||||
|
IrTypeOperator.NOT_INSTANCEOF -> context.builtIns.booleanType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
|
||||||
|
val typeOperand = substituteType(expression.typeOperand)!!
|
||||||
|
val returnType = getTypeOperatorReturnType(expression.operator, typeOperand)
|
||||||
|
return IrTypeOperatorCallImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = returnType,
|
||||||
|
operator = expression.operator,
|
||||||
|
typeOperand = typeOperand,
|
||||||
|
argument = expression.argument.transform(this, null)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrReturn =
|
||||||
|
IrReturnImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = substituteType(expression.type)!!,
|
||||||
|
returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
|
||||||
|
value = expression.value.transform(this, null)
|
||||||
|
)
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitBlock(expression: IrBlock): IrBlock {
|
||||||
|
return if (expression is IrReturnableBlock) {
|
||||||
|
IrReturnableBlockImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = expression.type,
|
||||||
|
descriptor = expression.descriptor,
|
||||||
|
origin = mapStatementOrigin(expression.origin),
|
||||||
|
statements = expression.statements.map { it.transform(this, null) },
|
||||||
|
sourceFileName = expression.sourceFileName
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
super.visitBlock(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
|
||||||
|
return irLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyValueParameters(oldValueParameters: List <ValueParameterDescriptor>, containingDeclaration: CallableDescriptor): List <ValueParameterDescriptor> {
|
||||||
|
|
||||||
|
return oldValueParameters.map { oldDescriptor ->
|
||||||
|
val newDescriptor = ValueParameterDescriptorImpl(
|
||||||
|
containingDeclaration = containingDeclaration,
|
||||||
|
original = oldDescriptor.original,
|
||||||
|
index = oldDescriptor.index,
|
||||||
|
annotations = oldDescriptor.annotations,
|
||||||
|
name = oldDescriptor.name,
|
||||||
|
outType = substituteType(oldDescriptor.type)!!,
|
||||||
|
declaresDefaultValue = oldDescriptor.declaresDefaultValue(),
|
||||||
|
isCrossinline = oldDescriptor.isCrossinline,
|
||||||
|
isNoinline = oldDescriptor.isNoinline,
|
||||||
|
varargElementType = substituteType(oldDescriptor.varargElementType),
|
||||||
|
source = oldDescriptor.source
|
||||||
|
)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
newDescriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun substituteType(oldType: KotlinType?): KotlinType? {
|
||||||
|
if (typeSubstitutor == null) return oldType
|
||||||
|
if (oldType == null) return oldType
|
||||||
|
return typeSubstitutor!!.substitute(oldType, Variance.INVARIANT) ?: oldType
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun substituteTypeArguments(oldTypeArguments: Map <TypeParameterDescriptor, KotlinType>?): Map <TypeParameterDescriptor, KotlinType>? {
|
||||||
|
|
||||||
|
if (oldTypeArguments == null) return null
|
||||||
|
if (typeSubstitutor == null) return oldTypeArguments
|
||||||
|
|
||||||
|
val newTypeArguments = oldTypeArguments.entries.associate {
|
||||||
|
val typeParameterDescriptor = it.key
|
||||||
|
val oldTypeArgument = it.value
|
||||||
|
val newTypeArgument = substituteType(oldTypeArgument)!!
|
||||||
|
typeParameterDescriptor to newTypeArgument
|
||||||
|
}
|
||||||
|
return newTypeArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
|
||||||
|
descriptorSubstituteMap.forEach { t, u ->
|
||||||
|
globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
|
||||||
|
|
||||||
|
internal class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
|
||||||
|
: IrElementTransformerVoidWithContext() {
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
val oldExpression = super.visitCall(expression) as IrCall
|
||||||
|
|
||||||
|
val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original]
|
||||||
|
?: return oldExpression
|
||||||
|
if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
|
||||||
|
return oldExpression
|
||||||
|
return when (oldExpression) {
|
||||||
|
is IrCallImpl -> copyIrCallImpl(oldExpression, substitutedDescriptor)
|
||||||
|
is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression, substitutedDescriptor)
|
||||||
|
else -> oldExpression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
|
||||||
|
|
||||||
|
val oldDescriptor = oldExpression.descriptor
|
||||||
|
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
|
||||||
|
|
||||||
|
if (newDescriptor == oldDescriptor)
|
||||||
|
return oldExpression
|
||||||
|
|
||||||
|
val newExpression = IrCallImpl(
|
||||||
|
startOffset = oldExpression.startOffset,
|
||||||
|
endOffset = oldExpression.endOffset,
|
||||||
|
type = oldExpression.type,
|
||||||
|
calleeDescriptor = newDescriptor,
|
||||||
|
typeArguments = oldExpression.typeArguments,
|
||||||
|
origin = oldExpression.origin,
|
||||||
|
superQualifierDescriptor = oldExpression.superQualifier
|
||||||
|
).apply {
|
||||||
|
oldExpression.descriptor.valueParameters.forEach {
|
||||||
|
val valueArgument = oldExpression.getValueArgument(it)
|
||||||
|
putValueArgument(it.index, valueArgument)
|
||||||
|
}
|
||||||
|
extensionReceiver = oldExpression.extensionReceiver
|
||||||
|
dispatchReceiver = oldExpression.dispatchReceiver
|
||||||
|
}
|
||||||
|
|
||||||
|
return newExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy, substitutedDescriptor: SubstitutedDescriptor): IrCall {
|
||||||
|
|
||||||
|
val oldDescriptor = oldExpression.descriptor
|
||||||
|
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
|
||||||
|
|
||||||
|
if (newDescriptor == oldDescriptor)
|
||||||
|
return oldExpression
|
||||||
|
|
||||||
|
return oldExpression.shallowCopy(oldExpression.origin, newDescriptor, oldExpression.superQualifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+365
@@ -0,0 +1,365 @@
|
|||||||
|
package org.jetbrains.kotlin.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.renderer.*
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.utils.Printer
|
||||||
|
|
||||||
|
class RenderIrElementWithDescriptorsVisitor : IrElementVisitor<String, Nothing?> {
|
||||||
|
override fun visitElement(element: IrElement, data: Nothing?): String =
|
||||||
|
"? ${element.javaClass.simpleName}"
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?): String =
|
||||||
|
"? ${declaration.javaClass.simpleName} ${declaration.descriptor.ref()}"
|
||||||
|
|
||||||
|
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): String =
|
||||||
|
"MODULE_FRAGMENT ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitFile(declaration: IrFile, data: Nothing?): String =
|
||||||
|
"FILE ${declaration.name}"
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction, data: Nothing?): String =
|
||||||
|
"FUN ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitConstructor(declaration: IrConstructor, data: Nothing?): String =
|
||||||
|
"CONSTRUCTOR ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitProperty(declaration: IrProperty, data: Nothing?): String =
|
||||||
|
"PROPERTY ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField, data: Nothing?): String =
|
||||||
|
"FIELD ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass, data: Nothing?): String =
|
||||||
|
"CLASS ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitTypeAlias(declaration: IrTypeAlias, data: Nothing?): String =
|
||||||
|
"TYPEALIAS ${declaration.descriptor} type=${declaration.descriptor.underlyingType.render()}"
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable, data: Nothing?): String =
|
||||||
|
"VAR ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitEnumEntry(declaration: IrEnumEntry, data: Nothing?): String =
|
||||||
|
"ENUM_ENTRY ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): String =
|
||||||
|
"ANONYMOUS_INITIALIZER ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?): String =
|
||||||
|
"LOCAL_DELEGATED_PROPERTY ${declaration.descriptor}"
|
||||||
|
|
||||||
|
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
|
||||||
|
"EXPRESSION_BODY"
|
||||||
|
|
||||||
|
override fun visitBlockBody(body: IrBlockBody, data: Nothing?): String =
|
||||||
|
"BLOCK_BODY"
|
||||||
|
|
||||||
|
override fun visitSyntheticBody(body: IrSyntheticBody, data: Nothing?): String =
|
||||||
|
"SYNTHETIC_BODY kind=${body.kind}"
|
||||||
|
|
||||||
|
override fun visitExpression(expression: IrExpression, data: Nothing?): String =
|
||||||
|
"? ${expression.javaClass.simpleName} type=${expression.type.render()}"
|
||||||
|
|
||||||
|
override fun <T> visitConst(expression: IrConst<T>, data: Nothing?): String =
|
||||||
|
"CONST ${expression.kind} type=${expression.type.render()} value='${expression.value}'"
|
||||||
|
|
||||||
|
override fun visitVararg(expression: IrVararg, data: Nothing?): String =
|
||||||
|
"VARARG type=${expression.type} varargElementType=${expression.varargElementType}"
|
||||||
|
|
||||||
|
override fun visitSpreadElement(spread: IrSpreadElement, data: Nothing?): String =
|
||||||
|
"SPREAD_ELEMENT"
|
||||||
|
|
||||||
|
override fun visitBlock(expression: IrBlock, data: Nothing?): String =
|
||||||
|
"BLOCK type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
override fun visitComposite(expression: IrComposite, data: Nothing?): String =
|
||||||
|
"COMPOSITE type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn, data: Nothing?): String =
|
||||||
|
"RETURN type=${expression.type.render()} from='${expression.returnTarget}'"
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall, data: Nothing?): String =
|
||||||
|
"CALL '${expression.descriptor}' ${expression.renderSuperQualifier()}" +
|
||||||
|
"type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
private fun IrCall.renderSuperQualifier(): String =
|
||||||
|
superQualifier?.let { "superQualifier=${it.name} " } ?: ""
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Nothing?): String =
|
||||||
|
"DELEGATING_CONSTRUCTOR_CALL '${expression.descriptor}'"
|
||||||
|
|
||||||
|
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall, data: Nothing?): String =
|
||||||
|
"ENUM_CONSTRUCTOR_CALL '${expression.descriptor}'"
|
||||||
|
|
||||||
|
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, data: Nothing?): String =
|
||||||
|
"INSTANCE_INITIALIZER_CALL classDescriptor='${expression.classDescriptor}'"
|
||||||
|
|
||||||
|
override fun visitGetValue(expression: IrGetValue, data: Nothing?): String =
|
||||||
|
"GET_VAR '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): String =
|
||||||
|
"SET_VAR '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
override fun visitGetField(expression: IrGetField, data: Nothing?): String =
|
||||||
|
"GET_FIELD '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
override fun visitSetField(expression: IrSetField, data: Nothing?): String =
|
||||||
|
"SET_FIELD '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
override fun visitGetObjectValue(expression: IrGetObjectValue, data: Nothing?): String =
|
||||||
|
"GET_OBJECT '${expression.descriptor}' type=${expression.type.render()}"
|
||||||
|
|
||||||
|
override fun visitGetEnumValue(expression: IrGetEnumValue, data: Nothing?): String =
|
||||||
|
"GET_ENUM '${expression.descriptor}' type=${expression.type.render()}"
|
||||||
|
|
||||||
|
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): String =
|
||||||
|
"STRING_CONCATENATION type=${expression.type.render()}"
|
||||||
|
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Nothing?): String =
|
||||||
|
"TYPE_OP origin=${expression.operator} typeOperand=${expression.typeOperand.render()}"
|
||||||
|
|
||||||
|
override fun visitWhen(expression: IrWhen, data: Nothing?): String =
|
||||||
|
"WHEN type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
override fun visitBranch(branch: IrBranch, data: Nothing?): String =
|
||||||
|
"BRANCH"
|
||||||
|
|
||||||
|
override fun visitWhileLoop(loop: IrWhileLoop, data: Nothing?): String =
|
||||||
|
"WHILE label=${loop.label} origin=${loop.origin}"
|
||||||
|
|
||||||
|
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Nothing?): String =
|
||||||
|
"DO_WHILE label=${loop.label} origin=${loop.origin}"
|
||||||
|
|
||||||
|
override fun visitBreak(jump: IrBreak, data: Nothing?): String =
|
||||||
|
"BREAK label=${jump.label} loop.label=${jump.loop.label}"
|
||||||
|
|
||||||
|
override fun visitContinue(jump: IrContinue, data: Nothing?): String =
|
||||||
|
"CONTINUE label=${jump.label} loop.label=${jump.loop.label}"
|
||||||
|
|
||||||
|
override fun visitThrow(expression: IrThrow, data: Nothing?): String =
|
||||||
|
"THROW type=${expression.type.render()}"
|
||||||
|
|
||||||
|
override fun visitCallableReference(expression: IrCallableReference, data: Nothing?): String =
|
||||||
|
"CALLABLE_REFERENCE '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
||||||
|
|
||||||
|
override fun visitClassReference(expression: IrClassReference, data: Nothing?): String =
|
||||||
|
"CLASS_REFERENCE '${expression.descriptor}' type=${expression.type.render()}"
|
||||||
|
|
||||||
|
override fun visitGetClass(expression: IrGetClass, data: Nothing?): String =
|
||||||
|
"GET_CLASS type=${expression.type.render()}"
|
||||||
|
|
||||||
|
override fun visitTry(aTry: IrTry, data: Nothing?): String =
|
||||||
|
"TRY type=${aTry.type.render()}"
|
||||||
|
|
||||||
|
override fun visitCatch(aCatch: IrCatch, data: Nothing?): String =
|
||||||
|
"CATCH parameter=${aCatch.parameter.ref()}"
|
||||||
|
|
||||||
|
override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: Nothing?): String =
|
||||||
|
"ERROR_DECL ${declaration.descriptor.javaClass.simpleName} ${declaration.descriptor.ref()}"
|
||||||
|
|
||||||
|
override fun visitErrorExpression(expression: IrErrorExpression, data: Nothing?): String =
|
||||||
|
"ERROR_EXPR '${expression.description}' type=${expression.type.render()}"
|
||||||
|
|
||||||
|
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: Nothing?): String =
|
||||||
|
"ERROR_CALL '${expression.description}' type=${expression.type.render()}"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DECLARATION_RENDERER = DescriptorRenderer.withOptions {
|
||||||
|
withDefinedIn = false
|
||||||
|
overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OPEN_OVERRIDE
|
||||||
|
includePropertyConstant = true
|
||||||
|
classifierNamePolicy = ClassifierNamePolicy.FULLY_QUALIFIED
|
||||||
|
verbose = false
|
||||||
|
modifiers = DescriptorRendererModifier.ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
val REFERENCE_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES
|
||||||
|
|
||||||
|
internal fun IrDeclaration.name(): String =
|
||||||
|
descriptor.let { it.name.toString() }
|
||||||
|
|
||||||
|
internal fun IrDeclaration.renderDeclared(): String =
|
||||||
|
DECLARATION_RENDERER.render(this.descriptor)
|
||||||
|
|
||||||
|
internal fun DeclarationDescriptor.ref(): String =
|
||||||
|
if (this is ReceiverParameterDescriptor)
|
||||||
|
"<receiver: ${containingDeclaration.ref()}>"
|
||||||
|
else
|
||||||
|
REFERENCE_RENDERER.render(this)
|
||||||
|
|
||||||
|
internal fun KotlinType.render(): String =
|
||||||
|
DECLARATION_RENDERER.renderType(this)
|
||||||
|
|
||||||
|
internal fun IrDeclaration.renderOrigin(): String =
|
||||||
|
if (origin != IrDeclarationOrigin.DEFINED) origin.toString() + " " else ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DumpIrTreeWithDescriptorsVisitor(out: Appendable): IrElementVisitor<Unit, String> {
|
||||||
|
val printer = Printer(out, " ")
|
||||||
|
val elementRenderer = RenderIrElementWithDescriptorsVisitor()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ANNOTATIONS_RENDERER = DescriptorRenderer.withOptions {
|
||||||
|
verbose = true
|
||||||
|
annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement, data: String) {
|
||||||
|
element.dumpLabeledSubTree(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFile(declaration: IrFile, data: String) {
|
||||||
|
declaration.dumpLabeledElementWith(data) {
|
||||||
|
if (declaration.fileAnnotations.isNotEmpty()) {
|
||||||
|
printer.println("fileAnnotations:")
|
||||||
|
indented {
|
||||||
|
declaration.fileAnnotations.forEach {
|
||||||
|
printer.println(ANNOTATIONS_RENDERER.renderAnnotation(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
declaration.declarations.forEach { it.accept(this, "") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBlock(expression: IrBlock, data: String) {
|
||||||
|
if (expression is IrReturnableBlock) {
|
||||||
|
printer.println("RETURNABLE BLOCK " + expression.descriptor)
|
||||||
|
indented { super.visitBlock(expression, data) }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
super.visitBlock(expression, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction, data: String) {
|
||||||
|
visitFunctionWithParameters(declaration, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstructor(declaration: IrConstructor, data: String) {
|
||||||
|
visitFunctionWithParameters(declaration, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: String) {
|
||||||
|
expression.dumpLabeledElementWith(data) {
|
||||||
|
expression.explicitReceiver?.accept(this, "receiver")
|
||||||
|
expression.arguments.forEach { it.accept(this, "") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitFunctionWithParameters(declaration: IrFunction, data: String) {
|
||||||
|
declaration.dumpLabeledElementWith(data) {
|
||||||
|
declaration.descriptor.valueParameters.forEach { valueParameter ->
|
||||||
|
declaration.getDefault(valueParameter)?.accept(this, valueParameter.name.asString())
|
||||||
|
}
|
||||||
|
declaration.body?.accept(this, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEnumEntry(declaration: IrEnumEntry, data: String) {
|
||||||
|
declaration.dumpLabeledElementWith(data) {
|
||||||
|
declaration.initializerExpression?.accept(this, "init")
|
||||||
|
declaration.correspondingClass?.accept(this, "class")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitMemberAccess(expression: IrMemberAccessExpression, data: String) {
|
||||||
|
expression.dumpLabeledElementWith(data) {
|
||||||
|
dumpTypeArguments(expression)
|
||||||
|
|
||||||
|
expression.dispatchReceiver?.accept(this, "\$this")
|
||||||
|
expression.extensionReceiver?.accept(this, "\$receiver")
|
||||||
|
for (valueParameter in expression.descriptor.valueParameters) {
|
||||||
|
expression.getValueArgument(valueParameter.index)?.accept(this, valueParameter.name.asString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dumpTypeArguments(expression: IrMemberAccessExpression) {
|
||||||
|
for (typeParameter in expression.descriptor.original.typeParameters) {
|
||||||
|
val typeArgument = expression.getTypeArgument(typeParameter) ?: continue
|
||||||
|
val renderedParameter = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(typeParameter)
|
||||||
|
val renderedType = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.renderType(typeArgument)
|
||||||
|
printer.println("$renderedParameter: $renderedType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetField(expression: IrGetField, data: String) {
|
||||||
|
expression.dumpLabeledElementWith(data) {
|
||||||
|
expression.receiver?.accept(this, "receiver")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetField(expression: IrSetField, data: String) {
|
||||||
|
expression.dumpLabeledElementWith(data) {
|
||||||
|
expression.receiver?.accept(this, "receiver")
|
||||||
|
expression.value.accept(this, "value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWhen(expression: IrWhen, data: String) {
|
||||||
|
expression.dumpLabeledElementWith(data) {
|
||||||
|
expression.branches.forEach {
|
||||||
|
it.accept(this, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBranch(branch: IrBranch, data: String) {
|
||||||
|
branch.dumpLabeledElementWith(data) {
|
||||||
|
branch.condition.accept(this, "if")
|
||||||
|
branch.result.accept(this, "then")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWhileLoop(loop: IrWhileLoop, data: String) {
|
||||||
|
loop.dumpLabeledElementWith(data) {
|
||||||
|
loop.condition.accept(this, "condition")
|
||||||
|
loop.body?.accept(this, "body")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: String) {
|
||||||
|
loop.dumpLabeledElementWith(data) {
|
||||||
|
loop.body?.accept(this, "body")
|
||||||
|
loop.condition.accept(this, "condition")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTry(aTry: IrTry, data: String) {
|
||||||
|
aTry.dumpLabeledElementWith(data) {
|
||||||
|
aTry.tryResult.accept(this, "try")
|
||||||
|
for (aCatch in aTry.catches) {
|
||||||
|
aCatch.accept(this, "")
|
||||||
|
}
|
||||||
|
aTry.finallyExpression?.accept(this, "finally")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
|
||||||
|
printer.println(accept(elementRenderer, null).withLabel(label))
|
||||||
|
indented(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrElement.dumpLabeledSubTree(label: String) {
|
||||||
|
printer.println(accept(elementRenderer, null).withLabel(label))
|
||||||
|
indented {
|
||||||
|
acceptChildren(this@DumpIrTreeWithDescriptorsVisitor, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun indented(body: () -> Unit) {
|
||||||
|
printer.pushIndent()
|
||||||
|
body()
|
||||||
|
printer.popIndent()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.withLabel(label: String) =
|
||||||
|
if (label.isEmpty()) this else "$label: $this"
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
|
||||||
|
import org.jetbrains.kotlin.ir.util.SymbolRemapper
|
||||||
|
|
||||||
|
open class DeepCopyIrTreeWithReturnableBlockSymbols(
|
||||||
|
private val symbolRemapper: SymbolRemapper
|
||||||
|
) : DeepCopyIrTreeWithSymbols(symbolRemapper) {
|
||||||
|
|
||||||
|
private inline fun <reified T : IrElement> T.transform() =
|
||||||
|
transform(this@DeepCopyIrTreeWithReturnableBlockSymbols, null) as T
|
||||||
|
|
||||||
|
private val transformedReturnableBlocks = mutableMapOf<IrReturnableBlock, IrReturnableBlock>()
|
||||||
|
|
||||||
|
override fun visitBlock(expression: IrBlock): IrBlock = if (expression is IrReturnableBlock) {
|
||||||
|
IrReturnableBlockImpl(
|
||||||
|
expression.startOffset, expression.endOffset,
|
||||||
|
expression.type,
|
||||||
|
expression.descriptor,
|
||||||
|
expression.origin,
|
||||||
|
expression.sourceFileName
|
||||||
|
).also {
|
||||||
|
transformedReturnableBlocks.put(expression, it)
|
||||||
|
it.statements.addAll(expression.statements.map { it.transform() })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.visitBlock(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrReturn {
|
||||||
|
val returnTargetSymbol = expression.returnTargetSymbol
|
||||||
|
return if (returnTargetSymbol is IrReturnableBlockSymbol) {
|
||||||
|
IrReturnImpl(
|
||||||
|
expression.startOffset, expression.endOffset,
|
||||||
|
expression.type,
|
||||||
|
transformedReturnableBlocks.getOrElse(returnTargetSymbol.owner) { returnTargetSymbol.owner }.symbol,
|
||||||
|
expression.value.transform()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
super.visitReturn(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+166
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.builders.Scope
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
|
||||||
|
class ScopeWithIr(val scope: Scope, val irElement: IrElement)
|
||||||
|
|
||||||
|
abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
private val scopeStack = mutableListOf<ScopeWithIr>()
|
||||||
|
|
||||||
|
override final fun visitFile(declaration: IrFile): IrFile {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
||||||
|
val result = visitFileNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun visitClass(declaration: IrClass): IrStatement {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
||||||
|
val result = visitClassNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun visitProperty(declaration: IrProperty): IrStatement {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
|
||||||
|
val result = visitPropertyNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun visitField(declaration: IrField): IrStatement {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
||||||
|
val result = visitFieldNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun visitFunction(declaration: IrFunction): IrStatement {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
||||||
|
val result = visitFunctionNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
protected val currentFile get() = scopeStack.lastOrNull { it.irElement is IrFile }!!.irElement as IrFile
|
||||||
|
protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor }
|
||||||
|
protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor }
|
||||||
|
protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor }
|
||||||
|
protected val currentScope get() = scopeStack.peek()
|
||||||
|
protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
|
||||||
|
protected val allScopes get() = scopeStack
|
||||||
|
|
||||||
|
fun printScopeStack() {
|
||||||
|
scopeStack.forEach { println(it.scope.scopeOwner) }
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitFileNew(declaration: IrFile): IrFile {
|
||||||
|
return super.visitFile(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitClassNew(declaration: IrClass): IrStatement {
|
||||||
|
return super.visitClass(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitFunctionNew(declaration: IrFunction): IrStatement {
|
||||||
|
return super.visitFunction(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitPropertyNew(declaration: IrProperty): IrStatement {
|
||||||
|
return super.visitProperty(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitFieldNew(declaration: IrField): IrStatement {
|
||||||
|
return super.visitField(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract internal class IrElementVisitorVoidWithContext : IrElementVisitorVoid {
|
||||||
|
|
||||||
|
private val scopeStack = mutableListOf<ScopeWithIr>()
|
||||||
|
|
||||||
|
override final fun visitFile(declaration: IrFile) {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
||||||
|
visitFileNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun visitClass(declaration: IrClass) {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
||||||
|
visitClassNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun visitProperty(declaration: IrProperty) {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
|
||||||
|
visitPropertyNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun visitField(declaration: IrField) {
|
||||||
|
val isDelegated = declaration.descriptor.isDelegated
|
||||||
|
if (isDelegated) scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
||||||
|
visitFieldNew(declaration)
|
||||||
|
if (isDelegated) scopeStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun visitFunction(declaration: IrFunction) {
|
||||||
|
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
|
||||||
|
visitFunctionNew(declaration)
|
||||||
|
scopeStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected val currentFile get() = scopeStack.lastOrNull { it.scope.scopeOwner is PackageFragmentDescriptor }
|
||||||
|
protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor }
|
||||||
|
protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor }
|
||||||
|
protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor }
|
||||||
|
protected val currentScope get() = scopeStack.peek()
|
||||||
|
protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
|
||||||
|
|
||||||
|
fun printScopeStack() {
|
||||||
|
scopeStack.forEach { println(it.scope.scopeOwner) }
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitFileNew(declaration: IrFile) {
|
||||||
|
super.visitFile(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitClassNew(declaration: IrClass) {
|
||||||
|
super.visitClass(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitFunctionNew(declaration: IrFunction) {
|
||||||
|
super.visitFunction(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitPropertyNew(declaration: IrProperty) {
|
||||||
|
super.visitProperty(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun visitFieldNew(declaration: IrField) {
|
||||||
|
super.visitField(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
|
|
||||||
|
fun validateIrFile(context: CommonBackendContext, irFile: IrFile) {
|
||||||
|
val visitor = IrValidator(context, false)
|
||||||
|
irFile.acceptVoid(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun validateIrModule(context: CommonBackendContext, irModule: IrModuleFragment) {
|
||||||
|
val visitor = IrValidator(context, true) // TODO: consider taking the boolean from settings.
|
||||||
|
irModule.acceptVoid(visitor)
|
||||||
|
|
||||||
|
// TODO: also check that all referenced symbol targets are reachable.
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CommonBackendContext.reportIrValidationError(message: String, irFile: IrFile, irElement: IrElement) {
|
||||||
|
try {
|
||||||
|
this.reportWarning("[IR VALIDATION] $message", irFile, irElement)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
println("an error trying to print a warning message: $e")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
// TODO: throw an exception after fixing bugs leading to invalid IR.
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IrValidator(val context: CommonBackendContext, performHeavyValidations: Boolean) : IrElementVisitorVoid {
|
||||||
|
|
||||||
|
val builtIns = context.builtIns
|
||||||
|
lateinit var currentFile: IrFile
|
||||||
|
|
||||||
|
override fun visitFile(declaration: IrFile) {
|
||||||
|
currentFile = declaration
|
||||||
|
super.visitFile(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun error(element: IrElement, message: String) {
|
||||||
|
// TODO: render all element's parents.
|
||||||
|
context.reportIrValidationError(
|
||||||
|
"$message\n" +
|
||||||
|
element.render(),
|
||||||
|
currentFile, element)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val elementChecker = CheckIrElementVisitor(builtIns, this::error, performHeavyValidations)
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptVoid(elementChecker)
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
+160
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.usesDefaultArguments
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects calls to be treated as tail recursion.
|
||||||
|
* The checks are partially based on the frontend implementation
|
||||||
|
* in `ControlFlowInformationProvider.markAndCheckRecursiveTailCalls()`.
|
||||||
|
*
|
||||||
|
* This analysis is not very precise and can miss some calls.
|
||||||
|
* It is also not guaranteed that each returned call is detected as tail recursion by the frontend.
|
||||||
|
* However any returned call can be correctly optimized as tail recursion.
|
||||||
|
*/
|
||||||
|
fun collectTailRecursionCalls(irFunction: IrFunction): Set<IrCall> {
|
||||||
|
if (!irFunction.descriptor.isTailrec) {
|
||||||
|
return emptySet()
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = mutableSetOf<IrCall>()
|
||||||
|
|
||||||
|
val visitor = object : IrElementVisitor<Unit, ElementKind> {
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement, data: ElementKind) {
|
||||||
|
val childKind = ElementKind.NOT_SURE // Not sure by default.
|
||||||
|
element.acceptChildren(this, childKind)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction, data: ElementKind) {
|
||||||
|
// Ignore local functions.
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass, data: ElementKind) {
|
||||||
|
// Ignore local classes.
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTry(aTry: IrTry, data: ElementKind) {
|
||||||
|
// We do not support tail calls in try-catch-finally, for simplicity of the mental model
|
||||||
|
// very few cases there would be real tail-calls, and it's often not so easy for the user to see why
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn, data: ElementKind) {
|
||||||
|
val valueKind = if (expression.returnTarget == irFunction.descriptor) {
|
||||||
|
ElementKind.TAIL_STATEMENT
|
||||||
|
} else {
|
||||||
|
ElementKind.NOT_SURE
|
||||||
|
}
|
||||||
|
expression.value.accept(this, valueKind)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitContainerExpression(expression: IrContainerExpression, data: ElementKind) {
|
||||||
|
expression.statements.forEachIndexed { index, irStatement ->
|
||||||
|
val statementKind = if (index == expression.statements.lastIndex) {
|
||||||
|
// The last statement defines the result of the container expression, so it has the same kind.
|
||||||
|
data
|
||||||
|
} else {
|
||||||
|
ElementKind.NOT_SURE
|
||||||
|
}
|
||||||
|
irStatement.accept(this, statementKind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWhen(expression: IrWhen, data: ElementKind) {
|
||||||
|
expression.branches.forEach {
|
||||||
|
it.condition.accept(this, ElementKind.NOT_SURE)
|
||||||
|
it.result.accept(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall, data: ElementKind) {
|
||||||
|
expression.acceptChildren(this, ElementKind.NOT_SURE)
|
||||||
|
|
||||||
|
// Is it a tail call?
|
||||||
|
if (data != ElementKind.TAIL_STATEMENT) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it a recursive call?
|
||||||
|
if (expression.descriptor.original != irFunction.descriptor) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: check type arguments
|
||||||
|
|
||||||
|
if (DescriptorUtils.isOverride(irFunction.descriptor) && expression.usesDefaultArguments()) {
|
||||||
|
// Overridden functions using default arguments at tail call are not included: KT-4285
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.dispatchReceiver?.let {
|
||||||
|
if (it !is IrGetValue || it.descriptor != irFunction.descriptor.dispatchReceiverParameter) {
|
||||||
|
// A tail call is not allowed to change dispatch receiver
|
||||||
|
// class C {
|
||||||
|
// fun foo(other: C) {
|
||||||
|
// other.foo(this) // not a tail call
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.add(expression)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
val body = irFunction.body
|
||||||
|
if (body !is IrBlockBody) {
|
||||||
|
return emptySet() // TODO: should an assert be here instead?
|
||||||
|
}
|
||||||
|
|
||||||
|
body.statements.forEachIndexed { index, irStatement ->
|
||||||
|
val kind = if (index == body.statements.lastIndex && irFunction.descriptor.returnType?.isUnit() == true) {
|
||||||
|
ElementKind.TAIL_STATEMENT
|
||||||
|
} else {
|
||||||
|
ElementKind.NOT_SURE
|
||||||
|
}
|
||||||
|
irStatement.accept(visitor, kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The kind of IR element used to detect tail calls.
|
||||||
|
*/
|
||||||
|
private enum class ElementKind {
|
||||||
|
/**
|
||||||
|
* This element is the last statement to be executed before the return from the function.
|
||||||
|
* If the return type is not `Unit`, the result of this statement defines the result of the entire function.
|
||||||
|
*/
|
||||||
|
TAIL_STATEMENT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not sure if the element meets the requirements to be [TAIL_STATEMENT].
|
||||||
|
*/
|
||||||
|
NOT_SURE
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.util.getCompilerMessageLocation
|
||||||
|
|
||||||
|
fun CommonBackendContext.reportWarning(message: String, irFile: IrFile, irElement: IrElement) {
|
||||||
|
val location = irElement.getCompilerMessageLocation(irFile)
|
||||||
|
messageCollector.report(CompilerMessageSeverity.WARNING, message, location)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <E> MutableList<E>.push(element: E) = this.add(element)
|
||||||
|
|
||||||
|
fun <E> MutableList<E>.pop() = this.removeAt(size - 1)
|
||||||
|
|
||||||
|
fun <E> MutableList<E>.peek(): E? = if (size == 0) null else this[size - 1]
|
||||||
|
|
||||||
|
fun <T> Collection<T>.atMostOne(): T? {
|
||||||
|
return when (this.size) {
|
||||||
|
0 -> null
|
||||||
|
1 -> this.iterator().next()
|
||||||
|
else -> throw IllegalArgumentException("Collection has more than one element.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T> Iterable<T>.atMostOne(predicate: (T) -> Boolean): T? = this.filter(predicate).atMostOne()
|
||||||
|
|
||||||
|
fun <T: Any> T.onlyIf(condition: T.()->Boolean, then: (T)->Unit): T {
|
||||||
|
if (this.condition()) then(this)
|
||||||
|
return this
|
||||||
|
}
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common.descriptors
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.replace
|
||||||
|
|
||||||
|
val CallableDescriptor.isSuspend: Boolean
|
||||||
|
get() = this is FunctionDescriptor && isSuspend
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return naturally-ordered list of all parameters available inside the function body.
|
||||||
|
*/
|
||||||
|
val CallableDescriptor.allParameters: List<ParameterDescriptor>
|
||||||
|
get() = if (this is ConstructorDescriptor) {
|
||||||
|
listOf(this.constructedClass.thisAsReceiverParameter) + explicitParameters
|
||||||
|
} else {
|
||||||
|
explicitParameters
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return naturally-ordered list of the parameters that can have values specified at call site.
|
||||||
|
*/
|
||||||
|
val CallableDescriptor.explicitParameters: List<ParameterDescriptor>
|
||||||
|
get() {
|
||||||
|
val result = ArrayList<ParameterDescriptor>(valueParameters.size + 2)
|
||||||
|
|
||||||
|
this.dispatchReceiverParameter?.let {
|
||||||
|
result.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.extensionReceiverParameter?.let {
|
||||||
|
result.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.addAll(valueParameters)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KotlinType.replace(types: List<KotlinType>) = this.replace(types.map(::TypeProjectionImpl))
|
||||||
|
|
||||||
|
fun FunctionDescriptor.substitute(vararg types: KotlinType): FunctionDescriptor {
|
||||||
|
val typeSubstitutor = TypeSubstitutor.create(
|
||||||
|
typeParameters
|
||||||
|
.withIndex()
|
||||||
|
.associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
|
||||||
|
)
|
||||||
|
return substitute(typeSubstitutor)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun FunctionDescriptor.substitute(typeArguments: Map<TypeParameterDescriptor, KotlinType>): FunctionDescriptor {
|
||||||
|
val typeSubstitutor = TypeSubstitutor.create(
|
||||||
|
typeParameters.associateBy({ it.typeConstructor }, { TypeProjectionImpl(typeArguments[it]!!) })
|
||||||
|
)
|
||||||
|
return substitute(typeSubstitutor)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ClassDescriptor.getFunction(name: String, types: List<KotlinType>): FunctionDescriptor {
|
||||||
|
val typeSubstitutor = TypeSubstitutor.create(
|
||||||
|
declaredTypeParameters
|
||||||
|
.withIndex()
|
||||||
|
.associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
|
||||||
|
)
|
||||||
|
return unsubstitutedMemberScope
|
||||||
|
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
val KotlinType.isFunctionOrKFunctionType: Boolean
|
||||||
|
get() {
|
||||||
|
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
|
||||||
|
return kind == FunctionClassDescriptor.Kind.Function || kind == FunctionClassDescriptor.Kind.KFunction
|
||||||
|
}
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common.descriptors
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
fun ClassDescriptor?.getter2Descriptor(methodName: Name) = this?.let {
|
||||||
|
this.unsubstitutedMemberScope.getContributedDescriptors{true}
|
||||||
|
.firstOrNull {
|
||||||
|
it.name == methodName
|
||||||
|
} ?.let {
|
||||||
|
return@let (it as? PropertyDescriptor)?.getter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ClassDescriptor?.signature2Descriptor(methodName: Name, signature:Array<KotlinType> = emptyArray()) = this?.let {
|
||||||
|
this
|
||||||
|
.unsubstitutedMemberScope
|
||||||
|
.getContributedFunctions(methodName, NoLookupLocation.FROM_BACKEND)
|
||||||
|
.firstOrNull {
|
||||||
|
return@firstOrNull it.valueParameters.size == signature.size
|
||||||
|
&& (signature.isEmpty() || it.valueParameters.any {
|
||||||
|
p -> val index = it.valueParameters.indexOf(p)
|
||||||
|
return@any p.type == signature[index]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val String.synthesizedName get() = Name.identifier(this.synthesizedString)
|
||||||
|
|
||||||
|
val String.synthesizedString get() = "\$$this"
|
||||||
|
|
||||||
|
val DeclarationDescriptor.propertyIfAccessor
|
||||||
|
get() = if (this is PropertyAccessorDescriptor)
|
||||||
|
this.correspondingProperty
|
||||||
|
else this
|
||||||
|
|
||||||
|
val CallableMemberDescriptor.propertyIfAccessor
|
||||||
|
get() = if (this is PropertyAccessorDescriptor)
|
||||||
|
this.correspondingProperty
|
||||||
|
else this
|
||||||
|
|
||||||
|
val FunctionDescriptor.deserializedPropertyIfAccessor: DeserializedCallableMemberDescriptor
|
||||||
|
get() {
|
||||||
|
val member = this.propertyIfAccessor
|
||||||
|
if (member is DeserializedCallableMemberDescriptor)
|
||||||
|
return member
|
||||||
|
else
|
||||||
|
error("Unexpected deserializable callable descriptor")
|
||||||
|
}
|
||||||
|
|
||||||
|
val CallableMemberDescriptor.isDeserializableCallable
|
||||||
|
get () = (this.propertyIfAccessor is DeserializedCallableMemberDescriptor)
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
package org.jetbrains.kotlin.backend.common.ir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
|
// This is what Context collects about IR.
|
||||||
|
abstract class Ir<out T: CommonBackendContext>(val context: T, val irModule: IrModuleFragment) {
|
||||||
|
|
||||||
|
abstract val symbols: Symbols<T>
|
||||||
|
|
||||||
|
val defaultParameterDeclarationsCache = mutableMapOf<FunctionDescriptor, IrFunction>()
|
||||||
|
|
||||||
|
open fun shouldGenerateHandlerParameterForDefaultBodyFun() = false
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Symbols<out T: CommonBackendContext>(val context: T, private val symbolTable: SymbolTable) {
|
||||||
|
|
||||||
|
private val builtIns
|
||||||
|
get() = context.builtIns
|
||||||
|
|
||||||
|
private fun builtInsPackage(vararg packageNameSegments: String) =
|
||||||
|
context.builtIns.builtInsModule.getPackage(FqName.fromSegments(listOf(*packageNameSegments))).memberScope
|
||||||
|
|
||||||
|
val refClass = symbolTable.referenceClass(context.getInternalClass("Ref"))
|
||||||
|
|
||||||
|
// val areEqualByValue = context.getInternalFunctions("areEqualByValue").map {
|
||||||
|
// symbolTable.referenceSimpleFunction(it)
|
||||||
|
// }
|
||||||
|
|
||||||
|
val areEqual = symbolTable.referenceSimpleFunction(context.getInternalFunctions("areEqual").single())
|
||||||
|
|
||||||
|
val ThrowNullPointerException = symbolTable.referenceSimpleFunction(
|
||||||
|
context.getInternalFunctions("ThrowNullPointerException").single())
|
||||||
|
|
||||||
|
val ThrowNoWhenBranchMatchedException = symbolTable.referenceSimpleFunction(
|
||||||
|
context.getInternalFunctions("ThrowNoWhenBranchMatchedException").single())
|
||||||
|
|
||||||
|
val ThrowTypeCastException = symbolTable.referenceSimpleFunction(
|
||||||
|
context.getInternalFunctions("ThrowTypeCastException").single())
|
||||||
|
|
||||||
|
val ThrowUninitializedPropertyAccessException = symbolTable.referenceSimpleFunction(
|
||||||
|
context.getInternalFunctions("ThrowUninitializedPropertyAccessException").single()
|
||||||
|
)
|
||||||
|
|
||||||
|
val stringBuilder = symbolTable.referenceClass(
|
||||||
|
context.getClass(FqName("java.lang.StringBuilder")) as ClassDescriptor
|
||||||
|
)
|
||||||
|
|
||||||
|
val iterator = symbolTable.referenceClass(
|
||||||
|
builtInsPackage("kotlin", "collections").getContributedClassifier(
|
||||||
|
Name.identifier("Iterator"), NoLookupLocation.FROM_BACKEND
|
||||||
|
) as ClassDescriptor)
|
||||||
|
|
||||||
|
val asserts = builtInsPackage("kotlin")
|
||||||
|
.getContributedFunctions(Name.identifier("assert"), NoLookupLocation.FROM_BACKEND)
|
||||||
|
.map { symbolTable.referenceFunction(it) }
|
||||||
|
|
||||||
|
private fun progression(name: String) = symbolTable.referenceClass(
|
||||||
|
builtInsPackage("kotlin", "ranges").getContributedClassifier(
|
||||||
|
Name.identifier(name), NoLookupLocation.FROM_BACKEND
|
||||||
|
) as ClassDescriptor
|
||||||
|
)
|
||||||
|
|
||||||
|
val charProgression = progression("CharProgression")
|
||||||
|
val intProgression = progression("IntProgression")
|
||||||
|
val longProgression = progression("LongProgression")
|
||||||
|
val progressionClasses = listOf(charProgression, intProgression, longProgression)
|
||||||
|
val progressionClassesTypes = progressionClasses.map { it.descriptor.defaultType }.toSet()
|
||||||
|
|
||||||
|
val checkProgressionStep = context.getInternalFunctions("checkProgressionStep")
|
||||||
|
.map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap()
|
||||||
|
val getProgressionLast = context.getInternalFunctions("getProgressionLast")
|
||||||
|
.map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap()
|
||||||
|
|
||||||
|
val defaultConstructorMarker = symbolTable.referenceClass(context.getInternalClass("DefaultConstructorMarker"))
|
||||||
|
|
||||||
|
val any = symbolTable.referenceClass(builtIns.any)
|
||||||
|
val unit = symbolTable.referenceClass(builtIns.unit)
|
||||||
|
|
||||||
|
val char = symbolTable.referenceClass(builtIns.char)
|
||||||
|
|
||||||
|
val byte = symbolTable.referenceClass(builtIns.byte)
|
||||||
|
val short = symbolTable.referenceClass(builtIns.short)
|
||||||
|
val int = symbolTable.referenceClass(builtIns.int)
|
||||||
|
val long = symbolTable.referenceClass(builtIns.long)
|
||||||
|
|
||||||
|
val integerClasses = listOf(byte, short, int, long)
|
||||||
|
val integerClassesTypes = integerClasses.map { it.descriptor.defaultType }
|
||||||
|
|
||||||
|
val arrayOf = symbolTable.referenceSimpleFunction(
|
||||||
|
builtInsPackage("kotlin").getContributedFunctions(
|
||||||
|
Name.identifier("arrayOf"), NoLookupLocation.FROM_BACKEND
|
||||||
|
).single()
|
||||||
|
)
|
||||||
|
|
||||||
|
val array = symbolTable.referenceClass(builtIns.array)
|
||||||
|
|
||||||
|
private fun primitiveArrayClass(type: PrimitiveType) =
|
||||||
|
symbolTable.referenceClass(builtIns.getPrimitiveArrayClassDescriptor(type))
|
||||||
|
|
||||||
|
val byteArray = primitiveArrayClass(PrimitiveType.BYTE)
|
||||||
|
val charArray = primitiveArrayClass(PrimitiveType.CHAR)
|
||||||
|
val shortArray = primitiveArrayClass(PrimitiveType.SHORT)
|
||||||
|
val intArray = primitiveArrayClass(PrimitiveType.INT)
|
||||||
|
val longArray = primitiveArrayClass(PrimitiveType.LONG)
|
||||||
|
val floatArray = primitiveArrayClass(PrimitiveType.FLOAT)
|
||||||
|
val doubleArray = primitiveArrayClass(PrimitiveType.DOUBLE)
|
||||||
|
val booleanArray = primitiveArrayClass(PrimitiveType.BOOLEAN)
|
||||||
|
|
||||||
|
val arrays = PrimitiveType.values().map { primitiveArrayClass(it) } + array
|
||||||
|
|
||||||
|
private fun arrayExtensionFun(type: KotlinType, name: String): IrSimpleFunctionSymbol {
|
||||||
|
val descriptor = builtInsPackage("kotlin")
|
||||||
|
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
|
||||||
|
.singleOrNull { it.valueParameters.isEmpty()
|
||||||
|
&& (it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.defaultType == type }
|
||||||
|
?: throw Error(type.toString())
|
||||||
|
return symbolTable.referenceSimpleFunction(descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val arrayTypes = arrayOf(
|
||||||
|
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.BYTE),
|
||||||
|
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.CHAR),
|
||||||
|
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.SHORT),
|
||||||
|
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.INT),
|
||||||
|
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.LONG),
|
||||||
|
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.FLOAT),
|
||||||
|
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.DOUBLE),
|
||||||
|
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.BOOLEAN),
|
||||||
|
builtIns.array.defaultType
|
||||||
|
)
|
||||||
|
val arrayContentToString = arrayTypes.associateBy({ it }, { arrayExtensionFun(it, "contentToString") })
|
||||||
|
val arrayContentHashCode = arrayTypes.associateBy({ it }, { arrayExtensionFun(it, "contentHashCode") })
|
||||||
|
|
||||||
|
val copyRangeTo = arrays.map { symbol ->
|
||||||
|
val packageViewDescriptor = builtIns.builtInsModule.getPackage(KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME)
|
||||||
|
val functionDescriptor = packageViewDescriptor.memberScope
|
||||||
|
.getContributedFunctions(Name.identifier("copyRangeTo"), NoLookupLocation.FROM_BACKEND)
|
||||||
|
.first {
|
||||||
|
it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == symbol.descriptor
|
||||||
|
}
|
||||||
|
symbol.descriptor to symbolTable.referenceSimpleFunction(functionDescriptor)
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
val intAnd = symbolTable.referenceFunction(
|
||||||
|
builtIns.intType.memberScope
|
||||||
|
.getContributedFunctions(OperatorNameConventions.AND, NoLookupLocation.FROM_BACKEND)
|
||||||
|
.single()
|
||||||
|
)
|
||||||
|
|
||||||
|
val intPlusInt = symbolTable.referenceFunction(
|
||||||
|
builtIns.intType.memberScope
|
||||||
|
.getContributedFunctions(OperatorNameConventions.PLUS, NoLookupLocation.FROM_BACKEND)
|
||||||
|
.single {
|
||||||
|
it.valueParameters.single().type == builtIns.intType
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val valuesForEnum = symbolTable.referenceSimpleFunction(
|
||||||
|
context.getInternalFunctions("valuesForEnum").single())
|
||||||
|
|
||||||
|
val valueOfForEnum = symbolTable.referenceSimpleFunction(
|
||||||
|
context.getInternalFunctions("valueOfForEnum").single())
|
||||||
|
|
||||||
|
val getContinuation = symbolTable.referenceSimpleFunction(
|
||||||
|
context.getInternalFunctions("getContinuation").single())
|
||||||
|
|
||||||
|
val coroutineImpl = symbolTable.referenceClass(context.getInternalClass("CoroutineImpl"))
|
||||||
|
|
||||||
|
val coroutineSuspendedGetter = symbolTable.referenceSimpleFunction(
|
||||||
|
builtInsPackage("kotlin", "coroutines", "experimental", "intrinsics")
|
||||||
|
.getContributedVariables(Name.identifier("COROUTINE_SUSPENDED"), NoLookupLocation.FROM_BACKEND)
|
||||||
|
.single().getter!!
|
||||||
|
)
|
||||||
|
|
||||||
|
val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl)
|
||||||
|
|
||||||
|
val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl)
|
||||||
|
val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl)
|
||||||
|
val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl)
|
||||||
|
val kMutableProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0Impl)
|
||||||
|
val kMutableProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty1Impl)
|
||||||
|
val kMutableProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty2Impl)
|
||||||
|
val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl)
|
||||||
|
val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl)
|
||||||
|
|
||||||
|
fun getFunction(name: Name, receiverType: KotlinType, vararg argTypes: KotlinType) =
|
||||||
|
symbolTable.referenceFunction(receiverType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
|
||||||
|
.single {
|
||||||
|
var i = 0
|
||||||
|
it.valueParameters.size == argTypes.size && it.valueParameters.all { type -> type == argTypes[i++] }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
private val binaryOperatorCache = mutableMapOf<Triple<Name, KotlinType, KotlinType>, IrFunctionSymbol>()
|
||||||
|
fun getBinaryOperator(name: Name, lhsType: KotlinType, rhsType: KotlinType): IrFunctionSymbol {
|
||||||
|
val key = Triple(name, lhsType, rhsType)
|
||||||
|
var result = binaryOperatorCache[key]
|
||||||
|
if (result == null) {
|
||||||
|
result = symbolTable.referenceFunction(lhsType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
|
||||||
|
.single { it.valueParameters.size == 1 && it.valueParameters[0].type == rhsType }
|
||||||
|
)
|
||||||
|
binaryOperatorCache[key] = result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private val unaryOperatorCache = mutableMapOf<Pair<Name, KotlinType>, IrFunctionSymbol>()
|
||||||
|
fun getUnaryOperator(name: Name, receiverType: KotlinType): IrFunctionSymbol {
|
||||||
|
val key = name to receiverType
|
||||||
|
var result = unaryOperatorCache[key]
|
||||||
|
if (result == null) {
|
||||||
|
result = symbolTable.referenceFunction(receiverType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
|
||||||
|
.single { it.valueParameters.isEmpty() }
|
||||||
|
)
|
||||||
|
unaryOperatorCache[key] = result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.backend.common.ir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
|
||||||
|
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import java.io.StringWriter
|
||||||
|
|
||||||
|
|
||||||
|
fun ir2string(ir: IrElement?): String = ir2stringWhole(ir).takeWhile { it != '\n' }
|
||||||
|
|
||||||
|
fun ir2stringWhole(ir: IrElement?, withDescriptors: Boolean = false): String {
|
||||||
|
val strWriter = StringWriter()
|
||||||
|
|
||||||
|
if (withDescriptors)
|
||||||
|
ir?.accept(DumpIrTreeWithDescriptorsVisitor(strWriter), "")
|
||||||
|
else
|
||||||
|
ir?.accept(DumpIrTreeVisitor(strWriter), "")
|
||||||
|
return strWriter.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DeclarationDescriptor.createFakeOverrideDescriptor(owner: ClassDescriptor): DeclarationDescriptor? {
|
||||||
|
// We need to copy descriptors for vtable building, thus take only functions and properties.
|
||||||
|
return when (this) {
|
||||||
|
is CallableMemberDescriptor ->
|
||||||
|
copy(
|
||||||
|
/* newOwner = */ owner,
|
||||||
|
/* modality = */ modality,
|
||||||
|
/* visibility = */ visibility,
|
||||||
|
/* kind = */ CallableMemberDescriptor.Kind.FAKE_OVERRIDE,
|
||||||
|
/* copyOverrides = */ true).apply {
|
||||||
|
overriddenDescriptors += this@createFakeOverrideDescriptor
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun FunctionDescriptor.createOverriddenDescriptor(owner: ClassDescriptor, final: Boolean = true): FunctionDescriptor {
|
||||||
|
return this.newCopyBuilder()
|
||||||
|
.setOwner(owner)
|
||||||
|
.setCopyOverrides(true)
|
||||||
|
.setModality(if (final) Modality.FINAL else Modality.OPEN)
|
||||||
|
.setDispatchReceiverParameter(owner.thisAsReceiverParameter)
|
||||||
|
.build()!!.apply {
|
||||||
|
overriddenDescriptors += this@createOverriddenDescriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun ClassDescriptor.createSimpleDelegatingConstructorDescriptor(superConstructorDescriptor: ClassConstructorDescriptor, isPrimary: Boolean = false)
|
||||||
|
: ClassConstructorDescriptor {
|
||||||
|
val constructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
|
||||||
|
/* containingDeclaration = */ this,
|
||||||
|
/* annotations = */ Annotations.EMPTY,
|
||||||
|
/* isPrimary = */ isPrimary,
|
||||||
|
/* source = */ SourceElement.NO_SOURCE)
|
||||||
|
val valueParameters = superConstructorDescriptor.valueParameters.map {
|
||||||
|
it.copy(constructorDescriptor, it.name, it.index)
|
||||||
|
}
|
||||||
|
constructorDescriptor.initialize(valueParameters, superConstructorDescriptor.visibility)
|
||||||
|
constructorDescriptor.returnType = superConstructorDescriptor.returnType
|
||||||
|
return constructorDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun IrClass.addSimpleDelegatingConstructor(superConstructorSymbol: IrConstructorSymbol,
|
||||||
|
constructorDescriptor: ClassConstructorDescriptor,
|
||||||
|
origin: IrDeclarationOrigin)
|
||||||
|
: IrConstructor {
|
||||||
|
|
||||||
|
return IrConstructorImpl(startOffset, endOffset, origin, constructorDescriptor).also { constructor ->
|
||||||
|
constructor.createParameterDeclarations()
|
||||||
|
|
||||||
|
constructor.body = IrBlockBodyImpl(startOffset, endOffset,
|
||||||
|
listOf(
|
||||||
|
IrDelegatingConstructorCallImpl(
|
||||||
|
startOffset, endOffset,
|
||||||
|
superConstructorSymbol, superConstructorSymbol.descriptor
|
||||||
|
).apply {
|
||||||
|
constructor.valueParameters.forEachIndexed { idx, parameter ->
|
||||||
|
putValueArgument(idx, IrGetValueImpl(startOffset, endOffset, parameter.symbol))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IrInstanceInitializerCallImpl(startOffset, endOffset, this.symbol)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
this.declarations.add(constructor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun CommonBackendContext.createArrayOfExpression(arrayElementType: KotlinType,
|
||||||
|
arrayElements: List<IrExpression>,
|
||||||
|
startOffset: Int, endOffset: Int): IrExpression {
|
||||||
|
|
||||||
|
val genericArrayOfFunSymbol = ir.symbols.arrayOf
|
||||||
|
val genericArrayOfFun = genericArrayOfFunSymbol.descriptor
|
||||||
|
val typeParameter0 = genericArrayOfFun.typeParameters[0]
|
||||||
|
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(arrayElementType)))
|
||||||
|
val substitutedArrayOfFun = genericArrayOfFun.substitute(typeSubstitutor)!!
|
||||||
|
|
||||||
|
val typeArguments = mapOf(typeParameter0 to arrayElementType)
|
||||||
|
|
||||||
|
val valueParameter0 = substitutedArrayOfFun.valueParameters[0]
|
||||||
|
val arg0VarargType = valueParameter0.type
|
||||||
|
val arg0VarargElementType = valueParameter0.varargElementType!!
|
||||||
|
val arg0 = IrVarargImpl(startOffset, endOffset, arg0VarargType, arg0VarargElementType, arrayElements)
|
||||||
|
|
||||||
|
return IrCallImpl(startOffset, endOffset, genericArrayOfFunSymbol, substitutedArrayOfFun, typeArguments).apply {
|
||||||
|
putValueArgument(0, arg0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.builders
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.descriptors.substitute
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irWhile(origin: IrStatementOrigin? = null) =
|
||||||
|
IrWhileLoopImpl(startOffset, endOffset, context.builtIns.unitType, origin)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irBreak(loop: IrLoop) =
|
||||||
|
IrBreakImpl(startOffset, endOffset, context.builtIns.nothingType, loop)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irContinue(loop: IrLoop) =
|
||||||
|
IrContinueImpl(startOffset, endOffset, context.builtIns.nothingType, loop)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irTrue() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, true)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irFalse() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, false)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: Map<TypeParameterDescriptor, KotlinType>) =
|
||||||
|
IrCallImpl(this.startOffset, this.endOffset, symbol, symbol.descriptor.substitute(typeArguments), typeArguments)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: List<KotlinType>) =
|
||||||
|
irCall(symbol, symbol.descriptor.typeParameters.zip(typeArguments).toMap())
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irGetObject(classSymbol: IrClassSymbol) =
|
||||||
|
IrGetObjectValueImpl(startOffset, endOffset, classSymbol.owner.defaultType, classSymbol)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irGetField(receiver: IrExpression?, symbol: IrFieldSymbol) =
|
||||||
|
IrGetFieldImpl(startOffset, endOffset, symbol, receiver)
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.atMostOne
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
|
||||||
|
* The arguments are to be evaluated in the same order as they appear in the resulting list.
|
||||||
|
*/
|
||||||
|
fun IrMemberAccessExpression.getArguments(): List<Pair<ParameterDescriptor, IrExpression>> {
|
||||||
|
val res = mutableListOf<Pair<ParameterDescriptor, IrExpression>>()
|
||||||
|
val descriptor = descriptor
|
||||||
|
|
||||||
|
// TODO: ensure the order below corresponds to the one defined in Kotlin specs.
|
||||||
|
|
||||||
|
dispatchReceiver?.let {
|
||||||
|
res += (descriptor.dispatchReceiverParameter!! to it)
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionReceiver?.let {
|
||||||
|
res += (descriptor.extensionReceiverParameter!! to it)
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.valueParameters.forEach {
|
||||||
|
val arg = getValueArgument(it.index)
|
||||||
|
if (arg != null) {
|
||||||
|
res += (it to arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
|
||||||
|
* The arguments are to be evaluated in the same order as they appear in the resulting list.
|
||||||
|
*/
|
||||||
|
internal fun IrFunctionAccessExpression.getArgumentsWithSymbols(): List<Pair<IrValueParameterSymbol, IrExpression>> {
|
||||||
|
val res = mutableListOf<Pair<IrValueParameterSymbol, IrExpression>>()
|
||||||
|
val irFunction = symbol.owner as IrFunction
|
||||||
|
|
||||||
|
dispatchReceiver?.let {
|
||||||
|
res += (irFunction.dispatchReceiverParameter!!.symbol to it)
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionReceiver?.let {
|
||||||
|
res += (irFunction.extensionReceiverParameter!!.symbol to it)
|
||||||
|
}
|
||||||
|
|
||||||
|
irFunction.valueParameters.forEach {
|
||||||
|
val arg = getValueArgument(it.descriptor as ValueParameterDescriptor)
|
||||||
|
if (arg != null) {
|
||||||
|
res += (it.symbol to arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets arguments that are specified by given mapping of parameters.
|
||||||
|
*/
|
||||||
|
internal fun IrMemberAccessExpression.addArguments(args: Map<ParameterDescriptor, IrExpression>) {
|
||||||
|
descriptor.dispatchReceiverParameter?.let {
|
||||||
|
val arg = args[it]
|
||||||
|
if (arg != null) {
|
||||||
|
this.dispatchReceiver = arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.extensionReceiverParameter?.let {
|
||||||
|
val arg = args[it]
|
||||||
|
if (arg != null) {
|
||||||
|
this.extensionReceiver = arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.valueParameters.forEach {
|
||||||
|
val arg = args[it]
|
||||||
|
if (arg != null) {
|
||||||
|
this.putValueArgument(it.index, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun IrMemberAccessExpression.addArguments(args: List<Pair<ParameterDescriptor, IrExpression>>) =
|
||||||
|
this.addArguments(args.toMap())
|
||||||
|
|
||||||
|
internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
|
||||||
|
|
||||||
|
fun IrCall.usesDefaultArguments(): Boolean =
|
||||||
|
this.descriptor.valueParameters.any { this.getValueArgument(it) == null }
|
||||||
|
|
||||||
|
fun IrElement.getCompilerMessageLocation(containingFile: IrFile): CompilerMessageLocation? {
|
||||||
|
val sourceRangeInfo = containingFile.fileEntry.getSourceRangeInfo(this.startOffset, this.endOffset)
|
||||||
|
return CompilerMessageLocation.create(
|
||||||
|
path = sourceRangeInfo.filePath,
|
||||||
|
line = sourceRangeInfo.startLineNumber,
|
||||||
|
column = sourceRangeInfo.startColumnNumber,
|
||||||
|
lineContent = null // TODO: retrieve the line content.
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrFunction.createParameterDeclarations() {
|
||||||
|
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
|
||||||
|
innerStartOffset(this), innerEndOffset(this),
|
||||||
|
IrDeclarationOrigin.DEFINED,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
|
||||||
|
dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter()
|
||||||
|
extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
|
||||||
|
|
||||||
|
assert(valueParameters.isEmpty())
|
||||||
|
descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
|
||||||
|
|
||||||
|
assert(typeParameters.isEmpty())
|
||||||
|
descriptor.typeParameters.mapTo(typeParameters) {
|
||||||
|
IrTypeParameterImpl(
|
||||||
|
innerStartOffset(it), innerEndOffset(it),
|
||||||
|
IrDeclarationOrigin.DEFINED,
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.createParameterDeclarations() {
|
||||||
|
descriptor.thisAsReceiverParameter.let {
|
||||||
|
thisReceiver = IrValueParameterImpl(
|
||||||
|
innerStartOffset(it), innerEndOffset(it),
|
||||||
|
IrDeclarationOrigin.INSTANCE_RECEIVER,
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(typeParameters.isEmpty())
|
||||||
|
descriptor.declaredTypeParameters.mapTo(typeParameters) {
|
||||||
|
IrTypeParameterImpl(
|
||||||
|
innerStartOffset(it), innerEndOffset(it),
|
||||||
|
IrDeclarationOrigin.DEFINED,
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrClass.addFakeOverrides() {
|
||||||
|
|
||||||
|
val startOffset = this.startOffset
|
||||||
|
val endOffset = this.endOffset
|
||||||
|
|
||||||
|
fun FunctionDescriptor.createFunction(): IrFunction = IrFunctionImpl(
|
||||||
|
startOffset, endOffset,
|
||||||
|
IrDeclarationOrigin.FAKE_OVERRIDE, this
|
||||||
|
).apply {
|
||||||
|
createParameterDeclarations()
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.unsubstitutedMemberScope.getContributedDescriptors()
|
||||||
|
.filterIsInstance<CallableMemberDescriptor>()
|
||||||
|
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
|
||||||
|
.mapTo(this.declarations) {
|
||||||
|
when (it) {
|
||||||
|
is FunctionDescriptor -> it.createFunction()
|
||||||
|
is PropertyDescriptor ->
|
||||||
|
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, it).apply {
|
||||||
|
// TODO: add field if getter is missing?
|
||||||
|
getter = it.getter?.createFunction()
|
||||||
|
setter = it.setter?.createFunction()
|
||||||
|
}
|
||||||
|
else -> TODO(it.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
|
||||||
|
descriptor.startOffset ?: this.startOffset
|
||||||
|
|
||||||
|
private fun IrElement.innerEndOffset(descriptor: DeclarationDescriptorWithSource): Int =
|
||||||
|
descriptor.endOffset ?: this.endOffset
|
||||||
|
|
||||||
|
val DeclarationDescriptorWithSource.startOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.startOffset
|
||||||
|
val DeclarationDescriptorWithSource.endOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.endOffset
|
||||||
|
|
||||||
|
val DeclarationDescriptorWithSource.startOffsetOrUndefined: Int get() = startOffset ?: UNDEFINED_OFFSET
|
||||||
|
val DeclarationDescriptorWithSource.endOffsetOrUndefined: Int get() = endOffset ?: UNDEFINED_OFFSET
|
||||||
|
|
||||||
|
val IrClassSymbol.functions: Sequence<IrSimpleFunctionSymbol>
|
||||||
|
get() = this.owner.declarations.asSequence().filterIsInstance<IrSimpleFunction>().map { it.symbol }
|
||||||
|
|
||||||
|
val IrClassSymbol.constructors: Sequence<IrConstructorSymbol>
|
||||||
|
get() = this.owner.declarations.asSequence().filterIsInstance<IrConstructor>().map { it.symbol }
|
||||||
|
|
||||||
|
private fun IrClassSymbol.getPropertyDeclaration(name: String) =
|
||||||
|
this.owner.declarations.filterIsInstance<IrProperty>()
|
||||||
|
.atMostOne { it.descriptor.name == Name.identifier(name) }
|
||||||
|
|
||||||
|
fun IrClassSymbol.getPropertyGetter(name: String): IrFunctionSymbol? =
|
||||||
|
this.getPropertyDeclaration(name)?.getter?.symbol
|
||||||
|
|
||||||
|
fun IrClassSymbol.getPropertySetter(name: String): IrFunctionSymbol? =
|
||||||
|
this.getPropertyDeclaration(name)?.setter?.symbol
|
||||||
|
|
||||||
|
val IrFunction.explicitParameters: List<IrValueParameterSymbol>
|
||||||
|
get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).map { it.symbol }
|
||||||
|
|
||||||
|
val IrValueParameter.type: KotlinType
|
||||||
|
get() = this.descriptor.type
|
||||||
|
|
||||||
|
val IrClass.defaultType: KotlinType
|
||||||
|
get() = this.descriptor.defaultType
|
||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.expressions
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||||
|
|
||||||
interface IrContainerExpression : IrExpression, IrStatementContainer {
|
interface IrContainerExpression : IrExpression, IrStatementContainer {
|
||||||
val origin: IrStatementOrigin?
|
val origin: IrStatementOrigin?
|
||||||
val isTransparentScope: Boolean
|
val isTransparentScope: Boolean
|
||||||
@@ -30,3 +34,9 @@ interface IrComposite : IrContainerExpression {
|
|||||||
override val isTransparentScope: Boolean
|
override val isTransparentScope: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IrReturnableBlock: IrBlock, IrSymbolOwner {
|
||||||
|
override val symbol: IrReturnableBlockSymbol
|
||||||
|
val descriptor: FunctionDescriptor
|
||||||
|
val sourceFileName: String
|
||||||
|
}
|
||||||
@@ -16,9 +16,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.expressions.impl
|
package org.jetbrains.kotlin.ir.expressions.impl
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrBindableSymbolBase
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
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
|
||||||
|
|
||||||
@@ -44,4 +50,44 @@ fun IrBlockImpl.inlineStatement(statement: IrStatement) {
|
|||||||
else {
|
else {
|
||||||
statements.add(statement)
|
statements.add(statement)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IrReturnableBlockImpl(startOffset: Int, endOffset: Int, type: KotlinType,
|
||||||
|
override val symbol: IrReturnableBlockSymbol, origin: IrStatementOrigin? = null, override val sourceFileName: String = "no source file")
|
||||||
|
: IrContainerExpressionBase(startOffset, endOffset, type, origin), IrReturnableBlock {
|
||||||
|
override val descriptor = symbol.descriptor
|
||||||
|
|
||||||
|
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
|
||||||
|
symbol: IrReturnableBlockSymbol, origin: IrStatementOrigin?, statements: List<IrStatement>, sourceFileName: String = "no source file") :
|
||||||
|
this(startOffset, endOffset, type, symbol, origin, sourceFileName) {
|
||||||
|
this.statements.addAll(statements)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
|
||||||
|
descriptor: FunctionDescriptor, origin: IrStatementOrigin? = null, sourceFileName: String = "no source file") :
|
||||||
|
this(startOffset, endOffset, type, IrReturnableBlockSymbolImpl(descriptor), origin, sourceFileName)
|
||||||
|
|
||||||
|
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
|
||||||
|
descriptor: FunctionDescriptor, origin: IrStatementOrigin?, statements: List<IrStatement>, sourceFileName: String = "no source file") :
|
||||||
|
this(startOffset, endOffset, type, descriptor, origin, sourceFileName) {
|
||||||
|
this.statements.addAll(statements)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
symbol.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
|
visitor.visitBlock(this, data)
|
||||||
|
|
||||||
|
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
|
statements.forEach { it.accept(visitor, data) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
|
||||||
|
statements.forEachIndexed { i, irStatement ->
|
||||||
|
statements[i] = irStatement.transform(transformer, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.ir.symbols
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||||
|
|
||||||
interface IrSymbol {
|
interface IrSymbol {
|
||||||
val owner : IrSymbolOwner
|
val owner : IrSymbolOwner
|
||||||
@@ -59,4 +60,6 @@ interface IrFunctionSymbol : IrSymbol {
|
|||||||
override val descriptor: FunctionDescriptor
|
override val descriptor: FunctionDescriptor
|
||||||
}
|
}
|
||||||
interface IrConstructorSymbol : IrFunctionSymbol, IrBindableSymbol<ClassConstructorDescriptor, IrConstructor>
|
interface IrConstructorSymbol : IrFunctionSymbol, IrBindableSymbol<ClassConstructorDescriptor, IrConstructor>
|
||||||
interface IrSimpleFunctionSymbol : IrFunctionSymbol, IrBindableSymbol<FunctionDescriptor, IrSimpleFunction>
|
interface IrSimpleFunctionSymbol : IrFunctionSymbol, IrBindableSymbol<FunctionDescriptor, IrSimpleFunction>
|
||||||
|
|
||||||
|
interface IrReturnableBlockSymbol : IrFunctionSymbol, IrBindableSymbol<FunctionDescriptor, IrReturnableBlock>
|
||||||
|
|||||||
@@ -17,8 +17,15 @@
|
|||||||
package org.jetbrains.kotlin.ir.symbols.impl
|
package org.jetbrains.kotlin.ir.symbols.impl
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
abstract class IrSymbolBase<out D : DeclarationDescriptor>(override val descriptor: D) : IrSymbol
|
abstract class IrSymbolBase<out D : DeclarationDescriptor>(override val descriptor: D) : IrSymbol
|
||||||
|
|
||||||
@@ -110,4 +117,8 @@ fun createFunctionSymbol(descriptor: CallableMemberDescriptor): IrFunctionSymbol
|
|||||||
is ClassConstructorDescriptor -> IrConstructorSymbolImpl(descriptor.original)
|
is ClassConstructorDescriptor -> IrConstructorSymbolImpl(descriptor.original)
|
||||||
is FunctionDescriptor -> IrSimpleFunctionSymbolImpl(descriptor.original)
|
is FunctionDescriptor -> IrSimpleFunctionSymbolImpl(descriptor.original)
|
||||||
else -> throw IllegalArgumentException("Unexpected descriptor kind: $descriptor")
|
else -> throw IllegalArgumentException("Unexpected descriptor kind: $descriptor")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class IrReturnableBlockSymbolImpl(descriptor: FunctionDescriptor) :
|
||||||
|
IrBindableSymbolBase<FunctionDescriptor, IrReturnableBlock>(descriptor),
|
||||||
|
IrReturnableBlockSymbol
|
||||||
Reference in New Issue
Block a user