Fix "Specify type explicitly" intention with generic type

#KT-27641 Fixed
 #KT-30252 Fixed
This commit is contained in:
Dmitry Gridin
2019-03-11 18:26:10 +07:00
parent 57040f6f9d
commit 6b8547f57b
25 changed files with 272 additions and 38 deletions
@@ -18,7 +18,10 @@
package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.builtins.replaceReturnType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
@@ -124,35 +127,70 @@ fun KotlinType.getResolvableApproximations(
): Sequence<KotlinType> {
return (listOf(this) + TypeUtils.getAllSupertypes(this))
.asSequence()
.filter { it.isResolvableInScope(scope, checkTypeParameters, allowIntersections) }
.mapNotNull mapArgs@{
val resolvableArgs = it.arguments.filterTo(SmartSet.create()) { typeProjection ->
typeProjection.type.isResolvableInScope(
scope,
checkTypeParameters
)
}
if (resolvableArgs.containsAll(it.arguments)) return@mapArgs it
val newArguments = (it.arguments zip it.constructor.parameters).map { pair ->
val (arg, param) = pair
when {
arg in resolvableArgs -> arg
arg.projectionKind == Variance.OUT_VARIANCE ||
param.variance == Variance.OUT_VARIANCE -> TypeProjectionImpl(
arg.projectionKind,
arg.type.approximateWithResolvableType(scope, checkTypeParameters)
)
else -> return@mapArgs null
}
}
it.replace(newArguments)
.mapNotNull {
it.asTypeProjection()
.fixTypeProjection(scope, checkTypeParameters, allowIntersections, isOutVariance = true)
?.type
}
}
private fun TypeProjection.fixTypeProjection(
scope: LexicalScope?,
checkTypeParameters: Boolean,
allowIntersections: Boolean,
isOutVariance: Boolean
): TypeProjection? {
if (!type.isResolvableInScope(scope, checkTypeParameters, allowIntersections)) return null
if (type.arguments.isEmpty()) return this
val resolvableArgs = type.arguments.filterTo(SmartSet.create()) { typeProjection ->
typeProjection.type.isResolvableInScope(scope, checkTypeParameters, allowIntersections)
}
if (resolvableArgs.containsAll(type.arguments)) {
fun fixArguments(type: KotlinType): KotlinType? = type.replace(
(type.arguments zip type.constructor.parameters).map { (arg, param) ->
if (arg.isStarProjection) arg
else arg.fixTypeProjection(
scope,
checkTypeParameters,
allowIntersections,
isOutVariance = isOutVariance && param.variance == Variance.OUT_VARIANCE
) ?: when {
!isOutVariance -> return null
param.variance == Variance.OUT_VARIANCE -> arg.type.approximateWithResolvableType(
scope,
checkTypeParameters
).asTypeProjection()
else -> type.replaceArgumentsWithStarProjections().arguments.first()
}
})
return if (type.isBuiltinFunctionalType) {
val returnType = type.getReturnTypeFromFunctionType()
type.replaceReturnType(fixArguments(returnType) ?: return null).asTypeProjection()
} else fixArguments(type)?.asTypeProjection()
}
if (!isOutVariance) return null
val newArguments = (type.arguments zip type.constructor.parameters).map { (arg, param) ->
when {
arg in resolvableArgs -> arg
arg.projectionKind == Variance.OUT_VARIANCE ||
param.variance == Variance.OUT_VARIANCE -> TypeProjectionImpl(
arg.projectionKind,
arg.type.approximateWithResolvableType(scope, checkTypeParameters)
)
else -> return if (isOutVariance) type.replaceArgumentsWithStarProjections().asTypeProjection() else null
}
}
return type.replace(newArguments).asTypeProjection()
}
fun KotlinType.isAbstract(): Boolean {
val modality = (constructor.declarationDescriptor as? ClassDescriptor)?.modality
return modality == Modality.ABSTRACT || modality == Modality.SEALED