Introduce 'SuspendFunction$n<...>' types.

This commit is contained in:
Dmitry Petrov
2016-12-14 13:45:34 +03:00
committed by Stanislav Erokhin
parent a15d423db4
commit 6e1340da82
8 changed files with 113 additions and 20 deletions
@@ -134,7 +134,7 @@ class TypeResolver(
val typeElement = typeReference.typeElement
val type = resolveTypeElement(c, annotations, typeElement)
val type = resolveTypeElement(c, annotations, typeReference.modifierList, typeElement)
c.trace.recordScope(c.scope, typeReference)
if (!type.isBare) {
@@ -175,8 +175,14 @@ class TypeResolver(
}
}
private fun resolveTypeElement(c: TypeResolutionContext, annotations: Annotations, typeElement: KtTypeElement?): PossiblyBareType {
private fun resolveTypeElement(c: TypeResolutionContext, annotations: Annotations, modifiers: KtModifierList?, typeElement: KtTypeElement?): PossiblyBareType {
var result: PossiblyBareType? = null
val hasSuspendModifier = modifiers?.hasModifier(KtTokens.SUSPEND_KEYWORD) ?: false
if (hasSuspendModifier && typeElement !is KtFunctionType) {
c.trace.report(Errors.WRONG_MODIFIER_TARGET.on(modifiers!!.getModifier(KtTokens.SUSPEND_KEYWORD)!!, KtTokens.SUSPEND_KEYWORD, "non-functional type"))
}
typeElement?.accept(object : KtVisitorVoid() {
override fun visitUserType(type: KtUserType) {
val qualifierResolutionResult = resolveDescriptorForType(c.scope, type, c.trace, c.isDebuggerContext)
@@ -198,7 +204,7 @@ class TypeResolver(
override fun visitNullableType(nullableType: KtNullableType) {
val innerType = nullableType.getInnerType()
val baseType = resolveTypeElement(c, annotations, innerType)
val baseType = resolveTypeElement(c, annotations, modifiers, innerType)
if (baseType.isNullable || innerType is KtNullableType || innerType is KtDynamicType) {
c.trace.report(REDUNDANT_NULLABLE.on(nullableType))
}
@@ -219,7 +225,8 @@ class TypeResolver(
moduleDescriptor.builtIns, annotations, receiverType,
parameterDescriptors.map { it.type },
parameterDescriptors.map { it.name },
returnType
returnType,
suspendFunction = hasSuspendModifier
))
}
@@ -0,0 +1,14 @@
typealias Action = () -> Unit
interface SAM {
fun run()
}
typealias Test1 = suspend () -> Unit
typealias Test2 = suspend Int.(String) -> Unit
typealias Test3 = <!WRONG_MODIFIER_TARGET!>suspend<!> Function0<Unit>
typealias Test4 = <!WRONG_MODIFIER_TARGET!>suspend<!> Action
typealias Test5 = List<suspend () -> Unit>
typealias Test6 = <!WRONG_MODIFIER_TARGET!>suspend<!> List<() -> Unit>
typealias Test7 = <!WRONG_MODIFIER_TARGET!>suspend<!> SAM
typealias Test8 = SuspendFunction0<Unit>
@@ -0,0 +1,17 @@
package
public interface SAM {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public typealias Action = () -> kotlin.Unit
public typealias Test1 = suspend () -> kotlin.Unit
public typealias Test2 = suspend kotlin.Int.(kotlin.String) -> kotlin.Unit
public typealias Test3 = () -> kotlin.Unit
public typealias Test4 = Action
public typealias Test5 = kotlin.collections.List<suspend () -> kotlin.Unit>
public typealias Test6 = kotlin.collections.List<() -> kotlin.Unit>
public typealias Test7 = SAM
public typealias Test8 = suspend () -> kotlin.Unit
@@ -523,6 +523,11 @@ public abstract class KotlinBuiltIns {
return "Function" + parameterCount;
}
@NotNull
public static String getSuspendFunctionName(int parameterCount) {
return "SuspendFunction" + parameterCount;
}
@NotNull
public static ClassId getFunctionClassId(int parameterCount) {
return new ClassId(BUILT_INS_PACKAGE_FQ_NAME, Name.identifier(getFunctionName(parameterCount)));
@@ -533,6 +538,11 @@ public abstract class KotlinBuiltIns {
return getBuiltInClassByName(getFunctionName(parameterCount));
}
@NotNull
public ClassDescriptor getSuspendFunction(int parameterCount) {
return getBuiltInClassByName(getSuspendFunctionName(parameterCount));
}
@NotNull
public ClassDescriptor getThrowable() {
return getBuiltInClassByName("Throwable");
@@ -18,6 +18,9 @@ package org.jetbrains.kotlin.builtins
import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
@@ -57,16 +60,23 @@ val KotlinType.isFunctionTypeOrSubtype: Boolean
)
val KotlinType.isFunctionType: Boolean
get() = constructor.declarationDescriptor?.getFunctionalClassKind() == FunctionClassDescriptor.Kind.Function
val KotlinType.isSuspendFunctionType: Boolean
get() = constructor.declarationDescriptor?.getFunctionalClassKind() == FunctionClassDescriptor.Kind.SuspendFunction
val KotlinType.isBuiltinFunctionalType: Boolean
get() {
val descriptor = constructor.declarationDescriptor
return descriptor != null && isNumberedFunctionClassFqName(descriptor.fqNameUnsafe)
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
return kind == FunctionClassDescriptor.Kind.Function ||
kind == FunctionClassDescriptor.Kind.SuspendFunction
}
val KotlinType.isNonExtensionFunctionType: Boolean
get() = isFunctionType && !isTypeAnnotatedWithExtensionFunctionType
get() = isBuiltinFunctionalType && !isTypeAnnotatedWithExtensionFunctionType
val KotlinType.isExtensionFunctionType: Boolean
get() = isFunctionType && isTypeAnnotatedWithExtensionFunctionType
get() = isBuiltinFunctionalType && isTypeAnnotatedWithExtensionFunctionType
private val KotlinType.isTypeAnnotatedWithExtensionFunctionType: Boolean
get() = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null
@@ -85,18 +95,29 @@ fun isNumberedFunctionClassFqName(fqName: FqNameUnsafe): Boolean {
return BuiltInFictitiousFunctionClassFactory.isFunctionClassName(shortName, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
}
fun DeclarationDescriptor.getFunctionalClassKind(): FunctionClassDescriptor.Kind? {
if (this !is ClassDescriptor) return null
val fqNameUnsafe = this.fqNameUnsafe
if (!fqNameUnsafe.isSafe || fqNameUnsafe.isRoot) return null
val fqName = fqNameUnsafe.toSafe()
return BuiltInFictitiousFunctionClassFactory.getFunctionalClassKind(fqName.shortName().asString(), fqName.parent())
}
fun KotlinType.getReceiverTypeFromFunctionType(): KotlinType? {
assert(isFunctionType) { "Not a function type: ${this}" }
assert(isBuiltinFunctionalType) { "Not a function type: ${this}" }
return if (isTypeAnnotatedWithExtensionFunctionType) arguments.first().type else null
}
fun KotlinType.getReturnTypeFromFunctionType(): KotlinType {
assert(isFunctionType) { "Not a function type: ${this}" }
assert(isBuiltinFunctionalType) { "Not a function type: ${this}" }
return arguments.last().type
}
fun KotlinType.getValueParameterTypesFromFunctionType(): List<TypeProjection> {
assert(isFunctionType) { "Not a function type: ${this}" }
assert(isBuiltinFunctionalType) { "Not a function type: ${this}" }
val arguments = arguments
val first = if (isExtensionFunctionType) 1 else 0
val last = arguments.size - 1
@@ -147,17 +168,20 @@ fun getFunctionTypeArgumentProjections(
return arguments
}
@JvmOverloads
fun createFunctionType(
builtIns: KotlinBuiltIns,
annotations: Annotations,
receiverType: KotlinType?,
parameterTypes: List<KotlinType>,
parameterNames: List<Name>?,
returnType: KotlinType
returnType: KotlinType,
suspendFunction: Boolean = false
): SimpleType {
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns)
val size = parameterTypes.size
val classDescriptor = builtIns.getFunction(if (receiverType == null) size else size + 1)
val parameterCount = if (receiverType == null) size else size + 1
val classDescriptor = if (suspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount)
val typeAnnotations =
if (receiverType == null || annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null) {
@@ -38,10 +38,9 @@ class BuiltInFictitiousFunctionClassFactory(
companion object {
private fun parseClassName(className: String, packageFqName: FqName): KindWithArity? {
val kind = FunctionClassDescriptor.Kind.byPackage(packageFqName) ?: return null
val kind = FunctionClassDescriptor.Kind.byClassNamePrefix(packageFqName, className) ?: return null
val prefix = kind.classNamePrefix
if (!className.startsWith(prefix)) return null
val arity = toInt(className.substring(prefix.length)) ?: return null
@@ -49,8 +48,14 @@ class BuiltInFictitiousFunctionClassFactory(
return KindWithArity(kind, arity)
}
@JvmStatic fun getFunctionalClassKind(className: String, packageFqName: FqName) =
parseClassName(className, packageFqName)?.kind
@JvmStatic fun isFunctionClassName(className: String, packageFqName: FqName) =
parseClassName(className, packageFqName) != null
getFunctionalClassKind(className, packageFqName) == Kind.Function
@JvmStatic fun isSuspendFunctionClassName(className: String, packageFqName: FqName) =
getFunctionalClassKind(className, packageFqName) == Kind.SuspendFunction
private fun toInt(s: String): Int? {
if (s.isEmpty()) return null
@@ -67,7 +72,7 @@ class BuiltInFictitiousFunctionClassFactory(
override fun shouldCreateClass(packageFqName: FqName, name: Name): Boolean {
val string = name.asString()
return (string.startsWith("Function") || string.startsWith("KFunction")) // an optimization
return (string.startsWith("Function") || string.startsWith("KFunction") || string.startsWith("SuspendFunction")) // an optimization
&& parseClassName(string, packageFqName) != null
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.*
@@ -49,6 +50,7 @@ class FunctionClassDescriptor(
enum class Kind(val packageFqName: FqName, val classNamePrefix: String) {
Function(BUILT_INS_PACKAGE_FQ_NAME, "Function"),
SuspendFunction(BUILT_INS_PACKAGE_FQ_NAME, "SuspendFunction"),
KFunction(KOTLIN_REFLECT_FQ_NAME, "KFunction");
fun numberedClassName(arity: Int) = Name.identifier("$classNamePrefix$arity")
@@ -59,6 +61,9 @@ class FunctionClassDescriptor(
KOTLIN_REFLECT_FQ_NAME -> KFunction
else -> null
}
fun byClassNamePrefix(packageFqName: FqName, className: String) =
Kind.values().firstOrNull { it.packageFqName == packageFqName && className.startsWith(it.classNamePrefix) }
}
}
@@ -128,8 +133,15 @@ class FunctionClassDescriptor(
result.add(KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, descriptor, arguments))
}
// Add unnumbered base class, e.g. Function for Function{n}, KFunction for KFunction{n}
add(containingDeclaration, Name.identifier(functionKind.classNamePrefix))
if (functionKind == Kind.SuspendFunction) {
// SuspendFunction$N<...> <: Any
result.add(containingDeclaration.builtIns.anyType)
}
else {
// Add unnumbered base class, e.g. Function for Function{n}, KFunction for KFunction{n}
add(containingDeclaration, Name.identifier(functionKind.classNamePrefix))
}
// For KFunction{n}, add corresponding numbered Function{n} class, e.g. Function2 for KFunction2
if (functionKind == Kind.KFunction) {
@@ -196,7 +196,7 @@ internal class DescriptorRendererImpl(
}
private fun shouldRenderAsPrettyFunctionType(type: KotlinType): Boolean {
return type.isFunctionType && type.arguments.none { it.isStarProjection }
return type.isBuiltinFunctionalType && type.arguments.none { it.isStarProjection }
}
override fun renderFlexibleType(lowerRendered: String, upperRendered: String, builtIns: KotlinBuiltIns): String {
@@ -322,6 +322,10 @@ internal class DescriptorRendererImpl(
if (needParenthesis) append("(")
if (type.isSuspendFunctionType) {
append("suspend ") // anything special about modifier?
}
if (receiverType != null) {
val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) && !receiverType.isMarkedNullable
if (surroundReceiver) {