From ed493c99e395b8df3ee5fa43e98e6cfcb65163bc Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Tue, 25 Jul 2023 07:03:04 +0000 Subject: [PATCH] [FIR] Unset `EnhancedNullability` on `withNullability()` calls Note that `FlexibleNullability` doesn't exist anymore: it was removed at `65ea4e18`. `preserveEnhancedNullability = true` was needed because if we have an `@EnhancedNullability DNN`, and we substitute something into it, then `withNullability` is called there becase that's how DNNs work, not becase we want to obtain some new type with a different nullability. This is backed by the `compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt` test where we first have `@EnhancedNullability T & Any`, then we substitute `{T -> kotlin/Int!}` and then inside `org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor#substituteOriginal` (this is a DNN-specific function) we call `withNullability(NOT_NULL)`, and expect the attribute to be preserved. Otherwise this test would fail with `OVERLOAD_RESOLUTION_AMBIGUITY` for `IntBox().put(1)`. ^KT-50221 Fixed Merge-request: KT-MR-11272 Merged-by: Nikolay Lunyak --- .../resolve/inference/javaCollector.fir.txt | 2 +- .../fir/resolve/substitution/Substitutors.kt | 3 +- .../jetbrains/kotlin/fir/types/TypeUtils.kt | 30 ++++++++++++------- .../firProblems/AbstractMutableMap.fir.ir.txt | 8 ++--- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/inference/javaCollector.fir.txt b/compiler/fir/analysis-tests/testData/resolve/inference/javaCollector.fir.txt index b674e2e2239..112b6957f95 100644 --- a/compiler/fir/analysis-tests/testData/resolve/inference/javaCollector.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/inference/javaCollector.fir.txt @@ -1,6 +1,6 @@ FILE: javaCollector.kt public final fun foo(): R|kotlin/Unit| { - R|kotlin/collections/listOf|(String()).R|SubstitutionOverride|>|().R|SubstitutionOverride|>|, kotlin/collections/Map<@EnhancedNullability kotlin/String!, kotlin/Int!>?>|, R|ft|>(Q|java/util/stream/Collectors|.R|java/util/stream/Collectors.groupingBy*s||, R|kotlin/Int!|>(groupingBy@fun (it: R|@EnhancedNullability kotlin/String!|): R|@EnhancedNullability kotlin/String!| { + R|kotlin/collections/listOf|(String()).R|SubstitutionOverride|>|().R|SubstitutionOverride|>|, kotlin/collections/Map?>|, R|ft|>(Q|java/util/stream/Collectors|.R|java/util/stream/Collectors.groupingBy*s||, R|kotlin/Int!|>(groupingBy@fun (it: R|@EnhancedNullability kotlin/String!|): R|@EnhancedNullability kotlin/String!| { ^ R|/it| } , Q|java/util/stream/Collectors|.R|java/util/stream/Collectors.collectingAndThen*s||, R|kotlin/Long!|, R|kotlin/Int!|>(Q|java/util/stream/Collectors|.R|java/util/stream/Collectors.counting*s|(), Q|kotlin/Long|::R|kotlin/Long.toInt|))) diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt index efe153d49d6..34c0e8f50b9 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt @@ -113,7 +113,8 @@ abstract class AbstractConeSubstitutor(protected val typeContext: ConeTypeContex val substituted = substitutedOriginal.withNullability( ConeNullability.NOT_NULL, typeContext, - substitutedOriginal.attributes.add(original.attributes) + substitutedOriginal.attributes.add(original.attributes), + preserveEnhancedNullability = true, ) return ConeDefinitelyNotNullType.create( substituted, typeContext, avoidComprehensiveCheck = true, diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index 7cab694b908..59542a8c39b 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.fir.utils.exceptions.withConeTypeEntry import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.model.* +import org.jetbrains.kotlin.utils.addToStdlib.butIf import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible as coneLowerBoundIfFlexible @@ -250,16 +251,21 @@ fun T.withNullability( nullability: ConeNullability, typeContext: ConeTypeContext, attributes: ConeAttributes = this.attributes, + preserveEnhancedNullability: Boolean = false, ): T { - if (this.nullability == nullability && this.attributes == attributes) { + val theAttributes = attributes.butIf(!preserveEnhancedNullability) { + it.remove(CompilerConeAttributes.EnhancedNullability) + } + + if (this.nullability == nullability && this.attributes == theAttributes) { return this } @Suppress("UNCHECKED_CAST") return when (this) { is ConeErrorType -> this - is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable, attributes) - is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable, attributes) + is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable, theAttributes) + is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable, theAttributes) is ConeDynamicType -> this is ConeFlexibleType -> { if (nullability == ConeNullability.UNKNOWN) { @@ -269,16 +275,16 @@ fun T.withNullability( } coneFlexibleOrSimpleType( typeContext, - lowerBound.withNullability(nullability, typeContext), - upperBound.withNullability(nullability, typeContext) + lowerBound.withNullability(nullability, typeContext, preserveEnhancedNullability = preserveEnhancedNullability), + upperBound.withNullability(nullability, typeContext, preserveEnhancedNullability = preserveEnhancedNullability) ) } - is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag, attributes) - is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor, attributes) + is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag, theAttributes) + is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor, theAttributes) is ConeIntersectionType -> when (nullability) { ConeNullability.NULLABLE -> this.mapTypes { - it.withNullability(nullability, typeContext) + it.withNullability(nullability, typeContext, preserveEnhancedNullability = preserveEnhancedNullability) } ConeNullability.UNKNOWN -> this // TODO: is that correct? @@ -290,8 +296,12 @@ fun T.withNullability( is ConeStubTypeForTypeVariableInSubtyping -> ConeStubTypeForTypeVariableInSubtyping(constructor, nullability) is ConeDefinitelyNotNullType -> when (nullability) { ConeNullability.NOT_NULL -> this - ConeNullability.NULLABLE -> original.withNullability(nullability, typeContext) - ConeNullability.UNKNOWN -> original.withNullability(nullability, typeContext) + ConeNullability.NULLABLE -> original.withNullability( + nullability, typeContext, preserveEnhancedNullability = preserveEnhancedNullability, + ) + ConeNullability.UNKNOWN -> original.withNullability( + nullability, typeContext, preserveEnhancedNullability = preserveEnhancedNullability, + ) } is ConeIntegerLiteralConstantType -> ConeIntegerLiteralConstantTypeImpl(value, possibleTypes, isUnsigned, nullability) diff --git a/compiler/testData/ir/irText/firProblems/AbstractMutableMap.fir.ir.txt b/compiler/testData/ir/irText/firProblems/AbstractMutableMap.fir.ir.txt index ab29ce5dd58..c90c788dbe4 100644 --- a/compiler/testData/ir/irText/firProblems/AbstractMutableMap.fir.ir.txt +++ b/compiler/testData/ir/irText/firProblems/AbstractMutableMap.fir.ir.txt @@ -140,25 +140,25 @@ FILE fqName: fileName:/AbstractMutableMap.kt $this: VALUE_PARAMETER name: type:kotlin.collections.MutableMap VALUE_PARAMETER name:p0 index:0 type:@[EnhancedNullability] K of .MyMap VALUE_PARAMETER name:p1 index:1 type:@[EnhancedNullability] java.util.function.Function.MyMap, out @[EnhancedNullability] V of .MyMap> - FUN FAKE_OVERRIDE name:computeIfPresent visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap, p0:@[EnhancedNullability] K of .MyMap, p1:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in @[EnhancedNullability] V of .MyMap, out V of .MyMap?>) returnType:V of .MyMap? [fake_override] + FUN FAKE_OVERRIDE name:computeIfPresent visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap, p0:@[EnhancedNullability] K of .MyMap, p1:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in V of .MyMap, out V of .MyMap?>) returnType:V of .MyMap? [fake_override] overridden: public open fun computeIfPresent (p0: @[EnhancedNullability] K of kotlin.collections.AbstractMutableMap, p1: @[EnhancedNullability] java.util.function.BiFunction): V of kotlin.collections.AbstractMutableMap? declared in kotlin.collections.AbstractMutableMap $this: VALUE_PARAMETER name: type:kotlin.collections.MutableMap VALUE_PARAMETER name:p0 index:0 type:@[EnhancedNullability] K of .MyMap - VALUE_PARAMETER name:p1 index:1 type:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in @[EnhancedNullability] V of .MyMap, out V of .MyMap?> + VALUE_PARAMETER name:p1 index:1 type:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in V of .MyMap, out V of .MyMap?> FUN FAKE_OVERRIDE name:compute visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap, p0:@[EnhancedNullability] K of .MyMap, p1:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in V of .MyMap?, out V of .MyMap?>) returnType:V of .MyMap? [fake_override] overridden: public open fun compute (p0: @[EnhancedNullability] K of kotlin.collections.AbstractMutableMap, p1: @[EnhancedNullability] java.util.function.BiFunction): V of kotlin.collections.AbstractMutableMap? declared in kotlin.collections.AbstractMutableMap $this: VALUE_PARAMETER name: type:kotlin.collections.MutableMap VALUE_PARAMETER name:p0 index:0 type:@[EnhancedNullability] K of .MyMap VALUE_PARAMETER name:p1 index:1 type:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in V of .MyMap?, out V of .MyMap?> - FUN FAKE_OVERRIDE name:merge visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap, p0:@[EnhancedNullability] K of .MyMap, p1:@[EnhancedNullability] {V of .MyMap & Any}, p2:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in @[EnhancedNullability] V of .MyMap, out V of .MyMap?>) returnType:V of .MyMap? [fake_override] + FUN FAKE_OVERRIDE name:merge visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap, p0:@[EnhancedNullability] K of .MyMap, p1:@[EnhancedNullability] {V of .MyMap & Any}, p2:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in V of .MyMap, out V of .MyMap?>) returnType:V of .MyMap? [fake_override] overridden: public open fun merge (p0: @[EnhancedNullability] K of kotlin.collections.AbstractMutableMap, p1: @[EnhancedNullability] {V of kotlin.collections.AbstractMutableMap & Any}, p2: @[EnhancedNullability] java.util.function.BiFunction): V of kotlin.collections.AbstractMutableMap? declared in kotlin.collections.AbstractMutableMap $this: VALUE_PARAMETER name: type:kotlin.collections.MutableMap VALUE_PARAMETER name:p0 index:0 type:@[EnhancedNullability] K of .MyMap VALUE_PARAMETER name:p1 index:1 type:@[EnhancedNullability] {V of .MyMap & Any} - VALUE_PARAMETER name:p2 index:2 type:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in @[EnhancedNullability] V of .MyMap, out V of .MyMap?> + VALUE_PARAMETER name:p2 index:2 type:@[EnhancedNullability] java.util.function.BiFunction.MyMap, in V of .MyMap, out V of .MyMap?> FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:java.util.AbstractMap, p0:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] overridden: public open fun equals (p0: kotlin.Any?): kotlin.Boolean declared in kotlin.collections.AbstractMutableMap