Support filterIsInstance with generic parameter

This commit is contained in:
Vitaliy.Bibaev
2017-12-25 15:38:58 +03:00
committed by Yan Zhulanow
parent e9d8398573
commit bfced7dd1e
4 changed files with 112 additions and 11 deletions
@@ -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<IntermediateOperation> =
names.map { SortedOperation(it) }.toTypedArray()
private class FilterIsInstanceOperationHandler()
: IntermediateOperationBase("filterIsInstance", ::FilterIsInstanceHandler,
SimplePeekCallTraceInterpreter(), FilteredMapResolver())
}
@@ -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
@@ -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<IntermediateStreamCall> = filterHandler.additionalCallsAfter()
override fun additionalCallsBefore(): List<IntermediateStreamCall> = filterHandler.additionalCallsBefore()
override fun additionalVariablesDeclaration(): List<VariableDeclaration> = 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<ClassName> -> 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<IntermediateStreamCall> {
val mapperType = functionalType(call.typeBefore.genericTypeName, call.typeAfter.genericTypeName)
val mapper = CallArgumentImpl(mapperType, "{ x -> x as ${call.typeAfter.genericTypeName} }")
val result: MutableList<IntermediateStreamCall> = mutableListOf(syntheticMapCall(mapper))
result.addAll(peekHandler.additionalCallsAfter())
return result
}
override fun additionalCallsBefore(): List<IntermediateStreamCall> = peekHandler.additionalCallsBefore()
override fun additionalVariablesDeclaration(): List<VariableDeclaration> =
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"
}
}
}
@@ -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 <reified R> Sequence<*>.filterIsInstance(): Sequence<R>
Please specify it explicitly.
, Type inference failed: Not enough information to infer parameter R in inline fun <reified R> Sequence<*>.filterIsInstance(): Sequence<R>
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