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
override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C> {
val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = false)
?: return KnownResultProcessor(emptyList())
return ExplicitReceiverScopeTowerProcessor(invokeContext, variableReceiver, ScopeTowerLevel::getFunctions)
}
}
@@ -110,6 +111,7 @@ internal class InvokeExtensionTowerProcessor<C>(
override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C> {
val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = true)
?: return KnownResultProcessor(emptyList())
val invokeDescriptor = functionContext.scopeTower.getExtensionInvokeCandidateDescriptor(variableReceiver)
?: return KnownResultProcessor(emptyList())
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.isAnnotatedAsHidden
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.DeferredType
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -243,7 +244,7 @@ class NewResolveOldInference(
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()) {
"Incorrect status: ${variable.resolvedCall.status} for variable call: ${variable.resolvedCall} " +
"and descriptor: ${variable.resolvedCall.candidateDescriptor}"
@@ -253,8 +254,13 @@ class NewResolveOldInference(
assert(variable.resolvedCall.status.possibleTransformToSuccess() && calleeExpression != null && variableDescriptor is VariableDescriptor) {
"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!!,
(variableDescriptor as VariableDescriptor).type,
variableType,
basicCallContext.trace.bindingContext)
// used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression
tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall)
@@ -39,7 +39,8 @@ interface TowerContext<C> {
fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext<C>
// 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 {
@@ -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);
}
@TestMetadata("InvokeAndRecursiveResolve.kt")
public void testInvokeAndRecursiveResolve() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/InvokeAndRecursiveResolve.kt");
doTest(fileName);
}
@TestMetadata("IsExpressions.kt")
public void testIsExpressions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/IsExpressions.kt");