diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 0852f81a325..ae214a72caf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 import org.jetbrains.kotlin.diagnostics.Errors @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier import org.jetbrains.kotlin.resolve.BindingContext.* import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.typeUtil.* @@ -214,6 +216,11 @@ class DeclarationsChecker( trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter)) } } + + override fun repeatedAnnotation(annotation: AnnotationDescriptor) { + val annotationEntry = (annotation.source as? KotlinSourceElement)?.psi as? KtAnnotationEntry ?: return + trace.report(REPEATED_ANNOTATION.on(annotationEntry)) + } } private fun checkTypeAliasExpansion(declaration: KtTypeAlias, typeAliasDescriptor: TypeAliasDescriptor) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt index 0f097afeab8..db5e3123e25 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations @@ -51,8 +52,7 @@ class TypeAliasExpander( "Type alias expansion: result for ${typeAliasExpansion.descriptor} is ${expandedProjection.projectionKind}, should be invariant" } - val expandedTypeWithExtraAnnotations = expandedType.replace( - newAnnotations = CompositeAnnotations(listOf(annotations, expandedType.annotations))) + val expandedTypeWithExtraAnnotations = combineAnnotations(expandedType, annotations) return if (withAbbreviatedType) expandedTypeWithExtraAnnotations.withAbbreviation(typeAliasExpansion.createAbbreviation(originalProjection, annotations)) @@ -60,6 +60,18 @@ class TypeAliasExpander( expandedTypeWithExtraAnnotations } + private fun combineAnnotations(type: SimpleType, annotations: Annotations): SimpleType { + val existingAnnotationTypes = type.annotations.getAllAnnotations().mapTo(hashSetOf()) { it.annotation.type } + + for (annotation in annotations) { + if (annotation.type in existingAnnotationTypes) { + reportStrategy.repeatedAnnotation(annotation) + } + } + + return type.replace(newAnnotations = CompositeAnnotations(listOf(annotations, type.annotations))) + } + private fun TypeAliasExpansion.createAbbreviation(originalProjection: TypeProjection, annotations: Annotations) = KotlinTypeFactory.simpleType( annotations, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt index 99325cb491a..e04c0f3e2d4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.types.KotlinType interface TypeAliasExpansionReportStrategy { @@ -25,11 +26,13 @@ interface TypeAliasExpansionReportStrategy { fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) + fun repeatedAnnotation(annotation: AnnotationDescriptor) object DO_NOTHING : TypeAliasExpansionReportStrategy { override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {} override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {} override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) {} override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {} + override fun repeatedAnnotation(annotation: AnnotationDescriptor) {} } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index fa66d9d2941..c75be75ac89 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.context.TypeLazinessToken import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.VariableDescriptorImpl import org.jetbrains.kotlin.diagnostics.Errors @@ -42,6 +43,7 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.utils.findFirstFromMeAndParent +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.source.toSourceElement import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.StorageManager @@ -519,7 +521,7 @@ class TypeResolver( override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) { val argumentElement = typeParameter?.let { mappedArguments[it] } - if (argumentElement != null && typeParameter != null) { + if (argumentElement != null) { trace.report(CONFLICTING_PROJECTION.on(argumentElement, typeParameter)) } else if (type != null) { @@ -544,10 +546,13 @@ class TypeResolver( trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(type, bound, argument, typeParameter)) } } + + override fun repeatedAnnotation(annotation: AnnotationDescriptor) { + val annotationEntry = (annotation.source as? KotlinSourceElement)?.psi as? KtAnnotationEntry ?: return + trace.report(REPEATED_ANNOTATION.on(annotationEntry)) + } } - - private fun createErrorTypeForTypeConstructor( c: TypeResolutionContext, arguments: List, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index 92bd73553f6..035e540b5a6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -20,6 +20,7 @@ import com.google.common.collect.Lists import com.google.common.collect.Sets import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors.* @@ -597,15 +598,19 @@ class CandidateResolver( private val argumentsMapping = typeAlias.declaredTypeParameters.zip(ktTypeArguments).toMap() override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) { - // TODO + // can't happen in single-step expansion } override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) { - // TODO + // can't happen in single-step expansion } override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) { - // can't happen in non-error type + // can't happen in single-step expansion + } + + override fun repeatedAnnotation(annotation: AnnotationDescriptor) { + // can't happen in single-step expansion } override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) { diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasExpansionRepeatedAnnotations.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasExpansionRepeatedAnnotations.kt new file mode 100644 index 00000000000..72359e44324 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasExpansionRepeatedAnnotations.kt @@ -0,0 +1,16 @@ +@Target(AnnotationTarget.TYPE) +annotation class A + +typealias AInt = @A Int +typealias AI = AInt + +typealias Test1 = @A AInt +typealias Test2 = @A AI +typealias Test3 = List<@A AInt> +typealias Test4 = List<@A AI> + +val testProperty1: @A AInt = 0 +val testProperty2: @A AI = 0 + +fun testFunction1(x: @A AInt): @A AInt = x +fun testFunction2(x: @A AI): @A AI = x \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasExpansionRepeatedAnnotations.txt b/compiler/testData/diagnostics/tests/typealias/typeAliasExpansionRepeatedAnnotations.txt new file mode 100644 index 00000000000..ef62f78bec9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasExpansionRepeatedAnnotations.txt @@ -0,0 +1,19 @@ +package + +public val testProperty1: @A AInt /* = @A @A kotlin.Int */ = 0 +public val testProperty2: @A AI /* = @A @A kotlin.Int */ = 0 +public fun testFunction1(/*0*/ x: @A AInt /* = @A @A kotlin.Int */): @A AInt /* = @A @A kotlin.Int */ +public fun testFunction2(/*0*/ x: @A AI /* = @A @A kotlin.Int */): @A AI /* = @A @A kotlin.Int */ + +@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 AI = AInt +public typealias AInt = @A kotlin.Int +public typealias Test1 = @A AInt +public typealias Test2 = @A AI +public typealias Test3 = kotlin.collections.List<@A AInt> +public typealias Test4 = kotlin.collections.List<@A AI> diff --git a/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.kt b/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.kt index abafc6009b9..5d30894a70d 100644 --- a/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.kt +++ b/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.kt @@ -14,8 +14,3 @@ fun test2(a: Alias3) = a typealias LA1 = List<@Ann2 Alias1> fun test3(la1: LA1) = la1 - -// see KT-14318 -typealias AliasRepeated = @Ann1 Alias1 -fun test4(a: AliasRepeated) = a -fun test4a(a: @Ann1 Alias1) = a \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.txt b/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.txt index 9e3cc5cec2e..5c2e42d3767 100644 --- a/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.txt +++ b/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.txt @@ -3,8 +3,6 @@ package public fun test1(/*0*/ a: Alias2 /* = @Ann2 @Ann1 kotlin.String */): Alias2 /* = @Ann2 @Ann1 kotlin.String */ public fun test2(/*0*/ a: Alias3 /* = @kotlin.ExtensionFunctionType @Ann1 kotlin.String */): Alias3 /* = @kotlin.ExtensionFunctionType @Ann1 kotlin.String */ public fun test3(/*0*/ la1: LA1 /* = kotlin.collections.List<@Ann2 Alias1 /* = @Ann2 @Ann1 kotlin.String */> */): LA1 /* = kotlin.collections.List<@Ann2 Alias1 /* = @Ann2 @Ann1 kotlin.String */> */ -public fun test4(/*0*/ a: AliasRepeated /* = @Ann1 @Ann1 kotlin.String */): AliasRepeated /* = @Ann1 @Ann1 kotlin.String */ -public fun test4a(/*0*/ a: @Ann1 Alias1 /* = @Ann1 @Ann1 kotlin.String */): @Ann1 Alias1 /* = @Ann1 @Ann1 kotlin.String */ @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) public final annotation class Ann1 : kotlin.Annotation { public constructor Ann1() @@ -22,5 +20,4 @@ public fun test4a(/*0*/ a: @Ann1 Alias1 /* = @Ann1 @Ann1 kotlin.String */): @Ann public typealias Alias1 = @Ann1 kotlin.String public typealias Alias2 = @Ann2 Alias1 public typealias Alias3 = @kotlin.ExtensionFunctionType Alias1 -public typealias AliasRepeated = @Ann1 Alias1 public typealias LA1 = kotlin.collections.List<@Ann2 Alias1> diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index af11f800f4c..43f0452ee6b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -20868,6 +20868,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("typeAliasExpansionRepeatedAnnotations.kt") + public void testTypeAliasExpansionRepeatedAnnotations() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasExpansionRepeatedAnnotations.kt"); + doTest(fileName); + } + @TestMetadata("typeAliasInAnonymousObjectType.kt") public void testTypeAliasInAnonymousObjectType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasInAnonymousObjectType.kt");