From 9efac8f68b35c7c95cb19d635ef257c175d1d75d Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Wed, 27 Jan 2021 16:27:20 +0300 Subject: [PATCH] Propagate all annotations during creating simple functional types ^KT-44563 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 6 +++++ .../kotlin/fir/types/ConeInferenceContext.kt | 3 ++- .../kotlin/fir/types/ConeTypeContext.kt | 5 ++++ .../kotlin/ir/types/IrTypeSystemContext.kt | 23 +++++++++++++--- .../PostponedArgumentInputTypesResolver.kt | 9 +++++-- .../propagteAnyAnnotations.fir.kt | 12 +++++++++ .../functionalTypes/propagteAnyAnnotations.kt | 12 +++++++++ .../propagteAnyAnnotations.txt | 12 +++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 +++++ .../kotlin/types/model/TypeSystemContext.kt | 6 ++++- .../annotations/AnnotationDescriptor.kt | 3 ++- .../descriptors/annotations/Annotations.kt | 1 + .../types/checker/ClassicTypeSystemContext.kt | 26 ++++++++++++++----- 13 files changed, 109 insertions(+), 15 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.fir.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.txt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index ff5f288d125..4f3716e24a4 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -1457,6 +1457,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti public void testParenthesizedAnnotations() throws Exception { runTest("compiler/testData/diagnostics/tests/annotations/functionalTypes/parenthesizedAnnotations.kt"); } + + @Test + @TestMetadata("propagteAnyAnnotations.kt") + public void testPropagteAnyAnnotations() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.kt"); + } } @Nested diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 0b16784e182..eafd1ba2afb 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -58,7 +58,8 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo constructor: TypeConstructorMarker, arguments: List, nullable: Boolean, - isExtensionFunction: Boolean + isExtensionFunction: Boolean, + annotations: List? // TODO: process annotations ): SimpleTypeMarker { val attributes = if (isExtensionFunction) // TODO: assert correct type constructor ConeAttributes.WithExtensionFunctionType 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 169e38722e2..91df2893bea 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 @@ -402,6 +402,11 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty return false } + override fun KotlinTypeMarker.getAnnotations(): List { + require(this is ConeKotlinType) + return emptyList() // TODO + } + override fun SimpleTypeMarker.isStubType(): Boolean { return this is StubTypeMarker } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index e6a34e2a4ed..2b89a9ab30e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -10,9 +10,12 @@ import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.symbols.FqNameEqualityChecker import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol @@ -237,13 +240,22 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon return IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT) } - // TODO: implement taking into account `isExtensionFunction` override fun createSimpleType( constructor: TypeConstructorMarker, arguments: List, nullable: Boolean, - isExtensionFunction: Boolean - ): SimpleTypeMarker = IrSimpleTypeImpl(constructor as IrClassifierSymbol, nullable, arguments.map { it as IrTypeArgument }, emptyList()) + isExtensionFunction: Boolean, + annotations: List? + ): SimpleTypeMarker { + val ourAnnotations = annotations?.filterIsInstance() + require(ourAnnotations?.size == annotations?.size) + return IrSimpleTypeImpl( + constructor as IrClassifierSymbol, + nullable, + arguments.map { it as IrTypeArgument }, + ourAnnotations ?: emptyList() + ) + } private fun TypeVariance.convertVariance(): Variance { return when (this) { @@ -298,6 +310,11 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon override fun SimpleTypeMarker.isPrimitiveType(): Boolean = this is IrSimpleType && irTypePredicates_isPrimitiveType() + override fun KotlinTypeMarker.getAnnotations(): List { + require(this is IrType) + return this.annotations.map { object : AnnotationMarker, IrElement by it {} } + } + override fun createErrorType(debugName: String): SimpleTypeMarker { TODO("IrTypeSystemContext doesn't support constraint system resolution") } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt index 4fa73b17809..14a1ceba84c 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt @@ -24,6 +24,7 @@ class PostponedArgumentInputTypesResolver( val parametersFromDeclaration: List?, val parametersFromDeclarationOfRelatedLambdas: Set>?, val parametersFromConstraints: Set>?, + val annotations: List?, val isExtensionFunction: Boolean, val isSuspend: Boolean, val isNullable: Boolean @@ -57,7 +58,7 @@ class PostponedArgumentInputTypesResolver( argument: PostponedAtomWithRevisableExpectedType, postponedArguments: List, variableDependencyProvider: TypeVariableDependencyInformationProvider - ): ParameterTypesInfo? = with(resolutionTypeSystemContext) { + ): ParameterTypesInfo? { val expectedType = argument.expectedType ?: return null val variableWithConstraints = notFixedTypeVariables[expectedType.typeConstructor()] ?: return null val functionalTypesFromConstraints = findFunctionalTypesInConstraints(variableWithConstraints, variableDependencyProvider) @@ -76,6 +77,8 @@ class PostponedArgumentInputTypesResolver( } } + val annotations = functionalTypesFromConstraints?.map { it.type.getAnnotations() }?.flatten()?.distinct() + // An extension function flag can only come from a declaration of anonymous function: `select({ this + it }, fun Int.(x: Int) = 10)` val (parameterTypesFromDeclarationOfRelatedLambdas, isThereExtensionFunctionAmongRelatedLambdas) = getDeclaredParametersFromRelatedLambdas(argument, postponedArguments, variableDependencyProvider) @@ -96,6 +99,7 @@ class PostponedArgumentInputTypesResolver( parameterTypesFromDeclaration, parameterTypesFromDeclarationOfRelatedLambdas, parameterTypesFromConstraints, + annotations = annotations, isExtensionFunction = isThereExtensionFunctionAmongRelatedLambdas || extensionFunctionTypePresentInConstraints, isSuspend = isSuspend, isNullable = isNullable @@ -344,7 +348,8 @@ class PostponedArgumentInputTypesResolver( shouldDiscriminateExtensionFunctionAnnotation -> false argument.isFunctionExpressionWithReceiver() -> true else -> parameterTypesInfo.isExtensionFunction - } + }, + annotations = parameterTypesInfo.annotations ) getBuilder().addSubtypeConstraint( diff --git a/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.fir.kt b/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.fir.kt new file mode 100644 index 00000000000..3e194a67450 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.fir.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE) +annotation class Composable + +fun bar(p: @Composable ()->Unit) {} + +@Composable fun foo() {} + +fun main() { + bar(if(true) { { foo() } } else { { } }) +} diff --git a/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.kt b/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.kt new file mode 100644 index 00000000000..bc85c6650c9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE) +annotation class Composable + +fun bar(p: @Composable ()->Unit) {} + +@Composable fun foo() {} + +fun main() { + bar( kotlin.Unit")!>if(true) { { foo() } } else { { } }) +} diff --git a/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.txt b/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.txt new file mode 100644 index 00000000000..3a62a513f88 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.txt @@ -0,0 +1,12 @@ +package + +public fun bar(/*0*/ p: @Composable () -> kotlin.Unit): kotlin.Unit +@Composable public fun foo(): kotlin.Unit +public fun main(): kotlin.Unit + +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FUNCTION, AnnotationTarget.TYPE}) public final annotation class Composable : kotlin.Annotation { + public constructor Composable() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 378bdfa2eff..9944b7b6e2c 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -1463,6 +1463,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { public void testParenthesizedAnnotations() throws Exception { runTest("compiler/testData/diagnostics/tests/annotations/functionalTypes/parenthesizedAnnotations.kt"); } + + @Test + @TestMetadata("propagteAnyAnnotations.kt") + public void testPropagteAnyAnnotations() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/functionalTypes/propagteAnyAnnotations.kt"); + } } @Nested diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index 6c7f40d41b6..81a35b99371 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -36,6 +36,7 @@ interface IntersectionTypeConstructorMarker : TypeConstructorMarker interface TypeSubstitutorMarker +interface AnnotationMarker enum class TypeVariance(val presentation: String) { IN("in"), @@ -73,7 +74,8 @@ interface TypeSystemTypeFactoryContext { constructor: TypeConstructorMarker, arguments: List, nullable: Boolean, - isExtensionFunction: Boolean = false + isExtensionFunction: Boolean = false, + annotations: List? = null ): SimpleTypeMarker fun createTypeArgument(type: KotlinTypeMarker, variance: TypeVariance): TypeArgumentMarker @@ -391,6 +393,8 @@ interface TypeSystemContext : TypeSystemOptimizationContext { fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker fun SimpleTypeMarker.isPrimitiveType(): Boolean + + fun KotlinTypeMarker.getAnnotations(): List } enum class CaptureStatus { diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt index b6dec08742d..6dda57cb627 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt @@ -25,8 +25,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.getAbbreviation +import org.jetbrains.kotlin.types.model.AnnotationMarker -interface AnnotationDescriptor { +interface AnnotationDescriptor : AnnotationMarker { val type: KotlinType val fqName: FqName? diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/Annotations.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/Annotations.kt index 90beb46f1ac..b173d458db9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/Annotations.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/Annotations.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.descriptors.annotations import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.types.model.AnnotationMarker interface Annotated { val annotations: Annotations diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index fa3f585b72e..4bc8700e92f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -29,8 +29,6 @@ import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound import org.jetbrains.kotlin.utils.addToStdlib.safeAs -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.contract import org.jetbrains.kotlin.types.typeUtil.isSignedOrUnsignedNumberType as classicIsSignedOrUnsignedNumberType interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSystemCommonBackendContext { @@ -437,16 +435,25 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy constructor: TypeConstructorMarker, arguments: List, nullable: Boolean, - isExtensionFunction: Boolean + isExtensionFunction: Boolean, + annotations: List? ): SimpleTypeMarker { require(constructor is TypeConstructor, constructor::errorMessage) - val annotations = if (isExtensionFunction) { - Annotations.create(listOf(BuiltInAnnotationDescriptor(builtIns, FqNames.extensionFunctionType, emptyMap()))) - } else Annotations.EMPTY + val ourAnnotations = annotations?.filterIsInstance() + require(ourAnnotations?.size == annotations?.size) + + fun createExtensionFunctionAnnotation() = BuiltInAnnotationDescriptor(builtIns, FqNames.extensionFunctionType, emptyMap()) + + val resultingAnnotations = when { + ourAnnotations.isNullOrEmpty() && isExtensionFunction -> Annotations.create(listOf(createExtensionFunctionAnnotation())) + !ourAnnotations.isNullOrEmpty() && !isExtensionFunction -> Annotations.create(ourAnnotations.filter { it.fqName != FqNames.extensionFunctionType }) + !ourAnnotations.isNullOrEmpty() && isExtensionFunction -> Annotations.create(ourAnnotations + createExtensionFunctionAnnotation()) + else -> Annotations.EMPTY + } @Suppress("UNCHECKED_CAST") - return KotlinTypeFactory.simpleType(annotations, constructor, arguments as List, nullable) + return KotlinTypeFactory.simpleType(resultingAnnotations, constructor, arguments as List, nullable) } override fun createTypeArgument(type: KotlinTypeMarker, variance: TypeVariance): TypeArgumentMarker { @@ -557,6 +564,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return KotlinBuiltIns.isPrimitiveType(this) } + override fun KotlinTypeMarker.getAnnotations(): List { + require(this is KotlinType, this::errorMessage) + return this.annotations.toList() + } + override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? { return captureFromExpressionInternal(type as UnwrappedType) }