diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt index b98783219de..d4246b286d2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt @@ -19,7 +19,7 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations +import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.containsTypeAliasParameters @@ -53,6 +53,7 @@ class TypeAliasExpander( "Type alias expansion: result for ${typeAliasExpansion.descriptor} is ${expandedProjection.projectionKind}, should be invariant" } + checkRepeatedAnnotations(expandedType.annotations, annotations) val expandedTypeWithExtraAnnotations = expandedType.combineAnnotations(annotations).let { TypeUtils.makeNullableIfNeeded(it, isNullable) } return if (withAbbreviatedType) @@ -82,59 +83,72 @@ class TypeAliasExpander( if (underlyingProjection.isStarProjection) return TypeUtils.makeStarProjection(typeParameterDescriptor!!) val underlyingType = underlyingProjection.type - val argument = typeAliasExpansion.getReplacement(underlyingType.constructor) - - if (argument == null) { - return expandNonArgumentTypeProjection(underlyingProjection, typeAliasExpansion, recursionDepth) - } + val argument = typeAliasExpansion.getReplacement(underlyingType.constructor) ?: + return expandNonArgumentTypeProjection(underlyingProjection, typeAliasExpansion, recursionDepth) if (argument.isStarProjection) return TypeUtils.makeStarProjection(typeParameterDescriptor!!) - val argumentVariance = argument.projectionKind - val underlyingVariance = underlyingProjection.projectionKind + val argumentType = argument.type.unwrap() - val argumentType = argument.type.unwrap().asSimpleType() + val resultingVariance = run { + val argumentVariance = argument.projectionKind + val underlyingVariance = underlyingProjection.projectionKind - val substitutionVariance = - when { - underlyingVariance == argumentVariance -> argumentVariance - underlyingVariance == Variance.INVARIANT -> argumentVariance - argumentVariance == Variance.INVARIANT -> underlyingVariance - else -> { - reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, argumentType) - argumentVariance + val substitutionVariance = + when { + underlyingVariance == argumentVariance -> argumentVariance + underlyingVariance == Variance.INVARIANT -> argumentVariance + argumentVariance == Variance.INVARIANT -> underlyingVariance + else -> { + reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, argumentType) + argumentVariance + } } - } - val parameterVariance = typeParameterDescriptor?.variance ?: Variance.INVARIANT - val resultingVariance = - when { - parameterVariance == substitutionVariance -> substitutionVariance - parameterVariance == Variance.INVARIANT -> substitutionVariance - substitutionVariance == Variance.INVARIANT -> Variance.INVARIANT - else -> { - reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, argumentType) - substitutionVariance - } - } + val parameterVariance = typeParameterDescriptor?.variance ?: Variance.INVARIANT - val substitutedType = argumentType.combineNullabilityAndAnnotations(underlyingType) + when { + parameterVariance == substitutionVariance -> substitutionVariance + parameterVariance == Variance.INVARIANT -> substitutionVariance + substitutionVariance == Variance.INVARIANT -> Variance.INVARIANT + else -> { + reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, argumentType) + substitutionVariance + } + } + } + + checkRepeatedAnnotations(underlyingType.annotations, argumentType.annotations) + + val substitutedType = + if (argumentType is DynamicType) + argumentType.combineAnnotations(underlyingType.annotations) + else + argumentType.asSimpleType().combineNullabilityAndAnnotations(underlyingType) return TypeProjectionImpl(resultingVariance, substitutedType) } - private fun SimpleType.combineAnnotations(annotations: Annotations): SimpleType { - if (isError) return this + private fun DynamicType.combineAnnotations(newAnnotations: Annotations): DynamicType = + replaceAnnotations(createCombinedAnnotations(newAnnotations)) - val existingAnnotationTypes = this.annotations.getAllAnnotations().mapTo(hashSetOf()) { it.annotation.type } + private fun SimpleType.combineAnnotations(newAnnotations: Annotations): SimpleType = + if (isError) this else replace(newAnnotations = createCombinedAnnotations(newAnnotations)) - for (annotation in annotations) { + private fun KotlinType.createCombinedAnnotations(newAnnotations: Annotations): Annotations { + if (isError) return annotations + + return composeAnnotations(newAnnotations, annotations) + } + + private fun checkRepeatedAnnotations(existingAnnotations: Annotations, newAnnotations: Annotations) { + val existingAnnotationTypes = existingAnnotations.mapTo(hashSetOf()) { it.type } + + for (annotation in newAnnotations) { if (annotation.type in existingAnnotationTypes) { reportStrategy.repeatedAnnotation(annotation) } } - - return replace(newAnnotations = CompositeAnnotations(listOf(annotations, this.annotations))) } private fun SimpleType.combineNullability(fromType: KotlinType) = @@ -148,7 +162,11 @@ class TypeAliasExpander( typeAliasExpansion: TypeAliasExpansion, recursionDepth: Int ): TypeProjection { - val type = originalProjection.type.asSimpleType() + val originalType = originalProjection.type.unwrap() + + if (originalType.isDynamic()) return originalProjection + + val type = originalType.asSimpleType() if (type.isError || !type.requiresTypeAliasExpansion()) { return originalProjection diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index f53e46f5b6f..11be0da109f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -301,7 +301,7 @@ class TypeResolver( } override fun visitDynamicType(type: KtDynamicType) { - result = type(dynamicCallableDescriptors.dynamicType) + result = type(dynamicCallableDescriptors.dynamicType.replaceAnnotations(annotations)) if (!dynamicTypesSettings.dynamicTypesAllowed) { c.trace.report(UNSUPPORTED.on(type, "Dynamic types are not supported in this context")) } diff --git a/compiler/testData/diagnostics/tests/typealias/typealiasRhsRepeatedAnnotationInArguments.kt b/compiler/testData/diagnostics/tests/typealias/typealiasRhsRepeatedAnnotationInArguments.kt new file mode 100644 index 00000000000..9a0154574dc --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/typealiasRhsRepeatedAnnotationInArguments.kt @@ -0,0 +1,6 @@ +@Target(AnnotationTarget.TYPE) +annotation class A + +typealias Gen = List<@A T> + +typealias Test1 = Gen<@A Int> diff --git a/compiler/testData/diagnostics/tests/typealias/typealiasRhsRepeatedAnnotationInArguments.txt b/compiler/testData/diagnostics/tests/typealias/typealiasRhsRepeatedAnnotationInArguments.txt new file mode 100644 index 00000000000..1aebe4afa3c --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/typealiasRhsRepeatedAnnotationInArguments.txt @@ -0,0 +1,10 @@ +package + +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) public final annotation class A : kotlin.Annotation { + public constructor A() + 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 +} +public typealias Gen = kotlin.collections.List<@A T> +public typealias Test1 = Gen<@A kotlin.Int> diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithAnnotatedDynamic.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithAnnotatedDynamic.kt new file mode 100644 index 00000000000..ec903aa9d3f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithAnnotatedDynamic.kt @@ -0,0 +1,16 @@ +@Target(AnnotationTarget.TYPE) +annotation class Ann1 + +@Target(AnnotationTarget.TYPE) +annotation class Ann2 + +typealias AnnGenList = List<@Ann1 T> +typealias TestAnnGen1 = AnnGenList +typealias TestAnnGen2 = AnnGenList<@Ann2 dynamic> +typealias TestAnnGen3 = AnnGenList<@Ann1 dynamic> + +fun useAnnGen1(x: TestAnnGen1) = x +fun useAnnGen2(x: TestAnnGen2) = x + +fun testUseAnnGen1(x: List) = useAnnGen1(x) +fun testUseAnnGen2(x: List) = useAnnGen2(x) \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithAnnotatedDynamic.txt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithAnnotatedDynamic.txt new file mode 100644 index 00000000000..27e5c76466a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithAnnotatedDynamic.txt @@ -0,0 +1,24 @@ +package + +public fun testUseAnnGen1(/*0*/ x: kotlin.collections.List): TestAnnGen1 /* = kotlin.collections.List */ +public fun testUseAnnGen2(/*0*/ x: kotlin.collections.List): TestAnnGen2 /* = kotlin.collections.List */ +public fun useAnnGen1(/*0*/ x: TestAnnGen1 /* = kotlin.collections.List */): TestAnnGen1 /* = kotlin.collections.List */ +public fun useAnnGen2(/*0*/ x: TestAnnGen2 /* = kotlin.collections.List */): TestAnnGen2 /* = kotlin.collections.List */ + +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) public final annotation class Ann1 : kotlin.Annotation { + public constructor Ann1() + 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 +} + +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) public final annotation class Ann2 : kotlin.Annotation { + public constructor Ann2() + 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 +} +public typealias AnnGenList = kotlin.collections.List<@Ann1 T> +public typealias TestAnnGen1 = AnnGenList +public typealias TestAnnGen2 = AnnGenList +public typealias TestAnnGen3 = AnnGenList diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithDynamic.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithDynamic.kt new file mode 100644 index 00000000000..c6e1aa941d3 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithDynamic.kt @@ -0,0 +1,13 @@ +typealias Test1 = List + +typealias Test2 = (dynamic) -> dynamic + +typealias GenList = List +typealias TestGen1 = GenList +typealias TestGen2 = GenList> + +fun useGen1(x: TestGen1) = x +fun useGen2(x: TestGen2) = x + +fun testUseGen1(x: List) = useGen1(x) +fun testUseGen2(x: List>) = useGen2(x) diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithDynamic.txt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithDynamic.txt new file mode 100644 index 00000000000..b191d601dc8 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithDynamic.txt @@ -0,0 +1,11 @@ +package + +public fun testUseGen1(/*0*/ x: kotlin.collections.List): TestGen1 /* = kotlin.collections.List */ +public fun testUseGen2(/*0*/ x: kotlin.collections.List>): TestGen2 /* = kotlin.collections.List> */ +public fun useGen1(/*0*/ x: TestGen1 /* = kotlin.collections.List */): TestGen1 /* = kotlin.collections.List */ +public fun useGen2(/*0*/ x: TestGen2 /* = kotlin.collections.List> */): TestGen2 /* = kotlin.collections.List> */ +public typealias GenList = kotlin.collections.List +public typealias Test1 = kotlin.collections.List +public typealias Test2 = (dynamic) -> dynamic +public typealias TestGen1 = GenList +public typealias TestGen2 = GenList> diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 882d55b4b56..a48fa2218ef 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -23014,6 +23014,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("typealiasRhsRepeatedAnnotationInArguments.kt") + public void testTypealiasRhsRepeatedAnnotationInArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typealiasRhsRepeatedAnnotationInArguments.kt"); + doTest(fileName); + } + @TestMetadata("typealiasRhsRepeatedAnnotations.kt") public void testTypealiasRhsRepeatedAnnotations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typealiasRhsRepeatedAnnotations.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java index fb704ee1007..f08e5c14dd9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -314,6 +314,18 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes doTest(fileName); } + @TestMetadata("typealiasWithAnnotatedDynamic.kt") + public void testTypealiasWithAnnotatedDynamic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithAnnotatedDynamic.kt"); + doTest(fileName); + } + + @TestMetadata("typealiasWithDynamic.kt") + public void testTypealiasWithDynamic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/typealiasWithDynamic.kt"); + doTest(fileName); + } + @TestMetadata("varargs.kt") public void testVarargs() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/varargs.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/dynamicTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/dynamicTypes.kt index db6a6189b88..f71d3dc2f19 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/dynamicTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/dynamicTypes.kt @@ -44,7 +44,7 @@ class DynamicType(builtIns: KotlinBuiltIns, override val annotations: Annotation override val isMarkedNullable: Boolean get() = false - override fun replaceAnnotations(newAnnotations: Annotations): DynamicType = DynamicType(delegate.builtIns, annotations) + override fun replaceAnnotations(newAnnotations: Annotations): DynamicType = DynamicType(delegate.builtIns, newAnnotations) override fun render(renderer: DescriptorRenderer, options: DescriptorRendererOptions): String = "dynamic" }