From a7854bc0ce5e402c18891840af45b82a8bb2d5d9 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 12 Mar 2018 12:14:18 +0300 Subject: [PATCH] Fix SAM detection algorithm for case of default overrides #KT-22652 Fixed --- .../tests/j+k/sam/withDefaultMethods.kt | 22 +++++++++++++++++++ .../tests/j+k/sam/withDefaultMethods.txt | 20 +++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 +++++ .../DiagnosticsUsingJavacTestGenerated.java | 6 +++++ .../descriptors/LazyJavaClassDescriptor.kt | 3 +++ 5 files changed, 57 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.txt diff --git a/compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.kt b/compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.kt new file mode 100644 index 00000000000..acc211a1064 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.kt @@ -0,0 +1,22 @@ +// FILE: ALambda.java + +public interface ALambda { + ALambda curried(); + + ALambda tupled(); +} + +// FILE: ACheckedFunction0.java + +public interface ACheckedFunction0 extends ALambda { + + Integer apply(); + + default ALambda curried() { return null; } + default ALambda tupled() { return null; } +} + +// FILE: main.kt +fun test() { + ACheckedFunction0 { 2 } // error: Interface ACheckedFunction0 does not have constructors +} diff --git a/compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.txt b/compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.txt new file mode 100644 index 00000000000..e6643d4cb08 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.txt @@ -0,0 +1,20 @@ +package + +public fun test(): kotlin.Unit + +public interface ACheckedFunction0 : ALambda { + public abstract fun apply(): kotlin.Int! + public open override /*1*/ fun curried(): ALambda! + 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 open override /*1*/ fun tupled(): ALambda! +} + +public interface ALambda { + public abstract fun curried(): ALambda! + 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 abstract fun tupled(): ALambda! +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 604cffe10f9..7cf880c9895 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13230,6 +13230,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/typeInferenceOnSamAdapters.kt"); doTest(fileName); } + + @TestMetadata("withDefaultMethods.kt") + public void testWithDefaultMethods() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/j+k/samByProjectedType") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 97d8f8d5aea..7ee70dc9738 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -13230,6 +13230,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/typeInferenceOnSamAdapters.kt"); doTest(fileName); } + + @TestMetadata("withDefaultMethods.kt") + public void testWithDefaultMethods() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/withDefaultMethods.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/j+k/samByProjectedType") diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt index ead17cc45b8..05701238722 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt @@ -140,6 +140,9 @@ class LazyJavaClassDescriptor( // we'll just say that the interface MAY BE a SAM when it's not and then more detailed check will be applied. if (candidates.count { it.name.identifier !in PUBLIC_METHOD_NAMES_IN_OBJECT } > 1) return true + // If we have default methods the interface could be a SAM even while a super interface has more than one abstract method + if (jClass.methods.any { !it.isAbstract && it.typeParameters.isEmpty() }) return false + // Check if any of the super-interfaces contain too many methods to be a SAM return typeConstructor.supertypes.any { it.constructor.declarationDescriptor.safeAs()?.isDefinitelyNotSamInterface == true