From 415c3d57af7c275ffe72c31ddf574be98c62c770 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 1 Mar 2017 20:02:51 +0300 Subject: [PATCH] Fix substitutor for synthetic SAM adapters When synthetic member comes not from the receiver type itself, but from one of its supertypes it doesn't make sense to subsitute the member with receiver type, we should obtain relevant supertype and use it instead. #KT-16578 Fixed --- .../synthetic/SamAdapterFunctionsScope.kt | 20 ++++++++++++------ .../tests/j+k/sam/samOnTypeParameter.kt | 17 +++++++++++++++ .../tests/j+k/sam/samOnTypeParameter.txt | 21 +++++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++++++ .../jetbrains/kotlin/types/checker/utils.kt | 4 ++-- 5 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.txt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt index 98b79206fc9..1cfdf0fab9c 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.SyntheticScope import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.checker.findCorrespondingSupertype import java.util.* import kotlin.properties.Delegates @@ -58,10 +59,8 @@ class SamAdapterFunctionsScope( override fun getSyntheticMemberFunctions(receiverTypes: Collection, name: Name, location: LookupLocation): Collection { var result: SmartList? = null for (type in receiverTypes) { - val substitutorForType by lazy { buildMemberScopeSubstitutorForType(type) } - for (function in type.memberScope.getContributedFunctions(name, location)) { - val extension = extensionForFunction(function.original)?.substitute(substitutorForType) + val extension = extensionForFunction(function.original)?.substituteForReceiverType(type) if (extension != null) { if (result == null) { result = SmartList() @@ -77,15 +76,24 @@ class SamAdapterFunctionsScope( } } - private fun buildMemberScopeSubstitutorForType(type: KotlinType) = - TypeConstructorSubstitution.create(type).wrapWithCapturingSubstitution(needApproximation = true).buildSubstitutor() + private fun FunctionDescriptor.substituteForReceiverType(receiverType: KotlinType): FunctionDescriptor? { + val containingClass = containingDeclaration as? ClassDescriptor ?: return null + val correspondingSupertype = findCorrespondingSupertype(receiverType, containingClass.defaultType) ?: return null + + return substitute( + TypeConstructorSubstitution + .create(correspondingSupertype) + .wrapWithCapturingSubstitution(needApproximation = true) + .buildSubstitutor() + ) + } override fun getSyntheticMemberFunctions(receiverTypes: Collection): Collection { return receiverTypes.flatMapTo(LinkedHashSet()) { type -> type.memberScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) .filterIsInstance() .mapNotNull { - extensionForFunction(it.original)?.substitute(buildMemberScopeSubstitutorForType(type)) + extensionForFunction(it.original)?.substituteForReceiverType(type) } } } diff --git a/compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.kt b/compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.kt new file mode 100644 index 00000000000..4b32b73471d --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.kt @@ -0,0 +1,17 @@ +// FILE: FormFieldValidatorPresenterTest.java +public class FormFieldValidatorPresenterTest { + + public void setValidationListenerTest(ValidationListenerTest validationListener) { + } + + public interface ValidationListenerTest { + void onValidityChanged(boolean valid); + } +} +// FILE: main.kt +fun

> setValidationListener( + presenter: P, + validationListener: (Boolean) -> Unit +) { + presenter.setValidationListenerTest(validationListener) // Error: Type mismatch: inferred type is (Boolean) -> Unit but FormFieldValidatorPresenterTest.ValidationListenerTest! was expected +} diff --git a/compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.txt b/compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.txt new file mode 100644 index 00000000000..03e070dfeec --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.txt @@ -0,0 +1,21 @@ +package + +public fun > setValidationListener(/*0*/ presenter: P, /*1*/ validationListener: (kotlin.Boolean) -> kotlin.Unit): kotlin.Unit + +public open class FormFieldValidatorPresenterTest { + public constructor FormFieldValidatorPresenterTest() + 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 open fun setValidationListenerTest(/*0*/ validationListener: FormFieldValidatorPresenterTest.ValidationListenerTest!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public interface ValidationListenerTest { + 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 onValidityChanged(/*0*/ valid: kotlin.Boolean): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + // Static members + public final /*synthesized*/ fun ValidationListenerTest(/*0*/ function: (valid: kotlin.Boolean) -> kotlin.Unit): FormFieldValidatorPresenterTest.ValidationListenerTest +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 65ab17d9739..48bba762f01 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -12234,6 +12234,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("samOnTypeParameter.kt") + public void testSamOnTypeParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.kt"); + doTest(fileName); + } + @TestMetadata("typeInferenceOnSamAdapters.kt") public void testTypeInferenceOnSamAdapters() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/typeInferenceOnSamAdapters.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt index cd9a2c8e613..3646b041b4f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt @@ -27,7 +27,7 @@ private class SubtypePathNode(val type: KotlinType, val previous: SubtypePathNod fun findCorrespondingSupertype( subtype: KotlinType, supertype: KotlinType, - typeCheckingProcedureCallbacks: TypeCheckingProcedureCallbacks + typeCheckingProcedureCallbacks: TypeCheckingProcedureCallbacks = TypeCheckerProcedureCallbacksImpl() ): KotlinType? { val queue = ArrayDeque() queue.add(SubtypePathNode(subtype, null)) @@ -99,4 +99,4 @@ private fun TypeConstructor.debugInfo() = buildString { declarationDescriptor = declarationDescriptor.containingDeclaration } -} \ No newline at end of file +}