FIR Java: use definitely not-null types for type parameters
We support & use ConeDefinitelyNotNullType more properly here
This commit is contained in:
@@ -168,11 +168,18 @@ class ConeTypeVariableType(
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection> get() = emptyArray()
|
||||
}
|
||||
|
||||
class ConeDefinitelyNotNullType(val original: ConeKotlinType): ConeKotlinType(), DefinitelyNotNullTypeMarker {
|
||||
class ConeDefinitelyNotNullType private constructor(val original: ConeKotlinType) : ConeKotlinType(), DefinitelyNotNullTypeMarker {
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
get() = original.typeArguments
|
||||
override val nullability: ConeNullability
|
||||
get() = ConeNullability.NOT_NULL
|
||||
|
||||
companion object {
|
||||
fun create(original: ConeKotlinType): ConeDefinitelyNotNullType {
|
||||
if (original is ConeFlexibleType) return create(original.lowerBound)
|
||||
return ConeDefinitelyNotNullType(original)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -47,7 +47,7 @@ fun FirTypeRef.toIrType(session: FirSession, declarationStorage: Fir2IrDeclarati
|
||||
return type.toIrType(session, declarationStorage)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDeclarationStorage): IrType {
|
||||
fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDeclarationStorage, definitelyNotNull: Boolean = false): IrType {
|
||||
return when (this) {
|
||||
is ConeKotlinErrorType -> createErrorType()
|
||||
is ConeLookupTagBasedType -> {
|
||||
@@ -55,20 +55,22 @@ fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDecla
|
||||
val irSymbol = firSymbol.toIrSymbol(session, declarationStorage)
|
||||
// TODO: annotations
|
||||
IrSimpleTypeImpl(
|
||||
irSymbol, this.isMarkedNullable,
|
||||
irSymbol, !definitelyNotNull && this.isMarkedNullable,
|
||||
typeArguments.map { it.toIrTypeArgument(session, declarationStorage) },
|
||||
emptyList()
|
||||
)
|
||||
}
|
||||
is ConeFlexibleType -> {
|
||||
// TODO: yet we take more general type. Not quite sure it's Ok
|
||||
upperBound.toIrType(session, declarationStorage)
|
||||
upperBound.toIrType(session, declarationStorage, definitelyNotNull)
|
||||
}
|
||||
is ConeCapturedType -> TODO()
|
||||
is ConeDefinitelyNotNullType -> TODO()
|
||||
is ConeDefinitelyNotNullType -> {
|
||||
original.toIrType(session, declarationStorage, definitelyNotNull = true)
|
||||
}
|
||||
is ConeIntersectionType -> {
|
||||
// TODO: add intersectionTypeApproximation
|
||||
intersectedTypes.first().toIrType(session, declarationStorage)
|
||||
intersectedTypes.first().toIrType(session, declarationStorage, definitelyNotNull)
|
||||
}
|
||||
is ConeStubType -> createErrorType()
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.toTypeProjection
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
@@ -116,6 +117,16 @@ private fun coneFlexibleOrSimpleType(
|
||||
upperBound: ConeLookupTagBasedType
|
||||
): ConeKotlinType {
|
||||
if (AbstractStrictEqualityTypeChecker.strictEqualTypes(session.typeContext, lowerBound, upperBound)) {
|
||||
val lookupTag = lowerBound.lookupTag
|
||||
if (lookupTag is ConeTypeParameterLookupTag && !lowerBound.isMarkedNullable) {
|
||||
if (lookupTag.typeParameterSymbol.fir.bounds.any {
|
||||
val type = (it as FirResolvedTypeRef).type
|
||||
type is ConeTypeParameterType || type.isNullable
|
||||
}
|
||||
) {
|
||||
return ConeDefinitelyNotNullType.create(lowerBound)
|
||||
}
|
||||
}
|
||||
return lowerBound
|
||||
}
|
||||
return ConeFlexibleType(lowerBound, upperBound)
|
||||
|
||||
@@ -188,6 +188,11 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability): T {
|
||||
ConeNullability.NOT_NULL -> this
|
||||
} as T
|
||||
is ConeStubType -> ConeStubType(variable, nullability) as T
|
||||
is ConeDefinitelyNotNullType -> when (nullability) {
|
||||
ConeNullability.NOT_NULL -> this
|
||||
ConeNullability.NULLABLE -> original.withNullability(nullability)
|
||||
ConeNullability.UNKNOWN -> original.withNullability(nullability)
|
||||
} as T
|
||||
else -> error("sealed: ${this::class}")
|
||||
}
|
||||
}
|
||||
@@ -206,6 +211,7 @@ fun <T : ConeKotlinType> T.withArguments(arguments: Array<out ConeKotlinTypeProj
|
||||
arguments,
|
||||
nullability.isNullable
|
||||
) as T
|
||||
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create(original.withArguments(arguments)) as T
|
||||
else -> error("Not supported: $this: ${this.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: ScopeSession)
|
||||
it.scope(useSiteSession, scopeSession)
|
||||
}
|
||||
)
|
||||
is ConeDefinitelyNotNullType -> original.scope(useSiteSession, scopeSession)
|
||||
else -> error("Failed type $this")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -251,7 +251,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext,
|
||||
|
||||
override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker {
|
||||
require(this is ConeDefinitelyNotNullType)
|
||||
return this.original()
|
||||
return this.original as SimpleTypeMarker
|
||||
}
|
||||
|
||||
override fun typeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, KotlinTypeMarker>): TypeSubstitutorMarker {
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() {
|
||||
}
|
||||
|
||||
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeDefinitelyNotNullType? {
|
||||
TODO()
|
||||
return ConeDefinitelyNotNullType.create(substituteType(original) ?: original)
|
||||
}
|
||||
|
||||
private fun ConeFlexibleType.substituteBounds(): ConeFlexibleType? {
|
||||
|
||||
@@ -112,7 +112,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
|
||||
override fun SimpleTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker? {
|
||||
require(this is ConeKotlinType)
|
||||
return null // TODO
|
||||
return this as? ConeDefinitelyNotNullType
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isMarkedNullable(): Boolean {
|
||||
@@ -130,11 +130,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
is ConeCapturedType -> constructor
|
||||
is ConeTypeVariableType -> this.lookupTag as ConeTypeVariableTypeConstructor // TODO: WTF
|
||||
is ConeAbbreviatedType -> this.directExpansionType(session)?.typeConstructor()
|
||||
?: ErrorTypeConstructor("Failed to expand alias: ${this}")
|
||||
?: ErrorTypeConstructor("Failed to expand alias: $this")
|
||||
is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
|
||||
is ConeIntersectionType -> this
|
||||
is ConeStubType -> variable.typeConstructor
|
||||
else -> error("?: ${this}")
|
||||
is ConeDefinitelyNotNullType -> original.typeConstructor()
|
||||
else -> error("?: $this")
|
||||
}
|
||||
|
||||
// TODO: get rid of class types with type-alias symbols
|
||||
@@ -371,6 +372,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
if (this is ConeTypeVariableType) return false
|
||||
if (this is ConeIntersectionType) return false
|
||||
if (this is ConeStubType) return true
|
||||
if (this is ConeDefinitelyNotNullType) return true
|
||||
require(this is ConeLookupTagBasedType)
|
||||
val typeConstructor = this.typeConstructor()
|
||||
return typeConstructor is FirClassSymbol<*> ||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// FILE: Descriptor.java
|
||||
// FULL_JDK
|
||||
|
||||
public interface Descriptor
|
||||
|
||||
// FILE: ResolvedCall.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface ResolvedCall<D extends Descriptor> {
|
||||
@NotNull
|
||||
D getResultingDescriptor();
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
val Descriptor.name = "123"
|
||||
|
||||
interface Call<D : Descriptor> {
|
||||
val resultingDescriptor: D
|
||||
}
|
||||
|
||||
fun <D> test(call: Call<D>, resolvedCall: ResolvedCall<D>) {
|
||||
call.resultingDescriptor.<!INAPPLICABLE_CANDIDATE!>name<!>
|
||||
resolvedCall.resultingDescriptor.name
|
||||
}
|
||||
|
||||
fun otherTest(call: Call<*>, resolvedCall: ResolvedCall<*>) {
|
||||
call.resultingDescriptor.name
|
||||
resolvedCall.resultingDescriptor.name
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
FILE: test.kt
|
||||
public final val R|Descriptor|.name: R|kotlin/String| = String(123)
|
||||
public get(): R|kotlin/String|
|
||||
public abstract interface Call<D : R|Descriptor|> : R|kotlin/Any| {
|
||||
public abstract val resultingDescriptor: R|D|
|
||||
public get(): R|D|
|
||||
|
||||
}
|
||||
public final fun <D> test(call: R|Call<D>|, resolvedCall: R|ResolvedCall<D>|): R|kotlin/Unit| {
|
||||
R|<local>/call|.R|FakeOverride</Call.resultingDescriptor: R|D|>|.<Inapplicable(WRONG_RECEIVER): [/name]>#
|
||||
R|<local>/resolvedCall|.R|/ResolvedCall.resultingDescriptor|.R|/name|
|
||||
}
|
||||
public final fun otherTest(call: R|Call<*>|, resolvedCall: R|ResolvedCall<*>|): R|kotlin/Unit| {
|
||||
R|<local>/call|.R|/Call.resultingDescriptor|.R|/name|
|
||||
R|<local>/resolvedCall|.R|/ResolvedCall.resultingDescriptor|.R|/name|
|
||||
}
|
||||
@@ -13,7 +13,7 @@ FILE: User.kt
|
||||
protected abstract fun createSettings(): R|T|
|
||||
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
this@R|/User|.R|FakeOverride</User.settings: R|T|>| = Q|StaticOwner|.R|/StaticOwner.newInstance|<R|T|>(this@R|/User|.R|FakeOverride</User.settings: R|T|>|.R|kotlin/jvm/javaClass|)
|
||||
this@R|/User|.R|FakeOverride</User.settings: R|T|>| = Q|StaticOwner|.R|/StaticOwner.newInstance|<R|ft<T, T>|>(this@R|/User|.R|FakeOverride</User.settings: R|T|>|.R|kotlin/jvm/javaClass|)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
@@ -374,6 +374,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/genericDecorator.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericDescriptor.kt")
|
||||
public void testGenericDescriptor() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericPropertyAccess.kt")
|
||||
public void testGenericPropertyAccess() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.kt");
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
public abstract interface SubclassOfMapEntry<K, V> : R|kotlin/collections/MutableMap.MutableEntry<K, V>| {
|
||||
public abstract operator fun setValue(value: R|V|): R|V|
|
||||
public abstract operator fun setValue(value: R|V!|): R|V!|
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user