Raw FIR: generate convention / infix binary expressions with receiver
This commit is contained in:
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.*
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
internal fun String.parseCharacter(): Char? {
|
||||
// Strip the quotes
|
||||
@@ -279,6 +280,48 @@ internal fun Array<KtWhenCondition>.toFirWhenCondition(
|
||||
return firCondition!!
|
||||
}
|
||||
|
||||
internal fun Array<KtStringTemplateEntry>.toInterpolatingCall(
|
||||
session: FirSession,
|
||||
base: KtStringTemplateExpression,
|
||||
convert: KtExpression?.(String) -> FirExpression
|
||||
): FirExpression {
|
||||
val sb = StringBuilder()
|
||||
var hasExpressions = false
|
||||
var result: FirExpression? = null
|
||||
for (entry in this) {
|
||||
val nextArgument = when (entry) {
|
||||
is KtLiteralStringTemplateEntry -> {
|
||||
sb.append(entry.text)
|
||||
FirConstExpressionImpl(session, entry, IrConstKind.String, entry.text)
|
||||
}
|
||||
is KtEscapeStringTemplateEntry -> {
|
||||
sb.append(entry.unescapedValue)
|
||||
FirConstExpressionImpl(session, entry, IrConstKind.String, entry.unescapedValue)
|
||||
}
|
||||
is KtStringTemplateEntryWithExpression -> {
|
||||
val innerExpression = entry.expression
|
||||
hasExpressions = true
|
||||
innerExpression.convert("Incorrect template argument")
|
||||
}
|
||||
else -> {
|
||||
hasExpressions = true
|
||||
FirErrorExpressionImpl(
|
||||
session, entry, "Incorrect template entry: ${entry.text}"
|
||||
)
|
||||
}
|
||||
}
|
||||
result = when (result) {
|
||||
null -> nextArgument
|
||||
else -> FirFunctionCallImpl(session, base).apply {
|
||||
calleeReference = FirSimpleNamedReference(session, base, OperatorNameConventions.PLUS)
|
||||
explicitReceiver = result
|
||||
arguments += nextArgument
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (hasExpressions) result!! else FirConstExpressionImpl(session, base, IrConstKind.String, sb.toString())
|
||||
}
|
||||
|
||||
internal fun generateIncrementOrDecrementBlock(
|
||||
session: FirSession,
|
||||
baseExpression: KtUnaryExpression,
|
||||
|
||||
@@ -923,41 +923,7 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
|
||||
generateConstantExpressionByLiteral(session, expression)
|
||||
|
||||
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Unit): FirElement {
|
||||
val sb = StringBuilder()
|
||||
var hasExpressions = false
|
||||
val interpolatingCall = FirFunctionCallImpl(session, expression).apply {
|
||||
calleeReference = FirSimpleNamedReference(this@RawFirBuilder.session, expression, OperatorNameConventions.PLUS)
|
||||
for (entry in expression.entries) {
|
||||
when (entry) {
|
||||
is KtLiteralStringTemplateEntry -> {
|
||||
sb.append(entry.text)
|
||||
arguments += FirConstExpressionImpl(this@RawFirBuilder.session, entry, IrConstKind.String, entry.text)
|
||||
}
|
||||
is KtEscapeStringTemplateEntry -> {
|
||||
sb.append(entry.unescapedValue)
|
||||
arguments += FirConstExpressionImpl(this@RawFirBuilder.session, entry, IrConstKind.String, entry.unescapedValue)
|
||||
}
|
||||
is KtStringTemplateEntryWithExpression -> {
|
||||
val innerExpression = entry.expression
|
||||
if (innerExpression != null) {
|
||||
arguments += innerExpression.toFirExpression("Incorrect template argument")
|
||||
hasExpressions = true
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
arguments += FirErrorExpressionImpl(
|
||||
this@RawFirBuilder.session, expression, "Incorrect template entry: ${entry.text}"
|
||||
)
|
||||
hasExpressions = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (hasExpressions) {
|
||||
interpolatingCall
|
||||
} else {
|
||||
FirConstExpressionImpl(session, expression, IrConstKind.String, sb.toString())
|
||||
}
|
||||
return expression.entries.toInterpolatingCall(session, expression) { toFirExpression(it) }
|
||||
}
|
||||
|
||||
override fun visitReturnExpression(expression: KtReturnExpression, data: Unit): FirElement {
|
||||
@@ -1166,13 +1132,13 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
|
||||
val operationToken = expression.operationToken
|
||||
val leftArgument = expression.left.toFirExpression("No left operand")
|
||||
val rightArgument = expression.right.toFirExpression("No right operand")
|
||||
if (operationToken == ELVIS) {
|
||||
return leftArgument.generateNotNullOrOther(session, rightArgument, "elvis", expression)
|
||||
when (operationToken) {
|
||||
ELVIS ->
|
||||
return leftArgument.generateNotNullOrOther(session, rightArgument, "elvis", expression)
|
||||
ANDAND, OROR ->
|
||||
return leftArgument.generateLazyLogicalOperation(session, rightArgument, operationToken == ANDAND, expression)
|
||||
}
|
||||
val conventionCallName = operationToken.toBinaryName()
|
||||
if (operationToken == ANDAND || operationToken == OROR) {
|
||||
return leftArgument.generateLazyLogicalOperation(session, rightArgument, operationToken == ANDAND, expression)
|
||||
}
|
||||
return if (conventionCallName != null || operationToken == IDENTIFIER) {
|
||||
FirFunctionCallImpl(
|
||||
session, expression
|
||||
@@ -1181,6 +1147,8 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
|
||||
this@RawFirBuilder.session, expression.operationReference,
|
||||
conventionCallName ?: expression.operationReference.getReferencedNameAsName()
|
||||
)
|
||||
explicitReceiver = leftArgument
|
||||
arguments += rightArgument
|
||||
}
|
||||
} else {
|
||||
val firOperation = operationToken.toFirOperation()
|
||||
@@ -1189,11 +1157,11 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
|
||||
toFirExpression("Incorrect expression in assignment: ${expression.text}")
|
||||
}
|
||||
} else {
|
||||
FirOperatorCallImpl(session, expression, firOperation)
|
||||
FirOperatorCallImpl(session, expression, firOperation).apply {
|
||||
arguments += leftArgument
|
||||
arguments += rightArgument
|
||||
}
|
||||
}
|
||||
}.apply {
|
||||
arguments += leftArgument
|
||||
arguments += rightArgument
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ FILE: enums.kt
|
||||
|
||||
}
|
||||
|
||||
public? final? val g: Double = div#(times#(G#, m#), times#(r#, r#))
|
||||
public? final? val g: Double = G#.times#(m#).div#(r#.times#(r#))
|
||||
public? get(): Double
|
||||
|
||||
public? abstract fun sayHello(): kotlin/Unit
|
||||
|
||||
@@ -13,7 +13,7 @@ FILE: simpleClass.kt
|
||||
private get(): <implicit>
|
||||
|
||||
public? open? override fun foo(x: Int, y: String): String {
|
||||
^foo plus#(plus#(y#, x#), baz#)
|
||||
^foo y#.plus#(x#).plus#(baz#)
|
||||
}
|
||||
|
||||
public? open? override var bar: Boolean
|
||||
|
||||
@@ -12,5 +12,5 @@ FILE: arrayAccess.kt
|
||||
|
||||
}
|
||||
public? final? fun test(a: IntArray, w: Wrapper): <implicit> {
|
||||
^test plus#(plus#(plus#(a#[Int(0)], a#[p#]), a#[foo#()]), w#.v#[Int(0)])
|
||||
^test a#[Int(0)].plus#(a#[p#]).plus#(a#[foo#()]).plus#(w#.v#[Int(0)])
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ FILE: branches.kt
|
||||
==($subj$, Int(3)) -> {
|
||||
String(Mediocre)
|
||||
}
|
||||
in($subj$, rangeTo#(Int(1), Int(2))) -> {
|
||||
in($subj$, Int(1).rangeTo#(Int(2))) -> {
|
||||
String(Fail)
|
||||
}
|
||||
($subj$ is Number) -> {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
FILE: calls.kt
|
||||
public? final? infix fun distance(x: Int, y: Int): <implicit> {
|
||||
^distance plus#(x#, y#)
|
||||
^distance x#.plus#(y#)
|
||||
}
|
||||
public? final? fun test(): Int {
|
||||
^test distance#(Int(3), Int(4))
|
||||
^test Int(3).distance#(Int(4))
|
||||
}
|
||||
public? final? fun testRegular(): Int {
|
||||
^testRegular distance#(Int(3), Int(4))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
FILE: for.kt
|
||||
public? final? fun foo(): kotlin/Unit {
|
||||
lval <range>: <implicit> = rangeTo#(Int(1), Int(10))
|
||||
lval <range>: <implicit> = Int(1).rangeTo#(Int(10))
|
||||
lval <iterator>: <implicit> = <range>#.iterator#()
|
||||
while(<iterator>#.hasNext#()) {
|
||||
lval i: <implicit> = <iterator>#.next#()
|
||||
@@ -41,7 +41,7 @@ FILE: for.kt
|
||||
lval <destruct>: <implicit> = <iterator>#.next#()
|
||||
lval x: <implicit> = <destruct>#.component1()
|
||||
lval y: <implicit> = <destruct>#.component2()
|
||||
println#(plus#(String(x = ), x#, String( y = ), y#))
|
||||
println#(String(x = ).plus#(x#).plus#(String( y = )).plus#(y#))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ FILE: lambda.kt
|
||||
^ {
|
||||
lval x: <implicit> = t#.x#
|
||||
lval y: <implicit> = t#.y#
|
||||
plus#(x#, y#)
|
||||
x#.plus#(y#)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ FILE: lambda.kt
|
||||
^ {
|
||||
lval x: <implicit> = <destruct>#.component1()
|
||||
lval y: <implicit> = <destruct>#.component2()
|
||||
plus#(x#, y#)
|
||||
x#.plus#(y#)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ FILE: locals.kt
|
||||
public? get(): Int
|
||||
|
||||
public? final? fun diff(): <implicit> {
|
||||
^diff minus#(pp#, p#)
|
||||
^diff pp#.minus#(p#)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lval x: <implicit> = Local#(Int(42)).diff#()
|
||||
local final? fun sum(y: Int, z: Int, f: ( (Int, Int) -> Int )): Int {
|
||||
^sum plus#(x#, f#(plus#(y#, z#)))
|
||||
^sum x#.plus#(f#(y#.plus#(z#)))
|
||||
}
|
||||
|
||||
lval code: <implicit> = object : Any {
|
||||
@@ -27,7 +27,7 @@ FILE: locals.kt
|
||||
}
|
||||
.foo#()
|
||||
^withLocals sum#(code#, Local#(Int(1)).diff#(), fun <anonymous>(x: Int, y: Int): <implicit> {
|
||||
^ plus#(x#, y#)
|
||||
^ x#.plus#(y#)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ FILE: these.kt
|
||||
}
|
||||
|
||||
public? final? fun String.extension(): Int {
|
||||
^extension plus#(this@Some.bar#(), this#.length#)
|
||||
^extension this@Some.bar#().plus#(this#.length#)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ FILE: these.kt
|
||||
public? final? fun test(some: Some): Int {
|
||||
^test with#(some#, with@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
plus#(this#.foo#(), this@with.extension#())
|
||||
this#.foo#().plus#(this@with.extension#())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
FILE: variables.kt
|
||||
public? final? fun foo(): kotlin/Unit {
|
||||
lval x: <implicit> = Int(1)
|
||||
lvar y: <implicit> = plus#(x#, Int(1))
|
||||
lval z: <implicit> = times#(y#, Int(2))
|
||||
y# = plus#(y#, z#)
|
||||
lval w: <implicit> = minus#(y#, x#)
|
||||
lvar y: <implicit> = x#.plus#(Int(1))
|
||||
lval z: <implicit> = y#.times#(Int(2))
|
||||
y# = y#.plus#(z#)
|
||||
lval w: <implicit> = y#.minus#(x#)
|
||||
^foo w#
|
||||
}
|
||||
|
||||
+1
@@ -251,6 +251,7 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
|
||||
it is KtLambdaExpression ||
|
||||
it is KtTypeConstraintList ||
|
||||
it is KtTypeConstraint ||
|
||||
it is KtStringTemplateExpression && it.entries.size <= 1 ||
|
||||
it is KtDestructuringDeclaration && it.parent is KtParameter ||
|
||||
it is KtArrayAccessExpression && it.parent is KtBinaryExpression ||
|
||||
it is KtNameReferenceExpression &&
|
||||
|
||||
@@ -32,8 +32,8 @@ FILE: access.kt
|
||||
^plus String()
|
||||
}
|
||||
|
||||
public final fun R|Foo|.check(): R|kotlin/String| {
|
||||
^check R|/Bar.plus|(R|/Foo.abc|(), R|/Bar.bar|())
|
||||
public final fun R|Foo|.check(): <ERROR TYPE REF: Ambiguity: plus, [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]> {
|
||||
^check R|/Foo.abc|().<Ambiguity: plus, [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]>#(R|/Bar.bar|())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ FILE: enums.kt
|
||||
|
||||
}
|
||||
|
||||
public final val g: R|kotlin/Double| = <Unresolved name: div>#(<Unresolved name: times>#(<Unresolved name: G>#, R|/Planet.m|), <Unresolved name: times>#(R|/Planet.r|, R|/Planet.r|))
|
||||
public final val g: R|kotlin/Double| = <Unresolved name: G>#.<Unresolved name: times>#(R|/Planet.m|).<Unresolved name: div>#(R|/Planet.r|.<Ambiguity: times, [kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times, kotlin/Double.times]>#(R|/Planet.r|))
|
||||
public get(): R|kotlin/Double|
|
||||
|
||||
public abstract fun sayHello(): R|kotlin/Unit|
|
||||
|
||||
@@ -13,7 +13,7 @@ FILE: simpleClass.kt
|
||||
private get(): R|kotlin/Int|
|
||||
|
||||
public final override fun foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| {
|
||||
^foo R|kotlin/plus|(R|kotlin/plus|(R|<local>/y|, R|<local>/x|), R|/SomeClass.baz|)
|
||||
^foo R|<local>/y|.R|kotlin/String.plus|(R|<local>/x|).R|kotlin/String.plus|(R|/SomeClass.baz|)
|
||||
}
|
||||
|
||||
public final override var bar: R|kotlin/Boolean|
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ FILE: simpleClass.kt
|
||||
private get(): R|kotlin/Int|
|
||||
|
||||
public final override fun foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| {
|
||||
^foo R|kotlin/plus|(R|kotlin/plus|(R|<local>/y|, R|<local>/x|), R|/SomeClass.baz|)
|
||||
^foo R|<local>/y|.R|kotlin/String.plus|(R|<local>/x|).R|kotlin/String.plus|(R|/SomeClass.baz|)
|
||||
}
|
||||
|
||||
public final override var bar: R|kotlin/Boolean|
|
||||
|
||||
Reference in New Issue
Block a user