From 59269ef1ae7f730bdca64aaaebabf74644833ca7 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 14 Sep 2016 19:37:44 +0300 Subject: [PATCH] ParameterName annotation on type argument used to hold parameter name --- .../resolve/FunctionDescriptorResolver.kt | 12 ++-- .../kotlin/resolve/calls/CallCompleter.kt | 2 +- .../kotlin/resolve/calls/CallResolverUtil.kt | 2 +- .../checkers/CoroutineModifierChecker.kt | 4 +- .../DoubleColonExpressionResolver.kt | 8 ++- .../expressions/FunctionsTypingVisitor.kt | 2 +- .../calls/util/functionTypeResolveUtils.kt | 10 +-- .../builtin-classes/default/kotlin.txt | 6 ++ .../testData/builtin-classes/java6/kotlin.txt | 6 ++ .../testData/builtin-classes/java8/kotlin.txt | 6 ++ .../builtin-classes/newMethods/kotlin.txt | 6 ++ .../tests/functionLiterals/kt11733_1.txt | 2 +- .../tests/j+k/computeIfAbsentConcurrent.txt | 4 +- .../j+k/overrideWithSamAndTypeParameter.txt | 2 +- .../genericInValueParameter.txt | 6 +- .../genericSuperWildcard.txt | 4 +- .../noAdapterBecuaseOfRecursiveUpperBound.txt | 2 +- .../starProjectionComplexUpperBound.txt | 4 +- .../platformTypes/noAnnotationInClassPath.txt | 4 +- .../enhancementFromAnnotation.txt | 2 +- .../tests/platformTypes/rawTypes/samRaw.txt | 2 +- .../saveAnnotationAfterSubstitution.txt | 2 +- .../samAdapters/InnerClassInGeneric.txt | 2 +- core/builtins/src/kotlin/Annotations.kt | 7 ++ .../kotlin/builtins/KotlinBuiltIns.java | 1 + .../kotlin/builtins/ReflectionTypes.kt | 6 +- .../kotlin/builtins/functionTypes.kt | 67 ++++++++++++++----- .../functions/FunctionInvokeDescriptor.kt | 14 +++- .../kotlin/renderer/DescriptorRendererImpl.kt | 16 ++--- .../jetbrains/kotlin/types/SpecialTypes.kt | 47 ------------- .../idea/completion/InsertHandlerProvider.kt | 2 +- .../completion/handlers/GenerateLambda.kt | 24 +++---- .../kotlin/idea/core/ExpectedInfos.kt | 2 +- .../internal/FindImplicitNothingAction.kt | 2 +- .../ConvertLambdaToReferenceIntention.kt | 2 +- .../ConvertExtensionToFunctionTypeFix.kt | 2 +- ...ctionFromCallableReferenceActionFactory.kt | 6 +- 37 files changed, 158 insertions(+), 140 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt index 556bc33845a..7ed20547612 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt @@ -16,7 +16,10 @@ package org.jetbrains.kotlin.resolve -import org.jetbrains.kotlin.builtins.* +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +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.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl @@ -48,7 +51,6 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices -import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral import java.util.* @@ -208,7 +210,7 @@ class FunctionDescriptorResolver( return listOf(it) } if (function.valueParameters.size != expectedValueParameters.size) { - val expectedParameterTypes = ExpressionTypingUtils.getValueParametersTypes(expectedValueParameters) + val expectedParameterTypes = expectedValueParameters.map { it.type } trace.report(EXPECTED_PARAMETERS_NUMBER_MISMATCH.on(function, expectedParameterTypes.size, expectedParameterTypes)) } } @@ -226,11 +228,11 @@ class FunctionDescriptorResolver( private fun KotlinType.functionTypeExpected() = !TypeUtils.noExpectedType(this) && isFunctionType private fun KotlinType.getReceiverType(): KotlinType? = - if (functionTypeExpected()) getReceiverTypeFromFunctionType(this) else null + if (functionTypeExpected()) this.getReceiverTypeFromFunctionType() else null private fun KotlinType.getValueParameters(owner: FunctionDescriptor): List? = if (functionTypeExpected()) { - createValueParametersForInvokeInFunctionType(owner, getValueParameterTypesFromFunctionType(this)) + createValueParametersForInvokeInFunctionType(owner, this.getValueParameterTypesFromFunctionType()) } else null diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index a6873e46da1..e88e42ccd4c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -181,7 +181,7 @@ class CallCompleter( if (call.isCallableReference()) { // TODO: compute generic type argument for R in the kotlin.Function supertype (KT-12963) // TODO: also add constraints for parameter types (KT-12964) - if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) getReturnTypeFromFunctionType(expectedType) + if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType() else TypeUtils.NO_EXPECTED_TYPE } else expectedType diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt index d165f0ebdb9..9d1e59e3d03 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt @@ -174,7 +174,7 @@ fun getEffectiveExpectedType(parameterDescriptor: ValueParameterDescriptor, argu argument.getArgumentExpression() is KtLambdaExpression && parameterDescriptor.type.isExtensionFunctionType ) { - val receiverType = getReceiverTypeFromFunctionType(parameterDescriptor.type)!! + val receiverType = parameterDescriptor.type.getReceiverTypeFromFunctionType()!! val newExpectedLambdaReturnType = receiverType.memberScope diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/CoroutineModifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/CoroutineModifierChecker.kt index 0a765f8e858..75a8778a1d4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/CoroutineModifierChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/CoroutineModifierChecker.kt @@ -56,7 +56,7 @@ object CoroutineModifierChecker : SimpleDeclarationChecker { continue } - val returnType = getReturnTypeFromFunctionType(parameterDescriptor.type) + val returnType = parameterDescriptor.type.getReturnTypeFromFunctionType() if (returnType.isMarkedNullable || !returnType.isValidContinuation() || !returnType.arguments.single().type.isUnit()) { report("parameter should have function type like 'Controller.() -> Continuation' (Continuation for return type is necessary)") @@ -68,7 +68,7 @@ object CoroutineModifierChecker : SimpleDeclarationChecker { continue } - val controller = getReceiverTypeFromFunctionType(parameterDescriptor.type)!! + val controller = parameterDescriptor.type.getReceiverTypeFromFunctionType()!! val handleResultFunctions = controller.memberScope diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index ef63ec120a0..97ca31b9377 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.calls.util.createValueParametersForInvokeInFunctionType +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver @@ -48,6 +49,7 @@ import org.jetbrains.kotlin.resolve.source.toSourceElement import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo +import java.lang.UnsupportedOperationException import javax.inject.Inject sealed class DoubleColonLHS(val type: KotlinType) { @@ -534,8 +536,10 @@ class DoubleColonExpressionResolver( return when (descriptor) { is FunctionDescriptor -> { val returnType = descriptor.returnType ?: return null - val valueParametersTypes = ExpressionTypingUtils.getValueParametersTypes(descriptor.valueParameters) - return reflectionTypes.getKFunctionType(Annotations.EMPTY, receiverType, valueParametersTypes, returnType) + val parametersTypes = descriptor.valueParameters.map { it.type } + val parametersNames = descriptor.valueParameters.map { it.name } + return reflectionTypes.getKFunctionType(Annotations.EMPTY, receiverType, + parametersTypes, parametersNames, returnType, descriptor.builtIns) } is PropertyDescriptor -> { val mutable = descriptor.isVar && run { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index 5cb941af306..cf3d7569476 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -187,7 +187,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre functionDescriptor: SimpleFunctionDescriptorImpl, functionTypeExpected: Boolean ): KotlinType { - val expectedReturnType = if (functionTypeExpected) getReturnTypeFromFunctionType(context.expectedType) else null + val expectedReturnType = if (functionTypeExpected) context.expectedType.getReturnTypeFromFunctionType() else null val returnType = computeUnsafeReturnType(expression, context, functionDescriptor, expectedReturnType) if (!expression.functionLiteral.hasDeclaredReturnType() && functionTypeExpected) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/util/functionTypeResolveUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/util/functionTypeResolveUtils.kt index dba5c0ed24b..f64a25ddaa6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/util/functionTypeResolveUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/util/functionTypeResolveUtils.kt @@ -54,7 +54,7 @@ fun createFunctionType( parameterNames: List?, returnType: KotlinType ): SimpleType { - val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType) + val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns) val size = parameterTypes.size val classDescriptor = builtIns.getFunction(if (receiverType == null) size else size + 1) @@ -72,13 +72,7 @@ fun createFunctionType( AnnotationsImpl(annotations + extensionFunctionAnnotation) } - val simpleType = KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments) - if (parameterNames == null || parameterNames.all { it.isSpecial }) { - return simpleType - } - else { - return FunctionType(simpleType, parameterNames) - } + return KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments) } fun getValueParametersCountFromFunctionType(type: KotlinType): Int { diff --git a/compiler/testData/builtin-classes/default/kotlin.txt b/compiler/testData/builtin-classes/default/kotlin.txt index 09618dc87ad..5530a28bddc 100644 --- a/compiler/testData/builtin-classes/default/kotlin.txt +++ b/compiler/testData/builtin-classes/default/kotlin.txt @@ -565,6 +565,12 @@ public abstract class Number { public abstract fun toShort(): kotlin.Short } +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE_PARAMETER}) @kotlin.annotation.MustBeDocumented() public final annotation class ParameterName : kotlin.Annotation { + /*primary*/ public constructor ParameterName(/*0*/ name: kotlin.String) + public final val name: kotlin.String + public final fun (): kotlin.String +} + @kotlin.annotation.Target(allowedTargets = {}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) @kotlin.annotation.MustBeDocumented() public final annotation class ReplaceWith : kotlin.Annotation { /*primary*/ public constructor ReplaceWith(/*0*/ expression: kotlin.String, /*1*/ vararg imports: kotlin.String /*kotlin.Array*/) public final val expression: kotlin.String diff --git a/compiler/testData/builtin-classes/java6/kotlin.txt b/compiler/testData/builtin-classes/java6/kotlin.txt index bfff6c96402..601b1bf94a7 100644 --- a/compiler/testData/builtin-classes/java6/kotlin.txt +++ b/compiler/testData/builtin-classes/java6/kotlin.txt @@ -569,6 +569,12 @@ public abstract class Number : kotlin.Any, java.io.Serializable { public abstract fun toShort(): kotlin.Short } +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE_PARAMETER}) @kotlin.annotation.MustBeDocumented() public final annotation class ParameterName : kotlin.Annotation { + /*primary*/ public constructor ParameterName(/*0*/ name: kotlin.String) + public final val name: kotlin.String + public final fun (): kotlin.String +} + @kotlin.annotation.Target(allowedTargets = {}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) @kotlin.annotation.MustBeDocumented() public final annotation class ReplaceWith : kotlin.Annotation { /*primary*/ public constructor ReplaceWith(/*0*/ expression: kotlin.String, /*1*/ vararg imports: kotlin.String /*kotlin.Array*/) public final val expression: kotlin.String diff --git a/compiler/testData/builtin-classes/java8/kotlin.txt b/compiler/testData/builtin-classes/java8/kotlin.txt index e71e4aab487..518f69ca653 100644 --- a/compiler/testData/builtin-classes/java8/kotlin.txt +++ b/compiler/testData/builtin-classes/java8/kotlin.txt @@ -571,6 +571,12 @@ public abstract class Number : kotlin.Any, java.io.Serializable { public abstract fun toShort(): kotlin.Short } +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE_PARAMETER}) @kotlin.annotation.MustBeDocumented() public final annotation class ParameterName : kotlin.Annotation { + /*primary*/ public constructor ParameterName(/*0*/ name: kotlin.String) + public final val name: kotlin.String + public final fun (): kotlin.String +} + @kotlin.annotation.Target(allowedTargets = {}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) @kotlin.annotation.MustBeDocumented() public final annotation class ReplaceWith : kotlin.Annotation { /*primary*/ public constructor ReplaceWith(/*0*/ expression: kotlin.String, /*1*/ vararg imports: kotlin.String /*kotlin.Array*/) public final val expression: kotlin.String diff --git a/compiler/testData/builtin-classes/newMethods/kotlin.txt b/compiler/testData/builtin-classes/newMethods/kotlin.txt index 9c0be382d7f..4d5b5f37113 100644 --- a/compiler/testData/builtin-classes/newMethods/kotlin.txt +++ b/compiler/testData/builtin-classes/newMethods/kotlin.txt @@ -569,6 +569,12 @@ public abstract class Number : kotlin.Any, java.io.Serializable { public abstract fun toShort(): kotlin.Short } +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE_PARAMETER}) @kotlin.annotation.MustBeDocumented() public final annotation class ParameterName : kotlin.Annotation { + /*primary*/ public constructor ParameterName(/*0*/ name: kotlin.String) + public final val name: kotlin.String + public final fun (): kotlin.String +} + @kotlin.annotation.Target(allowedTargets = {}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) @kotlin.annotation.MustBeDocumented() public final annotation class ReplaceWith : kotlin.Annotation { /*primary*/ public constructor ReplaceWith(/*0*/ expression: kotlin.String, /*1*/ vararg imports: kotlin.String /*kotlin.Array*/) public final val expression: kotlin.String diff --git a/compiler/testData/diagnostics/tests/functionLiterals/kt11733_1.txt b/compiler/testData/diagnostics/tests/functionLiterals/kt11733_1.txt index 9f6df691b6a..438c7c3362b 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/kt11733_1.txt +++ b/compiler/testData/diagnostics/tests/functionLiterals/kt11733_1.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun Predicate(/*0*/ function: (T) -> kotlin.Boolean): Predicate +public /*synthesized*/ fun Predicate(/*0*/ function: (t: @kotlin.ParameterName(name = "t") T) -> kotlin.Boolean): Predicate public fun main(/*0*/ args: kotlin.Array): kotlin.Unit public fun process(/*0*/ x: Predicate): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.txt b/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.txt index 2a0aa5263ac..507ef116c71 100644 --- a/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.txt +++ b/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.txt @@ -1,7 +1,7 @@ package -public /*synthesized*/ fun ConcMap(/*0*/ function: (K!, MyFunc!) -> V!): ConcMap -public /*synthesized*/ fun MyFunc(/*0*/ function: (K!) -> V!): MyFunc +public /*synthesized*/ fun ConcMap(/*0*/ function: (key: @kotlin.ParameterName(name = "key") K!, MyFunc!) -> V!): ConcMap +public /*synthesized*/ fun MyFunc(/*0*/ function: (String: @kotlin.ParameterName(name = "String") K!) -> V!): MyFunc public fun concurrentMap(): kotlin.Unit public open class ConcHashMap : ConcMap { diff --git a/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.txt b/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.txt index 13fce86be17..4a615dbe8a0 100644 --- a/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.txt +++ b/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun A(/*0*/ function: (K!, MyFunc!) -> K!): A +public /*synthesized*/ fun A(/*0*/ function: (key: @kotlin.ParameterName(name = "key") K!, MyFunc!) -> K!): A public /*synthesized*/ fun MyFunc(/*0*/ function: (x: kotlin.String!) -> kotlin.String!): MyFunc public fun main(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.txt index 715ff278e3c..1320cc0ea42 100644 --- a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.txt +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericInValueParameter.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun EventListener(/*0*/ function: (E!) -> kotlin.Unit): EventListener +public /*synthesized*/ fun EventListener(/*0*/ function: (e: @kotlin.ParameterName(name = "e") E!) -> kotlin.Unit): EventListener public fun main(): kotlin.Unit public open class A { @@ -11,9 +11,9 @@ public open class A { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members - public final /*synthesized*/ fun bar(/*0*/ l: ((kotlin.Any!) -> kotlin.Unit)!): kotlin.Unit + public final /*synthesized*/ fun bar(/*0*/ l: ((e: @kotlin.ParameterName(name = "e") kotlin.Any!) -> kotlin.Unit)!): kotlin.Unit public open fun bar(/*0*/ l: EventListener<*>!): kotlin.Unit - public final /*synthesized*/ fun baz(/*0*/ l: ((kotlin.CharSequence!) -> kotlin.Unit)!): kotlin.Unit + public final /*synthesized*/ fun baz(/*0*/ l: ((e: @kotlin.ParameterName(name = "e") kotlin.CharSequence!) -> kotlin.Unit)!): kotlin.Unit public open fun baz(/*0*/ l: EventListener!): kotlin.Unit } diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.txt index f36e44f7e29..c05b1a7629c 100644 --- a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.txt +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/genericSuperWildcard.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun EventListener(/*0*/ function: (E!) -> kotlin.Unit): EventListener +public /*synthesized*/ fun EventListener(/*0*/ function: (e: @kotlin.ParameterName(name = "e") E!) -> kotlin.Unit): EventListener public fun main(): kotlin.Unit public open class A { @@ -11,7 +11,7 @@ public open class A { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members - public final /*synthesized*/ fun bar(/*0*/ l: ((kotlin.String!) -> kotlin.Unit)!): kotlin.Unit + public final /*synthesized*/ fun bar(/*0*/ l: ((e: @kotlin.ParameterName(name = "e") kotlin.String!) -> kotlin.Unit)!): kotlin.Unit public open fun bar(/*0*/ l: EventListener!): kotlin.Unit } diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.txt index 8a0f4680f80..b74a97bbaf4 100644 --- a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.txt +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/noAdapterBecuaseOfRecursiveUpperBound.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun !> Function(/*0*/ function: (F!) -> E!): Function +public /*synthesized*/ fun !> Function(/*0*/ function: (f: @kotlin.ParameterName(name = "f") F!) -> E!): Function public fun main(): kotlin.Unit public open class A { diff --git a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.txt b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.txt index c5479fd3190..743e37dd352 100644 --- a/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.txt +++ b/compiler/testData/diagnostics/tests/j+k/samByProjectedType/starProjectionComplexUpperBound.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun !, /*1*/ F : kotlin.CharSequence!> Function(/*0*/ function: (E!) -> F!): Function +public /*synthesized*/ fun !, /*1*/ F : kotlin.CharSequence!> Function(/*0*/ function: (e: @kotlin.ParameterName(name = "e") E!) -> F!): Function public fun main(): kotlin.Unit public open class A { @@ -11,7 +11,7 @@ public open class A { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members - public final /*synthesized*/ fun bar(/*0*/ l: ((kotlin.collections.(Mutable)Map!) -> kotlin.CharSequence!)!): kotlin.Unit + public final /*synthesized*/ fun bar(/*0*/ l: ((e: (@kotlin.ParameterName(name = "e") kotlin.collections.MutableMap..@kotlin.ParameterName(name = "e") kotlin.collections.Map?)) -> kotlin.CharSequence!)!): kotlin.Unit public open fun bar(/*0*/ l: Function<*, *>!): kotlin.Unit } diff --git a/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.txt b/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.txt index 0c1976f1bd3..417db12bd4d 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.txt +++ b/compiler/testData/diagnostics/tests/platformTypes/noAnnotationInClassPath.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun A(/*0*/ function: (T?) -> kotlin.Boolean): A +public /*synthesized*/ fun A(/*0*/ function: (y: @kotlin.ParameterName(name = "y") T?) -> kotlin.Boolean): A public fun test(): kotlin.Unit public interface A { @@ -17,6 +17,6 @@ public open class B { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members - public final /*synthesized*/ fun bar(/*0*/ y: ((kotlin.String?) -> kotlin.Boolean)!): kotlin.Unit + public final /*synthesized*/ fun bar(/*0*/ y: ((y: @kotlin.ParameterName(name = "y") kotlin.String?) -> kotlin.Boolean)!): kotlin.Unit public open fun bar(/*0*/ y: A!): kotlin.Unit } diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.txt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.txt index 5e50485a22e..40ae7acd99f 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.txt +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun A(/*0*/ function: (T) -> kotlin.Unit): A +public /*synthesized*/ fun A(/*0*/ function: (x: @kotlin.ParameterName(name = "x") T) -> kotlin.Unit): A public fun test(): kotlin.Unit public interface A { diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/samRaw.txt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/samRaw.txt index a9e018842df..53f25a7d165 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/samRaw.txt +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/samRaw.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun A(/*0*/ function: (T!) -> kotlin.Boolean): A +public /*synthesized*/ fun A(/*0*/ function: (t: @kotlin.ParameterName(name = "t") T!) -> kotlin.Boolean): A public fun main(): kotlin.Unit public interface A { diff --git a/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.txt b/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.txt index 755ec5bd8c4..3cc0621fb0c 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.txt +++ b/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.txt @@ -1,6 +1,6 @@ package -public /*synthesized*/ fun A(/*0*/ function: (T, T?) -> kotlin.Unit): A +public /*synthesized*/ fun A(/*0*/ function: (x: @kotlin.ParameterName(name = "x") T, y: @kotlin.ParameterName(name = "y") T?) -> kotlin.Unit): A public /*synthesized*/ fun B1(/*0*/ function: (x: kotlin.String, y: kotlin.String?) -> kotlin.Unit): B1 public /*synthesized*/ fun B2(/*0*/ function: (x: kotlin.String, y: kotlin.String?) -> kotlin.Unit): B2 public /*synthesized*/ fun B3(/*0*/ function: (x: kotlin.String!, y: kotlin.String!) -> kotlin.Unit): B3 diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/samAdapters/InnerClassInGeneric.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/samAdapters/InnerClassInGeneric.txt index 0d53b232b77..4df33c56b7a 100644 --- a/compiler/testData/diagnostics/tests/syntheticExtensions/samAdapters/InnerClassInGeneric.txt +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/samAdapters/InnerClassInGeneric.txt @@ -17,5 +17,5 @@ public open class JavaClass { } // Static members - public final /*synthesized*/ fun Inner(/*0*/ function: (T!, X!, java.lang.Runnable!) -> T!): JavaClass.Inner + public final /*synthesized*/ fun Inner(/*0*/ function: (t: T!, x: @kotlin.ParameterName(name = "x") X!, java.lang.Runnable!) -> T!): JavaClass.Inner } diff --git a/core/builtins/src/kotlin/Annotations.kt b/core/builtins/src/kotlin/Annotations.kt index d5ad77a4115..ceb2af9c08e 100644 --- a/core/builtins/src/kotlin/Annotations.kt +++ b/core/builtins/src/kotlin/Annotations.kt @@ -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. diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 422a21606ec..58c976d31d4 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -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"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt index 0316c6b2ce3..7a67a9d9b0c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt @@ -73,9 +73,11 @@ class ReflectionTypes(module: ModuleDescriptor) { annotations: Annotations, receiverType: KotlinType?, parameterTypes: List, - returnType: KotlinType + parameterNames: List?, + 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 */) diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt index 5b1589e5749..acfddb499b3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt @@ -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 { - assert(type.isFunctionType) { "Not a function type: $type" } - val arguments = type.arguments - val first = if (type.isExtensionFunctionType) 1 else 0 +fun KotlinType.getValueParameterTypesFromFunctionType(): List { + 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, - returnType: KotlinType + parameterNames: List?, + returnType: KotlinType, + builtIns: KotlinBuiltIns ): List { fun KotlinType.defaultProjection() = TypeProjectionImpl(Variance.INVARIANT, this) val arguments = ArrayList(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 } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt index 8bffb9e6929..891f18c3cd6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt @@ -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): FunctionInvokeDescriptor { + private fun replaceParameterNames(parameterNames: List): 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 } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index f45fc292911..120b2c7d2d3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -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(")?") } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt index 519b93c1f37..985ac9f452f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt @@ -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 -) : DelegatingSimpleType() { - - override val memberScope = object: MemberScope by delegate.memberScope { - private val cache = HashMap(2) - - override fun getContributedFunctions(name: Name, location: LookupLocation): Collection { - return delegate.memberScope.getContributedFunctions(name, location).replaceParameterNames() - } - - override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { - return delegate.memberScope.getContributedDescriptors(kindFilter, nameFilter).replaceParameterNames() - } - - private fun Collection.replaceParameterNames(): List - = map { it.replaceParameterNames() } - - private fun 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? = (unwrap() as? FunctionType)?.parameterNames - class LazyWrappedType(storageManager: StorageManager, computation: () -> KotlinType): WrappedType() { private val lazyValue = storageManager.createLazyValue(computation) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/InsertHandlerProvider.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/InsertHandlerProvider.kt index 96e67604124..b5dd116fab7 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/InsertHandlerProvider.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/InsertHandlerProvider.kt @@ -100,7 +100,7 @@ class InsertHandlerProvider( if (type.isFunctionType && getValueParametersCountFromFunctionType(type) <= 1) { // do not rely on inference from input of function type with one or no arguments - use only return type of functional type - addPotentiallyInferred(getReturnTypeFromFunctionType(type)) + addPotentiallyInferred(type.getReturnTypeFromFunctionType()) return } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/GenerateLambda.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/GenerateLambda.kt index f5b9a8d77bc..9dd0df53fa4 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/GenerateLambda.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/GenerateLambda.kt @@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiDocumentManager import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.builtins.extractParameterNameFromFunctionTypeArgument import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade @@ -33,8 +34,6 @@ import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.core.fuzzyType import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.application.executeWriteCommand -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.renderer.render @@ -42,8 +41,6 @@ import org.jetbrains.kotlin.resolve.calls.util.getValueParametersCountFromFuncti import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjection -import org.jetbrains.kotlin.types.getParameterNamesFromFunctionType -import org.jetbrains.kotlin.utils.addToStdlib.check fun insertLambdaTemplate(context: InsertionContext, placeholderRange: TextRange, lambdaType: KotlinType) { val explicitParameterTypes = needExplicitParameterTypes(context, placeholderRange, lambdaType) @@ -74,10 +71,10 @@ fun insertLambdaTemplate(context: InsertionContext, placeholderRange: TextRange, fun lambdaPresentation(lambdaType: KotlinType?): String { if (lambdaType == null) return "{...}" - val (parameterTypes, parameterNames) = functionParameterTypesAndNames(lambdaType) - val parametersPresentation = parameterNames - .mapIndexed { index, name -> - name.check { !it.isSpecial } ?: IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(parameterTypes[index]) + val parameterTypes = functionParameterTypes(lambdaType) + val parametersPresentation = parameterTypes + .map { + it.extractParameterNameFromFunctionTypeArgument() ?: IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) } .joinToString(", ") return "{ $parametersPresentation -> ... }" @@ -104,7 +101,7 @@ private fun needExplicitParameterTypes(context: InsertionContext, placeholderRan } private fun buildTemplate(lambdaType: KotlinType, explicitParameterTypes: Boolean, project: Project): Template { - val (parameterTypes, parameterNames) = functionParameterTypesAndNames(lambdaType) + val parameterTypes = functionParameterTypes(lambdaType) val manager = TemplateManager.getInstance(project) @@ -118,7 +115,7 @@ private fun buildTemplate(lambdaType: KotlinType, explicitParameterTypes: Boolea template.addTextSegment(", ") } //TODO: check for names in scope - val parameterName = parameterNames[i].check { !it.isSpecial }?.render() + val parameterName = parameterType.extractParameterNameFromFunctionTypeArgument()?.render() val nameExpression = if (parameterName != null) { object : Expression() { override fun calculateResult(context: ExpressionContext?) = TextResult(parameterName) @@ -148,9 +145,6 @@ private fun buildTemplate(lambdaType: KotlinType, explicitParameterTypes: Boolea return template } -private fun functionParameterTypesAndNames(functionType: KotlinType): Pair, List> { - val types = getValueParameterTypesFromFunctionType(functionType).map(TypeProjection::getType) - val names = functionType.getParameterNamesFromFunctionType() ?: types.map { SpecialNames.NO_NAME_PROVIDED } - assert(names.size == types.size) { "Number of names does not match number of types for $functionType"} - return types to names +private fun functionParameterTypes(functionType: KotlinType): List { + return functionType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt index ef755731d8d..90fb4a6608b 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt @@ -497,7 +497,7 @@ class ExpectedInfos( .mapNotNull { it.fuzzyType } .filter { it.type.isFunctionType } .map { - val returnType = getReturnTypeFromFunctionType(it.type) + val returnType = it.type.getReturnTypeFromFunctionType() ExpectedInfo(returnType.toFuzzyType(it.freeParameters), null, Tail.RBRACE) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/internal/FindImplicitNothingAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/internal/FindImplicitNothingAction.kt index 2418208ad7d..9c290cb69cf 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/internal/FindImplicitNothingAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/internal/FindImplicitNothingAction.kt @@ -129,7 +129,7 @@ class FindImplicitNothingAction : AnAction() { private fun KotlinType.isNothingOrNothingFunctionType(): Boolean { return KotlinBuiltIns.isNothing(this) || - (isFunctionType && getReturnTypeFromFunctionType(this).isNothingOrNothingFunctionType()) + (isFunctionType && this.getReturnTypeFromFunctionType().isNothingOrNothingFunctionType()) } override fun update(e: AnActionEvent) { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertLambdaToReferenceIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertLambdaToReferenceIntention.kt index e54169295ee..2f7aa6eb20b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertLambdaToReferenceIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertLambdaToReferenceIntention.kt @@ -69,7 +69,7 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio // For lambda parameter with receiver, conversion is not allowed if (lambdaParameterType.isExtensionFunctionType) return false // Special Unit case (non-Unit returning lambda is accepted here, but non-Unit returning reference is not) - lambdaMustReturnUnit = getReturnTypeFromFunctionType(lambdaParameterType).isUnit() + lambdaMustReturnUnit = lambdaParameterType.getReturnTypeFromFunctionType().isUnit() } } val context = statement.analyze() diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertExtensionToFunctionTypeFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertExtensionToFunctionTypeFix.kt index 1ccd7c46a2e..b00ed7da103 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertExtensionToFunctionTypeFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertExtensionToFunctionTypeFix.kt @@ -52,7 +52,7 @@ class ConvertExtensionToFunctionTypeFix(element: KtTypeReference, type: KotlinTy append('(') arguments.dropLast(1).map { renderer.renderType(it.type) }.joinTo(this@buildString, ", ") append(") -> ") - append(renderer.renderType(getReturnTypeFromFunctionType(this@renderType))) + append(renderer.renderType(this@renderType.getReturnTypeFromFunctionType())) } companion object Factory : KotlinIntentionActionsFactory() { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt index 11fa7be98a9..26ba12a3918 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt @@ -47,18 +47,18 @@ object CreateFunctionFromCallableReferenceActionFactory : CreateCallableMemberFr .guessTypes(context, resolutionFacade.moduleDescriptor) .filter(KotlinType::isFunctionType) .mapNotNull { - val expectedReceiverType = getReceiverTypeFromFunctionType(it) + val expectedReceiverType = it.getReceiverTypeFromFunctionType() val receiverExpression = element.receiverExpression val qualifierType = (context.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) as? DoubleColonLHS.Type)?.type val receiverTypeInfo = qualifierType?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo.Empty - val returnTypeInfo = TypeInfo(getReturnTypeFromFunctionType(it), Variance.OUT_VARIANCE) + val returnTypeInfo = TypeInfo(it.getReturnTypeFromFunctionType(), Variance.OUT_VARIANCE) val containers = element.getExtractionContainers(includeAll = true).ifEmpty { return@mapNotNull null } val parameterInfos = SmartList().apply { if (receiverExpression == null && expectedReceiverType != null) { add(ParameterInfo(TypeInfo(expectedReceiverType, Variance.IN_VARIANCE))) } - getValueParameterTypesFromFunctionType(it) + it.getValueParameterTypesFromFunctionType() .let { if (receiverExpression != null && expectedReceiverType == null && it.isNotEmpty()) it.subList(1, it.size)