Don't generate delegation to java default methods

#KT-15226  Fixed
This commit is contained in:
Mikhael Bogdanov
2016-12-13 15:07:06 +01:00
parent 653d589f98
commit 268d55104c
18 changed files with 367 additions and 14 deletions
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.jvm
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
object JvmDelegationFilter : DelegationFilter {
override fun filter(interfaceMember: CallableMemberDescriptor): Boolean {
//We always have only one implementation otherwise it's an error in kotlin and java
return !isJavaDefaultMethod(DescriptorUtils.unwrapFakeOverride(interfaceMember))
}
private fun isJavaDefaultMethod(interfaceMember: CallableMemberDescriptor): Boolean {
return interfaceMember is JavaMethodDescriptor && interfaceMember.modality != Modality.ABSTRACT
}
}
@@ -24,10 +24,12 @@ import org.jetbrains.kotlin.resolve.PlatformConfigurator
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
import org.jetbrains.kotlin.resolve.checkers.MissingDependencyClassChecker
import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker
import org.jetbrains.kotlin.resolve.jvm.JvmDelegationFilter
import org.jetbrains.kotlin.resolve.jvm.JvmOverloadFilter
import org.jetbrains.kotlin.resolve.jvm.JvmTypeSpecificityComparator
import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionsTypeChecker
import org.jetbrains.kotlin.resolve.jvm.checkers.*
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
import org.jetbrains.kotlin.synthetic.JavaSyntheticConstructorsProvider
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
import org.jetbrains.kotlin.types.DynamicTypesSettings
@@ -82,7 +84,9 @@ object JvmPlatformConfigurator : PlatformConfigurator(
overloadFilter = JvmOverloadFilter,
platformToKotlinClassMap = JavaToKotlinClassMap.INSTANCE
platformToKotlinClassMap = JavaToKotlinClassMap.INSTANCE,
delegationFilter = JvmDelegationFilter
) {
override fun configureModuleComponents(container: StorageComponentContainer) {
container.useImpl<JvmReflectionAPICallChecker>()
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -32,8 +33,9 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
private val ownerDescriptor: ClassDescriptor,
private val existingMembers: Collection<CallableDescriptor>,
private val trace: BindingTrace,
private val memberExtractor: DelegationResolver.MemberExtractor<T>,
private val typeResolver: DelegationResolver.TypeResolver
private val memberExtractor: MemberExtractor<T>,
private val typeResolver: TypeResolver,
private val delegationFilter: DelegationFilter
) {
private fun generateDelegatedMembers(): Collection<T> {
@@ -86,7 +88,9 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
memberExtractor.getMembersByType(it)
} ?: emptyList<CallableMemberDescriptor>()
return memberExtractor.getMembersByType(interfaceType).filter { descriptor ->
descriptor.isOverridable && !classSupertypeMembers.any { isOverridableBy(it, descriptor) }
descriptor.isOverridable &&
!classSupertypeMembers.any { isOverridableBy(it, descriptor) } &&
delegationFilter.filter(descriptor)
}
}
@@ -105,9 +109,10 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
existingMembers: Collection<CallableDescriptor>,
trace: BindingTrace,
memberExtractor: MemberExtractor<T>,
typeResolver: TypeResolver
typeResolver: TypeResolver,
delegationFilter: DelegationFilter
): Collection<T> =
DelegationResolver(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver)
DelegationResolver(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver, delegationFilter)
.generateDelegatedMembers()
private fun isOverridingAnyOf(
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap
import org.jetbrains.kotlin.resolve.calls.checkers.*
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.resolve.checkers.*
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
import org.jetbrains.kotlin.resolve.scopes.SyntheticConstructorsProvider
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
import org.jetbrains.kotlin.types.DynamicTypesSettings
@@ -50,8 +51,10 @@ abstract class TargetPlatform(val platformName: String) {
}
override val platformConfigurator =
object : PlatformConfigurator(DynamicTypesSettings(), listOf(), listOf(), listOf(), listOf(), listOf(),
IdentifierChecker.DEFAULT, OverloadFilter.DEFAULT, PlatformToKotlinClassMap.EMPTY) {
object : PlatformConfigurator(
DynamicTypesSettings(), listOf(), listOf(), listOf(), listOf(), listOf(),
IdentifierChecker.DEFAULT, OverloadFilter.DEFAULT, PlatformToKotlinClassMap.EMPTY, DelegationFilter.DEFAULT
) {
override fun configureModuleComponents(container: StorageComponentContainer) {
container.useInstance(SyntheticScopes.Empty)
container.useInstance(SyntheticConstructorsProvider.Empty)
@@ -94,7 +97,8 @@ abstract class PlatformConfigurator(
private val additionalAnnotationCheckers: List<AdditionalAnnotationChecker>,
private val identifierChecker: IdentifierChecker,
private val overloadFilter: OverloadFilter,
private val platformToKotlinClassMap: PlatformToKotlinClassMap
private val platformToKotlinClassMap: PlatformToKotlinClassMap,
private val delegationFilter: DelegationFilter
) {
private val declarationCheckers: List<DeclarationChecker> = DEFAULT_DECLARATION_CHECKERS + additionalDeclarationCheckers
private val callCheckers: List<CallChecker> = DEFAULT_CALL_CHECKERS + additionalCallCheckers
@@ -113,6 +117,7 @@ abstract class PlatformConfigurator(
useInstance(identifierChecker)
useInstance(overloadFilter)
useInstance(platformToKotlinClassMap)
useInstance(delegationFilter)
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.lazy
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
interface DelegationFilter {
fun filter(interfaceMember: CallableMemberDescriptor): Boolean
object DEFAULT : DelegationFilter {
override fun filter(interfaceMember: CallableMemberDescriptor) = true
}
}
@@ -40,4 +40,5 @@ interface LazyClassContext {
val supertypeLoopChecker: SupertypeLoopChecker
val languageVersionSettings: LanguageVersionSettings
val syntheticResolveExtension: SyntheticResolveExtension
val delegationFilter: DelegationFilter
}
@@ -81,6 +81,7 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
private LocalDescriptorResolver localDescriptorResolver;
private SupertypeLoopChecker supertypeLoopsResolver;
private LanguageVersionSettings languageVersionSettings;
private DelegationFilter delegationFilter;
private final SyntheticResolveExtension syntheticResolveExtension;
@@ -134,6 +135,12 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
this.languageVersionSettings = languageVersionSettings;
}
@Inject
public void setDelegationFilter(@NotNull DelegationFilter delegationFilter) {
this.delegationFilter = delegationFilter;
}
// Only calls from injectors expected
@Deprecated
public ResolveSession(
@@ -445,6 +452,12 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
return languageVersionSettings;
}
@NotNull
@Override
public DelegationFilter getDelegationFilter() {
return delegationFilter;
}
@NotNull
@Override
public SyntheticResolveExtension getSyntheticResolveExtension() {
@@ -295,7 +295,9 @@ open class LazyClassMemberScope(
override fun getMembersByType(type: KotlinType): Collection<T> =
extractor.extract(type, name)
}
return DelegationResolver.generateDelegatedMembers(classOrObject, thisDescriptor, existingDescriptors, trace, lazyMemberExtractor, lazyTypeResolver)
return DelegationResolver.generateDelegatedMembers(
classOrObject, thisDescriptor, existingDescriptors, trace, lazyMemberExtractor, lazyTypeResolver, c.delegationFilter
)
}
private fun addDataClassMethods(result: MutableCollection<DeclarationDescriptor>, location: LookupLocation) {
@@ -60,7 +60,8 @@ class LocalClassifierAnalyzer(
private val platform: TargetPlatform,
private val lookupTracker: LookupTracker,
private val supertypeLoopChecker: SupertypeLoopChecker,
private val languageVersionSettings: LanguageVersionSettings
private val languageVersionSettings: LanguageVersionSettings,
private val delegationFilter: DelegationFilter
) {
fun processClassOrObject(
scope: LexicalWritableScope?,
@@ -91,7 +92,8 @@ class LocalClassifierAnalyzer(
annotationResolver,
supertypeLoopChecker,
languageVersionSettings,
SyntheticResolveExtension.getInstance(project)
SyntheticResolveExtension.getInstance(project),
delegationFilter
)
)
@@ -116,7 +118,8 @@ class LocalClassDescriptorHolder(
val annotationResolver: AnnotationResolver,
val supertypeLoopChecker: SupertypeLoopChecker,
val languageVersionSettings: LanguageVersionSettings,
val syntheticResolveExtension: SyntheticResolveExtension
val syntheticResolveExtension: SyntheticResolveExtension,
val delegationFilter: DelegationFilter
) {
// We do not need to synchronize here, because this code is used strictly from one thread
private var classDescriptor: ClassDescriptor? = null
@@ -154,6 +157,7 @@ class LocalClassDescriptorHolder(
override val supertypeLoopChecker = this@LocalClassDescriptorHolder.supertypeLoopChecker
override val languageVersionSettings = this@LocalClassDescriptorHolder.languageVersionSettings
override val syntheticResolveExtension = this@LocalClassDescriptorHolder.syntheticResolveExtension
override val delegationFilter: DelegationFilter = this@LocalClassDescriptorHolder.delegationFilter
}
,
containingDeclaration,
@@ -0,0 +1,27 @@
// FILE: Base.java
public interface Base {
String getValue();
default String test() {
return getValue();
}
}
// FILE: main.kt
public interface BaseKotlin : Base {
}
class Fail : BaseKotlin {
override fun getValue() = "Fail"
}
fun box(): String {
val z = object : BaseKotlin by Fail() {
override fun getValue() = "OK"
}
return z.test()
}
@@ -0,0 +1,31 @@
// FILE: Base.java
public interface Base {
String getValue();
default String test() {
return getValue();
}
}
// FILE: main.kt
public interface BaseKotlin : Base {
override fun getValue() = "OK"
override fun test(): String {
return getValue();
}
}
class OK : BaseKotlin {
override fun getValue() = "OK"
}
fun box(): String {
val ok = object : BaseKotlin by OK() {
override fun getValue() = "Fail"
}
return ok.test()
}
@@ -0,0 +1,35 @@
// FILE: Base.java
public interface Base {
String getValue();
default String test() {
return getValue();
}
}
// FILE: Base2.java
public interface Base2 extends Base {
default String test() {
return "O" + getValue();
}
}
// FILE: main.kt
interface KBase : Base
interface Derived : KBase, Base2
class Fail : Derived {
override fun getValue() = "Fail"
}
fun box(): String {
val z = object : Derived by Fail() {
override fun getValue() = "K"
}
return z.test()
}
@@ -0,0 +1,35 @@
// FILE: Base.java
public interface Base {
String getValue();
default String test()
{
return getValue();
}
}
// FILE: Base2.java
public interface Base2 extends Base {
}
// FILE: main.kt
interface KBase : Base {
override fun test() = "O" + getValue()
}
interface Derived : KBase, Base2
class K : Derived {
override fun getValue() = "K"
}
fun box(): String {
val z = object : Derived by K() {
override fun getValue() = "Fail"
}
return z.test()
}
@@ -0,0 +1,22 @@
// FILE: Base.java
public interface Base {
String getValue();
default String test() {
return getValue();
}
}
// FILE: main.kt
class Fail : Base {
override fun getValue() = "Fail"
}
class Derived : Base by Fail() {
override fun getValue() = "OK"
}
fun box(): String {
return Derived().test()
}
@@ -0,0 +1,32 @@
// FILE: Base.java
public interface Base extends KBase {
String getValue();
default String test() {
return getValue();
}
}
// FILE: main.kt
interface KBase {
fun getValue(): String
fun test(): String
}
class Fail : Base {
override fun getValue() = "Fail"
}
fun box(): String {
val z1 = object : KBase by Fail() {
override fun getValue() = "OK"
}
if (z1.test() != "Fail") return "fail 1"
val z2 = object : Base by Fail() {
override fun getValue() = "OK"
}
return z2.test()
}
@@ -0,0 +1,21 @@
// FILE: Base.java
public interface Base {
String getValue();
default String test() {
return getValue();
}
}
// FILE: main.kt
class Fail : Base {
override fun getValue() = "Fail"
}
fun box(): String {
val z = object : Base by Fail() {
override fun getValue() = "OK"
}
return z.test()
}
@@ -120,6 +120,57 @@ public class BlackBoxWithJava8CodegenTestGenerated extends AbstractBlackBoxCodeg
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/java8/box/delegationBy")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DelegationBy extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInDelegationBy() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/java8/box/delegationBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("byMiddleInterface.kt")
public void testByMiddleInterface() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/delegationBy/byMiddleInterface.kt");
doTest(fileName);
}
@TestMetadata("defaultOverride.kt")
public void testDefaultOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/delegationBy/defaultOverride.kt");
doTest(fileName);
}
@TestMetadata("diamond.kt")
public void testDiamond() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/delegationBy/diamond.kt");
doTest(fileName);
}
@TestMetadata("diamond2.kt")
public void testDiamond2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/delegationBy/diamond2.kt");
doTest(fileName);
}
@TestMetadata("inClassDeclaration.kt")
public void testInClassDeclaration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/delegationBy/inClassDeclaration.kt");
doTest(fileName);
}
@TestMetadata("mixed.kt")
public void testMixed() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/delegationBy/mixed.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/delegationBy/simple.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/java8/box/jvm8")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.OverloadFilter
import org.jetbrains.kotlin.resolve.PlatformConfigurator
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
import org.jetbrains.kotlin.resolve.scopes.SyntheticConstructorsProvider
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
import org.jetbrains.kotlin.types.DynamicTypesAllowed
@@ -45,7 +46,8 @@ object JsPlatformConfigurator : PlatformConfigurator(
additionalAnnotationCheckers = listOf(),
identifierChecker = IdentifierChecker.DEFAULT,
overloadFilter = OverloadFilter.DEFAULT,
platformToKotlinClassMap = PlatformToKotlinClassMap.EMPTY
platformToKotlinClassMap = PlatformToKotlinClassMap.EMPTY,
delegationFilter = DelegationFilter.DEFAULT
) {
override fun configureModuleComponents(container: StorageComponentContainer) {
container.useImpl<JsCallChecker>()