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:
Mikhail Glukhikh
2019-02-11 19:15:37 +03:00
parent 3d77f3d129
commit f8e165dbe4
15 changed files with 137 additions and 30 deletions
@@ -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")
}
@@ -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)
}
@@ -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}")
@@ -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 -1
View File
@@ -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;
}
}
@@ -0,0 +1,9 @@
class Some
class B : A<Some>() {
fun test() {
foo(Some())
}
}
@@ -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>#())
}
}
+2 -2
View File
@@ -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())
}
}
@@ -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/");