From 9189154caea7c93e042faabc4b0a8d4e9aa806ea Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Fri, 5 Jan 2024 15:10:28 +0100 Subject: [PATCH] [FIR] Let attributes opt-in to participating in ConeClassLikeTypeImpl structural equality This is required for EnhancedTypeForWarningAttribute because scopes should not be reused between cone types with different values of this attribute. #KT-63208 --- .../explicitReturnTypeAndAnnotations.txt | 6 ++-- .../FirPropertyAccessorsTypesChecker.kt | 7 ++-- .../kotlin/fir/types/ConeAttributes.kt | 33 +++++++++++++++++++ .../jetbrains/kotlin/fir/types/impl/Impl.kt | 1 + .../EnhancedTypeForWarningAttribute.kt | 19 +++++++++++ .../asWithMutable.jvm_abi.txt | 14 -------- .../isWithMutable.jvm_abi.txt | 14 -------- .../reifiedAsWithMutable.jvm_abi.txt | 14 -------- .../reifiedIsWithMutable.jvm_abi.txt | 14 -------- .../reifiedSafeAsWithMutable.jvm_abi.txt | 14 -------- .../safeAsWithMutable.jvm_abi.txt | 14 -------- 11 files changed, 58 insertions(+), 92 deletions(-) diff --git a/analysis/low-level-api-fir/testData/lazyResolve/syntheticProperties/explicitReturnTypeAndAnnotations.txt b/analysis/low-level-api-fir/testData/lazyResolve/syntheticProperties/explicitReturnTypeAndAnnotations.txt index 60a9037f3fd..ca2417bbfab 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/syntheticProperties/explicitReturnTypeAndAnnotations.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/syntheticProperties/explicitReturnTypeAndAnnotations.txt @@ -141,7 +141,7 @@ FILE: [ResolvedTo(IMPORTS)] Derived.kt BODY_RESOLVE: TARGET: public open override [ BODY_RESOLVE] val something: R|@R|Anno|(s = (String(type: ), R|/prop|)) kotlin/String| @R|Anno|[Types](s = (String(number: ), R|/prop|)) public [ ResolvedTo(BODY_RESOLVE)] get(): R|@R|Anno|(s = (String(type: ), R|/prop|)) kotlin/String| { - ^getSomething String(str).R|kotlin/also|(String(type: ), R|/prop|)) kotlin/String|>(::R|kotlin/io/println|) + ^getSomething String(str).R|kotlin/also|(::R|kotlin/io/println|) } FILE: [ResolvedTo(IMPORTS)] Derived.kt @@ -151,7 +151,7 @@ FILE: [ResolvedTo(IMPORTS)] Derived.kt } @R|Anno|[Types](s = (String(number: ), R|/prop|)) public open override [ResolvedTo(BODY_RESOLVE)] fun getSomething(): R|@R|Anno|(s = (String(type: ), R|/prop|)) kotlin/String| { - ^getSomething String(str).R|kotlin/also|(String(type: ), R|/prop|)) kotlin/String|>(::R|kotlin/io/println|) + ^getSomething String(str).R|kotlin/also|(::R|kotlin/io/println|) } } @@ -178,7 +178,7 @@ FILE: [ResolvedTo(BODY_RESOLVE)] Derived.kt } @R|Anno|[Types](s = (String(number: ), R|/prop|)) public open override [ResolvedTo(BODY_RESOLVE)] fun getSomething(): R|@R|Anno|(s = (String(type: ), R|/prop|)) kotlin/String| { - ^getSomething String(str).R|kotlin/also|(String(type: ), R|/prop|)) kotlin/String|>(::R|kotlin/io/println|) + ^getSomething String(str).R|kotlin/also|(::R|kotlin/io/println|) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirPropertyAccessorsTypesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirPropertyAccessorsTypesChecker.kt index 401d73fd717..91527bd819e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirPropertyAccessorsTypesChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirPropertyAccessorsTypesChecker.kt @@ -18,10 +18,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.utils.canHaveAbstractDeclaration import org.jetbrains.kotlin.fir.declarations.utils.isAbstract import org.jetbrains.kotlin.fir.declarations.utils.visibility -import org.jetbrains.kotlin.fir.types.ConeErrorType -import org.jetbrains.kotlin.fir.types.coneType -import org.jetbrains.kotlin.fir.types.hasError -import org.jetbrains.kotlin.fir.types.isUnit +import org.jetbrains.kotlin.fir.types.* object FirPropertyAccessorsTypesChecker : FirPropertyChecker() { override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) { @@ -100,7 +97,7 @@ object FirPropertyAccessorsTypesChecker : FirPropertyChecker() { return } - if (valueSetterType != propertyType && !valueSetterType.hasError()) { + if (valueSetterType.withAttributes(ConeAttributes.Empty) != propertyType.withAttributes(ConeAttributes.Empty) && !valueSetterType.hasError()) { reporter.reportOn(valueSetterTypeSource, FirErrors.WRONG_SETTER_PARAMETER_TYPE, propertyType, valueSetterType, context) } diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeAttributes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeAttributes.kt index 9855a3ac261..d358fc9f423 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeAttributes.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeAttributes.kt @@ -32,6 +32,13 @@ abstract class ConeAttribute> : AnnotationMarker { abstract override fun toString(): String open fun renderForReadability(): String? = null + /** + * Signals that this attribute properly implements the [equals] and [hashCode] protocol. + * + * If it returns `true`, attributes will be compared using structural equality in [ConeAttributes.definitelyDifferFrom]. + */ + open val implementsEquality: Boolean get() = false + abstract val key: KClass /** @@ -152,6 +159,32 @@ class ConeAttributes private constructor(attributes: List>) : A return create(attributes) } + /** + * Returns `true` if this instance is definitely not equal to the [other] instance. + * This is `true` when one instance contains an attribute **type** that the other doesn't contain or both instances contain + * an attribute of a type where [ConeAttribute.implementsEquality]` == true` and the attribute's [equals] method returns `false`. + * + * A return value of `false` doesn't guarantee that the instances are equal because [ConeAttribute.implementsEquality] is optional, + * i.e., not all attributes can be compared structurally. + * + * @see org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl.equals + */ + infix fun definitelyDifferFrom(other: ConeAttributes): Boolean { + if (this === other) return false + if (this.isEmpty() && other.isEmpty()) return false + + for (index in indices) { + val a = arrayMap[index] + val b = other.arrayMap[index] + + if (a == null && b == null) continue + if ((a == null) != (b == null)) return true + if (a!!.implementsEquality && a != b) return true + } + + return false + } + /** * Applies the [transform] to all attributes that are subtypes of [ConeAttributeWithConeType] and returns a [ConeAttributes] * with the results of transforms that were not-`null` or `null` if no attributes were transformed. diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt index f02a92fe243..ee2771a7ece 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt @@ -34,6 +34,7 @@ class ConeClassLikeTypeImpl( if (lookupTag != other.lookupTag) return false if (!typeArguments.contentEquals(other.typeArguments)) return false if (nullability != other.nullability) return false + if (attributes definitelyDifferFrom other.attributes) return false return true } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/EnhancedTypeForWarningAttribute.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/EnhancedTypeForWarningAttribute.kt index 4078015a5d4..ad0c8814c51 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/EnhancedTypeForWarningAttribute.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/EnhancedTypeForWarningAttribute.kt @@ -25,6 +25,25 @@ class EnhancedTypeForWarningAttribute( override val keepInInferredDeclarationType: Boolean get() = true + + override val implementsEquality: Boolean + get() = true + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as EnhancedTypeForWarningAttribute + + if (coneType != other.coneType) return false + + return true + } + + override fun hashCode(): Int { + var result = coneType.hashCode() + return result + } } val ConeAttributes.enhancedTypeForWarning: EnhancedTypeForWarningAttribute? by ConeAttributes.attributeAccessor() diff --git a/compiler/testData/codegen/box/casts/mutableCollections/asWithMutable.jvm_abi.txt b/compiler/testData/codegen/box/casts/mutableCollections/asWithMutable.jvm_abi.txt index 164ab4f7ae1..98aa5a72250 100644 --- a/compiler/testData/codegen/box/casts/mutableCollections/asWithMutable.jvm_abi.txt +++ b/compiler/testData/codegen/box/casts/mutableCollections/asWithMutable.jvm_abi.txt @@ -1,18 +1,4 @@ MODULE main - CLASS MLItr.class - CLASS METADATA - FUNCTION add(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) - FUNCTION set(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) CLASS C.class CLASS METADATA K1 diff --git a/compiler/testData/codegen/box/casts/mutableCollections/isWithMutable.jvm_abi.txt b/compiler/testData/codegen/box/casts/mutableCollections/isWithMutable.jvm_abi.txt index 164ab4f7ae1..98aa5a72250 100644 --- a/compiler/testData/codegen/box/casts/mutableCollections/isWithMutable.jvm_abi.txt +++ b/compiler/testData/codegen/box/casts/mutableCollections/isWithMutable.jvm_abi.txt @@ -1,18 +1,4 @@ MODULE main - CLASS MLItr.class - CLASS METADATA - FUNCTION add(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) - FUNCTION set(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) CLASS C.class CLASS METADATA K1 diff --git a/compiler/testData/codegen/box/casts/mutableCollections/reifiedAsWithMutable.jvm_abi.txt b/compiler/testData/codegen/box/casts/mutableCollections/reifiedAsWithMutable.jvm_abi.txt index 164ab4f7ae1..98aa5a72250 100644 --- a/compiler/testData/codegen/box/casts/mutableCollections/reifiedAsWithMutable.jvm_abi.txt +++ b/compiler/testData/codegen/box/casts/mutableCollections/reifiedAsWithMutable.jvm_abi.txt @@ -1,18 +1,4 @@ MODULE main - CLASS MLItr.class - CLASS METADATA - FUNCTION add(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) - FUNCTION set(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) CLASS C.class CLASS METADATA K1 diff --git a/compiler/testData/codegen/box/casts/mutableCollections/reifiedIsWithMutable.jvm_abi.txt b/compiler/testData/codegen/box/casts/mutableCollections/reifiedIsWithMutable.jvm_abi.txt index 164ab4f7ae1..98aa5a72250 100644 --- a/compiler/testData/codegen/box/casts/mutableCollections/reifiedIsWithMutable.jvm_abi.txt +++ b/compiler/testData/codegen/box/casts/mutableCollections/reifiedIsWithMutable.jvm_abi.txt @@ -1,18 +1,4 @@ MODULE main - CLASS MLItr.class - CLASS METADATA - FUNCTION add(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) - FUNCTION set(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) CLASS C.class CLASS METADATA K1 diff --git a/compiler/testData/codegen/box/casts/mutableCollections/reifiedSafeAsWithMutable.jvm_abi.txt b/compiler/testData/codegen/box/casts/mutableCollections/reifiedSafeAsWithMutable.jvm_abi.txt index 164ab4f7ae1..98aa5a72250 100644 --- a/compiler/testData/codegen/box/casts/mutableCollections/reifiedSafeAsWithMutable.jvm_abi.txt +++ b/compiler/testData/codegen/box/casts/mutableCollections/reifiedSafeAsWithMutable.jvm_abi.txt @@ -1,18 +1,4 @@ MODULE main - CLASS MLItr.class - CLASS METADATA - FUNCTION add(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) - FUNCTION set(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) CLASS C.class CLASS METADATA K1 diff --git a/compiler/testData/codegen/box/casts/mutableCollections/safeAsWithMutable.jvm_abi.txt b/compiler/testData/codegen/box/casts/mutableCollections/safeAsWithMutable.jvm_abi.txt index 164ab4f7ae1..98aa5a72250 100644 --- a/compiler/testData/codegen/box/casts/mutableCollections/safeAsWithMutable.jvm_abi.txt +++ b/compiler/testData/codegen/box/casts/mutableCollections/safeAsWithMutable.jvm_abi.txt @@ -1,18 +1,4 @@ MODULE main - CLASS MLItr.class - CLASS METADATA - FUNCTION add(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) - FUNCTION set(Ljava/lang/String;)V - Property: class.metadata.function.valueParameters - K1 - (element: kotlin/String) - K2 - (element: @kotlin/jvm/internal/EnhancedNullability kotlin/String) CLASS C.class CLASS METADATA K1