[FIR] Add conversion of FirElvisCall to backend IR
This commit is contained in:
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user