diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/IrExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/IrExpressionGenerator.kt index 6883e952a3a..db85ee46c22 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/IrExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/IrExpressionGenerator.kt @@ -39,19 +39,21 @@ class IrExpressionGenerator( fun generateExpression(ktExpression: KtExpression) = ktExpression.generate() private fun KtElement.generate(): IrExpression = - accept(this@IrExpressionGenerator, null).applySmartCast(this) + deparenthesize() + .accept(this@IrExpressionGenerator, null) + .smartCastIfNeeded(this) private fun KtExpression.type() = getType(this) ?: TODO("no type for expression") - private fun IrExpression.applySmartCast(ktElement: KtElement): IrExpression { + private fun IrExpression.smartCastIfNeeded(ktElement: KtElement): IrExpression { if (ktElement is KtExpression) { val smartCastType = get(BindingContext.SMARTCAST, ktElement) if (smartCastType != null) { return IrTypeOperatorExpressionImpl( ktElement.startOffset, ktElement.endOffset, smartCastType, IrTypeOperator.SMART_AS, smartCastType - ).apply { childExpression = this@applySmartCast } + ).apply { childExpression = this@smartCastIfNeeded } } } return this @@ -138,6 +140,24 @@ class IrExpressionGenerator( return generateCall(expression, resolvedCall, null, null) } + override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Nothing?): IrExpression = + expression.selectorExpression!!.accept(this, data) + + override fun visitSafeQualifiedExpression(expression: KtSafeQualifiedExpression, data: Nothing?): IrExpression = + expression.selectorExpression!!.accept(this, data) + + override fun visitThisExpression(expression: KtThisExpression, data: Nothing?): IrExpression { + val referenceTarget = getOrFail(BindingContext.REFERENCE_TARGET, expression.instanceReference) { "No reference target for this" } + return when (referenceTarget) { + is ClassDescriptor -> + IrThisExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), referenceTarget) + is CallableDescriptor -> + IrExtensionReceiverReferenceImpl(expression.startOffset, expression.endOffset, expression.type(), referenceTarget) + else -> + error("Expected this or receiver: $referenceTarget") + } + } + private fun generateCall( ktExpression: KtExpression, resolvedCall: ResolvedCall, @@ -179,8 +199,7 @@ class IrExpressionGenerator( null -> null else -> - IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, receiver.type, - "Receiver: ${receiver.javaClass.simpleName}") + TODO("Receiver: ${receiver.javaClass.simpleName}") } private fun generateValueArgument(valueParameter: ValueParameterDescriptor, valueArgument: ResolvedValueArgument): IrExpression? { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/KtElementUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/KtElementUtils.kt new file mode 100644 index 00000000000..efd3fedddb7 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/KtElementUtils.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.psi2ir + +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtPsiUtil + +fun KtElement.deparenthesize(): KtElement = + if (this is KtExpression) KtPsiUtil.safeDeparenthesize(this) else this + diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt index e513df74106..2e58b8fb6ee 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt @@ -76,7 +76,7 @@ class RenderIrElementVisitor : IrElementVisitor { "THIS ${expression.classDescriptor.render()}" override fun visitCallExpression(expression: IrCallExpression, data: Nothing?): String = - "CALL ${expression.callee.name} ${expression.operator ?: ""}" + "CALL ${if (expression.isSafe) "?." else "."}${expression.callee.name} ${expression.operator ?: ""}" override fun visitDummyExpression(expression: IrDummyExpression, data: Nothing?): String = "DUMMY ${expression.description}" diff --git a/compiler/testData/ir/irText/calls.txt b/compiler/testData/ir/irText/calls.txt index 42b9403a02b..c6034d1f3a5 100644 --- a/compiler/testData/ir/irText/calls.txt +++ b/compiler/testData/ir/irText/calls.txt @@ -6,14 +6,14 @@ IrFile /calls.kt IrFunction public fun bar(/*0*/ x: kotlin.Int): kotlin.Int IrExpressionBody RETURN type=kotlin.Int - CALL foo + CALL .foo x: VAR x y: LITERAL Int type=kotlin.Int value='1' IrFunction public fun qux(/*0*/ x: kotlin.Int): kotlin.Int IrExpressionBody RETURN type=kotlin.Int - CALL foo - x: CALL foo + CALL .foo + x: CALL .foo x: VAR x y: VAR x y: VAR x @@ -24,6 +24,6 @@ IrFile /calls.kt IrFunction public fun kotlin.Int.ext2(/*0*/ x: kotlin.Int): kotlin.Int IrExpressionBody RETURN type=kotlin.Int - CALL foo + CALL .foo x: $RECEIVER of: y: VAR x diff --git a/compiler/testData/ir/irText/dotQualified.kt b/compiler/testData/ir/irText/dotQualified.kt new file mode 100644 index 00000000000..36752cd6240 --- /dev/null +++ b/compiler/testData/ir/irText/dotQualified.kt @@ -0,0 +1,4 @@ +fun length(s: String) = s.length +fun lengthN(s: String?) = s?.length + +// IR_FILE_TXT dotQualified.txt diff --git a/compiler/testData/ir/irText/dotQualified.txt b/compiler/testData/ir/irText/dotQualified.txt new file mode 100644 index 00000000000..b6c5769e686 --- /dev/null +++ b/compiler/testData/ir/irText/dotQualified.txt @@ -0,0 +1,11 @@ +IrFile /dotQualified.kt + IrFunction public fun length(/*0*/ s: kotlin.String): kotlin.Int + IrExpressionBody + RETURN type=kotlin.Int + CALL .length PROPERTY_GET + $this: VAR s + IrFunction public fun lengthN(/*0*/ s: kotlin.String?): kotlin.Int? + IrExpressionBody + RETURN type=kotlin.Int? + CALL ?.length PROPERTY_GET + $this: VAR s diff --git a/compiler/testData/ir/irText/extensionPropertyGetterCall.txt b/compiler/testData/ir/irText/extensionPropertyGetterCall.txt index 405cafdc503..a7c0d845efe 100644 --- a/compiler/testData/ir/irText/extensionPropertyGetterCall.txt +++ b/compiler/testData/ir/irText/extensionPropertyGetterCall.txt @@ -7,5 +7,5 @@ IrFile /extensionPropertyGetterCall.kt IrFunction public fun kotlin.String.test5(): kotlin.String IrExpressionBody RETURN type=kotlin.String - CALL okext PROPERTY_GET + CALL .okext PROPERTY_GET $receiver: $RECEIVER of: test5 diff --git a/compiler/testData/ir/irText/references.txt b/compiler/testData/ir/irText/references.txt index 23e0cebed45..dfce09ab2b8 100644 --- a/compiler/testData/ir/irText/references.txt +++ b/compiler/testData/ir/irText/references.txt @@ -6,7 +6,7 @@ IrFile /references.kt IrProperty public val ok2: kotlin.String = "OK" getter=null setter=null IrExpressionBody RETURN type=kotlin.String - CALL ok PROPERTY_GET + CALL .ok PROPERTY_GET IrProperty public val ok3: kotlin.String getter= setter=null IrPropertyGetter public fun (): kotlin.String property=ok3 IrExpressionBody @@ -15,7 +15,7 @@ IrFile /references.kt IrFunction public fun test1(): kotlin.String IrExpressionBody RETURN type=kotlin.String - CALL ok PROPERTY_GET + CALL .ok PROPERTY_GET IrFunction public fun test2(/*0*/ x: kotlin.String): kotlin.String IrExpressionBody RETURN type=kotlin.String @@ -29,7 +29,7 @@ IrFile /references.kt IrFunction public fun test4(): kotlin.String IrExpressionBody RETURN type=kotlin.String - CALL ok3 PROPERTY_GET + CALL .ok3 PROPERTY_GET IrProperty public val kotlin.String.okext: kotlin.String getter= setter=null IrPropertyGetter public fun kotlin.String.(): kotlin.String property=okext IrExpressionBody @@ -38,5 +38,5 @@ IrFile /references.kt IrFunction public fun kotlin.String.test5(): kotlin.String IrExpressionBody RETURN type=kotlin.String - CALL okext PROPERTY_GET + CALL .okext PROPERTY_GET $receiver: $RECEIVER of: test5 diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 50ceed08853..70d029307d1 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -47,6 +47,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("dotQualified.kt") + public void testDotQualified() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/dotQualified.kt"); + doTest(fileName); + } + @TestMetadata("extensionPropertyGetterCall.kt") public void testExtensionPropertyGetterCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/extensionPropertyGetterCall.kt");