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() 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> override val typeArguments: Array<out ConeKotlinTypeProjection>
get() = original.typeArguments get() = original.typeArguments
override val nullability: ConeNullability override val nullability: ConeNullability
get() = ConeNullability.NOT_NULL 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) 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) { return when (this) {
is ConeKotlinErrorType -> createErrorType() is ConeKotlinErrorType -> createErrorType()
is ConeLookupTagBasedType -> { is ConeLookupTagBasedType -> {
@@ -55,20 +55,22 @@ fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDecla
val irSymbol = firSymbol.toIrSymbol(session, declarationStorage) val irSymbol = firSymbol.toIrSymbol(session, declarationStorage)
// TODO: annotations // TODO: annotations
IrSimpleTypeImpl( IrSimpleTypeImpl(
irSymbol, this.isMarkedNullable, irSymbol, !definitelyNotNull && this.isMarkedNullable,
typeArguments.map { it.toIrTypeArgument(session, declarationStorage) }, typeArguments.map { it.toIrTypeArgument(session, declarationStorage) },
emptyList() emptyList()
) )
} }
is ConeFlexibleType -> { is ConeFlexibleType -> {
// TODO: yet we take more general type. Not quite sure it's Ok // 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 ConeCapturedType -> TODO()
is ConeDefinitelyNotNullType -> TODO() is ConeDefinitelyNotNullType -> {
original.toIrType(session, declarationStorage, definitelyNotNull = true)
}
is ConeIntersectionType -> { is ConeIntersectionType -> {
// TODO: add intersectionTypeApproximation // TODO: add intersectionTypeApproximation
intersectedTypes.first().toIrType(session, declarationStorage) intersectedTypes.first().toIrType(session, declarationStorage, definitelyNotNull)
} }
is ConeStubType -> createErrorType() 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.resolve.toTypeProjection
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag 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.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -116,6 +117,16 @@ private fun coneFlexibleOrSimpleType(
upperBound: ConeLookupTagBasedType upperBound: ConeLookupTagBasedType
): ConeKotlinType { ): ConeKotlinType {
if (AbstractStrictEqualityTypeChecker.strictEqualTypes(session.typeContext, lowerBound, upperBound)) { 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 lowerBound
} }
return ConeFlexibleType(lowerBound, upperBound) return ConeFlexibleType(lowerBound, upperBound)
@@ -188,6 +188,11 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability): T {
ConeNullability.NOT_NULL -> this ConeNullability.NOT_NULL -> this
} as T } as T
is ConeStubType -> ConeStubType(variable, nullability) 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}") else -> error("sealed: ${this::class}")
} }
} }
@@ -206,6 +211,7 @@ fun <T : ConeKotlinType> T.withArguments(arguments: Array<out ConeKotlinTypeProj
arguments, arguments,
nullability.isNullable nullability.isNullable
) as T ) as T
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create(original.withArguments(arguments)) as T
else -> error("Not supported: $this: ${this.render()}") else -> error("Not supported: $this: ${this.render()}")
} }
} }
@@ -39,6 +39,7 @@ fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: ScopeSession)
it.scope(useSiteSession, scopeSession) it.scope(useSiteSession, scopeSession)
} }
) )
is ConeDefinitelyNotNullType -> original.scope(useSiteSession, scopeSession)
else -> error("Failed type $this") else -> error("Failed type $this")
} }
} }
@@ -251,7 +251,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext,
override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker { override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker {
require(this is ConeDefinitelyNotNullType) require(this is ConeDefinitelyNotNullType)
return this.original() return this.original as SimpleTypeMarker
} }
override fun typeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, KotlinTypeMarker>): TypeSubstitutorMarker { override fun typeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, KotlinTypeMarker>): TypeSubstitutorMarker {
@@ -93,7 +93,7 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() {
} }
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeDefinitelyNotNullType? { private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeDefinitelyNotNullType? {
TODO() return ConeDefinitelyNotNullType.create(substituteType(original) ?: original)
} }
private fun ConeFlexibleType.substituteBounds(): ConeFlexibleType? { private fun ConeFlexibleType.substituteBounds(): ConeFlexibleType? {
@@ -112,7 +112,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
override fun SimpleTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker? { override fun SimpleTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker? {
require(this is ConeKotlinType) require(this is ConeKotlinType)
return null // TODO return this as? ConeDefinitelyNotNullType
} }
override fun SimpleTypeMarker.isMarkedNullable(): Boolean { override fun SimpleTypeMarker.isMarkedNullable(): Boolean {
@@ -130,11 +130,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
is ConeCapturedType -> constructor is ConeCapturedType -> constructor
is ConeTypeVariableType -> this.lookupTag as ConeTypeVariableTypeConstructor // TODO: WTF is ConeTypeVariableType -> this.lookupTag as ConeTypeVariableTypeConstructor // TODO: WTF
is ConeAbbreviatedType -> this.directExpansionType(session)?.typeConstructor() 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 ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
is ConeIntersectionType -> this is ConeIntersectionType -> this
is ConeStubType -> variable.typeConstructor is ConeStubType -> variable.typeConstructor
else -> error("?: ${this}") is ConeDefinitelyNotNullType -> original.typeConstructor()
else -> error("?: $this")
} }
// TODO: get rid of class types with type-alias symbols // 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 ConeTypeVariableType) return false
if (this is ConeIntersectionType) return false if (this is ConeIntersectionType) return false
if (this is ConeStubType) return true if (this is ConeStubType) return true
if (this is ConeDefinitelyNotNullType) return true
require(this is ConeLookupTagBasedType) require(this is ConeLookupTagBasedType)
val typeConstructor = this.typeConstructor() val typeConstructor = this.typeConstructor()
return typeConstructor is FirClassSymbol<*> || 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| protected abstract fun createSettings(): R|T|
public final fun foo(): R|kotlin/Unit| { 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"); 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") @TestMetadata("genericPropertyAccess.kt")
public void testGenericPropertyAccess() throws Exception { public void testGenericPropertyAccess() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.kt"); 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 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!|
} }