diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt index 7391c2a3772..ac00ba1b552 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver import org.jetbrains.kotlin.resolve.sam.SamConversionOracle import org.jetbrains.kotlin.resolve.scopes.SyntheticScope import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes +import org.jetbrains.kotlin.resolve.scopes.synthetic.FunInterfaceConstructorsSyntheticScope import org.jetbrains.kotlin.storage.StorageManager class JavaSyntheticScopes( @@ -69,7 +70,10 @@ class JavaSyntheticScopes( ) ) - scopes = listOf(javaSyntheticPropertiesScope, samAdapterFunctionsScope) + scopesFromExtensions + val funInterfaceConstructorsScopes = + FunInterfaceConstructorsSyntheticScope(storageManager, lookupTracker, samConventionResolver, samConversionOracle) + + scopes = listOf(javaSyntheticPropertiesScope, samAdapterFunctionsScope, funInterfaceConstructorsScopes) + scopesFromExtensions if (samConversionPerArgumentIsEnabled) { val forceEnabledSamAdapterFunctionsScope = SamAdapterFunctionsScope( 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 4be6ee76dc1..40feaca70d4 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.incremental.record import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor +import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor import org.jetbrains.kotlin.load.java.sam.JavaSingleAbstractMethodUtils import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor import org.jetbrains.kotlin.name.Name @@ -71,7 +72,7 @@ class SamAdapterFunctionsScope( } private val samConstructorForClassifier = - storageManager.createMemoizedFunction { classifier -> + storageManager.createMemoizedFunction { classifier -> createSamConstructorFunction(classifier.containingDeclaration, classifier, samResolver, samConversionOracle) } @@ -257,15 +258,14 @@ class SamAdapterFunctionsScope( return getTypeAliasSamConstructor(classifier) } - if (classifier !is ClassDescriptor) return null - if (!JavaSingleAbstractMethodUtils.isSamClassDescriptor(classifier)) return null + if (classifier !is LazyJavaClassDescriptor || classifier.defaultFunctionTypeForSamInterface == null) return null return samConstructorForClassifier(classifier) } private fun getTypeAliasSamConstructor(classifier: TypeAliasDescriptor): SamConstructorDescriptor? { val classDescriptor = classifier.classDescriptor ?: return null - if (!JavaSingleAbstractMethodUtils.isSamClassDescriptor(classDescriptor)) return null + if (classDescriptor !is LazyJavaClassDescriptor || classDescriptor.defaultFunctionTypeForSamInterface == null) return null return createTypeAliasSamConstructorFunction( classifier, samConstructorForClassifier(classDescriptor), samResolver, samConversionOracle diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/funConstructorCallJS.kt b/compiler/testData/diagnostics/testsWithJsStdLib/funConstructorCallJS.kt new file mode 100644 index 00000000000..5f32ce48eb9 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/funConstructorCallJS.kt @@ -0,0 +1,10 @@ +fun interface Foo { + fun invoke(): T +} + +fun test() { + Foo { } + Foo { } + Foo { } + Foo { "" } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/funConstructorCallJS.txt b/compiler/testData/diagnostics/testsWithJsStdLib/funConstructorCallJS.txt new file mode 100644 index 00000000000..8ff950dbc19 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/funConstructorCallJS.txt @@ -0,0 +1,10 @@ +package + +public fun test(): kotlin.Unit + +public fun interface Foo { + 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 invoke(): T + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/multiplatform/funInterfaces/common.kt b/compiler/testData/multiplatform/funInterfaces/common.kt index c3c5999df7d..3d08a65a497 100644 --- a/compiler/testData/multiplatform/funInterfaces/common.kt +++ b/compiler/testData/multiplatform/funInterfaces/common.kt @@ -10,4 +10,5 @@ fun foo(k: KRunnable) = k.invoke() fun test() { foo { "OK" } + foo(KRunnable { "OK "}) } \ No newline at end of file diff --git a/compiler/testData/multiplatform/funInterfaces/js.kt b/compiler/testData/multiplatform/funInterfaces/js.kt index 68963025a89..b95746b5f68 100644 --- a/compiler/testData/multiplatform/funInterfaces/js.kt +++ b/compiler/testData/multiplatform/funInterfaces/js.kt @@ -10,4 +10,5 @@ fun foo(k: KRunnable) = k.invoke() fun test() { foo { "OK" } + foo(KRunnable { "OK " }) } \ No newline at end of file diff --git a/compiler/testData/multiplatform/funInterfaces/jvm.kt b/compiler/testData/multiplatform/funInterfaces/jvm.kt index 773e3b7724e..39433761d36 100644 --- a/compiler/testData/multiplatform/funInterfaces/jvm.kt +++ b/compiler/testData/multiplatform/funInterfaces/jvm.kt @@ -10,4 +10,5 @@ fun foo(k: KRunnable) = k.invoke() fun test() { foo { "OK" } + foo(KRunnable { "OK " }) } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java index bbcc1e9f755..702e5f51379 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -28,6 +28,11 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @TestMetadata("funConstructorCallJS.kt") + public void testFunConstructorCallJS() throws Exception { + runTest("compiler/testData/diagnostics/testsWithJsStdLib/funConstructorCallJS.kt"); + } + @TestMetadata("implementingFunction.kt") public void testImplementingFunction() throws Exception { runTest("compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SyntheticScopes.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SyntheticScopes.kt index 8b225162cfb..039f25a072d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SyntheticScopes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SyntheticScopes.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.scopes.synthetic.FunInterfaceConstructorsScopeProvider import org.jetbrains.kotlin.types.KotlinType @@ -96,7 +97,7 @@ interface SyntheticScope { } } -@DefaultImplementation(impl = SyntheticScopes.Empty::class) +@DefaultImplementation(impl = FunInterfaceConstructorsScopeProvider::class) interface SyntheticScopes { val scopes: Collection diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/synthetic/FunInterfaceConstructorsSyntheticScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/synthetic/FunInterfaceConstructorsSyntheticScope.kt new file mode 100644 index 00000000000..05351c4167f --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/synthetic/FunInterfaceConstructorsSyntheticScope.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.scopes.synthetic + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.incremental.components.LookupTracker +import org.jetbrains.kotlin.incremental.record +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.sam.* +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.ResolutionScope +import org.jetbrains.kotlin.resolve.scopes.SyntheticScope +import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes +import org.jetbrains.kotlin.storage.StorageManager + +class FunInterfaceConstructorsScopeProvider( + storageManager: StorageManager, + lookupTracker: LookupTracker, + samResolver: SamConversionResolver, + samConversionOracle: SamConversionOracle +) : SyntheticScopes { + override val scopes: Collection = listOf( + FunInterfaceConstructorsSyntheticScope(storageManager, lookupTracker, samResolver, samConversionOracle) + ) +} + +class FunInterfaceConstructorsSyntheticScope( + storageManager: StorageManager, + private val lookupTracker: LookupTracker, + private val samResolver: SamConversionResolver, + private val samConversionOracle: SamConversionOracle +) : SyntheticScope.Default() { + + private val samConstructorForClassifier = + storageManager.createMemoizedFunction { classifier -> + createSamConstructorFunction(classifier.containingDeclaration, classifier, samResolver, samConversionOracle) + } + + override fun getSyntheticConstructors(scope: ResolutionScope, name: Name, location: LookupLocation): Collection { + val classifier = scope.getContributedClassifier(name, location) ?: return emptyList() + recordSamLookupsToClassifier(classifier, location) + + return listOfNotNull(getSamConstructor(classifier)) + } + + override fun getSyntheticConstructors(scope: ResolutionScope): Collection { + val classifiers = scope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS).filterIsInstance() + + return classifiers.mapNotNull { getSamConstructor(it) } + } + + private fun getSamConstructor(classifier: ClassifierDescriptor): SamConstructorDescriptor? { + if (classifier is TypeAliasDescriptor) { + return getTypeAliasSamConstructor(classifier) + } + + if (classifier !is ClassDescriptor) return null + if (!classifier.isFun) return null + + return samConstructorForClassifier(classifier) + } + + private fun getTypeAliasSamConstructor(classifier: TypeAliasDescriptor): SamConstructorDescriptor? { + val classDescriptor = classifier.classDescriptor ?: return null + if (!classDescriptor.isFun) return null + + return createTypeAliasSamConstructorFunction( + classifier, samConstructorForClassifier(classDescriptor), samResolver, samConversionOracle + ) + } + + private fun recordSamLookupsToClassifier(classifier: ClassifierDescriptor, location: LookupLocation) { + if (classifier !is ClassDescriptor || !classifier.isFun) return + lookupTracker.record(location, classifier, SAM_LOOKUP_NAME) + } +} \ No newline at end of file