ParameterName annotation on type argument used to hold parameter name
This commit is contained in:
@@ -71,6 +71,13 @@ public enum class DeprecationLevel {
|
||||
@MustBeDocumented
|
||||
public annotation class ExtensionFunctionType
|
||||
|
||||
/**
|
||||
* Annotates type arguments of functional type and holds corresponding parameter name specified by the user in type declaration (if any).
|
||||
*/
|
||||
@Target(TYPE_PARAMETER)
|
||||
@MustBeDocumented
|
||||
public annotation class ParameterName(val name: String)
|
||||
|
||||
/**
|
||||
* Suppresses the given compilation warnings in the annotated element.
|
||||
* @property names names of the compiler diagnostics to suppress.
|
||||
|
||||
@@ -186,6 +186,7 @@ public abstract class KotlinBuiltIns {
|
||||
public final FqName deprecated = fqName("Deprecated");
|
||||
public final FqName deprecationLevel = fqName("DeprecationLevel");
|
||||
public final FqName extensionFunctionType = fqName("ExtensionFunctionType");
|
||||
public final FqName parameterName = fqName("ParameterName");
|
||||
public final FqName annotation = fqName("Annotation");
|
||||
public final FqName target = annotationName("Target");
|
||||
public final FqName annotationTarget = annotationName("AnnotationTarget");
|
||||
|
||||
@@ -73,9 +73,11 @@ class ReflectionTypes(module: ModuleDescriptor) {
|
||||
annotations: Annotations,
|
||||
receiverType: KotlinType?,
|
||||
parameterTypes: List<KotlinType>,
|
||||
returnType: KotlinType
|
||||
parameterNames: List<Name>?,
|
||||
returnType: KotlinType,
|
||||
builtIns: KotlinBuiltIns
|
||||
): KotlinType {
|
||||
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType)
|
||||
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns)
|
||||
|
||||
val classDescriptor = getKFunction(arguments.size - 1 /* return type */)
|
||||
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
package org.jetbrains.kotlin.builtins
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjection
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
import java.util.*
|
||||
|
||||
val KotlinType.isFunctionTypeOrSubtype: Boolean
|
||||
@@ -74,35 +77,65 @@ fun isNumberedFunctionClassFqName(fqName: FqNameUnsafe): Boolean {
|
||||
return BuiltInFictitiousFunctionClassFactory.isFunctionClassName(shortName, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
|
||||
}
|
||||
|
||||
fun getReceiverTypeFromFunctionType(type: KotlinType): KotlinType? {
|
||||
assert(type.isFunctionType) { "Not a function type: $type" }
|
||||
return if (type.isTypeAnnotatedWithExtensionFunctionType) type.arguments.first().type else null
|
||||
fun KotlinType.getReceiverTypeFromFunctionType(): KotlinType? {
|
||||
assert(isFunctionType) { "Not a function type: ${this}" }
|
||||
return if (isTypeAnnotatedWithExtensionFunctionType) arguments.first().type else null
|
||||
}
|
||||
|
||||
fun getReturnTypeFromFunctionType(type: KotlinType): KotlinType {
|
||||
assert(type.isFunctionType) { "Not a function type: $type" }
|
||||
return type.arguments.last().type
|
||||
fun KotlinType.getReturnTypeFromFunctionType(): KotlinType {
|
||||
assert(isFunctionType) { "Not a function type: ${this}" }
|
||||
return arguments.last().type
|
||||
}
|
||||
|
||||
fun getValueParameterTypesFromFunctionType(type: KotlinType): List<TypeProjection> {
|
||||
assert(type.isFunctionType) { "Not a function type: $type" }
|
||||
val arguments = type.arguments
|
||||
val first = if (type.isExtensionFunctionType) 1 else 0
|
||||
fun KotlinType.getValueParameterTypesFromFunctionType(): List<TypeProjection> {
|
||||
assert(isFunctionType) { "Not a function type: ${this}" }
|
||||
val arguments = arguments
|
||||
val first = if (isExtensionFunctionType) 1 else 0
|
||||
val last = arguments.size - 1
|
||||
assert(first <= last) { "Not an exact function type: $type" }
|
||||
assert(first <= last) { "Not an exact function type: ${this}" }
|
||||
return arguments.subList(first, last)
|
||||
}
|
||||
|
||||
fun KotlinType.extractParameterNameFromFunctionTypeArgument(): Name? {
|
||||
val annotation = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.parameterName) ?: return null
|
||||
val name = (annotation.allValueArguments.values.singleOrNull() as? StringValue)
|
||||
?.value
|
||||
?.check { Name.isValidIdentifier(it) }
|
||||
?: return null
|
||||
return Name.identifier(name)
|
||||
}
|
||||
|
||||
fun getFunctionTypeArgumentProjections(
|
||||
receiverType: KotlinType?,
|
||||
parameterTypes: List<KotlinType>,
|
||||
returnType: KotlinType
|
||||
parameterNames: List<Name>?,
|
||||
returnType: KotlinType,
|
||||
builtIns: KotlinBuiltIns
|
||||
): List<TypeProjection> {
|
||||
fun KotlinType.defaultProjection() = TypeProjectionImpl(Variance.INVARIANT, this)
|
||||
|
||||
val arguments = ArrayList<TypeProjection>(parameterTypes.size + (if (receiverType != null) 1 else 0) + 1)
|
||||
receiverType?.let { arguments.add(it.defaultProjection()) }
|
||||
parameterTypes.mapTo(arguments, KotlinType::defaultProjection)
|
||||
parameterTypes.mapIndexedTo(arguments) { index, type ->
|
||||
val name = parameterNames?.get(index)?.check { !it.isSpecial }
|
||||
val typeToUse = if (name != null) {
|
||||
val annotationClass = builtIns.getBuiltInClassByName(KotlinBuiltIns.FQ_NAMES.parameterName.shortName())
|
||||
val nameValue = ConstantValueFactory(builtIns).createStringValue(name.asString())
|
||||
val parameterNameAnnotation = AnnotationDescriptorImpl(
|
||||
annotationClass.defaultType,
|
||||
mapOf(annotationClass.unsubstitutedPrimaryConstructor!!.valueParameters.single() to nameValue),
|
||||
org.jetbrains.kotlin.descriptors.SourceElement.NO_SOURCE
|
||||
)
|
||||
object : WrappedType() {
|
||||
override val delegate = type
|
||||
override val annotations = AnnotationsImpl(type.annotations + parameterNameAnnotation)
|
||||
}
|
||||
}
|
||||
else {
|
||||
type
|
||||
}
|
||||
typeToUse.defaultProjection()
|
||||
}
|
||||
arguments.add(returnType.defaultProjection())
|
||||
return arguments
|
||||
}
|
||||
|
||||
+11
-3
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.builtins.functions
|
||||
|
||||
import org.jetbrains.kotlin.builtins.extractParameterNameFromFunctionTypeArgument
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
@@ -47,6 +48,13 @@ class FunctionInvokeDescriptor private constructor(
|
||||
|
||||
override fun hasSynthesizedParameterNames(): Boolean = hasSynthesizedParameterNames
|
||||
|
||||
override fun doSubstitute(configuration: CopyConfiguration): FunctionDescriptor? {
|
||||
val substituted = super.doSubstitute(configuration) as FunctionInvokeDescriptor? ?: return null
|
||||
if (substituted.valueParameters.none { it.type.extractParameterNameFromFunctionTypeArgument() != null }) return substituted
|
||||
val parameterNames = substituted.valueParameters.map { it.type.extractParameterNameFromFunctionTypeArgument() }
|
||||
return substituted.replaceParameterNames(parameterNames)
|
||||
}
|
||||
|
||||
override fun createSubstitutedCopy(
|
||||
newOwner: DeclarationDescriptor,
|
||||
original: FunctionDescriptor?,
|
||||
@@ -64,11 +72,11 @@ class FunctionInvokeDescriptor private constructor(
|
||||
|
||||
override fun isTailrec(): Boolean = false
|
||||
|
||||
fun replaceParameterNames(parameterNames: List<Name>): FunctionInvokeDescriptor {
|
||||
private fun replaceParameterNames(parameterNames: List<Name?>): FunctionInvokeDescriptor {
|
||||
val indexShift = valueParameters.size - parameterNames.size
|
||||
assert(indexShift == 0 || indexShift == 1) // indexShift == 1 for extension function type
|
||||
|
||||
val hasSynthesizedParameterNames = parameterNames.any { it.isSpecial }
|
||||
val hasSynthesizedParameterNames = parameterNames.any { it == null }
|
||||
val newDescriptor = FunctionInvokeDescriptor(containingDeclaration, this, kind, hasSynthesizedParameterNames)
|
||||
val newValueParameters = valueParameters.map {
|
||||
var newName = it.name
|
||||
@@ -76,7 +84,7 @@ class FunctionInvokeDescriptor private constructor(
|
||||
val nameIndex = parameterIndex - indexShift
|
||||
if (nameIndex >= 0) {
|
||||
val parameterName = parameterNames[nameIndex]
|
||||
if (!parameterName.isSpecial) {
|
||||
if (parameterName != null) {
|
||||
newName = parameterName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ internal class DescriptorRendererImpl(
|
||||
val isNullable = type.isMarkedNullable
|
||||
if (isNullable) append("(")
|
||||
|
||||
val receiverType = getReceiverTypeFromFunctionType(type)
|
||||
val receiverType = type.getReceiverTypeFromFunctionType()
|
||||
if (receiverType != null) {
|
||||
val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) && !receiverType.isMarkedNullable
|
||||
if (surroundReceiver) {
|
||||
@@ -309,17 +309,13 @@ internal class DescriptorRendererImpl(
|
||||
}
|
||||
|
||||
append("(")
|
||||
val parameterTypes = getValueParameterTypesFromFunctionType(type)
|
||||
val parameterNames = if (parameterNamesInFunctionalTypes) type.getParameterNamesFromFunctionType() else null
|
||||
assert(parameterNames == null || parameterNames.size == parameterTypes.size) { "Number of names does not match number of types for $type"}
|
||||
|
||||
for (index in parameterTypes.indices) {
|
||||
val typeProjection = parameterTypes[index]
|
||||
val name = parameterNames?.get(index)
|
||||
|
||||
val parameterTypes = type.getValueParameterTypesFromFunctionType()
|
||||
for ((index, typeProjection) in parameterTypes.withIndex()) {
|
||||
if (index > 0) append(", ")
|
||||
|
||||
if (name != null && !name.isSpecial) {
|
||||
val name = if (parameterNamesInFunctionalTypes) typeProjection.type.extractParameterNameFromFunctionTypeArgument() else null
|
||||
if (name != null) {
|
||||
append(renderName(name))
|
||||
append(": ")
|
||||
}
|
||||
@@ -327,7 +323,7 @@ internal class DescriptorRendererImpl(
|
||||
}
|
||||
|
||||
append(") ").append(arrow()).append(" ")
|
||||
renderNormalizedType(getReturnTypeFromFunctionType(type))
|
||||
renderNormalizedType(type.getReturnTypeFromFunctionType())
|
||||
|
||||
if (isNullable) append(")?")
|
||||
}
|
||||
|
||||
@@ -16,16 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.types
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import java.util.*
|
||||
|
||||
abstract class DelegatingSimpleType : SimpleType() {
|
||||
protected abstract val delegate: SimpleType
|
||||
@@ -56,46 +49,6 @@ fun SimpleType.withAbbreviation(abbreviatedType: SimpleType): SimpleType {
|
||||
return AbbreviatedType(this, abbreviatedType)
|
||||
}
|
||||
|
||||
class FunctionType(
|
||||
override val delegate: SimpleType,
|
||||
/**
|
||||
* SpecialNames.NO_NAME_PROVIDED if no parameter name specified
|
||||
*/
|
||||
val parameterNames: List<Name>
|
||||
) : DelegatingSimpleType() {
|
||||
|
||||
override val memberScope = object: MemberScope by delegate.memberScope {
|
||||
private val cache = HashMap<FunctionInvokeDescriptor, FunctionInvokeDescriptor>(2)
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> {
|
||||
return delegate.memberScope.getContributedFunctions(name, location).replaceParameterNames()
|
||||
}
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||
return delegate.memberScope.getContributedDescriptors(kindFilter, nameFilter).replaceParameterNames()
|
||||
}
|
||||
|
||||
private fun <TDescriptor : DeclarationDescriptor> Collection<TDescriptor>.replaceParameterNames(): List<TDescriptor>
|
||||
= map { it.replaceParameterNames() }
|
||||
|
||||
private fun <TDescriptor : DeclarationDescriptor> TDescriptor.replaceParameterNames(): TDescriptor {
|
||||
if (this !is FunctionInvokeDescriptor) return this
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return cache.getOrPut(this) { this.replaceParameterNames(parameterNames) } as TDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
override fun replaceAnnotations(newAnnotations: Annotations)
|
||||
= FunctionType(delegate.replaceAnnotations(newAnnotations), parameterNames)
|
||||
|
||||
override fun makeNullableAsSpecified(newNullability: Boolean)
|
||||
= FunctionType(delegate.makeNullableAsSpecified(newNullability), parameterNames)
|
||||
|
||||
override val isError: Boolean get() = false
|
||||
}
|
||||
|
||||
fun KotlinType.getParameterNamesFromFunctionType(): List<Name>? = (unwrap() as? FunctionType)?.parameterNames
|
||||
|
||||
class LazyWrappedType(storageManager: StorageManager, computation: () -> KotlinType): WrappedType() {
|
||||
private val lazyValue = storageManager.createLazyValue(computation)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user