CFA: No more UNRESOLVED_CALL for object / enum entry qualifiers
(cherry picked from commit 4b09de8)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
962c2e5dd2
commit
b7ed68db05
@@ -129,6 +129,8 @@ interface ControlFlowBuilder {
|
|||||||
operation: PredefinedOperation,
|
operation: PredefinedOperation,
|
||||||
inputValues: List<PseudoValue>): OperationInstruction
|
inputValues: List<PseudoValue>): OperationInstruction
|
||||||
|
|
||||||
|
fun read(element: KtElement, target: AccessTarget, receiverValues: Map<PseudoValue, ReceiverValue>): ReadValueInstruction
|
||||||
|
|
||||||
fun write(
|
fun write(
|
||||||
assignment: KtElement,
|
assignment: KtElement,
|
||||||
lValue: KtElement,
|
lValue: KtElement,
|
||||||
|
|||||||
@@ -176,6 +176,9 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
|
|||||||
delegateBuilder.returnNoValue(returnExpression, subroutine)
|
delegateBuilder.returnNoValue(returnExpression, subroutine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun read(element: KtElement, target: AccessTarget, receiverValues: Map<PseudoValue, ReceiverValue>) =
|
||||||
|
delegateBuilder.read(element, target, receiverValues)
|
||||||
|
|
||||||
override fun write(
|
override fun write(
|
||||||
assignment: KtElement,
|
assignment: KtElement,
|
||||||
lValue: KtElement,
|
lValue: KtElement,
|
||||||
|
|||||||
@@ -48,12 +48,11 @@ import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.getFakeDescriptorForObject
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
|
||||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -266,8 +265,14 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||||
generateCall(resolvedCall.variableCall)
|
generateCall(resolvedCall.variableCall)
|
||||||
}
|
}
|
||||||
else if (!generateCall(expression) && expression.parent !is KtCallExpression) {
|
else {
|
||||||
createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, generateAndGetReceiverIfAny(expression))
|
if (resolvedCall == null) {
|
||||||
|
val qualifier = trace.bindingContext[BindingContext.QUALIFIER, expression]
|
||||||
|
if (qualifier != null && generateQualifier(expression, qualifier)) return
|
||||||
|
}
|
||||||
|
if (!generateCall(expression) && expression.parent !is KtCallExpression) {
|
||||||
|
createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, generateAndGetReceiverIfAny(expression))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1366,6 +1371,18 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
createNonSyntheticValue(element, MagicKind.UNSUPPORTED_ELEMENT)
|
createNonSyntheticValue(element, MagicKind.UNSUPPORTED_ELEMENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateQualifier(expression: KtExpression, qualifier: Qualifier): Boolean {
|
||||||
|
val qualifierDescriptor = qualifier.descriptor
|
||||||
|
if (qualifierDescriptor is ClassDescriptor) {
|
||||||
|
getFakeDescriptorForObject(qualifierDescriptor)?.let {
|
||||||
|
mark(expression)
|
||||||
|
builder.read(expression, AccessTarget.Declaration(it), emptyMap())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateCall(callElement: KtElement): Boolean {
|
private fun generateCall(callElement: KtElement): Boolean {
|
||||||
return checkAndGenerateCall(callElement.getResolvedCall(trace.bindingContext))
|
return checkAndGenerateCall(callElement.getResolvedCall(trace.bindingContext))
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-22
@@ -331,21 +331,19 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
labelCount = pseudocode.repeatPart(startLabel, finishLabel, labelCount)
|
labelCount = pseudocode.repeatPart(startLabel, finishLabel, labelCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadConstant(expression: KtExpression, constant: CompileTimeConstant<*>?): InstructionWithValue {
|
override fun loadConstant(expression: KtExpression, constant: CompileTimeConstant<*>?) = read(expression)
|
||||||
return read(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createAnonymousObject(expression: KtObjectLiteralExpression): InstructionWithValue {
|
override fun createAnonymousObject(expression: KtObjectLiteralExpression) = read(expression)
|
||||||
return read(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createLambda(expression: KtFunction): InstructionWithValue {
|
override fun createLambda(expression: KtFunction) =
|
||||||
return read(if (expression is KtFunctionLiteral) expression.getParent() as KtLambdaExpression else expression)
|
read(if (expression is KtFunctionLiteral) expression.getParent() as KtLambdaExpression else expression)
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadStringTemplate(expression: KtStringTemplateExpression, inputValues: List<PseudoValue>): InstructionWithValue {
|
override fun loadStringTemplate(
|
||||||
return if (inputValues.isEmpty()) read(expression) else magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE)
|
expression: KtStringTemplateExpression,
|
||||||
}
|
inputValues: List<PseudoValue>
|
||||||
|
): InstructionWithValue =
|
||||||
|
if (inputValues.isEmpty()) read(expression)
|
||||||
|
else magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE)
|
||||||
|
|
||||||
override fun magic(
|
override fun magic(
|
||||||
instructionElement: KtElement,
|
instructionElement: KtElement,
|
||||||
@@ -367,9 +365,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
override fun readVariable(
|
override fun readVariable(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>): ReadValueInstruction {
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
return read(expression, resolvedCall, receiverValues)
|
) = read(expression, resolvedCall, receiverValues)
|
||||||
}
|
|
||||||
|
|
||||||
override fun call(
|
override fun call(
|
||||||
valueElement: KtElement,
|
valueElement: KtElement,
|
||||||
@@ -404,16 +401,19 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun read(
|
||||||
|
element: KtElement,
|
||||||
|
target: AccessTarget,
|
||||||
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
|
) = ReadValueInstruction(element, currentScope, target, receiverValues, valueFactory).apply {
|
||||||
|
add(this)
|
||||||
|
}
|
||||||
|
|
||||||
private fun read(
|
private fun read(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
resolvedCall: ResolvedCall<*>? = null,
|
resolvedCall: ResolvedCall<*>? = null,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap<PseudoValue, ReceiverValue>()): ReadValueInstruction {
|
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap<PseudoValue, ReceiverValue>()
|
||||||
val accessTarget = if (resolvedCall != null) AccessTarget.Call(resolvedCall) else AccessTarget.BlackBox
|
) = read(expression, if (resolvedCall != null) AccessTarget.Call(resolvedCall) else AccessTarget.BlackBox, receiverValues)
|
||||||
val instruction = ReadValueInstruction(
|
|
||||||
expression, currentScope, accessTarget, receiverValues, valueFactory)
|
|
||||||
add(instruction)
|
|
||||||
return instruction
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TryFinallyBlockInfo(private val finallyBlock: GenerationTrigger) : BlockInfo() {
|
private class TryFinallyBlockInfo(private val finallyBlock: GenerationTrigger) : BlockInfo() {
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ private fun ResolutionScope.getContributedObjectVariables(name: Name, location:
|
|||||||
return listOfNotNull(objectDescriptor)
|
return listOfNotNull(objectDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFakeDescriptorForObject(classifier: ClassifierDescriptor?): FakeCallableDescriptorForObject? =
|
fun getFakeDescriptorForObject(classifier: ClassifierDescriptor?): FakeCallableDescriptorForObject? =
|
||||||
when (classifier) {
|
when (classifier) {
|
||||||
is TypeAliasDescriptor ->
|
is TypeAliasDescriptor ->
|
||||||
getFakeDescriptorForObject(classifier.classDescriptor)
|
getFakeDescriptorForObject(classifier.classDescriptor)
|
||||||
|
|||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
== O ==
|
||||||
|
object O {
|
||||||
|
val y = 1
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
v(val y = 1)
|
||||||
|
r(1) -> <v0>
|
||||||
|
w(y|<v0>)
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== E ==
|
||||||
|
enum class E(val x: Int) {
|
||||||
|
E1(0)
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
v(val x: Int)
|
||||||
|
magic[FAKE_INITIALIZER](val x: Int) -> <v0>
|
||||||
|
w(x|<v0>)
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== C ==
|
||||||
|
class C {
|
||||||
|
companion object {
|
||||||
|
val z = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== foo ==
|
||||||
|
fun foo() = E1.x + O.y + C.z
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
mark(E1.x)
|
||||||
|
mark(E1)
|
||||||
|
r(E1) -> <v0>
|
||||||
|
r(x|<v0>) -> <v1>
|
||||||
|
mark(O.y)
|
||||||
|
mark(O)
|
||||||
|
r(O) -> <v2>
|
||||||
|
r(y|<v2>) -> <v3>
|
||||||
|
mark(E1.x + O.y)
|
||||||
|
call(E1.x + O.y, plus|<v1>, <v3>) -> <v4>
|
||||||
|
mark(C.z)
|
||||||
|
mark(C)
|
||||||
|
r(C, Companion) -> <v5>
|
||||||
|
r(z|<v5>) -> <v6>
|
||||||
|
mark(E1.x + O.y + C.z)
|
||||||
|
call(E1.x + O.y + C.z, plus|<v4>, <v6>) -> <v7>
|
||||||
|
ret(*|<v7>) L1
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import E.E1
|
||||||
|
|
||||||
|
object O {
|
||||||
|
val y = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class E(val x: Int) {
|
||||||
|
E1(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
companion object {
|
||||||
|
val z = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = E1.x + O.y + C.z
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
== O ==
|
||||||
|
object O {
|
||||||
|
val y = 1
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
1 <v0>: Int NEW: r(1) -> <v0>
|
||||||
|
=====================
|
||||||
|
== E ==
|
||||||
|
enum class E(val x: Int) {
|
||||||
|
E1(0)
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
<v0>: Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> <v0>
|
||||||
|
=====================
|
||||||
|
== C ==
|
||||||
|
class C {
|
||||||
|
companion object {
|
||||||
|
val z = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
=====================
|
||||||
|
== foo ==
|
||||||
|
fun foo() = E1.x + O.y + C.z
|
||||||
|
---------------------
|
||||||
|
E1 <v0>: E NEW: r(E1) -> <v0>
|
||||||
|
x <v1>: Int NEW: r(x|<v0>) -> <v1>
|
||||||
|
E1.x <v1>: Int COPY
|
||||||
|
O <v2>: O NEW: r(O) -> <v2>
|
||||||
|
y <v3>: Int NEW: r(y|<v2>) -> <v3>
|
||||||
|
O.y <v3>: Int COPY
|
||||||
|
E1.x + O.y <v4>: Int NEW: call(E1.x + O.y, plus|<v1>, <v3>) -> <v4>
|
||||||
|
C <v5>: C.Companion NEW: r(C, Companion) -> <v5>
|
||||||
|
z <v6>: Int NEW: r(z|<v5>) -> <v6>
|
||||||
|
C.z <v6>: Int COPY
|
||||||
|
E1.x + O.y + C.z <v7>: Int NEW: call(E1.x + O.y + C.z, plus|<v4>, <v6>) -> <v7>
|
||||||
|
=====================
|
||||||
Vendored
+171
@@ -0,0 +1,171 @@
|
|||||||
|
== A ==
|
||||||
|
class A {
|
||||||
|
companion object
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== B ==
|
||||||
|
object B {
|
||||||
|
val A.Companion.foo: X get() = X
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
v(val A.Companion.foo: X get() = X)
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== X ==
|
||||||
|
object X
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== C ==
|
||||||
|
object C {
|
||||||
|
operator fun X.invoke() = println("Hello!")
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== invoke ==
|
||||||
|
operator fun X.invoke() = println("Hello!")
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
mark("Hello!")
|
||||||
|
r("Hello!") -> <v0>
|
||||||
|
mark(println("Hello!"))
|
||||||
|
magic[UNRESOLVED_CALL](println("Hello!")|<v0>, !<v1>) -> <v2>
|
||||||
|
ret(*|<v2>) L1
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== with ==
|
||||||
|
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
v(receiver: T)
|
||||||
|
magic[FAKE_INITIALIZER](receiver: T) -> <v0>
|
||||||
|
w(receiver|<v0>)
|
||||||
|
v(block: T.() -> R)
|
||||||
|
magic[FAKE_INITIALIZER](block: T.() -> R) -> <v1>
|
||||||
|
w(block|<v1>)
|
||||||
|
mark(receiver.block())
|
||||||
|
r(block) -> <v2>
|
||||||
|
r(receiver) -> <v3>
|
||||||
|
mark(block())
|
||||||
|
call(block(), invoke|<v2>, <v3>) -> <v4>
|
||||||
|
ret(*|<v4>) L1
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== use ==
|
||||||
|
fun use() = with(C) {
|
||||||
|
with(B) {
|
||||||
|
A.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
1 <START>
|
||||||
|
r(C) -> <v0>
|
||||||
|
mark({ with(B) { A.foo() } })
|
||||||
|
jmp?(L2) NEXT:[r({ with(B) { A.foo() } }) -> <v1>, d({ with(B) { A.foo() } })]
|
||||||
|
d({ with(B) { A.foo() } }) NEXT:[<SINK>]
|
||||||
|
L2 [after local declaration]:
|
||||||
|
r({ with(B) { A.foo() } }) -> <v1> PREV:[jmp?(L2)]
|
||||||
|
mark(with(C) { with(B) { A.foo() } })
|
||||||
|
call(with(C) { with(B) { A.foo() } }, with|<v0>, <v1>) -> <v2>
|
||||||
|
ret(*|<v2>) L1
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>, d({ with(B) { A.foo() } })]
|
||||||
|
=====================
|
||||||
|
== anonymous_0 ==
|
||||||
|
{
|
||||||
|
with(B) {
|
||||||
|
A.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L3:
|
||||||
|
2 <START>
|
||||||
|
3 mark(with(B) { A.foo() })
|
||||||
|
r(B) -> <v0>
|
||||||
|
mark({ A.foo() })
|
||||||
|
jmp?(L5) NEXT:[r({ A.foo() }) -> <v1>, d({ A.foo() })]
|
||||||
|
d({ A.foo() }) NEXT:[<SINK>]
|
||||||
|
L5 [after local declaration]:
|
||||||
|
r({ A.foo() }) -> <v1> PREV:[jmp?(L5)]
|
||||||
|
mark(with(B) { A.foo() })
|
||||||
|
call(with(B) { A.foo() }, with|<v0>, <v1>) -> <v2>
|
||||||
|
2 ret(*|<v2>) L4
|
||||||
|
L4:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>, d({ A.foo() })]
|
||||||
|
=====================
|
||||||
|
== anonymous_1 ==
|
||||||
|
{
|
||||||
|
A.foo()
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L6:
|
||||||
|
4 <START>
|
||||||
|
5 mark(A.foo())
|
||||||
|
mark(A.foo())
|
||||||
|
magic[IMPLICIT_RECEIVER](foo) -> <v0>
|
||||||
|
mark(A)
|
||||||
|
r(A, Companion) -> <v1>
|
||||||
|
r(foo|<v0>, <v1>) -> <v2>
|
||||||
|
magic[IMPLICIT_RECEIVER](foo()) -> <v3>
|
||||||
|
mark(foo())
|
||||||
|
call(foo(), invoke|<v2>, <v3>) -> <v4>
|
||||||
|
4 ret(*|<v4>) L7
|
||||||
|
L7:
|
||||||
|
<END> NEXT:[<SINK>]
|
||||||
|
error:
|
||||||
|
<ERROR> PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
class A {
|
||||||
|
companion object
|
||||||
|
}
|
||||||
|
|
||||||
|
object B {
|
||||||
|
val A.Companion.foo: X get() = X
|
||||||
|
}
|
||||||
|
|
||||||
|
object X
|
||||||
|
|
||||||
|
object C {
|
||||||
|
operator fun X.invoke() = println("Hello!")
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||||
|
|
||||||
|
fun use() = with(C) {
|
||||||
|
with(B) {
|
||||||
|
A.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
== A ==
|
||||||
|
class A {
|
||||||
|
companion object
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
=====================
|
||||||
|
== B ==
|
||||||
|
object B {
|
||||||
|
val A.Companion.foo: X get() = X
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
=====================
|
||||||
|
== X ==
|
||||||
|
object X
|
||||||
|
---------------------
|
||||||
|
=====================
|
||||||
|
== C ==
|
||||||
|
object C {
|
||||||
|
operator fun X.invoke() = println("Hello!")
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
=====================
|
||||||
|
== invoke ==
|
||||||
|
operator fun X.invoke() = println("Hello!")
|
||||||
|
---------------------
|
||||||
|
println !<v1>: *
|
||||||
|
"Hello!" <v0>: * NEW: r("Hello!") -> <v0>
|
||||||
|
println("Hello!") <v2>: {<: [ERROR : Error function type]} NEW: magic[UNRESOLVED_CALL](println("Hello!")|<v0>, !<v1>) -> <v2>
|
||||||
|
=====================
|
||||||
|
== with ==
|
||||||
|
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||||
|
---------------------
|
||||||
|
<v0>: {<: T} NEW: magic[FAKE_INITIALIZER](receiver: T) -> <v0>
|
||||||
|
<v1>: {<: T.() -> R} NEW: magic[FAKE_INITIALIZER](block: T.() -> R) -> <v1>
|
||||||
|
receiver <v3>: {<: T} NEW: r(receiver) -> <v3>
|
||||||
|
block <v2>: {<: (T) -> R} NEW: r(block) -> <v2>
|
||||||
|
block() <v4>: {<: R} NEW: call(block(), invoke|<v2>, <v3>) -> <v4>
|
||||||
|
receiver.block() <v4>: {<: R} COPY
|
||||||
|
=====================
|
||||||
|
== use ==
|
||||||
|
fun use() = with(C) {
|
||||||
|
with(B) {
|
||||||
|
A.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
C <v0>: C NEW: r(C) -> <v0>
|
||||||
|
{ with(B) { A.foo() } } <v1>: {<: C.() -> ???} NEW: r({ with(B) { A.foo() } }) -> <v1>
|
||||||
|
with(C) { with(B) { A.foo() } } <v2>: {<: [ERROR : Error function type]} NEW: call(with(C) { with(B) { A.foo() } }, with|<v0>, <v1>) -> <v2>
|
||||||
|
=====================
|
||||||
|
== anonymous_0 ==
|
||||||
|
{
|
||||||
|
with(B) {
|
||||||
|
A.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
B <v0>: B NEW: r(B) -> <v0>
|
||||||
|
{ A.foo() } <v1>: {<: B.() -> ???} NEW: r({ A.foo() }) -> <v1>
|
||||||
|
with(B) { A.foo() } <v2>: {<: ???} NEW: call(with(B) { A.foo() }, with|<v0>, <v1>) -> <v2>
|
||||||
|
with(B) { A.foo() } <v2>: {<: ???} COPY
|
||||||
|
=====================
|
||||||
|
== anonymous_1 ==
|
||||||
|
{
|
||||||
|
A.foo()
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
<v0>: B NEW: magic[IMPLICIT_RECEIVER](foo) -> <v0>
|
||||||
|
<v3>: C NEW: magic[IMPLICIT_RECEIVER](foo()) -> <v3>
|
||||||
|
A <v1>: A.Companion NEW: r(A, Companion) -> <v1>
|
||||||
|
foo <v2>: X NEW: r(foo|<v0>, <v1>) -> <v2>
|
||||||
|
foo() <v4>: {<: [ERROR : Error function type]} NEW: call(foo(), invoke|<v2>, <v3>) -> <v4>
|
||||||
|
A.foo() <v4>: {<: [ERROR : Error function type]} COPY
|
||||||
|
A.foo() <v4>: {<: [ERROR : Error function type]} COPY
|
||||||
|
=====================
|
||||||
@@ -4,5 +4,5 @@ fun <T> foo() {
|
|||||||
}
|
}
|
||||||
---------------------
|
---------------------
|
||||||
T <v0>: * NEW: magic[UNRESOLVED_CALL](T) -> <v0>
|
T <v0>: * NEW: magic[UNRESOLVED_CALL](T) -> <v0>
|
||||||
{ T } <v0>: * COPY
|
{ T } <v0>: * COPY
|
||||||
=====================
|
=====================
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// FILE: Owner.java
|
||||||
|
|
||||||
|
public class Owner {
|
||||||
|
public static final String name = "Owner";
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: Use.kt
|
||||||
|
|
||||||
|
val x = Owner.name
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public val x: kotlin.String = "Owner"
|
||||||
|
|
||||||
|
public open class Owner {
|
||||||
|
public constructor Owner()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
public const final val name: kotlin.String = "Owner"
|
||||||
|
}
|
||||||
@@ -374,6 +374,18 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/classesAndObjects/delegationBySuperCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/classesAndObjects/delegationBySuperCall.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ObjectEnumQualifiers.kt")
|
||||||
|
public void testObjectEnumQualifiers() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/classesAndObjects/ObjectEnumQualifiers.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("QualifierReceiverWithOthers.kt")
|
||||||
|
public void testQualifierReceiverWithOthers() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/classesAndObjects/QualifierReceiverWithOthers.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/cfg/declarations/functionLiterals")
|
@TestMetadata("compiler/testData/cfg/declarations/functionLiterals")
|
||||||
|
|||||||
@@ -376,6 +376,18 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/classesAndObjects/delegationBySuperCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/classesAndObjects/delegationBySuperCall.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ObjectEnumQualifiers.kt")
|
||||||
|
public void testObjectEnumQualifiers() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/classesAndObjects/ObjectEnumQualifiers.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("QualifierReceiverWithOthers.kt")
|
||||||
|
public void testQualifierReceiverWithOthers() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/classesAndObjects/QualifierReceiverWithOthers.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/cfg/declarations/functionLiterals")
|
@TestMetadata("compiler/testData/cfg/declarations/functionLiterals")
|
||||||
|
|||||||
@@ -13959,6 +13959,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("JavaQualifier.kt")
|
||||||
|
public void testJavaQualifier() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/qualifiedExpression/JavaQualifier.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("PackageVsClass.kt")
|
@TestMetadata("PackageVsClass.kt")
|
||||||
public void testPackageVsClass() throws Exception {
|
public void testPackageVsClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user