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 typeElement = typeReference.typeElement
val type = resolveTypeElement(c, annotations, typeElement) val type = resolveTypeElement(c, annotations, typeReference.modifierList, typeElement)
c.trace.recordScope(c.scope, typeReference) c.trace.recordScope(c.scope, typeReference)
if (!type.isBare) { 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 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() { typeElement?.accept(object : KtVisitorVoid() {
override fun visitUserType(type: KtUserType) { override fun visitUserType(type: KtUserType) {
val qualifierResolutionResult = resolveDescriptorForType(c.scope, type, c.trace, c.isDebuggerContext) val qualifierResolutionResult = resolveDescriptorForType(c.scope, type, c.trace, c.isDebuggerContext)
@@ -198,7 +204,7 @@ class TypeResolver(
override fun visitNullableType(nullableType: KtNullableType) { override fun visitNullableType(nullableType: KtNullableType) {
val innerType = nullableType.getInnerType() 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) { if (baseType.isNullable || innerType is KtNullableType || innerType is KtDynamicType) {
c.trace.report(REDUNDANT_NULLABLE.on(nullableType)) c.trace.report(REDUNDANT_NULLABLE.on(nullableType))
} }
@@ -219,7 +225,8 @@ class TypeResolver(
moduleDescriptor.builtIns, annotations, receiverType, moduleDescriptor.builtIns, annotations, receiverType,
parameterDescriptors.map { it.type }, parameterDescriptors.map { it.type },
parameterDescriptors.map { it.name }, 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; return "Function" + parameterCount;
} }
@NotNull
public static String getSuspendFunctionName(int parameterCount) {
return "SuspendFunction" + parameterCount;
}
@NotNull @NotNull
public static ClassId getFunctionClassId(int parameterCount) { public static ClassId getFunctionClassId(int parameterCount) {
return new ClassId(BUILT_INS_PACKAGE_FQ_NAME, Name.identifier(getFunctionName(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)); return getBuiltInClassByName(getFunctionName(parameterCount));
} }
@NotNull
public ClassDescriptor getSuspendFunction(int parameterCount) {
return getBuiltInClassByName(getSuspendFunctionName(parameterCount));
}
@NotNull @NotNull
public ClassDescriptor getThrowable() { public ClassDescriptor getThrowable() {
return getBuiltInClassByName("Throwable"); return getBuiltInClassByName("Throwable");
@@ -18,6 +18,9 @@ package org.jetbrains.kotlin.builtins
import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory
import org.jetbrains.kotlin.descriptors.SourceElement 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.AnnotationDescriptorImpl
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
@@ -57,16 +60,23 @@ val KotlinType.isFunctionTypeOrSubtype: Boolean
) )
val KotlinType.isFunctionType: 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() { get() {
val descriptor = constructor.declarationDescriptor val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
return descriptor != null && isNumberedFunctionClassFqName(descriptor.fqNameUnsafe) return kind == FunctionClassDescriptor.Kind.Function ||
kind == FunctionClassDescriptor.Kind.SuspendFunction
} }
val KotlinType.isNonExtensionFunctionType: Boolean val KotlinType.isNonExtensionFunctionType: Boolean
get() = isFunctionType && !isTypeAnnotatedWithExtensionFunctionType get() = isBuiltinFunctionalType && !isTypeAnnotatedWithExtensionFunctionType
val KotlinType.isExtensionFunctionType: Boolean val KotlinType.isExtensionFunctionType: Boolean
get() = isFunctionType && isTypeAnnotatedWithExtensionFunctionType get() = isBuiltinFunctionalType && isTypeAnnotatedWithExtensionFunctionType
private val KotlinType.isTypeAnnotatedWithExtensionFunctionType: Boolean private val KotlinType.isTypeAnnotatedWithExtensionFunctionType: Boolean
get() = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null 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) 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? { 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 return if (isTypeAnnotatedWithExtensionFunctionType) arguments.first().type else null
} }
fun KotlinType.getReturnTypeFromFunctionType(): KotlinType { fun KotlinType.getReturnTypeFromFunctionType(): KotlinType {
assert(isFunctionType) { "Not a function type: ${this}" } assert(isBuiltinFunctionalType) { "Not a function type: ${this}" }
return arguments.last().type return arguments.last().type
} }
fun KotlinType.getValueParameterTypesFromFunctionType(): List<TypeProjection> { fun KotlinType.getValueParameterTypesFromFunctionType(): List<TypeProjection> {
assert(isFunctionType) { "Not a function type: ${this}" } assert(isBuiltinFunctionalType) { "Not a function type: ${this}" }
val arguments = arguments val arguments = arguments
val first = if (isExtensionFunctionType) 1 else 0 val first = if (isExtensionFunctionType) 1 else 0
val last = arguments.size - 1 val last = arguments.size - 1
@@ -147,17 +168,20 @@ fun getFunctionTypeArgumentProjections(
return arguments return arguments
} }
@JvmOverloads
fun createFunctionType( fun createFunctionType(
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
annotations: Annotations, annotations: Annotations,
receiverType: KotlinType?, receiverType: KotlinType?,
parameterTypes: List<KotlinType>, parameterTypes: List<KotlinType>,
parameterNames: List<Name>?, parameterNames: List<Name>?,
returnType: KotlinType returnType: KotlinType,
suspendFunction: Boolean = false
): SimpleType { ): SimpleType {
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns) val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns)
val size = parameterTypes.size 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 = val typeAnnotations =
if (receiverType == null || annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null) { if (receiverType == null || annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null) {
@@ -38,10 +38,9 @@ class BuiltInFictitiousFunctionClassFactory(
companion object { companion object {
private fun parseClassName(className: String, packageFqName: FqName): KindWithArity? { 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 val prefix = kind.classNamePrefix
if (!className.startsWith(prefix)) return null
val arity = toInt(className.substring(prefix.length)) ?: return null val arity = toInt(className.substring(prefix.length)) ?: return null
@@ -49,8 +48,14 @@ class BuiltInFictitiousFunctionClassFactory(
return KindWithArity(kind, arity) return KindWithArity(kind, arity)
} }
@JvmStatic fun getFunctionalClassKind(className: String, packageFqName: FqName) =
parseClassName(className, packageFqName)?.kind
@JvmStatic fun isFunctionClassName(className: String, packageFqName: FqName) = @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? { private fun toInt(s: String): Int? {
if (s.isEmpty()) return null if (s.isEmpty()) return null
@@ -67,7 +72,7 @@ class BuiltInFictitiousFunctionClassFactory(
override fun shouldCreateClass(packageFqName: FqName, name: Name): Boolean { override fun shouldCreateClass(packageFqName: FqName, name: Name): Boolean {
val string = name.asString() 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 && 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.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
@@ -49,6 +50,7 @@ class FunctionClassDescriptor(
enum class Kind(val packageFqName: FqName, val classNamePrefix: String) { enum class Kind(val packageFqName: FqName, val classNamePrefix: String) {
Function(BUILT_INS_PACKAGE_FQ_NAME, "Function"), Function(BUILT_INS_PACKAGE_FQ_NAME, "Function"),
SuspendFunction(BUILT_INS_PACKAGE_FQ_NAME, "SuspendFunction"),
KFunction(KOTLIN_REFLECT_FQ_NAME, "KFunction"); KFunction(KOTLIN_REFLECT_FQ_NAME, "KFunction");
fun numberedClassName(arity: Int) = Name.identifier("$classNamePrefix$arity") fun numberedClassName(arity: Int) = Name.identifier("$classNamePrefix$arity")
@@ -59,6 +61,9 @@ class FunctionClassDescriptor(
KOTLIN_REFLECT_FQ_NAME -> KFunction KOTLIN_REFLECT_FQ_NAME -> KFunction
else -> null 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)) 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 // For KFunction{n}, add corresponding numbered Function{n} class, e.g. Function2 for KFunction2
if (functionKind == Kind.KFunction) { if (functionKind == Kind.KFunction) {
@@ -196,7 +196,7 @@ internal class DescriptorRendererImpl(
} }
private fun shouldRenderAsPrettyFunctionType(type: KotlinType): Boolean { 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 { override fun renderFlexibleType(lowerRendered: String, upperRendered: String, builtIns: KotlinBuiltIns): String {
@@ -322,6 +322,10 @@ internal class DescriptorRendererImpl(
if (needParenthesis) append("(") if (needParenthesis) append("(")
if (type.isSuspendFunctionType) {
append("suspend ") // anything special about modifier?
}
if (receiverType != null) { if (receiverType != null) {
val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) && !receiverType.isMarkedNullable val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) && !receiverType.isMarkedNullable
if (surroundReceiver) { if (surroundReceiver) {