Do not enter in recursion for implicit invoke on variable with un inferred type

This commit is contained in:
Stanislav Erokhin
2015-12-08 15:11:50 +03:00
parent 1dca49cecc
commit 66a031f7a0
6 changed files with 63 additions and 3 deletions
@@ -96,6 +96,7 @@ internal class InvokeTowerProcessor<C>(
// todo filter by operator // todo filter by operator
override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C> { override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C> {
val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = false) val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = false)
?: return KnownResultProcessor(emptyList())
return ExplicitReceiverScopeTowerProcessor(invokeContext, variableReceiver, ScopeTowerLevel::getFunctions) return ExplicitReceiverScopeTowerProcessor(invokeContext, variableReceiver, ScopeTowerLevel::getFunctions)
} }
} }
@@ -110,6 +111,7 @@ internal class InvokeExtensionTowerProcessor<C>(
override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C> { override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C> {
val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = true) val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = true)
?: return KnownResultProcessor(emptyList())
val invokeDescriptor = functionContext.scopeTower.getExtensionInvokeCandidateDescriptor(variableReceiver) val invokeDescriptor = functionContext.scopeTower.getExtensionInvokeCandidateDescriptor(variableReceiver)
?: return KnownResultProcessor(emptyList()) ?: return KnownResultProcessor(emptyList())
return InvokeExtensionScopeTowerProcessor(invokeContext, invokeDescriptor, explicitReceiver) return InvokeExtensionScopeTowerProcessor(invokeContext, invokeDescriptor, explicitReceiver)
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyForInvoke import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyForInvoke
import org.jetbrains.kotlin.resolve.isAnnotatedAsHidden import org.jetbrains.kotlin.resolve.isAnnotatedAsHidden
import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.DeferredType
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.isDynamic import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -243,7 +244,7 @@ class NewResolveOldInference(
return Context(scopeTower, name, basicCallResolutionContext, tracing) return Context(scopeTower, name, basicCallResolutionContext, tracing)
} }
override fun contextForInvoke(variable: Candidate, useExplicitReceiver: Boolean): Pair<ReceiverValue, TowerContext<Candidate>> { override fun contextForInvoke(variable: Candidate, useExplicitReceiver: Boolean): Pair<ReceiverValue, TowerContext<Candidate>>? {
assert(variable.resolvedCall.status.possibleTransformToSuccess()) { assert(variable.resolvedCall.status.possibleTransformToSuccess()) {
"Incorrect status: ${variable.resolvedCall.status} for variable call: ${variable.resolvedCall} " + "Incorrect status: ${variable.resolvedCall.status} for variable call: ${variable.resolvedCall} " +
"and descriptor: ${variable.resolvedCall.candidateDescriptor}" "and descriptor: ${variable.resolvedCall.candidateDescriptor}"
@@ -253,8 +254,13 @@ class NewResolveOldInference(
assert(variable.resolvedCall.status.possibleTransformToSuccess() && calleeExpression != null && variableDescriptor is VariableDescriptor) { assert(variable.resolvedCall.status.possibleTransformToSuccess() && calleeExpression != null && variableDescriptor is VariableDescriptor) {
"Unexpected varialbe candidate: $variable" "Unexpected varialbe candidate: $variable"
} }
val variableType = (variableDescriptor as VariableDescriptor).type
if (variableType is DeferredType && variableType.isComputing) {
return null // todo: create special check that there is no invoke on variable
}
val variableReceiver = ExpressionReceiver.create(calleeExpression!!, val variableReceiver = ExpressionReceiver.create(calleeExpression!!,
(variableDescriptor as VariableDescriptor).type, variableType,
basicCallContext.trace.bindingContext) basicCallContext.trace.bindingContext)
// used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression // used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression
tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall) tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall)
@@ -39,7 +39,8 @@ interface TowerContext<C> {
fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext<C> fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext<C>
// foo() -> ReceiverValue(foo), context for invoke // foo() -> ReceiverValue(foo), context for invoke
fun contextForInvoke(variable: C, useExplicitReceiver: Boolean): Pair<ReceiverValue, TowerContext<C>> // null means that there is no invoke on variable
fun contextForInvoke(variable: C, useExplicitReceiver: Boolean): Pair<ReceiverValue, TowerContext<C>>?
} }
internal sealed class TowerData { internal sealed class TowerData {
@@ -0,0 +1,16 @@
fun test() = 3
fun <T> proxy(t: T) = t
class A {
val test = test()
}
class B {
val test = proxy(test())
}
class C {
val bar = <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!><!UNINITIALIZED_VARIABLE!>test<!>()<!>
val test = <!FUNCTION_EXPECTED!>bar<!>()
}
@@ -0,0 +1,29 @@
package
public fun </*0*/ T> proxy(/*0*/ t: T): T
public fun test(): kotlin.Int
public final class A {
public constructor A()
public final val test: kotlin.Int
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
}
public final class B {
public constructor B()
public final val test: kotlin.Int
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
}
public final class C {
public constructor C()
public final val bar: [ERROR : <ERROR FUNCTION RETURN TYPE>]
public final val test: [ERROR : Type for bar()]
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
}
@@ -325,6 +325,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("InvokeAndRecursiveResolve.kt")
public void testInvokeAndRecursiveResolve() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/InvokeAndRecursiveResolve.kt");
doTest(fileName);
}
@TestMetadata("IsExpressions.kt") @TestMetadata("IsExpressions.kt")
public void testIsExpressions() throws Exception { public void testIsExpressions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/IsExpressions.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/IsExpressions.kt");