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 1db23b54f78..3a435612599 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 @@ -168,11 +168,18 @@ class ConeTypeVariableType( override val typeArguments: Array get() = emptyArray() } -class ConeDefinitelyNotNullType(val original: ConeKotlinType): ConeKotlinType(), DefinitelyNotNullTypeMarker { +class ConeDefinitelyNotNullType private constructor(val original: ConeKotlinType) : ConeKotlinType(), DefinitelyNotNullTypeMarker { override val typeArguments: Array 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) + } + } } /* diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index 35c65158f62..7bfab4e9383 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -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() } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt index 1abfc535c2c..af441705653 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt @@ -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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 9e059a7781d..bd5cd0fdbf8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -188,6 +188,11 @@ fun 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.withArguments(arguments: Array ConeDefinitelyNotNullType.create(original.withArguments(arguments)) as T else -> error("Not supported: $this: ${this.render()}") } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt index c3631dbbf76..5daae27763b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt @@ -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") } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeInferenceContext.kt index 664f5c23f99..ec7beddcb62 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeInferenceContext.kt @@ -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): TypeSubstitutorMarker { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt index faf422e1df9..efa5ac77ba1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt @@ -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? { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index 6ed490535a7..73c226a2d40 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -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<*> || diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt b/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt new file mode 100644 index 00000000000..aff396941c0 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt @@ -0,0 +1,31 @@ +// FILE: Descriptor.java +// FULL_JDK + +public interface Descriptor + +// FILE: ResolvedCall.java + +import org.jetbrains.annotations.NotNull; + +public interface ResolvedCall { + @NotNull + D getResultingDescriptor(); +} + +// FILE: test.kt + +val Descriptor.name = "123" + +interface Call { + val resultingDescriptor: D +} + +fun test(call: Call, resolvedCall: ResolvedCall) { + call.resultingDescriptor.name + resolvedCall.resultingDescriptor.name +} + +fun otherTest(call: Call<*>, resolvedCall: ResolvedCall<*>) { + call.resultingDescriptor.name + resolvedCall.resultingDescriptor.name +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.txt b/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.txt new file mode 100644 index 00000000000..3533d72aef0 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.txt @@ -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 : R|kotlin/Any| { + public abstract val resultingDescriptor: R|D| + public get(): R|D| + + } + public final fun test(call: R|Call|, resolvedCall: R|ResolvedCall|): R|kotlin/Unit| { + R|/call|.R|FakeOverride|.# + R|/resolvedCall|.R|/ResolvedCall.resultingDescriptor|.R|/name| + } + public final fun otherTest(call: R|Call<*>|, resolvedCall: R|ResolvedCall<*>|): R|kotlin/Unit| { + R|/call|.R|/Call.resultingDescriptor|.R|/name| + R|/resolvedCall|.R|/ResolvedCall.resultingDescriptor|.R|/name| + } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/j+k/StaticGenericMethod.txt b/compiler/fir/resolve/testData/resolve/stdlib/j+k/StaticGenericMethod.txt index d2614e93033..731dbe6ce48 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/j+k/StaticGenericMethod.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/j+k/StaticGenericMethod.txt @@ -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| = Q|StaticOwner|.R|/StaticOwner.newInstance|(this@R|/User|.R|FakeOverride|.R|kotlin/jvm/javaClass|) + this@R|/User|.R|FakeOverride| = Q|StaticOwner|.R|/StaticOwner.newInstance||>(this@R|/User|.R|FakeOverride|.R|kotlin/jvm/javaClass|) } } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index 4850ccb2604..f4fcf85f1cb 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/SubclassOfMapEntry.fir.txt b/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/SubclassOfMapEntry.fir.txt index 99af87fa9e7..a69735fdf33 100644 --- a/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/SubclassOfMapEntry.fir.txt +++ b/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/SubclassOfMapEntry.fir.txt @@ -1,4 +1,4 @@ public abstract interface SubclassOfMapEntry : R|kotlin/collections/MutableMap.MutableEntry| { - public abstract operator fun setValue(value: R|V|): R|V| + public abstract operator fun setValue(value: R|V!|): R|V!| }