Simplify compatibility mode with ll=1.0 on JDK dependent built-ins

A lot of problem arise with current solution
(loading them with lowpriority annotation + additional call checkers):
- We errorneously treated ArrayList.stream as an existing method, while
  it's just a fake override from List
- The same problem arises when creating a class delegating to List.
  Also the latter case is failing with codegen internal error
  (see issue KT-16171)

The negative side of this solution is that instead of reporting meaningful
diagnostic, there will be UNRESOLVED_REFERENCE.
But it seems to be better than having strange problems like ones described above.

 #KT-16073 Fixed
 #KT-16171 Fixed
This commit is contained in:
Denis Zharkov
2017-02-07 18:59:25 +03:00
parent d84c303029
commit 1bb40afada
7 changed files with 58 additions and 120 deletions

View File

@@ -1,67 +0,0 @@
/*
* 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.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
object AdditionalBuiltInsMembersCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) return
val resultingDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return
if (resultingDescriptor.isAdditionalBuiltInMember()) {
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(reportOn, LanguageFeature.AdditionalBuiltInsMembers))
}
}
}
object AdditionalBuiltInsMemberOverrideDeclarationChecker : DeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings
) {
if (languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) return
val resultingDescriptor = descriptor as? CallableMemberDescriptor ?: return
val overrideKeyword = declaration.modifierList?.getModifier(KtTokens.OVERRIDE_KEYWORD) ?: return
val overriddenDescriptors = resultingDescriptor.original.overriddenDescriptors
if (overriddenDescriptors.isNotEmpty() && overriddenDescriptors.all { it.isAdditionalBuiltInMember() }) {
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(overrideKeyword, LanguageFeature.AdditionalBuiltInsMembers))
}
}
}
private fun CallableMemberDescriptor.isAdditionalBuiltInMember() =
KotlinBuiltIns.isBuiltIn(this) && this is JavaCallableMemberDescriptor

View File

@@ -44,7 +44,6 @@ object JvmPlatformConfigurator : PlatformConfigurator(
TypeParameterBoundIsNotArrayChecker(),
JvmSyntheticApplicabilityChecker(),
StrictfpApplicabilityChecker(),
AdditionalBuiltInsMemberOverrideDeclarationChecker,
HeaderImplDeclarationChecker()
),
@@ -57,8 +56,7 @@ object JvmPlatformConfigurator : PlatformConfigurator(
SuperCallWithDefaultArgumentsChecker(),
MissingDependencyClassChecker,
ProtectedSyntheticExtensionCallChecker,
ReifiedTypeParameterSubstitutionChecker(),
AdditionalBuiltInsMembersCallChecker
ReifiedTypeParameterSubstitutionChecker()
),
additionalTypeCheckers = listOf(

View File

@@ -0,0 +1,8 @@
// LANGUAGE_VERSION: 1.0
// WITH_RUNTIME
// FULL_JDK
class A(val x: List<String>) : List<String> by x
fun box(): String {
return A(listOf("OK"))[0]
}

View File

@@ -3,24 +3,44 @@
// SKIP_TXT
class A : java.util.ArrayList<String>() {
override fun stream(): java.util.stream.Stream<String> = super.stream()
// `stream` is defined in ArrayList, so it was impossible to override it in 1.0
<!NOTHING_TO_OVERRIDE!>override<!> fun stream(): java.util.stream.Stream<String> = super.<!UNRESOLVED_REFERENCE!>stream<!>()
// `sort` is defined in ArrayList, so it was possible to override it in 1.0
override fun sort(c: Comparator<in String>?) {
super.sort(c)
}
}
class A1 : java.util.ArrayList<String>() {
fun stream(): java.util.stream.Stream<String> = super.stream()
// `stream` is defined in ArrayList, so it was possible to declare it in 1.0 without an 'override' keyword
fun stream(): java.util.stream.Stream<String> = super.<!UNRESOLVED_REFERENCE!>stream<!>()
// `sort` is defined in ArrayList, so it was impossible to declare it in 1.0 without an 'override' keyword
<!VIRTUAL_MEMBER_HIDDEN!>fun sort(c: Comparator<in String>?)<!> {
super.sort(c)
}
}
interface A2 : List<String> {
<!UNSUPPORTED_FEATURE!>override<!> fun stream(): java.util.stream.Stream<String> = null!!
<!NOTHING_TO_OVERRIDE!>override<!> fun stream(): java.util.stream.Stream<String> = null!!
}
class B : <!UNSUPPORTED_FEATURE!>Throwable<!>("", null, false, false)
class B : <!NONE_APPLICABLE!>Throwable<!>("", null, false, false)
fun Throwable.<!EXTENSION_SHADOWED_BY_MEMBER!>fillInStackTrace<!>() = 1
class B1 : RuntimeException() {
<!NOTHING_TO_OVERRIDE!>override<!> fun fillInStackTrace(): Throwable { // 'override' keyword must be prohibited, as it was in 1.0.x
return this
}
}
fun foo(x: List<String>, y: Throwable) {
x.<!UNSUPPORTED_FEATURE!>stream<!>()
java.util.ArrayList<String>().stream()
class A3(val x: List<String>) : List<String> by x
fun Throwable.fillInStackTrace() = 1
fun foo(x: List<String>, y: Throwable, z: A3) {
x.<!UNRESOLVED_REFERENCE!>stream<!>()
java.util.ArrayList<String>().<!UNRESOLVED_REFERENCE!>stream<!>()
y.fillInStackTrace() checkType { _<Int>() }
@@ -28,6 +48,8 @@ fun foo(x: List<String>, y: Throwable) {
// Falls back to extension in stdlib
y.printStackTrace()
z.<!UNRESOLVED_REFERENCE!>stream<!>()
}
interface X {

View File

@@ -120,6 +120,12 @@ public class BlackBoxWithJava8CodegenTestGenerated extends AbstractBlackBoxCodeg
doTest(fileName);
}
@TestMetadata("streamBackwardCompatibility.kt")
public void testStreamBackwardCompatibility() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/streamBackwardCompatibility.kt");
doTest(fileName);
}
@TestMetadata("useStream.kt")
public void testUseStream() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/useStream.kt");

View File

@@ -21,8 +21,6 @@ import org.jetbrains.kotlin.builtins.CloneableClassScope
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
import org.jetbrains.kotlin.descriptors.annotations.createDeprecatedAnnotation
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
@@ -36,7 +34,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.platform.createMappedTypeParametersSubstitution
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
@@ -53,7 +50,6 @@ import org.jetbrains.kotlin.types.LazyWrappedType
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.SmartSet
import org.jetbrains.kotlin.utils.addToStdlib.check
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
import java.io.Serializable
import java.util.*
@@ -82,22 +78,6 @@ open class JvmBuiltInsSettings(
).let { AnnotationsImpl(listOf(it)) }
}
private val lowPriorityAnnotation: Annotations by storageManager.createLazyValue {
// We use both LowPriorityInOverloadResolution to achieve the following goal:
// If there is something to resolve to beside an additional built-in member, it's *almost* always will win
val lowPriorityAnnotation =
ClassDescriptorImpl(
moduleDescriptor.getPackage(LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME.parent()), LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME.shortName(),
Modality.FINAL, ClassKind.ANNOTATION_CLASS, moduleDescriptor.builtIns.anyType.singletonList(),
SourceElement.NO_SOURCE, /* isExternal = */ false
).run {
initialize(MemberScope.Empty, emptySet(), null)
AnnotationDescriptorImpl(defaultType, emptyMap(), SourceElement.NO_SOURCE)
}
AnnotationsImpl(listOf(lowPriorityAnnotation))
}
private fun StorageManager.createMockJavaIoSerializableType(): KotlinType {
val mockJavaIoPackageFragment = object : PackageFragmentDescriptorImpl(moduleDescriptor, FqName("java.io")) {
override fun getMemberScope() = MemberScope.Empty
@@ -131,6 +111,8 @@ open class JvmBuiltInsSettings(
))
}
if (!isAdditionalBuiltInsFeatureSupported) return emptyList()
return getAdditionalFunctions(classDescriptor) {
it.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS)
}.mapNotNull {
@@ -156,31 +138,24 @@ open class JvmBuiltInsSettings(
}
JDKMemberStatus.NOT_CONSIDERED -> {
if (!isAdditionalBuiltInsFeatureSupported) {
setAdditionalAnnotations(lowPriorityAnnotation)
}
else {
setAdditionalAnnotations(notConsideredDeprecation)
}
setAdditionalAnnotations(notConsideredDeprecation)
}
JDKMemberStatus.DROP -> return@mapNotNull null
JDKMemberStatus.WHITE_LIST -> {
if (!isAdditionalBuiltInsFeatureSupported) {
setAdditionalAnnotations(lowPriorityAnnotation)
}
}
JDKMemberStatus.WHITE_LIST -> Unit // Do nothing
}
}.build()!!
}
}
override fun getFunctionsNames(classDescriptor: DeserializedClassDescriptor): Set<Name> =
// NB: It's just an approximation that could be calculated relatively fast
// More precise computation would look like `getAdditionalFunctions` (and the measurements show that it would be rather slow)
classDescriptor.getJavaAnalogue()?.unsubstitutedMemberScope?.getFunctionNames() ?: emptySet()
override fun getFunctionsNames(classDescriptor: DeserializedClassDescriptor): Set<Name> {
if (!isAdditionalBuiltInsFeatureSupported) return emptySet()
// NB: It's just an approximation that could be calculated relatively fast
// More precise computation would look like `getAdditionalFunctions` (and the measurements show that it would be rather slow)
return classDescriptor.getJavaAnalogue()?.unsubstitutedMemberScope?.getFunctionNames() ?: emptySet()
}
private fun getAdditionalFunctions(
classDescriptor: DeserializedClassDescriptor,
@@ -287,7 +262,7 @@ open class JvmBuiltInsSettings(
}
override fun getConstructors(classDescriptor: DeserializedClassDescriptor): Collection<ClassConstructorDescriptor> {
if (classDescriptor.kind != ClassKind.CLASS) return emptyList()
if (classDescriptor.kind != ClassKind.CLASS || !isAdditionalBuiltInsFeatureSupported) return emptyList()
val javaAnalogueDescriptor = classDescriptor.getJavaAnalogue() ?: return emptyList()
@@ -314,11 +289,7 @@ open class JvmBuiltInsSettings(
setReturnType(classDescriptor.defaultType)
setPreserveSourceElement()
setSubstitution(substitutor.substitution)
if (!isAdditionalBuiltInsFeatureSupported) {
setAdditionalAnnotations(lowPriorityAnnotation)
}
else if (SignatureBuildingComponents.signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in WHITE_LIST_CONSTRUCTOR_SIGNATURES) {
if (SignatureBuildingComponents.signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in WHITE_LIST_CONSTRUCTOR_SIGNATURES) {
setAdditionalAnnotations(notConsideredDeprecation)
}

View File

@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.types.KotlinType
private val NO_INFER_ANNOTATION_FQ_NAME = FqName("kotlin.internal.NoInfer")
private val EXACT_ANNOTATION_FQ_NAME = FqName("kotlin.internal.Exact")
val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME = FqName("kotlin.internal.LowPriorityInOverloadResolution")
private val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME = FqName("kotlin.internal.LowPriorityInOverloadResolution")
private val HIDES_MEMBERS_ANNOTATION_FQ_NAME = FqName("kotlin.internal.HidesMembers")
private val ONLY_INPUT_TYPES_FQ_NAME = FqName("kotlin.internal.OnlyInputTypes")
private val DYNAMIC_EXTENSION_FQ_NAME = FqName("kotlin.internal.DynamicExtension")