diff --git a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/lib/sequence/KotlinSequencesSupport.kt b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/lib/sequence/KotlinSequencesSupport.kt index 7c5b40f76e7..8db6d852847 100644 --- a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/lib/sequence/KotlinSequencesSupport.kt +++ b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/lib/sequence/KotlinSequencesSupport.kt @@ -2,13 +2,15 @@ package com.intellij.debugger.streams.kotlin.lib.sequence import com.intellij.debugger.streams.kotlin.resolve.ChunkedResolver -import com.intellij.debugger.streams.kotlin.resolve.MapNotNullResolver +import com.intellij.debugger.streams.kotlin.resolve.FilteredMapResolver import com.intellij.debugger.streams.kotlin.resolve.WindowedResolver +import com.intellij.debugger.streams.kotlin.trace.impl.handler.sequence.FilterIsInstanceHandler import com.intellij.debugger.streams.lib.IntermediateOperation import com.intellij.debugger.streams.lib.impl.* import com.intellij.debugger.streams.resolve.AppendResolver import com.intellij.debugger.streams.resolve.PairMapResolver import com.intellij.debugger.streams.trace.impl.handler.unified.DistinctTraceHandler +import com.intellij.debugger.streams.trace.impl.interpret.SimplePeekCallTraceInterpreter /** * @author Vitaliy.Bibaev @@ -16,7 +18,9 @@ import com.intellij.debugger.streams.trace.impl.handler.unified.DistinctTraceHan class KotlinSequencesSupport : LibrarySupportBase() { init { addIntermediateOperationsSupport(*filterOperations("filter", "filterNot", "filterIndexed", - "filterIsInstance", "drop", "dropWhile", "minus", "minusElement", "take", "takeWhile", "onEach", "asSequence")) + "drop", "dropWhile", "minus", "minusElement", "take", "takeWhile", "onEach", "asSequence")) + + addIntermediateOperationsSupport(FilterIsInstanceOperationHandler()) addIntermediateOperationsSupport(*mapOperations("map", "mapIndexed", "requireNoNulls", "withIndex", "zip", "constrainOnce")) @@ -33,7 +37,7 @@ class KotlinSequencesSupport : LibrarySupportBase() { addIntermediateOperationsSupport(OrderBasedOperation("zipWithNext", PairMapResolver())) - addIntermediateOperationsSupport(OrderBasedOperation("mapNotNull", MapNotNullResolver())) + addIntermediateOperationsSupport(OrderBasedOperation("mapNotNull", FilteredMapResolver())) addIntermediateOperationsSupport(OrderBasedOperation("chunked", ChunkedResolver())) addIntermediateOperationsSupport(OrderBasedOperation("windowed", WindowedResolver())) } @@ -49,4 +53,8 @@ class KotlinSequencesSupport : LibrarySupportBase() { private fun sortedOperations(vararg names: String): Array = names.map { SortedOperation(it) }.toTypedArray() + + private class FilterIsInstanceOperationHandler() + : IntermediateOperationBase("filterIsInstance", ::FilterIsInstanceHandler, + SimplePeekCallTraceInterpreter(), FilteredMapResolver()) } \ No newline at end of file diff --git a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/resolve/MapNotNullResolver.kt b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/resolve/FilteredMapResolver.kt similarity index 96% rename from idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/resolve/MapNotNullResolver.kt rename to idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/resolve/FilteredMapResolver.kt index e22d26ced72..c3da36d3a2f 100644 --- a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/resolve/MapNotNullResolver.kt +++ b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/resolve/FilteredMapResolver.kt @@ -8,7 +8,7 @@ import com.intellij.debugger.streams.trace.TraceInfo /** * @author Vitaliy.Bibaev */ -class MapNotNullResolver : ValuesOrderResolver { +class FilteredMapResolver : ValuesOrderResolver { override fun resolve(info: TraceInfo): ValuesOrderResolver.Result { val before = info.valuesOrderBefore val after = info.valuesOrderAfter diff --git a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/trace/impl/handler/sequence/FilterIsInstanceHandler.kt b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/trace/impl/handler/sequence/FilterIsInstanceHandler.kt new file mode 100644 index 00000000000..fd6d4df25b0 --- /dev/null +++ b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/trace/impl/handler/sequence/FilterIsInstanceHandler.kt @@ -0,0 +1,77 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.debugger.streams.kotlin.trace.impl.handler.sequence + +import com.intellij.debugger.streams.kotlin.trace.dsl.KotlinTypes +import com.intellij.debugger.streams.trace.dsl.CodeBlock +import com.intellij.debugger.streams.trace.dsl.Dsl +import com.intellij.debugger.streams.trace.dsl.Expression +import com.intellij.debugger.streams.trace.dsl.VariableDeclaration +import com.intellij.debugger.streams.trace.impl.handler.unified.HandlerBase +import com.intellij.debugger.streams.trace.impl.handler.unified.PeekTraceHandler +import com.intellij.debugger.streams.wrapper.CallArgument +import com.intellij.debugger.streams.wrapper.IntermediateStreamCall +import com.intellij.debugger.streams.wrapper.impl.CallArgumentImpl +import com.intellij.debugger.streams.wrapper.impl.IntermediateStreamCallImpl +import com.intellij.openapi.util.TextRange.EMPTY_RANGE + +/** + * @author Vitaliy.Bibaev + */ +class FilterIsInstanceHandler(num: Int, call: IntermediateStreamCall, dsl: Dsl) : HandlerBase.Intermediate(dsl) { + private companion object { + fun createHandler(num: Int, call: IntermediateStreamCall, dsl: Dsl): HandlerBase.Intermediate = + if (call.arguments.isEmpty()) MyWithGenericsHandler(num, call, dsl) + else PeekTraceHandler(num, call.name, call.typeBefore, call.typeAfter, dsl) + } + + private val filterHandler = createHandler(num, call, dsl) + + // use explicit delegation to avoid issues with navigation + + override fun additionalCallsAfter(): MutableList = filterHandler.additionalCallsAfter() + override fun additionalCallsBefore(): List = filterHandler.additionalCallsBefore() + override fun additionalVariablesDeclaration(): List = filterHandler.additionalVariablesDeclaration() + override fun getResultExpression(): Expression = filterHandler.resultExpression + override fun prepareResult(): CodeBlock = filterHandler.prepareResult() + override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall = filterHandler.transformCall(call) + + /* + * Transforms filterIsInstance -> filter { it is ClassName }.map { it as ClassName } + */ + private class MyWithGenericsHandler(num: Int, private val call: IntermediateStreamCall, dsl: Dsl) : HandlerBase.Intermediate(dsl) { + private val peekHandler = PeekTraceHandler(num, "filterIsInstance", call.typeBefore, call.typeAfter, dsl) + override fun additionalCallsAfter(): List { + val mapperType = functionalType(call.typeBefore.genericTypeName, call.typeAfter.genericTypeName) + val mapper = CallArgumentImpl(mapperType, "{ x -> x as ${call.typeAfter.genericTypeName} }") + val result: MutableList = mutableListOf(syntheticMapCall(mapper)) + result.addAll(peekHandler.additionalCallsAfter()) + return result + } + + override fun additionalCallsBefore(): List = peekHandler.additionalCallsBefore() + + override fun additionalVariablesDeclaration(): List = + peekHandler.additionalVariablesDeclaration() + + override fun getResultExpression(): Expression = peekHandler.resultExpression + + override fun prepareResult(): CodeBlock = peekHandler.prepareResult() + + override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall { + val typeAfter = call.typeAfter.genericTypeName + val predicateType = functionalType(typeAfter, KotlinTypes.BOOLEAN.genericTypeName) + val predicate = CallArgumentImpl(predicateType, " { x -> x is $typeAfter} ") + return syntheticFilterCall(predicate) + } + + private fun syntheticMapCall(mapper: CallArgument): IntermediateStreamCall = + IntermediateStreamCallImpl("map", listOf(mapper), call.typeBefore, call.typeAfter, EMPTY_RANGE) + + private fun syntheticFilterCall(predicate: CallArgument): IntermediateStreamCall = + IntermediateStreamCallImpl("filter", listOf(predicate), call.typeBefore, call.typeBefore, EMPTY_RANGE) + + private fun functionalType(argType: String, resultType: String): String { + return "($argType) -> $resultType" + } + } +} \ No newline at end of file diff --git a/idea/testData/debugger/sequence/exec/sequence/outs/filterIsInstance.out b/idea/testData/debugger/sequence/exec/sequence/outs/filterIsInstance.out index 6ee1cb9159f..146be5473d1 100644 --- a/idea/testData/debugger/sequence/exec/sequence/outs/filterIsInstance.out +++ b/idea/testData/debugger/sequence/exec/sequence/outs/filterIsInstance.out @@ -2,13 +2,29 @@ LineBreakpoint created at FilterIsInstance.kt:5 Run Java Connected to the target VM FilterIsInstance.kt:5 -Exception caught: junit.framework.AssertionFailedError: Type inference failed: Not enough information to infer parameter R in inline fun Sequence<*>.filterIsInstance(): Sequence -Please specify it explicitly. -, Type inference failed: Not enough information to infer parameter R in inline fun Sequence<*>.filterIsInstance(): Sequence -Please specify it explicitly. - -WRONG! Should be fixed in the platform - +arrayOf(true, "12", false).asSequence() +.filterIsInstance() +.forEach({}) +filterIsInstance + before: 1,3,4 + after: 2,5 +forEach + before: 2,5 + after: nothing +mappings for filterIsInstance + direct: + 1 -> 2 + 3 -> nothing + 4 -> 5 + reverse: + 1 <- 2 + 4 <- 5 +mappings for forEach + direct: + 2 -> nothing + 5 -> nothing + reverse: + empty Disconnected from the target VM Process finished with exit code 0