Generic type arguments inference for lambdas as suspend functions.

This commit is contained in:
Dmitry Petrov
2016-12-14 18:00:52 +03:00
committed by Stanislav Erokhin
parent bf987cff5f
commit 6d73e13798
10 changed files with 55 additions and 26 deletions
@@ -17,10 +17,7 @@
package org.jetbrains.kotlin.resolve package org.jetbrains.kotlin.resolve
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
@@ -239,7 +236,7 @@ class FunctionDescriptorResolver(
return replaceAnnotations(AnnotationsImpl(annotations.filter { it != parameterNameAnnotation })) return replaceAnnotations(AnnotationsImpl(annotations.filter { it != parameterNameAnnotation }))
} }
private fun KotlinType.functionTypeExpected() = !TypeUtils.noExpectedType(this) && isFunctionType private fun KotlinType.functionTypeExpected() = !TypeUtils.noExpectedType(this) && isBuiltinFunctionalType
private fun KotlinType.getReceiverType(): KotlinType? = private fun KotlinType.getReceiverType(): KotlinType? =
if (functionTypeExpected()) this.getReceiverTypeFromFunctionType() else null if (functionTypeExpected()) this.getReceiverTypeFromFunctionType() else null
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.callResolverUtil
import com.google.common.collect.Lists import com.google.common.collect.Lists
import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptorImpl
import org.jetbrains.kotlin.lexer.KtToken import org.jetbrains.kotlin.lexer.KtToken
@@ -50,19 +51,19 @@ enum class ResolveArgumentsMode {
fun hasUnknownFunctionParameter(type: KotlinType): Boolean { fun hasUnknownFunctionParameter(type: KotlinType): Boolean {
assert(ReflectionTypes.isCallableType(type)) { "type $type is not a function or property" } assert(ReflectionTypes.isCallableType(type) || type.isSuspendFunctionType) { "type $type is not a function or property" }
return getParameterArgumentsOfCallableType(type).any { return getParameterArgumentsOfCallableType(type).any {
it.type.contains { TypeUtils.isDontCarePlaceholder(it) } || ErrorUtils.containsUninferredParameter(it.type) it.type.contains { TypeUtils.isDontCarePlaceholder(it) } || ErrorUtils.containsUninferredParameter(it.type)
} }
} }
fun hasUnknownReturnType(type: KotlinType): Boolean { fun hasUnknownReturnType(type: KotlinType): Boolean {
assert(ReflectionTypes.isCallableType(type)) { "type $type is not a function or property" } assert(ReflectionTypes.isCallableType(type) || type.isSuspendFunctionType) { "type $type is not a function or property" }
return ErrorUtils.containsErrorType(getReturnTypeForCallable(type)) return ErrorUtils.containsErrorType(getReturnTypeForCallable(type))
} }
fun replaceReturnTypeForCallable(type: KotlinType, given: KotlinType): KotlinType { fun replaceReturnTypeForCallable(type: KotlinType, given: KotlinType): KotlinType {
assert(ReflectionTypes.isCallableType(type)) { "type $type is not a function or property" } assert(ReflectionTypes.isCallableType(type) || type.isSuspendFunctionType) { "type $type is not a function or property" }
val newArguments = Lists.newArrayList<TypeProjection>() val newArguments = Lists.newArrayList<TypeProjection>()
newArguments.addAll(getParameterArgumentsOfCallableType(type)) newArguments.addAll(getParameterArgumentsOfCallableType(type))
newArguments.add(TypeProjectionImpl(Variance.INVARIANT, given)) newArguments.add(TypeProjectionImpl(Variance.INVARIANT, given))
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
@@ -308,7 +309,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) { if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false) expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false)
} }
if (expectedType == null || !expectedType.isFunctionTypeOrSubtype || hasUnknownFunctionParameter(expectedType)) { if (expectedType == null || !expectedType.isBuiltinFunctionalTypeOrSubtype || hasUnknownFunctionParameter(expectedType)) {
return return
} }
val dataFlowInfoForArguments = context.candidateCall.dataFlowInfoForArguments val dataFlowInfoForArguments = context.candidateCall.dataFlowInfoForArguments
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl.ConstraintKind.EQUAL import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl.ConstraintKind.EQUAL
@@ -448,5 +449,6 @@ internal fun createTypeForFunctionPlaceholder(
functionPlaceholderTypeConstructor.argumentTypes functionPlaceholderTypeConstructor.argumentTypes
} }
val receiverType = if (isExtension) DONT_CARE else null val receiverType = if (isExtension) DONT_CARE else null
return createFunctionType(functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE) return createFunctionType(functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE,
suspendFunction = expectedType.isSuspendFunctionType)
} }
@@ -14,4 +14,4 @@ fun test4(): suspend () -> Unit = useSuspendFn {}
fun test5(sfn: suspend () -> Unit) = ambiguous(sfn) fun test5(sfn: suspend () -> Unit) = ambiguous(sfn)
fun test6(fn: () -> Unit) = ambiguous(fn) fun test6(fn: () -> Unit) = ambiguous(fn)
fun test7(): () -> Unit = ambiguous {} fun test7(): () -> Unit = <!OVERLOAD_RESOLUTION_AMBIGUITY!>ambiguous<!> {}
@@ -0,0 +1,7 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun <T> withS(x: T, sfn: suspend (T) -> Unit) = x
val test1 = withS(100) {}
fun <TT> test2(x: TT) = withS(x) {}
@@ -0,0 +1,5 @@
package
public val test1: kotlin.Int
public fun </*0*/ TT> test2(/*0*/ x: TT): TT
public fun </*0*/ T> withS(/*0*/ x: T, /*1*/ sfn: suspend (T) -> kotlin.Unit): T
@@ -0,0 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun <T1, T2> withS2(x: T1, sfn1: suspend (T1) -> T2, sfn2: suspend (T2) -> Unit): T2 = null!!
val test1 = withS2(100, { "" }, { })
@@ -0,0 +1,4 @@
package
public val test1: kotlin.String
public fun </*0*/ T1, /*1*/ T2> withS2(/*0*/ x: T1, /*1*/ sfn1: suspend (T1) -> T2, /*2*/ sfn2: suspend (T2) -> kotlin.Unit): T2
@@ -41,24 +41,31 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.addToStdlib.check
import java.util.* import java.util.*
val KotlinType.isFunctionTypeOrSubtype: Boolean private fun KotlinType.isTypeOrSubtypeOf(predicate: (KotlinType) -> Boolean): Boolean =
get() = isFunctionType || DFS.dfsFromNode( predicate(this) ||
this, DFS.dfsFromNode(
DFS.Neighbors { it.constructor.supertypes }, this,
DFS.VisitedWithSet(), DFS.Neighbors { it.constructor.supertypes },
object : DFS.AbstractNodeHandler<KotlinType, Boolean>() { DFS.VisitedWithSet(),
private var result = false object : DFS.AbstractNodeHandler<KotlinType, Boolean>() {
private var result = false
override fun beforeChildren(current: KotlinType): Boolean { override fun beforeChildren(current: KotlinType): Boolean {
if (current.isFunctionType) { if (predicate(current)) {
result = true result = true
}
return !result
} }
return !result
}
override fun result() = result override fun result() = result
} }
) )
val KotlinType.isFunctionTypeOrSubtype: Boolean
get() = isTypeOrSubtypeOf { it.isFunctionType }
val KotlinType.isBuiltinFunctionalTypeOrSubtype: Boolean
get() = isTypeOrSubtypeOf { it.isBuiltinFunctionalType }
val KotlinType.isFunctionType: Boolean val KotlinType.isFunctionType: Boolean
get() = constructor.declarationDescriptor?.getFunctionalClassKind() == FunctionClassDescriptor.Kind.Function get() = constructor.declarationDescriptor?.getFunctionalClassKind() == FunctionClassDescriptor.Kind.Function