IrSyntheticBody (for 'values', 'valueOf').

This commit is contained in:
Dmitry Petrov
2016-08-31 17:32:01 +03:00
committed by Dmitry Petrov
parent c47e82f965
commit 2d2100b1b5
13 changed files with 174 additions and 24 deletions
@@ -17,6 +17,10 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiUtil
@@ -26,6 +30,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.builtIns
@@ -67,3 +72,9 @@ fun KtSecondaryConstructor.isConstructorDelegatingToSuper(bindingContext: Bindin
val targetClassDescriptor = delegatingResolvedCall.resultingDescriptor.containingDeclaration
return targetClassDescriptor != ownerClassDescriptor
}
inline fun ClassDescriptor.findFirstFunction(name: String, predicate: (CallableMemberDescriptor) -> Boolean) =
unsubstitutedMemberScope.findFirstFunction(name, predicate)
inline fun MemberScope.findFirstFunction(name: String, predicate: (CallableMemberDescriptor) -> Boolean) =
getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).first(predicate)
@@ -126,4 +126,4 @@ fun IrBuilderWithScope.irString(value: String) =
IrConstImpl.string(startOffset, endOffset, context.builtIns.stringType, value)
fun IrBuilderWithScope.irConcat() =
IrStringConcatenationImpl(startOffset, endOffset, context.builtIns.stringType)
IrStringConcatenationImpl(startOffset, endOffset, context.builtIns.stringType)
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.psi2ir.builders
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunctionImpl
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.Scope
class IrMemberFunctionBuilder(
context: GeneratorContext,
val irClass: IrClassImpl,
val function: FunctionDescriptor,
val origin: IrDeclarationOrigin,
startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET
) : IrBlockBodyBuilder(context, Scope(function), startOffset, endOffset) {
inline fun addToClass(body: IrMemberFunctionBuilder.() -> Unit) {
val irFunction = IrFunctionImpl(startOffset, endOffset, origin, function)
body()
irFunction.body = doBuild()
irClass.addMember(irFunction)
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.IrGetVariableImpl
@@ -47,6 +48,10 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
generateAdditionalMembersForDataClass(irClass, ktClassOrObject)
}
if (descriptor.kind == ClassKind.ENUM_CLASS) {
generateAdditionalMembersForEnumClass(irClass)
}
return irClass
}
@@ -54,6 +59,10 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
DataClassMembersGenerator(ktClassOrObject, context, irClass).generate()
}
private fun generateAdditionalMembersForEnumClass(irClass: IrClassImpl) {
EnumClassMembersGenerator(context).generateSpecialMembers(irClass)
}
private fun shouldGenerateNestedInitializers(ktClassOrObject: KtClassOrObject): Boolean {
val ktClassBody = ktClassOrObject.getBody() ?: return false
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.mapValueParameters
import org.jetbrains.kotlin.name.Name
@@ -33,6 +32,7 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.builders.*
import org.jetbrains.kotlin.psi2ir.containsNull
import org.jetbrains.kotlin.psi2ir.findFirstFunction
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.types.KotlinType
@@ -44,27 +44,11 @@ class DataClassMembersGenerator(
override val context: GeneratorContext,
val irClass: IrClassImpl
) : Generator, DataClassMethodGenerator(ktClassOrObject, context.bindingContext) {
private class IrMemberFunctionBuilder(
context: GeneratorContext,
val irClass: IrClassImpl,
val function: FunctionDescriptor,
startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET
) : IrBlockBodyBuilder(context, Scope(function), startOffset, endOffset){
inline fun addToClass(body: IrMemberFunctionBuilder.() -> Unit) {
val irFunction = IrFunctionImpl(startOffset, endOffset, IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER, function)
body()
irFunction.body = doBuild()
irClass.addMember(irFunction)
}
}
private inline fun buildMember(function: FunctionDescriptor, psiElement: PsiElement? = null, body: IrMemberFunctionBuilder.() -> Unit) {
IrMemberFunctionBuilder(context, irClass, function,
psiElement?.startOffset ?: UNDEFINED_OFFSET,
psiElement?.endOffset ?: UNDEFINED_OFFSET
IrMemberFunctionBuilder(
context, irClass, function, IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER,
psiElement?.startOffset ?: UNDEFINED_OFFSET, psiElement?.endOffset ?: UNDEFINED_OFFSET
).addToClass(body)
}
override fun generateComponentFunction(function: FunctionDescriptor, parameter: ValueParameterDescriptor) {
@@ -104,9 +88,6 @@ class DataClassMembersGenerator(
private val INT = context.builtIns.int
private val INT_TYPE = context.builtIns.intType
private inline fun ClassDescriptor.findFirstFunction(name: String, predicate: (CallableMemberDescriptor) -> Boolean) =
unsubstitutedMemberScope.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).first(predicate)
private val IMUL = INT.findFirstFunction("times") { KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, INT_TYPE) }
private val IADD = INT.findFirstFunction("plus") { KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, INT_TYPE) }
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyImpl
import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind
import org.jetbrains.kotlin.psi2ir.findFirstFunction
class EnumClassMembersGenerator(override val context: GeneratorContext) : Generator {
fun generateSpecialMembers(irClass: IrClassImpl) {
generateValues(irClass)
generateValueOf(irClass)
}
private fun generateValues(irClass: IrClassImpl) {
val valuesFunction = irClass.descriptor.staticScope.findFirstFunction("values") {
it.dispatchReceiverParameter == null &&
it.extensionReceiverParameter == null &&
it.valueParameters.size == 0
}
irClass.addMember(
IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER,
valuesFunction, IrSyntheticBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrSyntheticBodyKind.ENUM_VALUES)))
}
private fun generateValueOf(irClass: IrClassImpl) {
val valueOfFunction = irClass.descriptor.staticScope.findFirstFunction("valueOf") {
it.dispatchReceiverParameter == null &&
it.extensionReceiverParameter == null &&
it.valueParameters.size == 1
}
irClass.addMember(
IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER,
valueOfFunction, IrSyntheticBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrSyntheticBodyKind.ENUM_VALUEOF)))
}
}
@@ -44,6 +44,7 @@ enum class IrDeclarationKind {
enum class IrDeclarationOrigin {
DEFINED,
CLASS_FOR_ENUM_ENTRY,
ENUM_CLASS_SPECIAL_MEMBER,
GENERATED_DATA_CLASS_MEMBER,
LOCAL_FUNCTION_FOR_LAMBDA,
IR_TEMPORARY_VARIABLE,
@@ -30,6 +30,15 @@ interface IrBlockBody : IrBody {
val statements: List<IrStatement>
}
interface IrSyntheticBody : IrBody {
val kind: IrSyntheticBodyKind
}
enum class IrSyntheticBodyKind {
ENUM_VALUES,
ENUM_VALUEOF
}
class IrExpressionBodyImpl(startOffset: Int, endOffset: Int) : IrElementBase(startOffset, endOffset), IrExpressionBody {
constructor(startOffset: Int, endOffset: Int, expression: IrExpression) : this(startOffset, endOffset) {
this.expression = expression
@@ -93,6 +102,20 @@ class IrBlockBodyImpl(startOffset: Int, endOffset: Int) : IrElementBase(startOff
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
statements.forEach { it.accept(visitor, data) }
}
}
class IrSyntheticBodyImpl(startOffset: Int, endOffset: Int, override val kind: IrSyntheticBodyKind) : IrElementBase(startOffset, endOffset), IrSyntheticBody {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitSyntheticBody(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
// no children
}
override fun getChild(slot: Int): IrElement? = null
override fun replaceChild(slot: Int, newChild: IrElement) {
throwNoSuchSlot(slot)
}
}
@@ -69,6 +69,9 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
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()}"
@@ -41,6 +41,7 @@ interface IrElementVisitor<out R, in D> {
fun visitBody(body: IrBody, data: D): R = visitElement(body, data)
fun visitExpressionBody(body: IrExpressionBody, data: D): R = visitBody(body, data)
fun visitBlockBody(body: IrBlockBody, data: D) = visitBody(body, data)
fun visitSyntheticBody(body: IrSyntheticBody, data: D) = visitBody(body, data)
fun visitExpression(expression: IrExpression, data: D): R = visitElement(expression, data)
fun <T> visitConst(expression: IrConst<T>, data: D): R = visitExpression(expression, data)
+4
View File
@@ -13,3 +13,7 @@ FILE /classes.kt
FUN private constructor TestEnumClass()
BLOCK_BODY
ENUM_CONSTRUCTOR_CALL Enum super
FUN public final /*synthesized*/ fun values(): kotlin.Array<TestEnumClass>
SYNTHETIC_BODY kind=ENUM_VALUES
FUN public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestEnumClass
SYNTHETIC_BODY kind=ENUM_VALUEOF
+16
View File
@@ -7,6 +7,10 @@ FILE /enum.kt
init: ENUM_CONSTRUCTOR_CALL TestEnum1 TEST1
ENUM_ENTRY enum entry TEST2
init: ENUM_CONSTRUCTOR_CALL TestEnum1 TEST2
FUN public final /*synthesized*/ fun values(): kotlin.Array<TestEnum1>
SYNTHETIC_BODY kind=ENUM_VALUES
FUN public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestEnum1
SYNTHETIC_BODY kind=ENUM_VALUEOF
CLASS ENUM_CLASS TestEnum2
FUN private constructor TestEnum2(/*0*/ x: kotlin.Int)
BLOCK_BODY
@@ -25,6 +29,10 @@ FILE /enum.kt
ENUM_ENTRY enum entry TEST3
init: ENUM_CONSTRUCTOR_CALL TestEnum2 TEST3
x: CONST Int type=kotlin.Int value='3'
FUN public final /*synthesized*/ fun values(): kotlin.Array<TestEnum2>
SYNTHETIC_BODY kind=ENUM_VALUES
FUN public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestEnum2
SYNTHETIC_BODY kind=ENUM_VALUEOF
CLASS ENUM_CLASS TestEnum3
FUN private constructor TestEnum3()
BLOCK_BODY
@@ -40,6 +48,10 @@ FILE /enum.kt
CALL .println type=kotlin.Unit operator=null
message: CONST String type=kotlin.String value='Hello, world!'
FUN public abstract fun foo(): kotlin.Unit
FUN public final /*synthesized*/ fun values(): kotlin.Array<TestEnum3>
SYNTHETIC_BODY kind=ENUM_VALUES
FUN public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestEnum3
SYNTHETIC_BODY kind=ENUM_VALUEOF
CLASS ENUM_CLASS TestEnum4
FUN private constructor TestEnum4(/*0*/ x: kotlin.Int)
BLOCK_BODY
@@ -77,3 +89,7 @@ FILE /enum.kt
CALL .println type=kotlin.Unit operator=null
message: GET_ENUM_VALUE TEST2 type=TestEnum4
FUN public abstract fun foo(): kotlin.Unit
FUN public final /*synthesized*/ fun values(): kotlin.Array<TestEnum4>
SYNTHETIC_BODY kind=ENUM_VALUES
FUN public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestEnum4
SYNTHETIC_BODY kind=ENUM_VALUEOF
+4
View File
@@ -5,6 +5,10 @@ FILE /values.kt
ENUM_CONSTRUCTOR_CALL Enum super
ENUM_ENTRY enum entry A
init: ENUM_CONSTRUCTOR_CALL Enum A
FUN public final /*synthesized*/ fun values(): kotlin.Array<Enum>
SYNTHETIC_BODY kind=ENUM_VALUES
FUN public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): Enum
SYNTHETIC_BODY kind=ENUM_VALUEOF
CLASS OBJECT A
FUN private constructor A()
BLOCK_BODY