diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt index c058dfd2959..99ab4040d34 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt @@ -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 get() = EMPTY_ARRAY + override val nullability: ConeNullability + get() = ConeNullability.UNKNOWN + override fun toString(): String { return "" } @@ -68,6 +85,9 @@ class ConeClassErrorType(val reason: String) : ConeClassLikeType() { override val typeArguments: Array get() = EMPTY_ARRAY + override val nullability: ConeNullability + get() = ConeNullability.UNKNOWN + override fun toString(): String { return "" } @@ -99,3 +119,11 @@ abstract class ConeFunctionType : ConeClassLikeType() { abstract val parameterTypes: List abstract val returnType: ConeKotlinType } + +class ConeFlexibleType(val lowerBound: ConeKotlinType, val upperBound: ConeKotlinType) : ConeKotlinType() { + override val typeArguments: Array + get() = emptyArray() + + override val nullability: ConeNullability + get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN +} diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/ConeFunctionTypeImpl.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/ConeFunctionTypeImpl.kt index 1a46c5d71a6..69382410b14 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/ConeFunctionTypeImpl.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/ConeFunctionTypeImpl.kt @@ -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, override val returnType: ConeKotlinType, - override val symbol: ConeClassLikeSymbol + override val symbol: ConeClassLikeSymbol, + isNullable: Boolean ) : ConeFunctionType() { override val typeArguments: Array get() = EMPTY_ARRAY + + override val nullability: ConeNullability = ConeNullability.create(isNullable) } \ No newline at end of file diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt index 78c127dc92d..8cb063d341d 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt @@ -11,19 +11,30 @@ import org.jetbrains.kotlin.fir.types.* open class ConeClassTypeImpl( override val symbol: ConeClassLikeSymbol, - override val typeArguments: Array -) : ConeClassLikeType() + override val typeArguments: Array, + isNullable: Boolean +) : ConeClassLikeType() { + override val nullability: ConeNullability = ConeNullability.create(isNullable) +} class ConeAbbreviatedTypeImpl( override val abbreviationSymbol: ConeClassLikeSymbol, override val typeArguments: Array, - 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 get() = EMPTY_ARRAY + + override val nullability: ConeNullability = ConeNullability.create(isNullable) } \ No newline at end of file diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt index 9683282e109..321f98b9c02 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt @@ -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().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") } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt index d6ab7f11d3e..eef28b4a9fc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt @@ -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) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirTypeResolverImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirTypeResolverImpl.kt index df94d2584a2..ddf89324960 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirTypeResolverImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirTypeResolverImpl.kt @@ -42,20 +42,21 @@ class FirTypeResolverImpl : FirTypeResolver { } }.toTypedArray() - private fun ConeSymbol.toConeKotlinType(parts: List): ConeKotlinType? { + private fun ConeSymbol.toConeKotlinType(parts: List, 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}") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt index b53cf1263bc..f385c19963b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt @@ -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) + is ConeClassTypeImpl -> ConeClassTypeImpl(symbol, newArguments as Array, nullability.isNullable) is ConeAbbreviatedTypeImpl -> ConeAbbreviatedTypeImpl( abbreviationSymbol, newArguments as Array, - 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 diff --git a/compiler/fir/resolve/testData/resolve/genericFunctions.txt b/compiler/fir/resolve/testData/resolve/genericFunctions.txt index 40549cc2644..a9235a5f4d2 100644 --- a/compiler/fir/resolve/testData/resolve/genericFunctions.txt +++ b/compiler/fir/resolve/testData/resolve/genericFunctions.txt @@ -1,7 +1,7 @@ FILE: genericFunctions.kt public abstract interface Any { } - public final inline function safeAs R|Any|.(): R|T| { + public final inline function safeAs R|Any|.(): R|T|? { return@@@safeAs as?/R|T|(this#) } public abstract class Summator { diff --git a/compiler/fir/resolve/testData/resolve/overrides/simpleFakeOverride.txt b/compiler/fir/resolve/testData/resolve/overrides/simpleFakeOverride.txt index cd972cd3685..725e3ef3029 100644 --- a/compiler/fir/resolve/testData/resolve/overrides/simpleFakeOverride.txt +++ b/compiler/fir/resolve/testData/resolve/overrides/simpleFakeOverride.txt @@ -15,7 +15,7 @@ FILE: simpleFakeOverride.kt public constructor(): super|>() public final function test(): R|kotlin/Unit| { - R|FakeOverride|(#()) + R|FakeOverride|(#()) } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index ebd04a9ca2b..3621bc622be 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -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("|") diff --git a/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/A.java b/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/A.java new file mode 100644 index 00000000000..e90456e8b55 --- /dev/null +++ b/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/A.java @@ -0,0 +1,5 @@ +public class A { + public T foo(T t) { + return t; + } +} \ No newline at end of file diff --git a/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/simpleFakeOverride.kt b/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/simpleFakeOverride.kt new file mode 100644 index 00000000000..a43197bc0d8 --- /dev/null +++ b/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/simpleFakeOverride.kt @@ -0,0 +1,9 @@ + +class Some + +class B : A() { + fun test() { + foo(Some()) + } +} + diff --git a/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/simpleFakeOverride.txt b/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/simpleFakeOverride.txt new file mode 100644 index 00000000000..06a184d6a51 --- /dev/null +++ b/idea/testData/fir/multiModule/basicWithJavaFakeOverride/jvm/simpleFakeOverride.txt @@ -0,0 +1,13 @@ +FILE: simpleFakeOverride.kt + public final class Some { + public constructor(): super() + + } + public final class B : R|A| { + public constructor(): super|>() + + public final function test(): R|kotlin/Unit| { + R|FakeOverride|!>|(#()) + } + + } diff --git a/idea/testData/fir/multiModule/mppFakeOverrides/jvm/jvm.txt b/idea/testData/fir/multiModule/mppFakeOverrides/jvm/jvm.txt index c9d882403ad..567e60a7c9f 100644 --- a/idea/testData/fir/multiModule/mppFakeOverrides/jvm/jvm.txt +++ b/idea/testData/fir/multiModule/mppFakeOverrides/jvm/jvm.txt @@ -14,8 +14,8 @@ FILE: jvm.kt public constructor(): super() public final function test(): R|kotlin/Unit| { - R|FakeOverride|(String()) - R|FakeOverride|(String()) + R|FakeOverride|(String()) + R|FakeOverride|(String()) } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java index de474c90690..ab743cd46b1 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/fir/FirMultiModuleResolveTestGenerated.java @@ -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/");