[FIR2IR] Fix and refactor generation of dynamic call receiver generation
#KT-57988 Fixed
This commit is contained in:
committed by
Space Team
parent
8b47a4fa48
commit
35c6da1aa7
+30
-26
@@ -290,7 +290,7 @@ class CallAndReferenceGenerator(
|
|||||||
|
|
||||||
private fun convertToIrCallForDynamic(
|
private fun convertToIrCallForDynamic(
|
||||||
qualifiedAccess: FirQualifiedAccessExpression,
|
qualifiedAccess: FirQualifiedAccessExpression,
|
||||||
explicitReceiverExpression: IrExpression,
|
explicitReceiverExpression: IrExpression?,
|
||||||
type: IrType,
|
type: IrType,
|
||||||
calleeReference: FirReference,
|
calleeReference: FirReference,
|
||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
@@ -298,7 +298,7 @@ class CallAndReferenceGenerator(
|
|||||||
dynamicOperator: IrDynamicOperator? = null,
|
dynamicOperator: IrDynamicOperator? = null,
|
||||||
noArguments: Boolean = false,
|
noArguments: Boolean = false,
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
var convertedExplicitReceiver = explicitReceiverExpression
|
val selectedReceiver = qualifiedAccess.findIrDynamicReceiver(explicitReceiverExpression)
|
||||||
|
|
||||||
return qualifiedAccess.convertWithOffsets { startOffset, endOffset ->
|
return qualifiedAccess.convertWithOffsets { startOffset, endOffset ->
|
||||||
when (symbol) {
|
when (symbol) {
|
||||||
@@ -314,22 +314,24 @@ class CallAndReferenceGenerator(
|
|||||||
} else {
|
} else {
|
||||||
type
|
type
|
||||||
}
|
}
|
||||||
if (operator == IrDynamicOperator.INVOKE && qualifiedAccess !is FirImplicitInvokeCall) {
|
IrDynamicOperatorExpressionImpl(startOffset, endOffset, theType, operator).apply {
|
||||||
convertedExplicitReceiver = IrDynamicMemberExpressionImpl(
|
receiver = if (operator == IrDynamicOperator.INVOKE && qualifiedAccess !is FirImplicitInvokeCall) {
|
||||||
startOffset, endOffset, type, name.identifier, explicitReceiverExpression
|
IrDynamicMemberExpressionImpl(startOffset, endOffset, type, name.identifier, selectedReceiver)
|
||||||
)
|
} else {
|
||||||
|
selectedReceiver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
IrDynamicOperatorExpressionImpl(startOffset, endOffset, theType, operator)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is FirPropertySymbol -> {
|
is FirPropertySymbol -> {
|
||||||
val name = calleeReference.resolved?.name ?: error("There must be a name")
|
val name = calleeReference.resolved?.name ?: error("There must be a name")
|
||||||
IrDynamicMemberExpressionImpl(startOffset, endOffset, type, name.identifier, explicitReceiverExpression)
|
IrDynamicMemberExpressionImpl(startOffset, endOffset, type, name.identifier, selectedReceiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference, type)
|
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference, type)
|
||||||
}
|
}
|
||||||
}.applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess, convertedExplicitReceiver)
|
}
|
||||||
|
.applyTypeArguments(qualifiedAccess)
|
||||||
.applyCallArguments((qualifiedAccess as? FirCall)?.takeIf { !noArguments }, annotationMode)
|
.applyCallArguments((qualifiedAccess as? FirCall)?.takeIf { !noArguments }, annotationMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,7 +358,7 @@ class CallAndReferenceGenerator(
|
|||||||
if (isDynamicAccess) {
|
if (isDynamicAccess) {
|
||||||
return convertToIrCallForDynamic(
|
return convertToIrCallForDynamic(
|
||||||
qualifiedAccess,
|
qualifiedAccess,
|
||||||
explicitReceiverExpression ?: error("Must've had a receiver"),
|
explicitReceiverExpression,
|
||||||
type,
|
type,
|
||||||
calleeReference,
|
calleeReference,
|
||||||
firSymbol ?: error("Must have had a symbol"),
|
firSymbol ?: error("Must have had a symbol"),
|
||||||
@@ -483,33 +485,43 @@ class CallAndReferenceGenerator(
|
|||||||
|
|
||||||
private fun convertToIrSetCallForDynamic(
|
private fun convertToIrSetCallForDynamic(
|
||||||
variableAssignment: FirVariableAssignment,
|
variableAssignment: FirVariableAssignment,
|
||||||
receiverExpression: IrExpression,
|
explicitReceiverExpression: IrExpression?,
|
||||||
type: IrType,
|
type: IrType,
|
||||||
calleeReference: FirReference,
|
calleeReference: FirReference,
|
||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
assignedValue: IrExpression,
|
assignedValue: IrExpression,
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
var convertedExplicitReceiver = receiverExpression
|
val selectedReceiver =
|
||||||
|
(variableAssignment.unwrapLValue() ?: error("Assignment has no lValue")).findIrDynamicReceiver(explicitReceiverExpression)
|
||||||
|
|
||||||
return variableAssignment.convertWithOffsets { startOffset, endOffset ->
|
return variableAssignment.convertWithOffsets { startOffset, endOffset ->
|
||||||
when (symbol) {
|
when (symbol) {
|
||||||
is FirPropertySymbol -> {
|
is FirPropertySymbol -> {
|
||||||
val name = calleeReference.resolved?.name ?: error("There must be a name")
|
val name = calleeReference.resolved?.name ?: error("There must be a name")
|
||||||
convertedExplicitReceiver = IrDynamicMemberExpressionImpl(
|
|
||||||
startOffset, endOffset, type, name.identifier, receiverExpression
|
|
||||||
)
|
|
||||||
IrDynamicOperatorExpressionImpl(startOffset, endOffset, type, IrDynamicOperator.EQ).apply {
|
IrDynamicOperatorExpressionImpl(startOffset, endOffset, type, IrDynamicOperator.EQ).apply {
|
||||||
|
receiver = IrDynamicMemberExpressionImpl(
|
||||||
|
startOffset, endOffset, type, name.identifier, selectedReceiver
|
||||||
|
)
|
||||||
arguments.add(assignedValue)
|
arguments.add(assignedValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
||||||
}
|
}
|
||||||
}.apply {
|
|
||||||
variableAssignment.unwrapLValue()?.let { applyReceivers(it, convertedExplicitReceiver) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dynamic call has either an explicit receiver or an implicit this dispatch receiver.
|
||||||
|
*/
|
||||||
|
private fun FirQualifiedAccessExpression.findIrDynamicReceiver(
|
||||||
|
explicitReceiverExpression: IrExpression?,
|
||||||
|
): IrExpression {
|
||||||
|
return explicitReceiverExpression
|
||||||
|
?: (dispatchReceiver as? FirThisReceiverExpression)?.let(visitor::convertToIrExpression)
|
||||||
|
?: error("No receiver for dynamic call")
|
||||||
|
}
|
||||||
|
|
||||||
fun convertToIrSetCall(variableAssignment: FirVariableAssignment, explicitReceiverExpression: IrExpression?): IrExpression {
|
fun convertToIrSetCall(variableAssignment: FirVariableAssignment, explicitReceiverExpression: IrExpression?): IrExpression {
|
||||||
try {
|
try {
|
||||||
val type = irBuiltIns.unitType
|
val type = irBuiltIns.unitType
|
||||||
@@ -520,13 +532,9 @@ class CallAndReferenceGenerator(
|
|||||||
val isDynamicAccess = firSymbol?.origin == FirDeclarationOrigin.DynamicScope
|
val isDynamicAccess = firSymbol?.origin == FirDeclarationOrigin.DynamicScope
|
||||||
|
|
||||||
if (isDynamicAccess) {
|
if (isDynamicAccess) {
|
||||||
val receiverExpression = (explicitReceiverExpression
|
|
||||||
?: (variableAssignment.dispatchReceiver as? FirThisReceiverExpression)?.let(visitor::convertToIrExpression)
|
|
||||||
?: error("Must've had a receiver"))
|
|
||||||
|
|
||||||
return convertToIrSetCallForDynamic(
|
return convertToIrSetCallForDynamic(
|
||||||
variableAssignment,
|
variableAssignment,
|
||||||
receiverExpression,
|
explicitReceiverExpression,
|
||||||
type,
|
type,
|
||||||
calleeReference,
|
calleeReference,
|
||||||
firSymbol ?: error("Must've had a symbol"),
|
firSymbol ?: error("Must've had a symbol"),
|
||||||
@@ -1152,10 +1160,6 @@ class CallAndReferenceGenerator(
|
|||||||
receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
|
receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is IrDynamicOperatorExpression -> {
|
|
||||||
receiver = explicitReceiverExpression ?: error("No receiver for dynamic")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
FILE: getOperatorOnDynamicThis.kt
|
||||||
|
public final inline fun <T : R|kotlin/Any|> jso(): R|T| {
|
||||||
|
^jso R|kotlin/js/js|(String(({})))
|
||||||
|
}
|
||||||
|
public final inline fun <T : R|kotlin/Any|> jso(block: R|T.() -> kotlin/Unit|): R|T| {
|
||||||
|
^jso R|/jso|<R|T|>().R|kotlin/apply|<R|T|>(R|<local>/block|)
|
||||||
|
}
|
||||||
|
public abstract external interface Z : R|kotlin/Any| {
|
||||||
|
public abstract var a: R|dynamic|
|
||||||
|
public get(): R|dynamic|
|
||||||
|
public set(value: R|dynamic|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun foo(): R|kotlin/Unit| {
|
||||||
|
R|/jso|<R|Z|>().R|kotlin/apply|<R|Z|>(<L> = apply@fun R|Z|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||||
|
this@R|special/anonymous|.R|/Z.a| = R|/jso|<R|dynamic|>(<L> = jso@fun R|dynamic|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=UNKNOWN> {
|
||||||
|
this@R|special/anonymous|.R|<dynamic>/get|(vararg(this@R|special/anonymous|.R|<dynamic>/foo|.R|<dynamic>/bar|))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
public final fun box(): R|kotlin/String| {
|
||||||
|
^box String(OK)
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// TARGET_BACKEND: JS
|
||||||
|
// ISSUE: KT-57988
|
||||||
|
// FIR_DUMP
|
||||||
|
|
||||||
|
inline fun <T : Any> jso(): T = js("({})")
|
||||||
|
inline fun <T : Any> jso(block: T.() -> Unit): T = jso<T>().apply(block)
|
||||||
|
|
||||||
|
external interface Z {
|
||||||
|
var a: dynamic
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
jso<Z>().apply {
|
||||||
|
a = jso {
|
||||||
|
this[foo.bar]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = "OK"
|
||||||
+6
@@ -21665,6 +21665,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/js"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/js"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("getOperatorOnDynamicThis.kt")
|
||||||
|
public void testGetOperatorOnDynamicThis() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/js/getOperatorOnDynamicThis.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithDynamicReceiver.kt")
|
@TestMetadata("lambdaWithDynamicReceiver.kt")
|
||||||
public void testLambdaWithDynamicReceiver() throws Exception {
|
public void testLambdaWithDynamicReceiver() throws Exception {
|
||||||
|
|||||||
+6
@@ -21803,6 +21803,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/js"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/js"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("getOperatorOnDynamicThis.kt")
|
||||||
|
public void testGetOperatorOnDynamicThis() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/js/getOperatorOnDynamicThis.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithDynamicReceiver.kt")
|
@TestMetadata("lambdaWithDynamicReceiver.kt")
|
||||||
public void testLambdaWithDynamicReceiver() throws Exception {
|
public void testLambdaWithDynamicReceiver() throws Exception {
|
||||||
|
|||||||
+6
@@ -21803,6 +21803,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/js"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/js"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("getOperatorOnDynamicThis.kt")
|
||||||
|
public void testGetOperatorOnDynamicThis() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/js/getOperatorOnDynamicThis.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithDynamicReceiver.kt")
|
@TestMetadata("lambdaWithDynamicReceiver.kt")
|
||||||
public void testLambdaWithDynamicReceiver() throws Exception {
|
public void testLambdaWithDynamicReceiver() throws Exception {
|
||||||
|
|||||||
+6
@@ -21803,6 +21803,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/js"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/js"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("getOperatorOnDynamicThis.kt")
|
||||||
|
public void testGetOperatorOnDynamicThis() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/js/getOperatorOnDynamicThis.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithDynamicReceiver.kt")
|
@TestMetadata("lambdaWithDynamicReceiver.kt")
|
||||||
public void testLambdaWithDynamicReceiver() throws Exception {
|
public void testLambdaWithDynamicReceiver() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user