[FIR] Add conversion of FirElvisCall to backend IR

This commit is contained in:
Dmitriy Novozhilov
2020-06-30 15:59:22 +03:00
parent 102c9c08d0
commit a7ed9c7dc5
2 changed files with 91 additions and 15 deletions
@@ -7,17 +7,23 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.backend.generators.ClassMemberGenerator import org.jetbrains.kotlin.fir.backend.generators.ClassMemberGenerator
import org.jetbrains.kotlin.fir.backend.generators.OperatorExpressionGenerator import org.jetbrains.kotlin.fir.backend.generators.OperatorExpressionGenerator
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
import org.jetbrains.kotlin.fir.expressions.impl.FirStubStatement import org.jetbrains.kotlin.fir.expressions.impl.FirStubStatement
import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression
import org.jetbrains.kotlin.fir.expressions.impl.buildSingleExpressionBlock
import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.isIteratorNext import org.jetbrains.kotlin.fir.resolve.isIteratorNext
import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.scope
@@ -27,6 +33,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
@@ -777,6 +784,72 @@ class Fir2IrVisitor(
} }
} }
override fun visitElvisCall(elvisCall: FirElvisCall, data: Any?): IrElement {
val subjectName = Name.special("<elvis>")
val subjectVariable = buildProperty {
source = elvisCall.source
session = this@Fir2IrVisitor.session
origin = FirDeclarationOrigin.Source
returnTypeRef = elvisCall.lhs.typeRef
name = subjectName
initializer = elvisCall.lhs
symbol = FirPropertySymbol(name)
isVar = false
isLocal = true
status = FirDeclarationStatusImpl(Visibilities.LOCAL, Modality.FINAL)
}
@OptIn(FirContractViolation::class)
val ref = FirExpressionRef<FirWhenExpression>()
val subjectExpression = buildWhenSubjectExpression {
source = elvisCall.source
whenRef = ref
}
val whenExpression = buildWhenExpression {
source = elvisCall.source
this.subject = elvisCall.lhs
this.subjectVariable = subjectVariable
branches += buildWhenBranch {
condition = buildOperatorCall {
operation = FirOperation.EQ
argumentList = buildBinaryArgumentList(
subjectExpression, buildConstExpression(null, FirConstKind.Null, null).apply {
replaceTypeRef(session.builtinTypes.nullableNothingType)
}
)
}
result = buildSingleExpressionBlock(elvisCall.rhs)
}
branches += buildWhenBranch {
condition = buildElseIfTrueCondition {}
var resultExpression = buildQualifiedAccessExpression {
calleeReference = buildResolvedNamedReference {
name = subjectVariable.name
resolvedSymbol = subjectVariable.symbol
}
typeRef = subjectVariable.returnTypeRef
}
val originalType = resultExpression.typeRef.coneTypeUnsafe<ConeKotlinType>()
val notNullType = originalType.withNullability(ConeNullability.NOT_NULL)
if (notNullType != originalType) {
resultExpression = buildExpressionWithSmartcast {
originalExpression = resultExpression
typeRef = resultExpression.typeRef.resolvedTypeFromPrototype(notNullType)
typesFromSmartCast = setOf(notNullType)
}
}
result = buildSingleExpressionBlock(resultExpression)
}
typeRef = elvisCall.typeRef
isExhaustive = true
}.also {
ref.bind(it)
}
val result = whenExpression.accept(this, data)
return result
}
override fun visitGetClassCall(getClassCall: FirGetClassCall, data: Any?): IrElement { override fun visitGetClassCall(getClassCall: FirGetClassCall, data: Any?): IrElement {
val argument = getClassCall.argument val argument = getClassCall.argument
val irType = getClassCall.typeRef.toIrType() val irType = getClassCall.typeRef.toIrType()
+18 -15
View File
@@ -97,18 +97,19 @@ FILE fqName:<root> fileName:/kt30796.kt
then: GET_VAR 'val tmp_5: T of <root>.test [val] declared in <root>.test' type=T of <root>.test origin=null then: GET_VAR 'val tmp_5: T of <root>.test [val] declared in <root>.test' type=T of <root>.test origin=null
VAR name:x5 type:kotlin.Any [val] VAR name:x5 type:kotlin.Any [val]
BLOCK type=kotlin.Int origin=ELVIS BLOCK type=kotlin.Int origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_7 type:kotlin.Nothing [val] VAR IR_TEMPORARY_VARIABLE name:tmp_7 type:kotlin.Int? [val]
CALL 'public final fun magic <T> (): T of <root>.magic declared in <root>' type=kotlin.Nothing origin=null CALL 'public final fun magic <T> (): T of <root>.magic declared in <root>' type=kotlin.Int? origin=null
<T>: kotlin.Nothing <T>: kotlin.Int?
WHEN type=kotlin.Int origin=ELVIS WHEN type=kotlin.Int origin=ELVIS
BRANCH BRANCH
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: GET_VAR 'val tmp_7: kotlin.Nothing [val] declared in <root>.test' type=kotlin.Nothing origin=null arg0: GET_VAR 'val tmp_7: kotlin.Int? [val] declared in <root>.test' type=kotlin.Int? origin=null
arg1: CONST Null type=kotlin.Nothing? value=null arg1: CONST Null type=kotlin.Nothing? value=null
then: CONST Int type=kotlin.Int value=42 then: CONST Int type=kotlin.Int value=42
BRANCH BRANCH
if: CONST Boolean type=kotlin.Boolean value=true if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val tmp_7: kotlin.Nothing [val] declared in <root>.test' type=kotlin.Nothing origin=null then: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'val tmp_7: kotlin.Int? [val] declared in <root>.test' type=kotlin.Int? origin=null
VAR name:x6 type:kotlin.Any [val] VAR name:x6 type:kotlin.Any [val]
BLOCK type=T of <root>.test origin=ELVIS BLOCK type=T of <root>.test origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_8 type:T of <root>.test [val] VAR IR_TEMPORARY_VARIABLE name:tmp_8 type:T of <root>.test [val]
@@ -136,26 +137,28 @@ FILE fqName:<root> fileName:/kt30796.kt
then: GET_VAR 'val tmp_8: T of <root>.test [val] declared in <root>.test' type=T of <root>.test origin=null then: GET_VAR 'val tmp_8: T of <root>.test [val] declared in <root>.test' type=T of <root>.test origin=null
VAR name:x7 type:kotlin.Any [val] VAR name:x7 type:kotlin.Any [val]
BLOCK type=T of <root>.test origin=ELVIS BLOCK type=T of <root>.test origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_10 type:T of <root>.test [val] VAR IR_TEMPORARY_VARIABLE name:tmp_10 type:T of <root>.test? [val]
BLOCK type=T of <root>.test origin=ELVIS BLOCK type=T of <root>.test? origin=ELVIS
VAR IR_TEMPORARY_VARIABLE name:tmp_11 type:kotlin.Nothing [val] VAR IR_TEMPORARY_VARIABLE name:tmp_11 type:T of <root>.test? [val]
CALL 'public final fun magic <T> (): T of <root>.magic declared in <root>' type=kotlin.Nothing origin=null CALL 'public final fun magic <T> (): T of <root>.magic declared in <root>' type=T of <root>.test? origin=null
<T>: kotlin.Nothing <T>: T of <root>.test?
WHEN type=T of <root>.test origin=ELVIS WHEN type=T of <root>.test? origin=ELVIS
BRANCH BRANCH
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: GET_VAR 'val tmp_11: kotlin.Nothing [val] declared in <root>.test' type=kotlin.Nothing origin=null arg0: GET_VAR 'val tmp_11: T of <root>.test? [val] declared in <root>.test' type=T of <root>.test? origin=null
arg1: CONST Null type=kotlin.Nothing? value=null arg1: CONST Null type=kotlin.Nothing? value=null
then: GET_VAR 'value: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null then: GET_VAR 'value: T of <root>.test declared in <root>.test' type=T of <root>.test origin=null
BRANCH BRANCH
if: CONST Boolean type=kotlin.Boolean value=true if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val tmp_11: kotlin.Nothing [val] declared in <root>.test' type=kotlin.Nothing origin=null then: TYPE_OP type=T of <root>.test origin=IMPLICIT_CAST typeOperand=T of <root>.test
GET_VAR 'val tmp_11: T of <root>.test? [val] declared in <root>.test' type=T of <root>.test? origin=null
WHEN type=T of <root>.test origin=ELVIS WHEN type=T of <root>.test origin=ELVIS
BRANCH BRANCH
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: GET_VAR 'val tmp_10: T of <root>.test [val] declared in <root>.test' type=T of <root>.test origin=null arg0: GET_VAR 'val tmp_10: T of <root>.test? [val] declared in <root>.test' type=T of <root>.test? origin=null
arg1: CONST Null type=kotlin.Nothing? value=null arg1: CONST Null type=kotlin.Nothing? value=null
then: CONST Int type=kotlin.Int value=42 then: CONST Int type=kotlin.Int value=42
BRANCH BRANCH
if: CONST Boolean type=kotlin.Boolean value=true if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val tmp_10: T of <root>.test [val] declared in <root>.test' type=T of <root>.test origin=null then: TYPE_OP type=T of <root>.test origin=IMPLICIT_CAST typeOperand=T of <root>.test
GET_VAR 'val tmp_10: T of <root>.test? [val] declared in <root>.test' type=T of <root>.test? origin=null