Integrate nullability into cone types, add & use FIR flexible type
FIR fake overrides are rendered now more precisely to test this process
This commit is contained in:
@@ -40,6 +40,18 @@ class ConeKotlinTypeProjectionOut(override val type: ConeKotlinType) : ConeKotli
|
||||
get() = ProjectionKind.OUT
|
||||
}
|
||||
|
||||
enum class ConeNullability(val suffix: String) {
|
||||
NULLABLE("?"),
|
||||
UNKNOWN("!"),
|
||||
NOT_NULL("");
|
||||
|
||||
val isNullable: Boolean get() = this != NOT_NULL
|
||||
|
||||
companion object {
|
||||
fun create(isNullable: Boolean) = if (isNullable) NULLABLE else NOT_NULL
|
||||
}
|
||||
}
|
||||
|
||||
// We assume type IS an invariant type projection to prevent additional wrapper here
|
||||
// (more exactly, invariant type projection contains type)
|
||||
sealed class ConeKotlinType : ConeKotlinTypeProjection(), ConeTypedProjection {
|
||||
@@ -50,12 +62,17 @@ sealed class ConeKotlinType : ConeKotlinTypeProjection(), ConeTypedProjection {
|
||||
|
||||
override val type: ConeKotlinType
|
||||
get() = this
|
||||
|
||||
abstract val nullability: ConeNullability
|
||||
}
|
||||
|
||||
class ConeKotlinErrorType(val reason: String) : ConeKotlinType() {
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
get() = EMPTY_ARRAY
|
||||
|
||||
override val nullability: ConeNullability
|
||||
get() = ConeNullability.UNKNOWN
|
||||
|
||||
override fun toString(): String {
|
||||
return "<ERROR TYPE: $reason>"
|
||||
}
|
||||
@@ -68,6 +85,9 @@ class ConeClassErrorType(val reason: String) : ConeClassLikeType() {
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
get() = EMPTY_ARRAY
|
||||
|
||||
override val nullability: ConeNullability
|
||||
get() = ConeNullability.UNKNOWN
|
||||
|
||||
override fun toString(): String {
|
||||
return "<ERROR CLASS: $reason>"
|
||||
}
|
||||
@@ -99,3 +119,11 @@ abstract class ConeFunctionType : ConeClassLikeType() {
|
||||
abstract val parameterTypes: List<ConeKotlinType>
|
||||
abstract val returnType: ConeKotlinType
|
||||
}
|
||||
|
||||
class ConeFlexibleType(val lowerBound: ConeKotlinType, val upperBound: ConeKotlinType) : ConeKotlinType() {
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
get() = emptyArray()
|
||||
|
||||
override val nullability: ConeNullability
|
||||
get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN
|
||||
}
|
||||
|
||||
@@ -9,13 +9,17 @@ import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeFunctionType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.ConeNullability
|
||||
|
||||
class ConeFunctionTypeImpl(
|
||||
override val receiverType: ConeKotlinType?,
|
||||
override val parameterTypes: List<ConeKotlinType>,
|
||||
override val returnType: ConeKotlinType,
|
||||
override val symbol: ConeClassLikeSymbol
|
||||
override val symbol: ConeClassLikeSymbol,
|
||||
isNullable: Boolean
|
||||
) : ConeFunctionType() {
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
get() = EMPTY_ARRAY
|
||||
|
||||
override val nullability: ConeNullability = ConeNullability.create(isNullable)
|
||||
}
|
||||
@@ -11,19 +11,30 @@ import org.jetbrains.kotlin.fir.types.*
|
||||
|
||||
open class ConeClassTypeImpl(
|
||||
override val symbol: ConeClassLikeSymbol,
|
||||
override val typeArguments: Array<ConeKotlinTypeProjection>
|
||||
) : ConeClassLikeType()
|
||||
override val typeArguments: Array<ConeKotlinTypeProjection>,
|
||||
isNullable: Boolean
|
||||
) : ConeClassLikeType() {
|
||||
override val nullability: ConeNullability = ConeNullability.create(isNullable)
|
||||
}
|
||||
|
||||
class ConeAbbreviatedTypeImpl(
|
||||
override val abbreviationSymbol: ConeClassLikeSymbol,
|
||||
override val typeArguments: Array<ConeKotlinTypeProjection>,
|
||||
override val directExpansion: ConeClassLikeType
|
||||
override val directExpansion: ConeClassLikeType,
|
||||
isNullable: Boolean
|
||||
) : ConeAbbreviatedType() {
|
||||
override val symbol: ConeClassLikeSymbol
|
||||
get() = abbreviationSymbol
|
||||
|
||||
override val nullability: ConeNullability = ConeNullability.create(isNullable)
|
||||
}
|
||||
|
||||
class ConeTypeParameterTypeImpl(override val symbol: ConeTypeParameterSymbol) : ConeTypeParameterType() {
|
||||
class ConeTypeParameterTypeImpl(
|
||||
override val symbol: ConeTypeParameterSymbol,
|
||||
isNullable: Boolean
|
||||
) : ConeTypeParameterType() {
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
get() = EMPTY_ARRAY
|
||||
|
||||
override val nullability: ConeNullability = ConeNullability.create(isNullable)
|
||||
}
|
||||
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||
@@ -53,7 +50,7 @@ class JavaSymbolProvider(
|
||||
annotationTypeRef = FirResolvedTypeRefImpl(
|
||||
session = session,
|
||||
psi = null,
|
||||
type = ConeClassTypeImpl(FirClassSymbol(classId!!), emptyArray()),
|
||||
type = ConeClassTypeImpl(FirClassSymbol(classId!!), emptyArray(), isNullable = false),
|
||||
isMarkedNullable = true,
|
||||
annotations = emptyList()
|
||||
)
|
||||
@@ -87,18 +84,24 @@ class JavaSymbolProvider(
|
||||
}
|
||||
}
|
||||
|
||||
private fun flexibleType(create: (isNullable: Boolean) -> ConeKotlinType): ConeFlexibleType {
|
||||
return ConeFlexibleType(create(false), create(true))
|
||||
}
|
||||
|
||||
private fun JavaClassifierType.toFirResolvedTypeRef(): FirResolvedTypeRef {
|
||||
val coneType = when (val classifier = classifier) {
|
||||
is JavaClass -> {
|
||||
val symbol = session.service<FirSymbolProvider>().getClassLikeSymbolByFqName(classifier.classId!!) as? ConeClassSymbol
|
||||
if (symbol == null) ConeKotlinErrorType("Symbol not found, for `${classifier.classId}`")
|
||||
else ConeClassTypeImpl(symbol, typeArguments = typeArguments.map { it.toConeProjection() }.toTypedArray())
|
||||
else flexibleType { isNullable ->
|
||||
ConeClassTypeImpl(symbol, typeArguments.map { it.toConeProjection() }.toTypedArray(), isNullable)
|
||||
}
|
||||
}
|
||||
is JavaTypeParameter -> {
|
||||
// TODO: it's unclear how to identify type parameter by the symbol
|
||||
// TODO: some type parameter cache (provider?)
|
||||
val symbol = createTypeParameterSymbol(classifier.name)
|
||||
ConeTypeParameterTypeImpl(symbol)
|
||||
flexibleType { isNullable -> ConeTypeParameterTypeImpl(symbol, isNullable) }
|
||||
}
|
||||
else -> ConeClassErrorType(reason = "Unexpected classifier: $classifier")
|
||||
}
|
||||
|
||||
+4
-3
@@ -46,7 +46,8 @@ class FirTypeDeserializer(
|
||||
val id = nameResolver.getString(proto.flexibleTypeCapabilitiesId)
|
||||
val lowerBound = classLikeType(proto)
|
||||
val upperBound = classLikeType(proto.flexibleUpperBound(typeTable)!!)
|
||||
return ConeKotlinErrorType("Not supported: Flexible types")//c.components.flexibleTypeDeserializer.create(proto, id, lowerBound, upperBound)
|
||||
return ConeFlexibleType(lowerBound!!, upperBound!!)
|
||||
//c.components.flexibleTypeDeserializer.create(proto, id, lowerBound, upperBound)
|
||||
}
|
||||
|
||||
return classLikeType(proto) ?: ConeKotlinErrorType("?!id:0")
|
||||
@@ -97,12 +98,12 @@ class FirTypeDeserializer(
|
||||
//createSuspendFunctionType(annotations, constructor, arguments, proto.nullable)
|
||||
ConeClassErrorType("createSuspendFunctionType not supported")
|
||||
} else {
|
||||
ConeClassTypeImpl(constructor, arguments)
|
||||
ConeClassTypeImpl(constructor, arguments, isNullable = false)
|
||||
}
|
||||
|
||||
val abbreviatedTypeProto = proto.abbreviatedType(typeTable) ?: return simpleType
|
||||
|
||||
return ConeAbbreviatedTypeImpl(typeSymbol(abbreviatedTypeProto) as ConeClassLikeSymbol, arguments, simpleType)
|
||||
return ConeAbbreviatedTypeImpl(typeSymbol(abbreviatedTypeProto) as ConeClassLikeSymbol, arguments, simpleType, isNullable = false)
|
||||
|
||||
}
|
||||
|
||||
|
||||
+10
-7
@@ -42,20 +42,21 @@ class FirTypeResolverImpl : FirTypeResolver {
|
||||
}
|
||||
}.toTypedArray()
|
||||
|
||||
private fun ConeSymbol.toConeKotlinType(parts: List<FirQualifierPart>): ConeKotlinType? {
|
||||
private fun ConeSymbol.toConeKotlinType(parts: List<FirQualifierPart>, isNullable: Boolean): ConeKotlinType? {
|
||||
|
||||
return when (this) {
|
||||
is ConeTypeParameterSymbol -> {
|
||||
ConeTypeParameterTypeImpl(this)
|
||||
ConeTypeParameterTypeImpl(this, isNullable)
|
||||
}
|
||||
is ConeClassSymbol -> {
|
||||
ConeClassTypeImpl(this, parts.toTypeProjections())
|
||||
ConeClassTypeImpl(this, parts.toTypeProjections(), isNullable)
|
||||
}
|
||||
is FirTypeAliasSymbol -> {
|
||||
ConeAbbreviatedTypeImpl(
|
||||
abbreviationSymbol = this as ConeClassLikeSymbol,
|
||||
typeArguments = parts.toTypeProjections(),
|
||||
directExpansion = fir.expandedConeType ?: ConeClassErrorType("Unresolved expansion")
|
||||
directExpansion = fir.expandedConeType ?: ConeClassErrorType("Unresolved expansion"),
|
||||
isNullable = isNullable
|
||||
)
|
||||
}
|
||||
else -> error("!")
|
||||
@@ -118,7 +119,8 @@ class FirTypeResolverImpl : FirTypeResolver {
|
||||
|
||||
override fun resolveUserType(typeRef: FirUserTypeRef, symbol: ConeSymbol?, scope: FirScope): ConeKotlinType {
|
||||
symbol ?: return ConeKotlinErrorType("Symbol not found, for `${typeRef.render()}`")
|
||||
return symbol.toConeKotlinType(typeRef.qualifier) ?: ConeKotlinErrorType("Failed to resolve qualified type")
|
||||
return symbol.toConeKotlinType(typeRef.qualifier, typeRef.isMarkedNullable)
|
||||
?: ConeKotlinErrorType("Failed to resolve qualified type")
|
||||
}
|
||||
|
||||
override fun resolveType(
|
||||
@@ -139,11 +141,12 @@ class FirTypeResolverImpl : FirTypeResolver {
|
||||
(typeRef.receiverTypeRef as FirResolvedTypeRef?)?.type,
|
||||
typeRef.valueParameters.map { it.returnTypeRef.coneTypeUnsafe() },
|
||||
typeRef.returnTypeRef.coneTypeUnsafe(),
|
||||
resolveBuiltInQualified(KotlinBuiltIns.getFunctionClassId(typeRef.parametersCount), typeRef.session)
|
||||
resolveBuiltInQualified(KotlinBuiltIns.getFunctionClassId(typeRef.parametersCount), typeRef.session),
|
||||
typeRef.isMarkedNullable
|
||||
)
|
||||
}
|
||||
is FirImplicitBuiltinTypeRef -> {
|
||||
resolveToSymbol(typeRef, scope, position)!!.toConeKotlinType(emptyList())!!
|
||||
resolveToSymbol(typeRef, scope, position)!!.toConeKotlinType(emptyList(), isNullable = false)!!
|
||||
}
|
||||
is FirDynamicTypeRef, is FirImplicitTypeRef, is FirDelegatedTypeRef -> {
|
||||
ConeKotlinErrorType("Not supported: ${typeRef::class.simpleName}")
|
||||
|
||||
+4
-2
@@ -63,14 +63,16 @@ class FirClassSubstitutionScope(
|
||||
return when (this) {
|
||||
is ConeKotlinErrorType -> error("Trying to substitute arguments for error type")
|
||||
is ConeTypeParameterType -> error("Trying to substitute arguments for type parameter")
|
||||
is ConeClassTypeImpl -> ConeClassTypeImpl(symbol, newArguments as Array<ConeKotlinTypeProjection>)
|
||||
is ConeClassTypeImpl -> ConeClassTypeImpl(symbol, newArguments as Array<ConeKotlinTypeProjection>, nullability.isNullable)
|
||||
is ConeAbbreviatedTypeImpl -> ConeAbbreviatedTypeImpl(
|
||||
abbreviationSymbol,
|
||||
newArguments as Array<ConeKotlinTypeProjection>,
|
||||
directExpansion.substitute() as? ConeClassLikeType ?: directExpansion
|
||||
directExpansion.substitute() as? ConeClassLikeType ?: directExpansion,
|
||||
nullability.isNullable
|
||||
)
|
||||
is ConeFunctionType -> TODO("Substitute function type properly")
|
||||
is ConeClassLikeType -> error("Unknown class-like type to substitute: $this, ${this::class}")
|
||||
is ConeFlexibleType -> error("Trying to substitute arguments for flexible type")
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FILE: genericFunctions.kt
|
||||
public abstract interface Any {
|
||||
}
|
||||
<reified T : R|Any|> public final inline function safeAs R|Any|.(): R|T| {
|
||||
<reified T : R|Any|> public final inline function safeAs R|Any|.(): R|T|? {
|
||||
return@@@safeAs as?/R|T|(this#)
|
||||
}
|
||||
public abstract class Summator {
|
||||
|
||||
@@ -15,7 +15,7 @@ FILE: simpleFakeOverride.kt
|
||||
public constructor(): super<R|A<Some>|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
R|FakeOverride</A.foo>|(<Unresolved name: Some>#())
|
||||
R|FakeOverride</A.foo: R|T|>|(<Unresolved name: Some>#())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
|
||||
@@ -652,6 +653,15 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
||||
append(returnType.asString())
|
||||
}
|
||||
}
|
||||
is ConeFlexibleType -> {
|
||||
buildString {
|
||||
append("ft<")
|
||||
append(lowerBound.asString())
|
||||
append(", ")
|
||||
append(upperBound.asString())
|
||||
append(">")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,7 +671,9 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
||||
val coneType = resolvedTypeRef.type
|
||||
print(coneType.asString())
|
||||
print("|")
|
||||
visitTypeRefWithNullability(resolvedTypeRef)
|
||||
if (coneType !is ConeKotlinErrorType && coneType !is ConeClassErrorType) {
|
||||
print(coneType.nullability.suffix)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitUserTypeRef(userTypeRef: FirUserTypeRef) {
|
||||
@@ -704,8 +716,19 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
||||
if (isFakeOverride) {
|
||||
print("FakeOverride<")
|
||||
}
|
||||
print(resolvedCallableReference.callableSymbol.callableId)
|
||||
val symbol = resolvedCallableReference.callableSymbol
|
||||
print(symbol.callableId)
|
||||
if (isFakeOverride) {
|
||||
when (symbol) {
|
||||
is FirFunctionSymbol -> {
|
||||
print(": ")
|
||||
symbol.fir.returnTypeRef.accept(this)
|
||||
}
|
||||
is FirPropertySymbol -> {
|
||||
print(": ")
|
||||
symbol.fir.returnTypeRef.accept(this)
|
||||
}
|
||||
}
|
||||
print(">")
|
||||
}
|
||||
print("|")
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
public class A<T> {
|
||||
public T foo(T t) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
|
||||
class Some
|
||||
|
||||
class B : A<Some>() {
|
||||
fun test() {
|
||||
foo(Some())
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
FILE: simpleFakeOverride.kt
|
||||
public final class Some {
|
||||
public constructor(): super<R|kotlin/Any|>()
|
||||
|
||||
}
|
||||
public final class B : R|A<Some>| {
|
||||
public constructor(): super<R|A<Some>|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
R|FakeOverride</A.foo: R|ft<T, T>|!>|(<Unresolved name: Some>#())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,8 +14,8 @@ FILE: jvm.kt
|
||||
public constructor(): super<R|C|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
R|FakeOverride</A.foo>|(String())
|
||||
R|FakeOverride</A.bar>|(String())
|
||||
R|FakeOverride</A.foo: R|kotlin/Unit|>|(String())
|
||||
R|FakeOverride</A.bar: R|T|>|(String())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
@@ -39,6 +39,11 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
|
||||
runTest("idea/testData/fir/multiModule/basicWithJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithJavaFakeOverride")
|
||||
public void testBasicWithJavaFakeOverride() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithJavaFakeOverride/");
|
||||
}
|
||||
|
||||
@TestMetadata("mppFakeOverrides")
|
||||
public void testMppFakeOverrides() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/mppFakeOverrides/");
|
||||
|
||||
Reference in New Issue
Block a user