diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SamAdapterOverridabilityCondition.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SamAdapterOverridabilityCondition.java index 6606487ef60..59776faff0d 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SamAdapterOverridabilityCondition.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SamAdapterOverridabilityCondition.java @@ -50,19 +50,27 @@ public class SamAdapterOverridabilityCondition implements ExternalOverridability for (ValueParameterDescriptor param1 : parameters1) { ValueParameterDescriptor param2 = parameters2.get(param1.getIndex()); - if (!equalClasses(param2.getType(), param1.getType())) { + if (differentClasses(param2.getType(), param1.getType())) { return false; } } return true; } - private static boolean equalClasses(@NotNull JetType type1, @NotNull JetType type2) { + private static boolean differentClasses(@NotNull JetType type1, @NotNull JetType type2) { DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor(); - if (declarationDescriptor1 == null) return false; // No class, classes are not equal + if (declarationDescriptor1 == null) return true; // No class, classes are not equal DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor(); - if (declarationDescriptor2 == null) return false; // Class of type1 is not null - return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal()); + if (declarationDescriptor2 == null) return true; // Class of type1 is not null + + if (declarationDescriptor1 instanceof TypeParameterDescriptor && declarationDescriptor2 instanceof TypeParameterDescriptor) { + // if type of value parameter is some generic parameter then their equality was checked by OverridingUtil before calling ExternalOverridabilityCondition + // Note that it's true unless we generate sam adapter for type parameter with SAM interface as upper bound: + // void foo(K runnable) {} + return false; + } + + return !declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal()); } // if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters diff --git a/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.kt b/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.kt new file mode 100644 index 00000000000..abd047b6ccd --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.kt @@ -0,0 +1,22 @@ +// FILE: MyFunc.java +public interface MyFunc { + V apply(K String); +} + +// FILE: ConcMap.java +public interface ConcMap { + V computeIfAbsent(K key, MyFunc mappingFunction); +} + +// FILE: ConcHashMap.java +public class ConcHashMap implements ConcMap { + @Override + V computeIfAbsent(K key, MyFunc mappingFunction) { } +} + +// FILE: main.kt + +public fun concurrentMap() { + val map = ConcHashMap() + map.computeIfAbsent("") { "" } // here +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.txt b/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.txt new file mode 100644 index 00000000000..e66188e9423 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.txt @@ -0,0 +1,29 @@ +package + +public /*synthesized*/ fun ConcMap(/*0*/ function: (K!, MyFunc!) -> V!): ConcMap +public /*synthesized*/ fun MyFunc(/*0*/ function: (K!) -> V!): MyFunc +public fun concurrentMap(): kotlin.Unit + +public open class ConcHashMap : ConcMap { + public constructor ConcHashMap() + java.lang.Override() public/*package*/ final override /*1*/ /*synthesized*/ fun computeIfAbsent(/*0*/ key: K!, /*1*/ mappingFunction: ((K!) -> V!)!): V! + java.lang.Override() public/*package*/ open override /*1*/ fun computeIfAbsent(/*0*/ key: K!, /*1*/ mappingFunction: MyFunc!): V! + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface ConcMap { + public final /*synthesized*/ fun computeIfAbsent(/*0*/ key: K!, /*1*/ mappingFunction: ((K!) -> V!)!): V! + public abstract fun computeIfAbsent(/*0*/ key: K!, /*1*/ mappingFunction: MyFunc!): V! + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface MyFunc { + public abstract fun apply(/*0*/ String: K!): V! + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.kt b/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.kt new file mode 100644 index 00000000000..8ce4c73cbd9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.kt @@ -0,0 +1,22 @@ +// FILE: MyFunc.java + +public interface MyFunc { + String apply(String x); +} + +// FILE: A.java +public interface A { + K foo(K key, MyFunc f); +} + +// FILE: B.java +public class B implements A { + @Override + public E foo(E key, MyFunc f) {return null;} +} + +// FILE: main.kt + +fun main() { + B().foo("") { "" } +} diff --git a/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.txt b/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.txt new file mode 100644 index 00000000000..fb416b164fe --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.txt @@ -0,0 +1,29 @@ +package + +public /*synthesized*/ fun A(/*0*/ function: (K!, MyFunc!) -> K!): A +public /*synthesized*/ fun MyFunc(/*0*/ function: (kotlin.String!) -> kotlin.String!): MyFunc +internal fun main(): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final /*synthesized*/ fun foo(/*0*/ key: K!, /*1*/ f: ((kotlin.String!) -> kotlin.String!)!): K! + public abstract fun foo(/*0*/ key: K!, /*1*/ f: MyFunc!): K! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class B : A { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + java.lang.Override() public final override /*1*/ /*synthesized*/ fun foo(/*0*/ key: E!, /*1*/ f: ((kotlin.String!) -> kotlin.String!)!): E! + java.lang.Override() public open override /*1*/ fun foo(/*0*/ key: E!, /*1*/ f: MyFunc!): E! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface MyFunc { + public abstract fun apply(/*0*/ x: kotlin.String!): kotlin.String! + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForClassTypeParameter.java b/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForClassTypeParameter.java new file mode 100644 index 00000000000..9ca4c1a9bfa --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForClassTypeParameter.java @@ -0,0 +1,24 @@ +package test; + +class NoSamForTypeParameter { + void foo(K runnable1, Runnable runnable2) {} +} + +class NoSamForTypeParameterDerived1 extends NoSamForTypeParameter { + @Override + void foo(Runnable runnable1, Runnable runnable2) {} +} + +class NoSamForTypeParameterDerived2 extends NoSamForTypeParameter { + void foo(E runnable1, Runnable runnable2) {} +} + +class NoSamForTypeParameterDerived3 extends NoSamForTypeParameterDerived1 { + @Override + void foo(Runnable runnable1, Runnable runnable2) {} +} + +class NoSamForTypeParameterDerived4 extends NoSamForTypeParameterDerived2 { + @Override + void foo(Runnable runnable1, Runnable runnable2) {} +} diff --git a/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForClassTypeParameter.txt b/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForClassTypeParameter.txt new file mode 100644 index 00000000000..41549d6757e --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForClassTypeParameter.txt @@ -0,0 +1,34 @@ +package test + +public/*package*/ open class NoSamForTypeParameter { + public/*package*/ constructor NoSamForTypeParameter() + public/*package*/ final /*synthesized*/ fun foo(/*0*/ p0: K!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open fun foo(/*0*/ p0: K!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} + +public/*package*/ open class NoSamForTypeParameterDerived1 : test.NoSamForTypeParameter { + public/*package*/ constructor NoSamForTypeParameterDerived1() + public/*package*/ final /*synthesized*/ fun foo(/*0*/ p0: (() -> kotlin.Unit)!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ final override /*1*/ /*fake_override*/ fun foo(/*0*/ p0: java.lang.Runnable!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open override /*1*/ fun foo(/*0*/ p0: java.lang.Runnable!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} + +public/*package*/ open class NoSamForTypeParameterDerived2 : test.NoSamForTypeParameter { + public/*package*/ constructor NoSamForTypeParameterDerived2() + public/*package*/ final override /*1*/ /*synthesized*/ fun foo(/*0*/ p0: E!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open override /*1*/ fun foo(/*0*/ p0: E!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} + +public/*package*/ open class NoSamForTypeParameterDerived3 : test.NoSamForTypeParameterDerived1 { + public/*package*/ constructor NoSamForTypeParameterDerived3() + public/*package*/ final override /*1*/ /*synthesized*/ fun foo(/*0*/ p0: (() -> kotlin.Unit)!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ final override /*1*/ /*fake_override*/ fun foo(/*0*/ p0: java.lang.Runnable!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open override /*1*/ fun foo(/*0*/ p0: java.lang.Runnable!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} + +public/*package*/ open class NoSamForTypeParameterDerived4 : test.NoSamForTypeParameterDerived2 { + public/*package*/ constructor NoSamForTypeParameterDerived4() + public/*package*/ final /*synthesized*/ fun foo(/*0*/ p0: (() -> kotlin.Unit)!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ final override /*1*/ /*fake_override*/ fun foo(/*0*/ p0: java.lang.Runnable!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open override /*1*/ fun foo(/*0*/ p0: java.lang.Runnable!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} diff --git a/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForMethodTypeParameter.java b/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForMethodTypeParameter.java new file mode 100644 index 00000000000..0b938967e81 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForMethodTypeParameter.java @@ -0,0 +1,20 @@ +package test; + +class NoSamForTypeParameter { + void foo(K runnable1, Runnable runnable2) {} +} + +class NoSamForTypeParameterDerived1 extends NoSamForTypeParameter { + @Override + void foo(Runnable runnable1, Runnable runnable2) {} +} + +class NoSamForTypeParameterDerived2 extends NoSamForTypeParameter { + @Override + void foo(K runnable1, Runnable runnable2) {} +} + +class NoSamForTypeParameterDerived3 extends NoSamForTypeParameterDerived1 { + @Override + void foo(Runnable runnable1, Runnable runnable2) {} +} diff --git a/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForMethodTypeParameter.txt b/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForMethodTypeParameter.txt new file mode 100644 index 00000000000..502943c5a02 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForMethodTypeParameter.txt @@ -0,0 +1,27 @@ +package test + +public/*package*/ open class NoSamForTypeParameter { + public/*package*/ constructor NoSamForTypeParameter() + public/*package*/ final /*synthesized*/ fun foo(/*0*/ p0: K!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open fun foo(/*0*/ p0: K!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} + +public/*package*/ open class NoSamForTypeParameterDerived1 : test.NoSamForTypeParameter { + public/*package*/ constructor NoSamForTypeParameterDerived1() + public/*package*/ final /*synthesized*/ fun foo(/*0*/ p0: (() -> kotlin.Unit)!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ final override /*1*/ /*fake_override*/ fun foo(/*0*/ p0: K!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open fun foo(/*0*/ p0: java.lang.Runnable!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} + +public/*package*/ open class NoSamForTypeParameterDerived2 : test.NoSamForTypeParameter { + public/*package*/ constructor NoSamForTypeParameterDerived2() + public/*package*/ final override /*1*/ /*synthesized*/ fun foo(/*0*/ p0: K!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open override /*1*/ fun foo(/*0*/ p0: K!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} + +public/*package*/ open class NoSamForTypeParameterDerived3 : test.NoSamForTypeParameterDerived1 { + public/*package*/ constructor NoSamForTypeParameterDerived3() + public/*package*/ final override /*1*/ /*synthesized*/ fun foo(/*0*/ p0: (() -> kotlin.Unit)!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ final override /*1*/ /*fake_override*/ fun foo(/*0*/ p0: K!, /*1*/ p1: (() -> kotlin.Unit)!): kotlin.Unit + public/*package*/ open override /*1*/ fun foo(/*0*/ p0: java.lang.Runnable!, /*1*/ p1: java.lang.Runnable!): kotlin.Unit +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 20b1715069e..fc9cbd12a0a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -7956,6 +7956,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("computeIfAbsentConcurrent.kt") + public void testComputeIfAbsentConcurrent() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/computeIfAbsentConcurrent.kt"); + doTest(fileName); + } + @TestMetadata("GenericsInSupertypes.kt") public void testGenericsInSupertypes() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/GenericsInSupertypes.kt"); @@ -8100,6 +8106,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("overrideWithSamAndTypeParameter.kt") + public void testOverrideWithSamAndTypeParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/overrideWithSamAndTypeParameter.kt"); + doTest(fileName); + } + @TestMetadata("packagePrivateClassStaticMember.kt") public void testPackagePrivateClassStaticMember() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/packagePrivateClassStaticMember.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java index 76e902d4c03..8787889e66f 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java @@ -1580,6 +1580,18 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { doTestCompiledJava(fileName); } + @TestMetadata("NoSamForClassTypeParameter.java") + public void testNoSamForClassTypeParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForClassTypeParameter.java"); + doTestCompiledJava(fileName); + } + + @TestMetadata("NoSamForMethodTypeParameter.java") + public void testNoSamForMethodTypeParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledJava/sam/adapters/NoSamForMethodTypeParameter.java"); + doTestCompiledJava(fileName); + } + @TestMetadata("NonTrivialFunctionType.java") public void testNonTrivialFunctionType() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledJava/sam/adapters/NonTrivialFunctionType.java");