From af67aff3030cecdd7f5a7a40c347bf6ee3398454 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 5 Mar 2020 18:12:48 +0300 Subject: [PATCH] [FIR] Support `Clonable` #KT-36762 Fixed --- .../fir/java/FirJavaModuleBasedSession.kt | 6 +- .../deserialization/ClassDeserialization.kt | 63 +++++++++++++-- .../resolve/impl/FirClonableSymbolProvider.kt | 76 +++++++++++++++++++ .../fir/resolve/testData/builtIns/kotlin.txt | 36 ++++++--- .../resolveWithStdlib/problems/cloneArray.kt | 4 +- .../resolveWithStdlib/problems/cloneArray.txt | 4 +- .../codegen/box/arrays/arraysAreCloneable.kt | 1 - .../testData/codegen/box/arrays/cloneArray.kt | 1 - .../box/arrays/clonePrimitiveArrays.kt | 1 - .../builtins/arraysAreCloneable.fir.kt | 36 ++++----- 10 files changed, 185 insertions(+), 43 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirClonableSymbolProvider.kt diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt index b29a6b8c635..dd55a4b5ea0 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt @@ -19,10 +19,7 @@ import org.jetbrains.kotlin.fir.resolve.FirProvider import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory import org.jetbrains.kotlin.fir.resolve.calls.jvm.JvmCallConflictResolverFactory -import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider -import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl -import org.jetbrains.kotlin.fir.resolve.impl.FirBuiltinSymbolProvider -import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl +import org.jetbrains.kotlin.fir.resolve.impl.* import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped import org.jetbrains.kotlin.fir.scopes.KotlinScopeProvider import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider @@ -104,6 +101,7 @@ class FirLibrarySession private constructor( kotlinScopeProvider ), FirBuiltinSymbolProvider(this, kotlinScopeProvider), + FirClonableSymbolProvider(this, kotlinScopeProvider), javaSymbolProvider, FirDependenciesSymbolProviderImpl(this) ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt index 601bd59bda9..1f292378859 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt @@ -5,22 +5,24 @@ package org.jetbrains.kotlin.fir.deserialization +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.addDeclarations -import org.jetbrains.kotlin.fir.declarations.builder.FirClassImplBuilder -import org.jetbrains.kotlin.fir.declarations.builder.FirSealedClassBuilder -import org.jetbrains.kotlin.fir.declarations.builder.buildEnumEntry +import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall +import org.jetbrains.kotlin.fir.resolve.impl.FirClonableSymbolProvider.Companion.CLONE +import org.jetbrains.kotlin.fir.resolve.impl.FirClonableSymbolProvider.Companion.CLONABLE_CLASS_ID import org.jetbrains.kotlin.fir.scopes.KotlinScopeProvider import org.jetbrains.kotlin.fir.symbols.CallableId -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol +import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl +import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.deserialization.NameResolver @@ -133,7 +135,58 @@ fun deserializeClassToSymbol( ClassId.fromString(nameResolver.getQualifiedClassName(it)) } } + addCloneForArrayIfNeeded(classId) }.build().also { (it.annotations as MutableList) += context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver) } } + +private val ARRAY = Name.identifier("Array") +private val ARRAY_CLASSES: Set = setOf( + ARRAY, + Name.identifier("ByteArray"), + Name.identifier("CharArray"), + Name.identifier("ShortArray"), + Name.identifier("IntArray"), + Name.identifier("LongArray"), + Name.identifier("FloatArray"), + Name.identifier("DoubleArray"), + Name.identifier("BooleanArray"), +) + +private fun AbstractFirRegularClassBuilder.addCloneForArrayIfNeeded(classId: ClassId) { + if (classId.packageFqName != KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) return + if (classId.shortClassName !in ARRAY_CLASSES) return + superTypeRefs += buildResolvedTypeRef { + type = ConeClassLikeTypeImpl( + ConeClassLikeLookupTagImpl(CLONABLE_CLASS_ID), + typeArguments = emptyArray(), + isNullable = false + ) + } + declarations += buildSimpleFunction { + session = this@addCloneForArrayIfNeeded.session + resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES + returnTypeRef = buildResolvedTypeRef { + val typeArguments = if (classId.shortClassName == ARRAY) { + arrayOf( + ConeTypeParameterTypeImpl( + ConeTypeParameterLookupTag(this@addCloneForArrayIfNeeded.typeParameters.first().symbol), isNullable = false + ) + ) + } else { + emptyArray() + } + type = ConeClassLikeTypeImpl( + ConeClassLikeLookupTagImpl(classId), + typeArguments = typeArguments, + isNullable = false + ) + } + status = FirDeclarationStatusImpl(Visibilities.PUBLIC, Modality.FINAL).apply { + isOverride = true + } + name = CLONE + symbol = FirNamedFunctionSymbol(CallableId(classId, CLONE)) + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirClonableSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirClonableSymbolProvider.kt new file mode 100644 index 00000000000..8d64c98d2cd --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirClonableSymbolProvider.kt @@ -0,0 +1,76 @@ +/* + * 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.fir.resolve.impl + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.declarations.builder.buildClassImpl +import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction +import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl +import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider +import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.FirScopeProvider +import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +class FirClonableSymbolProvider(session: FirSession, scopeProvider: FirScopeProvider) : FirSymbolProvider() { + companion object { + val CLONABLE: Name = Name.identifier("Cloneable") + val CLONABLE_CLASS_ID: ClassId = ClassId(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME, CLONABLE) + + val CLONE: Name = Name.identifier("clone") + } + + private val klass = buildClassImpl { + resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES + this.session = session + status = FirDeclarationStatusImpl( + Visibilities.PUBLIC, + Modality.ABSTRACT + ) + classKind = ClassKind.INTERFACE + declarations += buildSimpleFunction { + this.session = session + resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES + returnTypeRef = buildResolvedTypeRef { + type = session.builtinTypes.anyType.type + } + status = FirDeclarationStatusImpl(Visibilities.PROTECTED, Modality.OPEN) + name = CLONE + symbol = FirNamedFunctionSymbol(CallableId(CLONABLE_CLASS_ID, CLONE)) + } + this.scopeProvider = scopeProvider + name = CLONABLE + symbol = FirRegularClassSymbol(CLONABLE_CLASS_ID) + } + + override fun getClassLikeSymbolByFqName(classId: ClassId): FirClassLikeSymbol<*>? { + return if (classId == CLONABLE_CLASS_ID) klass.symbol else null + } + + override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List> { + return emptyList() + } + + override fun getNestedClassifierScope(classId: ClassId): FirScope? { + return null + } + + override fun getPackage(fqName: FqName): FqName? { + return null + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/builtIns/kotlin.txt b/compiler/fir/resolve/testData/builtIns/kotlin.txt index 8a200721ad1..24b70eccc37 100644 --- a/compiler/fir/resolve/testData/builtIns/kotlin.txt +++ b/compiler/fir/resolve/testData/builtIns/kotlin.txt @@ -42,7 +42,7 @@ public open class Any { } -public final class Array : R|kotlin/Any| { +public final class Array : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|T| public final operator fun iterator(): R|kotlin/collections/Iterator| @@ -54,6 +54,8 @@ public final class Array : R|kotlin/Any| { public constructor(size: R|kotlin/Int|, init: R|(kotlin/Int) -> T|): R|kotlin/Array| + public final override fun clone(): R|kotlin/Array| + } public final class Boolean : R|kotlin/Comparable| { @@ -76,7 +78,7 @@ public final class Boolean : R|kotlin/Comparable| { } -public final class BooleanArray : R|kotlin/Any| { +public final class BooleanArray : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|kotlin/Boolean| public final operator fun iterator(): R|kotlin/collections/BooleanIterator| @@ -90,6 +92,8 @@ public final class BooleanArray : R|kotlin/Any| { public constructor(size: R|kotlin/Int|): R|kotlin/BooleanArray| + public final override fun clone(): R|kotlin/BooleanArray| + } public final class Byte : R|kotlin/Number|, R|kotlin/Comparable| { @@ -216,7 +220,7 @@ public final class Byte : R|kotlin/Number|, R|kotlin/Comparable| { } -public final class ByteArray : R|kotlin/Any| { +public final class ByteArray : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|kotlin/Byte| public final operator fun iterator(): R|kotlin/collections/ByteIterator| @@ -230,6 +234,8 @@ public final class ByteArray : R|kotlin/Any| { public constructor(size: R|kotlin/Int|): R|kotlin/ByteArray| + public final override fun clone(): R|kotlin/ByteArray| + } public final class Char : R|kotlin/Comparable| { @@ -300,7 +306,7 @@ public final class Char : R|kotlin/Comparable| { } -public final class CharArray : R|kotlin/Any| { +public final class CharArray : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|kotlin/Char| public final operator fun iterator(): R|kotlin/collections/CharIterator| @@ -314,6 +320,8 @@ public final class CharArray : R|kotlin/Any| { public constructor(size: R|kotlin/Int|): R|kotlin/CharArray| + public final override fun clone(): R|kotlin/CharArray| + } public abstract interface CharSequence : R|kotlin/Any| { @@ -477,7 +485,7 @@ public final class Double : R|kotlin/Number|, R|kotlin/Comparable } -public final class DoubleArray : R|kotlin/Any| { +public final class DoubleArray : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|kotlin/Double| public final operator fun iterator(): R|kotlin/collections/DoubleIterator| @@ -491,6 +499,8 @@ public final class DoubleArray : R|kotlin/Any| { public constructor(size: R|kotlin/Int|): R|kotlin/DoubleArray| + public final override fun clone(): R|kotlin/DoubleArray| + } @R|kotlin/annotation/Target|() @R|kotlin/annotation/Retention|(value = R|kotlin/annotation/AnnotationRetention.BINARY|()) @R|kotlin/annotation/MustBeDocumented|() @R|kotlin/SinceKotlin|(version = String(1.1)) public final annotation class DslMarker : R|kotlin/Annotation| { @@ -648,7 +658,7 @@ public final class Float : R|kotlin/Number|, R|kotlin/Comparable| } -public final class FloatArray : R|kotlin/Any| { +public final class FloatArray : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|kotlin/Float| public final operator fun iterator(): R|kotlin/collections/FloatIterator| @@ -662,6 +672,8 @@ public final class FloatArray : R|kotlin/Any| { public constructor(size: R|kotlin/Int|): R|kotlin/FloatArray| + public final override fun clone(): R|kotlin/FloatArray| + } public abstract interface Function : R|kotlin/Any| { @@ -805,7 +817,7 @@ public final class Int : R|kotlin/Number|, R|kotlin/Comparable| { } -public final class IntArray : R|kotlin/Any| { +public final class IntArray : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|kotlin/Int| public final operator fun iterator(): R|kotlin/collections/IntIterator| @@ -819,6 +831,8 @@ public final class IntArray : R|kotlin/Any| { public constructor(size: R|kotlin/Int|): R|kotlin/IntArray| + public final override fun clone(): R|kotlin/IntArray| + } public final class Long : R|kotlin/Number|, R|kotlin/Comparable| { @@ -959,7 +973,7 @@ public final class Long : R|kotlin/Number|, R|kotlin/Comparable| { } -public final class LongArray : R|kotlin/Any| { +public final class LongArray : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|kotlin/Long| public final operator fun iterator(): R|kotlin/collections/LongIterator| @@ -973,6 +987,8 @@ public final class LongArray : R|kotlin/Any| { public constructor(size: R|kotlin/Int|): R|kotlin/LongArray| + public final override fun clone(): R|kotlin/LongArray| + } public final class Nothing { @@ -1147,7 +1163,7 @@ public final class Short : R|kotlin/Number|, R|kotlin/Comparable| } -public final class ShortArray : R|kotlin/Any| { +public final class ShortArray : R|kotlin/Any|, R|kotlin/Cloneable| { public final operator fun get(index: R|kotlin/Int|): R|kotlin/Short| public final operator fun iterator(): R|kotlin/collections/ShortIterator| @@ -1161,6 +1177,8 @@ public final class ShortArray : R|kotlin/Any| { public constructor(size: R|kotlin/Int|): R|kotlin/ShortArray| + public final override fun clone(): R|kotlin/ShortArray| + } @R|kotlin/annotation/Target|() @R|kotlin/annotation/Retention|(value = R|kotlin/annotation/AnnotationRetention.BINARY|()) @R|kotlin/annotation/MustBeDocumented|() public final annotation class SinceKotlin : R|kotlin/Annotation| { diff --git a/compiler/fir/resolve/testData/resolveWithStdlib/problems/cloneArray.kt b/compiler/fir/resolve/testData/resolveWithStdlib/problems/cloneArray.kt index a894f10fef6..b098561560a 100644 --- a/compiler/fir/resolve/testData/resolveWithStdlib/problems/cloneArray.kt +++ b/compiler/fir/resolve/testData/resolveWithStdlib/problems/cloneArray.kt @@ -1,7 +1,7 @@ fun test_1(array: Array) { - array.clone() + array.clone() } fun test_2(array: IntArray) { - array.clone() + array.clone() } \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolveWithStdlib/problems/cloneArray.txt b/compiler/fir/resolve/testData/resolveWithStdlib/problems/cloneArray.txt index b82932643db..0f6092958e2 100644 --- a/compiler/fir/resolve/testData/resolveWithStdlib/problems/cloneArray.txt +++ b/compiler/fir/resolve/testData/resolveWithStdlib/problems/cloneArray.txt @@ -1,7 +1,7 @@ FILE: cloneArray.kt public final fun test_1(array: R|kotlin/Array|): R|kotlin/Unit| { - R|/array|.#() + R|/array|.R|FakeOverride|>|() } public final fun test_2(array: R|kotlin/IntArray|): R|kotlin/Unit| { - R|/array|.#() + R|/array|.R|kotlin/IntArray.clone|() } diff --git a/compiler/testData/codegen/box/arrays/arraysAreCloneable.kt b/compiler/testData/codegen/box/arrays/arraysAreCloneable.kt index 21bfb2c3499..2e5d2ace414 100644 --- a/compiler/testData/codegen/box/arrays/arraysAreCloneable.kt +++ b/compiler/testData/codegen/box/arrays/arraysAreCloneable.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/arrays/cloneArray.kt b/compiler/testData/codegen/box/arrays/cloneArray.kt index 1111b305ffa..412bef94083 100644 --- a/compiler/testData/codegen/box/arrays/cloneArray.kt +++ b/compiler/testData/codegen/box/arrays/cloneArray.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/arrays/clonePrimitiveArrays.kt b/compiler/testData/codegen/box/arrays/clonePrimitiveArrays.kt index 89e305a2158..a890f7fc587 100644 --- a/compiler/testData/codegen/box/arrays/clonePrimitiveArrays.kt +++ b/compiler/testData/codegen/box/arrays/clonePrimitiveArrays.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/diagnostics/testsWithStdLib/builtins/arraysAreCloneable.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/builtins/arraysAreCloneable.fir.kt index a0cc68a4eec..b6e40ce955e 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/builtins/arraysAreCloneable.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/builtins/arraysAreCloneable.fir.kt @@ -3,23 +3,23 @@ fun foo(x: Cloneable) = x fun test() { - foo(arrayOf("")) - foo(intArrayOf()) - foo(longArrayOf()) - foo(shortArrayOf()) - foo(byteArrayOf()) - foo(charArrayOf()) - foo(doubleArrayOf()) - foo(floatArrayOf()) - foo(booleanArrayOf()) + foo(arrayOf("")) + foo(intArrayOf()) + foo(longArrayOf()) + foo(shortArrayOf()) + foo(byteArrayOf()) + foo(charArrayOf()) + foo(doubleArrayOf()) + foo(floatArrayOf()) + foo(booleanArrayOf()) - arrayOf("").clone() checkType { _>() } - intArrayOf().clone() checkType { _() } - longArrayOf().clone() checkType { _() } - shortArrayOf().clone() checkType { _() } - byteArrayOf().clone() checkType { _() } - charArrayOf().clone() checkType { _() } - doubleArrayOf().clone() checkType { _() } - floatArrayOf().clone() checkType { _() } - booleanArrayOf().clone() checkType { _() } + arrayOf("").clone() checkType { _>() } + intArrayOf().clone() checkType { _() } + longArrayOf().clone() checkType { _() } + shortArrayOf().clone() checkType { _() } + byteArrayOf().clone() checkType { _() } + charArrayOf().clone() checkType { _() } + doubleArrayOf().clone() checkType { _() } + floatArrayOf().clone() checkType { _() } + booleanArrayOf().clone() checkType { _() } }