FIR Java: use definitely not-null types for type parameters

We support & use ConeDefinitelyNotNullType more properly here
This commit is contained in:
Mikhail Glukhikh
2019-11-12 11:51:16 +03:00
parent 63f38bb28a
commit bd70daa3d1
13 changed files with 94 additions and 13 deletions
@@ -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")
}
}
@@ -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 {
@@ -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|)
}
}
@@ -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,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!|
}