Raw FIR: generate convention / infix binary expressions with receiver

This commit is contained in:
Mikhail Glukhikh
2019-04-05 10:55:43 +03:00
parent 4f8e29ad23
commit 007edcb4a4
17 changed files with 80 additions and 68 deletions
@@ -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#
}
@@ -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
View File
@@ -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|