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.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.*
|
import org.jetbrains.kotlin.resolve.constants.evaluate.*
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
internal fun String.parseCharacter(): Char? {
|
internal fun String.parseCharacter(): Char? {
|
||||||
// Strip the quotes
|
// Strip the quotes
|
||||||
@@ -279,6 +280,48 @@ internal fun Array<KtWhenCondition>.toFirWhenCondition(
|
|||||||
return firCondition!!
|
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(
|
internal fun generateIncrementOrDecrementBlock(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
baseExpression: KtUnaryExpression,
|
baseExpression: KtUnaryExpression,
|
||||||
|
|||||||
@@ -923,41 +923,7 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
|
|||||||
generateConstantExpressionByLiteral(session, expression)
|
generateConstantExpressionByLiteral(session, expression)
|
||||||
|
|
||||||
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Unit): FirElement {
|
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Unit): FirElement {
|
||||||
val sb = StringBuilder()
|
return expression.entries.toInterpolatingCall(session, expression) { toFirExpression(it) }
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitReturnExpression(expression: KtReturnExpression, data: Unit): FirElement {
|
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 operationToken = expression.operationToken
|
||||||
val leftArgument = expression.left.toFirExpression("No left operand")
|
val leftArgument = expression.left.toFirExpression("No left operand")
|
||||||
val rightArgument = expression.right.toFirExpression("No right operand")
|
val rightArgument = expression.right.toFirExpression("No right operand")
|
||||||
if (operationToken == ELVIS) {
|
when (operationToken) {
|
||||||
return leftArgument.generateNotNullOrOther(session, rightArgument, "elvis", expression)
|
ELVIS ->
|
||||||
|
return leftArgument.generateNotNullOrOther(session, rightArgument, "elvis", expression)
|
||||||
|
ANDAND, OROR ->
|
||||||
|
return leftArgument.generateLazyLogicalOperation(session, rightArgument, operationToken == ANDAND, expression)
|
||||||
}
|
}
|
||||||
val conventionCallName = operationToken.toBinaryName()
|
val conventionCallName = operationToken.toBinaryName()
|
||||||
if (operationToken == ANDAND || operationToken == OROR) {
|
|
||||||
return leftArgument.generateLazyLogicalOperation(session, rightArgument, operationToken == ANDAND, expression)
|
|
||||||
}
|
|
||||||
return if (conventionCallName != null || operationToken == IDENTIFIER) {
|
return if (conventionCallName != null || operationToken == IDENTIFIER) {
|
||||||
FirFunctionCallImpl(
|
FirFunctionCallImpl(
|
||||||
session, expression
|
session, expression
|
||||||
@@ -1181,6 +1147,8 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
|
|||||||
this@RawFirBuilder.session, expression.operationReference,
|
this@RawFirBuilder.session, expression.operationReference,
|
||||||
conventionCallName ?: expression.operationReference.getReferencedNameAsName()
|
conventionCallName ?: expression.operationReference.getReferencedNameAsName()
|
||||||
)
|
)
|
||||||
|
explicitReceiver = leftArgument
|
||||||
|
arguments += rightArgument
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val firOperation = operationToken.toFirOperation()
|
val firOperation = operationToken.toFirOperation()
|
||||||
@@ -1189,11 +1157,11 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
|
|||||||
toFirExpression("Incorrect expression in assignment: ${expression.text}")
|
toFirExpression("Incorrect expression in assignment: ${expression.text}")
|
||||||
}
|
}
|
||||||
} else {
|
} 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? get(): Double
|
||||||
|
|
||||||
public? abstract fun sayHello(): kotlin/Unit
|
public? abstract fun sayHello(): kotlin/Unit
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ FILE: simpleClass.kt
|
|||||||
private get(): <implicit>
|
private get(): <implicit>
|
||||||
|
|
||||||
public? open? override fun foo(x: Int, y: String): String {
|
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
|
public? open? override var bar: Boolean
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ FILE: arrayAccess.kt
|
|||||||
|
|
||||||
}
|
}
|
||||||
public? final? fun test(a: IntArray, w: Wrapper): <implicit> {
|
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)) -> {
|
==($subj$, Int(3)) -> {
|
||||||
String(Mediocre)
|
String(Mediocre)
|
||||||
}
|
}
|
||||||
in($subj$, rangeTo#(Int(1), Int(2))) -> {
|
in($subj$, Int(1).rangeTo#(Int(2))) -> {
|
||||||
String(Fail)
|
String(Fail)
|
||||||
}
|
}
|
||||||
($subj$ is Number) -> {
|
($subj$ is Number) -> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
FILE: calls.kt
|
FILE: calls.kt
|
||||||
public? final? infix fun distance(x: Int, y: Int): <implicit> {
|
public? final? infix fun distance(x: Int, y: Int): <implicit> {
|
||||||
^distance plus#(x#, y#)
|
^distance x#.plus#(y#)
|
||||||
}
|
}
|
||||||
public? final? fun test(): Int {
|
public? final? fun test(): Int {
|
||||||
^test distance#(Int(3), Int(4))
|
^test Int(3).distance#(Int(4))
|
||||||
}
|
}
|
||||||
public? final? fun testRegular(): Int {
|
public? final? fun testRegular(): Int {
|
||||||
^testRegular distance#(Int(3), Int(4))
|
^testRegular distance#(Int(3), Int(4))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
FILE: for.kt
|
FILE: for.kt
|
||||||
public? final? fun foo(): kotlin/Unit {
|
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#()
|
lval <iterator>: <implicit> = <range>#.iterator#()
|
||||||
while(<iterator>#.hasNext#()) {
|
while(<iterator>#.hasNext#()) {
|
||||||
lval i: <implicit> = <iterator>#.next#()
|
lval i: <implicit> = <iterator>#.next#()
|
||||||
@@ -41,7 +41,7 @@ FILE: for.kt
|
|||||||
lval <destruct>: <implicit> = <iterator>#.next#()
|
lval <destruct>: <implicit> = <iterator>#.next#()
|
||||||
lval x: <implicit> = <destruct>#.component1()
|
lval x: <implicit> = <destruct>#.component1()
|
||||||
lval y: <implicit> = <destruct>#.component2()
|
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 x: <implicit> = t#.x#
|
||||||
lval y: <implicit> = t#.y#
|
lval y: <implicit> = t#.y#
|
||||||
plus#(x#, y#)
|
x#.plus#(y#)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ FILE: lambda.kt
|
|||||||
^ {
|
^ {
|
||||||
lval x: <implicit> = <destruct>#.component1()
|
lval x: <implicit> = <destruct>#.component1()
|
||||||
lval y: <implicit> = <destruct>#.component2()
|
lval y: <implicit> = <destruct>#.component2()
|
||||||
plus#(x#, y#)
|
x#.plus#(y#)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ FILE: locals.kt
|
|||||||
public? get(): Int
|
public? get(): Int
|
||||||
|
|
||||||
public? final? fun diff(): <implicit> {
|
public? final? fun diff(): <implicit> {
|
||||||
^diff minus#(pp#, p#)
|
^diff pp#.minus#(p#)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lval x: <implicit> = Local#(Int(42)).diff#()
|
lval x: <implicit> = Local#(Int(42)).diff#()
|
||||||
local final? fun sum(y: Int, z: Int, f: ( (Int, Int) -> Int )): Int {
|
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 {
|
lval code: <implicit> = object : Any {
|
||||||
@@ -27,7 +27,7 @@ FILE: locals.kt
|
|||||||
}
|
}
|
||||||
.foo#()
|
.foo#()
|
||||||
^withLocals sum#(code#, Local#(Int(1)).diff#(), fun <anonymous>(x: Int, y: Int): <implicit> {
|
^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 {
|
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 {
|
public? final? fun test(some: Some): Int {
|
||||||
^test with#(some#, with@fun <implicit>.<anonymous>(): <implicit> {
|
^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
|
FILE: variables.kt
|
||||||
public? final? fun foo(): kotlin/Unit {
|
public? final? fun foo(): kotlin/Unit {
|
||||||
lval x: <implicit> = Int(1)
|
lval x: <implicit> = Int(1)
|
||||||
lvar y: <implicit> = plus#(x#, Int(1))
|
lvar y: <implicit> = x#.plus#(Int(1))
|
||||||
lval z: <implicit> = times#(y#, Int(2))
|
lval z: <implicit> = y#.times#(Int(2))
|
||||||
y# = plus#(y#, z#)
|
y# = y#.plus#(z#)
|
||||||
lval w: <implicit> = minus#(y#, x#)
|
lval w: <implicit> = y#.minus#(x#)
|
||||||
^foo w#
|
^foo w#
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -251,6 +251,7 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
|
|||||||
it is KtLambdaExpression ||
|
it is KtLambdaExpression ||
|
||||||
it is KtTypeConstraintList ||
|
it is KtTypeConstraintList ||
|
||||||
it is KtTypeConstraint ||
|
it is KtTypeConstraint ||
|
||||||
|
it is KtStringTemplateExpression && it.entries.size <= 1 ||
|
||||||
it is KtDestructuringDeclaration && it.parent is KtParameter ||
|
it is KtDestructuringDeclaration && it.parent is KtParameter ||
|
||||||
it is KtArrayAccessExpression && it.parent is KtBinaryExpression ||
|
it is KtArrayAccessExpression && it.parent is KtBinaryExpression ||
|
||||||
it is KtNameReferenceExpression &&
|
it is KtNameReferenceExpression &&
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ FILE: access.kt
|
|||||||
^plus String()
|
^plus String()
|
||||||
}
|
}
|
||||||
|
|
||||||
public final fun R|Foo|.check(): R|kotlin/String| {
|
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|/Bar.plus|(R|/Foo.abc|(), R|/Bar.bar|())
|
^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 get(): R|kotlin/Double|
|
||||||
|
|
||||||
public abstract fun sayHello(): R|kotlin/Unit|
|
public abstract fun sayHello(): R|kotlin/Unit|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ FILE: simpleClass.kt
|
|||||||
private get(): R|kotlin/Int|
|
private get(): R|kotlin/Int|
|
||||||
|
|
||||||
public final override fun foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| {
|
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|
|
public final override var bar: R|kotlin/Boolean|
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ FILE: simpleClass.kt
|
|||||||
private get(): R|kotlin/Int|
|
private get(): R|kotlin/Int|
|
||||||
|
|
||||||
public final override fun foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| {
|
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|
|
public final override var bar: R|kotlin/Boolean|
|
||||||
|
|||||||
Reference in New Issue
Block a user