From 6b94e5fd34c3193667330759cb8781a1deed4531 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 13 Sep 2016 22:02:59 +0300 Subject: [PATCH] Use parameter names from function type for invoke() function #KT-435 Fixed #KT-9016 Fixed --- .../funcitonTypes.txt | 2 +- .../typeReferenceError.txt | 2 +- compiler/testData/diagnostics/tests/kt435.kt | 7 ++++ compiler/testData/diagnostics/tests/kt435.txt | 4 ++ .../checkers/DiagnosticsTestGenerated.java | 6 +++ .../functions/FunctionInvokeDescriptor.kt | 39 ++++++++++++++++--- .../jetbrains/kotlin/types/SpecialTypes.kt | 28 +++++++++++++ .../functionCall/FunctionalValue1.kt | 3 +- .../functionCall/FunctionalValue2.kt | 3 +- 9 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/kt435.kt create mode 100644 compiler/testData/diagnostics/tests/kt435.txt diff --git a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/funcitonTypes.txt b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/funcitonTypes.txt index 59c834dade1..9bccfbba559 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/funcitonTypes.txt +++ b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/funcitonTypes.txt @@ -4,6 +4,6 @@ public final class A : (categoryName: [ERROR : No type element]) -> [ERROR : No public constructor A() 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 override /*1*/ /*fake_override*/ fun invoke(/*0*/ p1: [ERROR : No type element]): [ERROR : No type element] + public abstract override /*1*/ /*fake_override*/ fun invoke(/*0*/ categoryName: [ERROR : No type element]): [ERROR : No type element] public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/typeReferenceError.txt b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/typeReferenceError.txt index 7179979e202..97e4554e8e1 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/typeReferenceError.txt +++ b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/typeReferenceError.txt @@ -6,7 +6,7 @@ package typeReferenceError { public constructor Pair() 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 override /*1*/ /*fake_override*/ fun invoke(/*0*/ p1: [ERROR : No type element]): [ERROR : main] + public abstract override /*1*/ /*fake_override*/ fun invoke(/*0*/ c: [ERROR : No type element]): [ERROR : main] public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } } diff --git a/compiler/testData/diagnostics/tests/kt435.kt b/compiler/testData/diagnostics/tests/kt435.kt new file mode 100644 index 00000000000..6d446e7b5d6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/kt435.kt @@ -0,0 +1,7 @@ +fun Any.foo1() : (i : Int) -> Unit { + return {} +} + +fun test(a : Any) { + a.foo1()() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/kt435.txt b/compiler/testData/diagnostics/tests/kt435.txt new file mode 100644 index 00000000000..624bb69c6ef --- /dev/null +++ b/compiler/testData/diagnostics/tests/kt435.txt @@ -0,0 +1,4 @@ +package + +public fun test(/*0*/ a: kotlin.Any): kotlin.Unit +public fun kotlin.Any.foo1(): (i: kotlin.Int) -> kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 637abe57621..73248aa792d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -367,6 +367,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt435.kt") + public void testKt435() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/kt435.kt"); + doTest(fileName); + } + @TestMetadata("kt53.kt") public void testKt53() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/kt53.kt"); 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 df6d93b438d..8bffb9e6929 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt @@ -23,23 +23,29 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.util.OperatorNameConventions class FunctionInvokeDescriptor private constructor( container: DeclarationDescriptor, original: FunctionInvokeDescriptor?, - callableKind: CallableMemberDescriptor.Kind + callableKind: CallableMemberDescriptor.Kind, + private val hasSynthesizedParameterNames: Boolean ) : SimpleFunctionDescriptorImpl( container, original, Annotations.EMPTY, - Name.identifier("invoke"), + OperatorNameConventions.INVOKE, callableKind, SourceElement.NO_SOURCE ) { + init { + this.isOperator = true + } + // "p0", "p1", etc. should not be baked into the language override fun hasStableParameterNames(): Boolean = false - override fun hasSynthesizedParameterNames(): Boolean = true + override fun hasSynthesizedParameterNames(): Boolean = hasSynthesizedParameterNames override fun createSubstitutedCopy( newOwner: DeclarationDescriptor, @@ -49,7 +55,7 @@ class FunctionInvokeDescriptor private constructor( annotations: Annotations, source: SourceElement ): FunctionDescriptorImpl { - return FunctionInvokeDescriptor(newOwner, original as FunctionInvokeDescriptor?, kind) + return FunctionInvokeDescriptor(newOwner, original as FunctionInvokeDescriptor?, kind, hasSynthesizedParameterNames) } override fun isExternal(): Boolean = false @@ -58,11 +64,33 @@ class FunctionInvokeDescriptor private constructor( override fun isTailrec(): Boolean = false + 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 newDescriptor = FunctionInvokeDescriptor(containingDeclaration, this, kind, hasSynthesizedParameterNames) + val newValueParameters = valueParameters.map { + var newName = it.name + val parameterIndex = it.index + val nameIndex = parameterIndex - indexShift + if (nameIndex >= 0) { + val parameterName = parameterNames[nameIndex] + if (!parameterName.isSpecial) { + newName = parameterName + } + } + it.copy(newDescriptor, newName, parameterIndex) + } + newDescriptor.initialize(extensionReceiverParameterType, dispatchReceiverParameter, typeParameters, newValueParameters, returnType, modality, visibility) + return newDescriptor + } + companion object Factory { fun create(functionClass: FunctionClassDescriptor): FunctionInvokeDescriptor { val typeParameters = functionClass.declaredTypeParameters - val result = FunctionInvokeDescriptor(functionClass, null, CallableMemberDescriptor.Kind.DECLARATION) + val result = FunctionInvokeDescriptor(functionClass, null, CallableMemberDescriptor.Kind.DECLARATION, hasSynthesizedParameterNames = true) result.initialize( null, functionClass.thisAsReceiverParameter, @@ -74,7 +102,6 @@ class FunctionInvokeDescriptor private constructor( Modality.ABSTRACT, Visibilities.PUBLIC ) - result.isOperator = true return result } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt index 89a6986939c..519b93c1f37 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt @@ -16,10 +16,16 @@ 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 @@ -57,6 +63,28 @@ class FunctionType( */ 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) diff --git a/idea/testData/parameterInfo/functionCall/FunctionalValue1.kt b/idea/testData/parameterInfo/functionCall/FunctionalValue1.kt index 80176adec69..9447582d25d 100644 --- a/idea/testData/parameterInfo/functionCall/FunctionalValue1.kt +++ b/idea/testData/parameterInfo/functionCall/FunctionalValue1.kt @@ -2,7 +2,6 @@ fun x(name: String, next: (name: String) -> String): String { return next() } -//TODO: use parameter names from functional type /* -Text: (String), Disabled: false, Strikeout: false, Green: true +Text: (name: String), Disabled: false, Strikeout: false, Green: true */ diff --git a/idea/testData/parameterInfo/functionCall/FunctionalValue2.kt b/idea/testData/parameterInfo/functionCall/FunctionalValue2.kt index 9bc7eb2de70..f5f7f8958b5 100644 --- a/idea/testData/parameterInfo/functionCall/FunctionalValue2.kt +++ b/idea/testData/parameterInfo/functionCall/FunctionalValue2.kt @@ -5,8 +5,7 @@ fun call() { header("sdf", "sdjfn") } -//TODO: use parameter names from functional type /* -Text: (String, String), Disabled: false, Strikeout: false, Green: true Text: (name: String, value: Int), Disabled: false, Strikeout: false, Green: false +Text: (s: String, s1: String), Disabled: false, Strikeout: false, Green: true */