[FIR] Support Clonable

#KT-36762 Fixed
This commit is contained in:
Dmitriy Novozhilov
2020-03-05 18:12:48 +03:00
parent 83d01fbaaa
commit af67aff303
10 changed files with 185 additions and 43 deletions
@@ -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)
)
@@ -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<FirAnnotationCall>) += context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver)
}
}
private val ARRAY = Name.identifier("Array")
private val ARRAY_CLASSES: Set<Name> = 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))
}
}
@@ -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<FirCallableSymbol<*>> {
return emptyList()
}
override fun getNestedClassifierScope(classId: ClassId): FirScope? {
return null
}
override fun getPackage(fqName: FqName): FqName? {
return null
}
}
+27 -9
View File
@@ -42,7 +42,7 @@ public open class Any {
}
public final class Array<T> : R|kotlin/Any| {
public final class Array<T> : 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<T>|
@@ -54,6 +54,8 @@ public final class Array<T> : R|kotlin/Any| {
public constructor<T>(size: R|kotlin/Int|, init: R|(kotlin/Int) -> T|): R|kotlin/Array<T>|
public final override fun clone(): R|kotlin/Array<T>|
}
public final class Boolean : R|kotlin/Comparable<kotlin/Boolean>| {
@@ -76,7 +78,7 @@ public final class Boolean : R|kotlin/Comparable<kotlin/Boolean>| {
}
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<kotlin/Byte>| {
@@ -216,7 +220,7 @@ public final class Byte : R|kotlin/Number|, R|kotlin/Comparable<kotlin/Byte>| {
}
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<kotlin/Char>| {
@@ -300,7 +306,7 @@ public final class Char : R|kotlin/Comparable<kotlin/Char>| {
}
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<kotlin/Double>
}
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<kotlin/Float>|
}
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<out R> : R|kotlin/Any| {
@@ -805,7 +817,7 @@ public final class Int : R|kotlin/Number|, R|kotlin/Comparable<kotlin/Int>| {
}
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<kotlin/Long>| {
@@ -959,7 +973,7 @@ public final class Long : R|kotlin/Number|, R|kotlin/Comparable<kotlin/Long>| {
}
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<kotlin/Short>|
}
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| {
@@ -1,7 +1,7 @@
fun test_1(array: Array<String>) {
array.<!UNRESOLVED_REFERENCE!>clone<!>()
array.clone()
}
fun test_2(array: IntArray) {
array.<!UNRESOLVED_REFERENCE!>clone<!>()
array.clone()
}
@@ -1,7 +1,7 @@
FILE: cloneArray.kt
public final fun test_1(array: R|kotlin/Array<kotlin/String>|): R|kotlin/Unit| {
R|<local>/array|.<Unresolved name: clone>#()
R|<local>/array|.R|FakeOverride<kotlin/Array.clone: R|kotlin/Array<kotlin/String>|>|()
}
public final fun test_2(array: R|kotlin/IntArray|): R|kotlin/Unit| {
R|<local>/array|.<Unresolved name: clone>#()
R|<local>/array|.R|kotlin/IntArray.clone|()
}
@@ -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
-1
View File
@@ -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
@@ -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
@@ -3,23 +3,23 @@
fun foo(x: Cloneable) = x
fun test() {
<!INAPPLICABLE_CANDIDATE!>foo<!>(arrayOf(""))
<!INAPPLICABLE_CANDIDATE!>foo<!>(intArrayOf())
<!INAPPLICABLE_CANDIDATE!>foo<!>(longArrayOf())
<!INAPPLICABLE_CANDIDATE!>foo<!>(shortArrayOf())
<!INAPPLICABLE_CANDIDATE!>foo<!>(byteArrayOf())
<!INAPPLICABLE_CANDIDATE!>foo<!>(charArrayOf())
<!INAPPLICABLE_CANDIDATE!>foo<!>(doubleArrayOf())
<!INAPPLICABLE_CANDIDATE!>foo<!>(floatArrayOf())
<!INAPPLICABLE_CANDIDATE!>foo<!>(booleanArrayOf())
foo(arrayOf(""))
foo(intArrayOf())
foo(longArrayOf())
foo(shortArrayOf())
foo(byteArrayOf())
foo(charArrayOf())
foo(doubleArrayOf())
foo(floatArrayOf())
foo(booleanArrayOf())
arrayOf("").<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><Array<String>>() }
intArrayOf().<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><IntArray>() }
longArrayOf().<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><LongArray>() }
shortArrayOf().<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><ShortArray>() }
byteArrayOf().<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><ByteArray>() }
charArrayOf().<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><CharArray>() }
doubleArrayOf().<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><DoubleArray>() }
floatArrayOf().<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><FloatArray>() }
booleanArrayOf().<!UNRESOLVED_REFERENCE!>clone<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><BooleanArray>() }
arrayOf("").clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><Array<String>>() }
intArrayOf().clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><IntArray>() }
longArrayOf().clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><LongArray>() }
shortArrayOf().clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><ShortArray>() }
byteArrayOf().clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><ByteArray>() }
charArrayOf().clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><CharArray>() }
doubleArrayOf().clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><DoubleArray>() }
floatArrayOf().clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><FloatArray>() }
booleanArrayOf().clone() checkType { <!UNRESOLVED_REFERENCE!>_<!><BooleanArray>() }
}