Debugger: Fix evaluation for local extension functions (KT-13188)

This commit is contained in:
Yan Zhulanow
2019-04-16 22:29:57 +03:00
parent 8b3c22cea6
commit cbbb3c35da
5 changed files with 49 additions and 17 deletions
@@ -122,7 +122,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
val functionalTypeExpected = expectedType.isBuiltinFunctionalType()
// We forbid anonymous function expressions to suspend type coercion for now, until `suspend fun` syntax is supported
val resultType = functionDescriptor.createFunctionType(suspendFunction = false)
val resultType = functionDescriptor.createFunctionType(components.builtIns, suspendFunction = false)
if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) && functionalTypeExpected && !expectedType.isSuspendFunctionType)
createTypeInfo(resultType, context)
@@ -131,18 +131,6 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
}
}
private fun SimpleFunctionDescriptor.createFunctionType(suspendFunction: Boolean = false): KotlinType? {
return createFunctionType(
components.builtIns,
Annotations.EMPTY,
extensionReceiverParameter?.type,
valueParameters.map { it.type },
null,
returnType ?: return null,
suspendFunction = suspendFunction
)
}
override fun visitLambdaExpression(expression: KtLambdaExpression, context: ExpressionTypingContext): KotlinTypeInfo? {
checkReservedYieldBeforeLambda(expression, context.trace)
if (!expression.functionLiteral.hasBody()) return null
@@ -159,7 +147,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
val safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected)
functionDescriptor.setReturnType(safeReturnType)
val resultType = functionDescriptor.createFunctionType(suspendFunctionTypeExpected)!!
val resultType = functionDescriptor.createFunctionType(components.builtIns, suspendFunctionTypeExpected)!!
if (functionTypeExpected) {
// all checks were done before
return createTypeInfo(resultType, context)
@@ -365,3 +353,15 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
return returns
}
}
fun SimpleFunctionDescriptor.createFunctionType(builtIns: KotlinBuiltIns, suspendFunction: Boolean = false): KotlinType? {
return createFunctionType(
builtIns,
Annotations.EMPTY,
extensionReceiverParameter?.type,
valueParameters.map { it.type },
null,
returnType ?: return null,
suspendFunction = suspendFunction
)
}
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory.Com
import org.jetbrains.kotlin.idea.debugger.safeLocation
import org.jetbrains.kotlin.idea.debugger.safeMethod
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
@@ -28,12 +27,14 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_3_FQ_NAME
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.createFunctionType
class CodeFragmentParameterInfo(
val parameters: List<Smart>,
@@ -262,8 +263,8 @@ class CodeFragmentParameterAnalyzer(
}
return when (target) {
is FunctionDescriptor -> {
val type = SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(target, false)
is SimpleFunctionDescriptor -> {
val type = target.createFunctionType(target.builtIns, target.isSuspend) ?: return null
parameters.getOrPut(target) {
Smart(Dumb(Kind.LOCAL_FUNCTION, target.name.asString()), type, target)
}
@@ -0,0 +1,17 @@
package localFunctionsWithReceivers
fun main() {
fun String.foo(s: String) = this + 1
fun String.foo() = this + 2
val x = "a".foo("b")
val y = "b".foo()
//Breakpoint!
val a = x + y
}
// EXPRESSION: "a".foo("b")
// RESULT: "a1": Ljava/lang/String;
// EXPRESSION: "b".foo()
// RESULT: "b2": Ljava/lang/String;
@@ -0,0 +1,9 @@
LineBreakpoint created at localFunctionsWithReceivers.kt:10
Run Java
Connected to the target VM
localFunctionsWithReceivers.kt:10
Compile bytecode for "a".foo("b")
Compile bytecode for "b".foo()
Disconnected from the target VM
Process finished with exit code 0
@@ -296,6 +296,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/localClass.kt");
}
@TestMetadata("localFunctionsWithReceivers.kt")
public void testLocalFunctionsWithReceivers() throws Exception {
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/localFunctionsWithReceivers.kt");
}
@TestMetadata("localVariables.kt")
public void testLocalVariables() throws Exception {
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/localVariables.kt");