diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt index 9386d7b2ca3..40960df03ea 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt @@ -18,16 +18,30 @@ val ConeKotlinType.isMarkedNullable: Boolean get() = nullability == ConeNullabil val ConeKotlinType.classId: ClassId? get() = this.safeAs()?.lookupTag?.classId -fun ConeKotlinType.contains(predicate: (ConeKotlinType) -> Boolean): Boolean { - return contains(predicate, null) +/** + * Recursively visits each [ConeKotlinType] inside (including itself) and performs the given action. + */ +fun ConeKotlinType.forEachType(action: (ConeKotlinType) -> Unit) { + action(this) + + return when (this) { + is ConeFlexibleType -> { + lowerBound.forEachType(action) + upperBound.forEachType(action) + } + is ConeDefinitelyNotNullType -> original.forEachType(action) + is ConeIntersectionType -> intersectedTypes.forEach { it.forEachType(action) } + else -> typeArguments.forEach { if (it is ConeKotlinTypeProjection) it.type.forEachType(action) } + } } -private fun ConeKotlinType.contains(predicate: (ConeKotlinType) -> Boolean, visited: SmartSet?): Boolean { - if (visited?.contains(this) == true) return false - if (predicate(this)) return true +fun ConeKotlinType.contains(predicate: (ConeKotlinType) -> Boolean): Boolean { + return contains(predicate, SmartSet.create()) +} - @Suppress("NAME_SHADOWING") - val visited = visited ?: SmartSet.create() +private fun ConeKotlinType.contains(predicate: (ConeKotlinType) -> Boolean, visited: SmartSet): Boolean { + if (this in visited) return false + if (predicate(this)) return true visited += this return when (this) { @@ -74,6 +88,7 @@ val ConeKotlinType.isArrayType: Boolean return isBuiltinType(StandardClassIds.Array, false) || StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, false) } } + // Same as [KotlinBuiltIns#isNonPrimitiveArray] val ConeKotlinType.isNonPrimitiveArray: Boolean get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.Array diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt index 45e5b0b283d..519dea82fcd 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt @@ -21,9 +21,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorForFull import org.jetbrains.kotlin.fir.resolve.transformers.ScopeClassDeclaration import org.jetbrains.kotlin.fir.scopes.FirCompositeScope import org.jetbrains.kotlin.fir.scopes.impl.createCurrentScopeList -import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.FirTransformer open class FirBodyResolveTransformer( @@ -77,6 +75,13 @@ open class FirBodyResolveTransformer( ) } } + + resolvedTypeRef.coneType.forEachType { + it.type.attributes.customAnnotations.forEach { typeArgumentAnnotation -> + typeArgumentAnnotation.accept(this, data) + } + } + return resolvedTypeRef.transformAnnotations(this, data) } diff --git a/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.fir.kt b/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.fir.kt index 4b86f649e7f..fccca04c458 100644 --- a/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.fir.kt @@ -26,4 +26,19 @@ annotation class TypeAnn val onType: (@TypeAnn A).(@Ann a: @TypeAnn A, @TypeAnn A)->@TypeAnn A? = { null } -fun (@TypeAnn A).extFun(@Ann a: @TypeAnn A): @TypeAnn A? = null \ No newline at end of file +fun (@TypeAnn A).extFun(@Ann a: @TypeAnn A): @TypeAnn A? = null + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnnWithArg(val arg: String) + +fun badArgs(a: (@TypeAnnWithArg(unresolved = "") Int) -> Unit) {} + +typealias BadArgsInTypeAlias = (@TypeAnnWithArg Int) -> Unit +fun badArgsInTypeAlias(a: BadArgsInTypeAlias) {} + +typealias T = (X) -> Unit +fun badArgsInTypeAliasInstance(a: T<@TypeAnnWithArg(arg = 123) Int>) {} + +typealias BadArgsInRecursive = (((@TypeAnnWithArg Int) -> Unit) -> @TypeAnnWithArg String) -> Unit + +typealias BadArgsMultiple = (@TypeAnnWithArg Int, @TypeAnnWithArg(arg = 123) Int) -> Unit diff --git a/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.kt b/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.kt index c34c0bf809c..70180573b2f 100644 --- a/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.kt +++ b/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.kt @@ -26,4 +26,19 @@ annotation class TypeAnn val onType: (@TypeAnn A).(@Ann a: @TypeAnn A, @TypeAnn A)->@TypeAnn A? = { null } -fun (@TypeAnn A).extFun(@Ann a: @TypeAnn A): @TypeAnn A? = null \ No newline at end of file +fun (@TypeAnn A).extFun(@Ann a: @TypeAnn A): @TypeAnn A? = null + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnnWithArg(val arg: String) + +fun badArgs(a: (@TypeAnnWithArg(unresolved = "") Int) -> Unit) {} + +typealias BadArgsInTypeAlias = (@TypeAnnWithArg Int) -> Unit +fun badArgsInTypeAlias(a: BadArgsInTypeAlias) {} + +typealias T = (X) -> Unit +fun badArgsInTypeAliasInstance(a: T<@TypeAnnWithArg(arg = 123) Int>) {} + +typealias BadArgsInRecursive = (((@TypeAnnWithArg Int) -> Unit) -> @TypeAnnWithArg String) -> Unit + +typealias BadArgsMultiple = (@TypeAnnWithArg Int, @TypeAnnWithArg(arg = 123) Int) -> Unit diff --git a/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.txt b/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.txt index cc539fb4035..16dd6840b8c 100644 --- a/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.txt +++ b/compiler/testData/diagnostics/tests/annotations/annotationOnParameterInFunctionType.txt @@ -2,6 +2,9 @@ package public val inVal: (x: kotlin.Int) -> kotlin.Unit public val onType: (@TypeAnn A).(a: @TypeAnn A, @TypeAnn A) -> @TypeAnn A? +public fun badArgs(/*0*/ a: (@TypeAnnWithArg kotlin.Int) -> kotlin.Unit): kotlin.Unit +public fun badArgsInTypeAlias(/*0*/ a: BadArgsInTypeAlias /* = (@TypeAnnWithArg kotlin.Int) -> kotlin.Unit */): kotlin.Unit +public fun badArgsInTypeAliasInstance(/*0*/ a: T<@TypeAnnWithArg(arg = 123) kotlin.Int> /* = (@TypeAnnWithArg(arg = 123) kotlin.Int) -> kotlin.Unit */): kotlin.Unit public fun f(/*0*/ @Ann x: kotlin.Int): kotlin.Unit public fun inParam(/*0*/ fn: (x: kotlin.Int) -> kotlin.Unit): kotlin.Unit public fun inParamNested(/*0*/ fn1: (fn2: (n: kotlin.Int) -> kotlin.Unit) -> kotlin.Unit): kotlin.Unit @@ -30,3 +33,15 @@ public final annotation class Ann : kotlin.Annotation { 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 TypeAnnWithArg : kotlin.Annotation { + public constructor TypeAnnWithArg(/*0*/ arg: kotlin.String) + public final val arg: kotlin.String + 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 BadArgsInRecursive = (((@TypeAnnWithArg kotlin.Int) -> kotlin.Unit) -> @TypeAnnWithArg kotlin.String) -> kotlin.Unit +public typealias BadArgsInTypeAlias = (@TypeAnnWithArg kotlin.Int) -> kotlin.Unit +public typealias BadArgsMultiple = (@TypeAnnWithArg kotlin.Int, @TypeAnnWithArg(arg = 123) kotlin.Int) -> kotlin.Unit +public typealias T = (X) -> kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/annotations/typeAnnotations.fir.kt b/compiler/testData/diagnostics/tests/annotations/typeAnnotations.fir.kt new file mode 100644 index 00000000000..8a38e14befe --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/typeAnnotations.fir.kt @@ -0,0 +1,33 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE, -UNUSED_PARAMETER +class A + +@Target(AnnotationTarget.TYPE) +annotation class x + +fun @x A.foo(a: @x Int) { + val v: @x Int = 1 +} + +fun @x List<@x T>.foo(l: List<@x T>): @x List<@x T> = throw Exception() + +fun List<@x T>.firstTyped(): U = throw Exception() + +val @x List<@x T>.f: Int get() = 42 + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnnWithArg(val arg: String) + +fun badArgs(a: List<@TypeAnnWithArg(unresolved = "") Int>) {} +fun badArgsWithProjection(a: Arrayunresolved = "") Int>) {} + +typealias BadArgsInTypeAlias = List<@TypeAnnWithArg Int> +fun badArgsInTypeAlias(a: BadArgsInTypeAlias) {} + +typealias T = List +fun badArgsInTypeAliasInstance(a: T<@TypeAnnWithArg(arg = 123) Int>) {} + +typealias BadArgsInTypeParameter<@TypeAnnWithArg(arg = 123) X> = List + +typealias BadArgsInRecursive = List@TypeAnnWithArg Int>, @TypeAnnWithArg String>> + +typealias BadArgsMultiple = Map<@TypeAnnWithArg Int, @TypeAnnWithArg(arg = 123) Int> diff --git a/compiler/testData/diagnostics/tests/annotations/typeAnnotations.kt b/compiler/testData/diagnostics/tests/annotations/typeAnnotations.kt index f8c4a8c0fdc..89ab2823bfe 100644 --- a/compiler/testData/diagnostics/tests/annotations/typeAnnotations.kt +++ b/compiler/testData/diagnostics/tests/annotations/typeAnnotations.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_VARIABLE, -UNUSED_PARAMETER class A @@ -13,4 +12,22 @@ fun @x List<@x T>.foo(l: List<@x T>): @x List<@x T> = throw Exception() fun List<@x T>.firstTyped(): U = throw Exception() -val @x List<@x T>.f: Int get() = 42 \ No newline at end of file +val @x List<@x T>.f: Int get() = 42 + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnnWithArg(val arg: String) + +fun badArgs(a: List<@TypeAnnWithArg(unresolved = "") Int>) {} +fun badArgsWithProjection(a: Arrayunresolved = "") Int>) {} + +typealias BadArgsInTypeAlias = List<@TypeAnnWithArg Int> +fun badArgsInTypeAlias(a: BadArgsInTypeAlias) {} + +typealias T = List +fun badArgsInTypeAliasInstance(a: T<@TypeAnnWithArg(arg = 123) Int>) {} + +typealias BadArgsInTypeParameter<@TypeAnnWithArg(arg = 123) X> = List + +typealias BadArgsInRecursive = ListTypeAnnWithArg Int>, @TypeAnnWithArg String>> + +typealias BadArgsMultiple = Map<@TypeAnnWithArg Int, @TypeAnnWithArg(arg = 123) Int> diff --git a/compiler/testData/diagnostics/tests/annotations/typeAnnotations.txt b/compiler/testData/diagnostics/tests/annotations/typeAnnotations.txt index e2b9a6a525b..ac1bfc589eb 100644 --- a/compiler/testData/diagnostics/tests/annotations/typeAnnotations.txt +++ b/compiler/testData/diagnostics/tests/annotations/typeAnnotations.txt @@ -1,6 +1,10 @@ package public val @x kotlin.collections.List<@x T>.f: kotlin.Int +public fun badArgs(/*0*/ a: kotlin.collections.List<@TypeAnnWithArg kotlin.Int>): kotlin.Unit +public fun badArgsInTypeAlias(/*0*/ a: BadArgsInTypeAlias /* = kotlin.collections.List<@TypeAnnWithArg kotlin.Int> */): kotlin.Unit +public fun badArgsInTypeAliasInstance(/*0*/ a: T<@TypeAnnWithArg(arg = 123) kotlin.Int> /* = kotlin.collections.List<@TypeAnnWithArg(arg = 123) kotlin.Int> */): kotlin.Unit +public fun badArgsWithProjection(/*0*/ a: kotlin.Array): kotlin.Unit public fun kotlin.collections.List<@x T>.firstTyped(): U public fun @x A.foo(/*0*/ a: @x kotlin.Int): kotlin.Unit public fun @x kotlin.collections.List<@x T>.foo(/*0*/ l: kotlin.collections.List<@x T>): @x kotlin.collections.List<@x T> @@ -12,9 +16,22 @@ public final class A { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) public final annotation class TypeAnnWithArg : kotlin.Annotation { + public constructor TypeAnnWithArg(/*0*/ arg: kotlin.String) + public final val arg: kotlin.String + 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 x : kotlin.Annotation { public constructor x() 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 BadArgsInRecursive = kotlin.collections.List, @TypeAnnWithArg kotlin.String>> +public typealias BadArgsInTypeAlias = kotlin.collections.List<@TypeAnnWithArg kotlin.Int> +public typealias BadArgsInTypeParameter = kotlin.collections.List +public typealias BadArgsMultiple = kotlin.collections.Map<@TypeAnnWithArg kotlin.Int, @TypeAnnWithArg(arg = 123) kotlin.Int> +public typealias T = kotlin.collections.List diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/10.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/10.fir.kt deleted file mode 100644 index 65e28f35db5..00000000000 --- a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/10.fir.kt +++ /dev/null @@ -1,26 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_VARIABLE - -// TESTCASE NUMBER: 1, 2 -@Target(AnnotationTarget.TYPE) -annotation class Ann(val x: Int) - -/* - * TESTCASE NUMBER: 1 - * UNEXPECTED BEHAVIOUR - */ -fun case_1() { - val x: (Int) -> @Ann(unresolved_reference) Unit = {} // OK, no error in IDE and in the compiler -} - -/* - * TESTCASE NUMBER: 2 - * UNEXPECTED BEHAVIOUR - */ -fun case_2() { - val x: (@Ann(unresolved_reference) Int) -> Unit = { a: Int -> println(a) } // OK, no error in IDE and in the compiler -} - -// TESTCASE NUMBER: 3 -fun case_3() { - val x: (@Ann(unresolved_reference) Int) -> Unit = { a -> println(a) } // ERROR (if argument type isn't specified explicitly) -} diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/10.kt b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/10.kt index 77b3ed19f2b..9e70ae9c331 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/10.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/10.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_VARIABLE /* diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/3.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/3.fir.kt index e33b9733d06..b62e3668c6b 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/3.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/3.fir.kt @@ -5,7 +5,7 @@ annotation class Ann(val x: Int) // TESTCASE NUMBER: 1 -fun foo(i: Inv<@Ann(unresolved_reference) String>) {} +fun foo(i: Inv<@Ann(unresolved_reference) String>) {} // TESTCASE NUMBER: 2 fun test(vararg a: @Ann(unresolved_reference) Any) {} diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/4.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/4.fir.kt index 34d1a6060dc..1c7a77bcc9f 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/4.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/4.fir.kt @@ -2,4 +2,4 @@ @Target(AnnotationTarget.TYPE) annotation class Ann(val x: Int) -fun case_1(): Inv<@Ann(unresolved_reference) String> = TODO() +fun case_1(): Inv<@Ann(unresolved_reference) String> = TODO() diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/7.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/7.fir.kt deleted file mode 100644 index 6ef987fdf1a..00000000000 --- a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/7.fir.kt +++ /dev/null @@ -1,20 +0,0 @@ - -// TESTCASE NUMBER: 1, 2 -@Target(AnnotationTarget.TYPE) -annotation class Ann - -/* - * TESTCASE NUMBER: 1 - * UNEXPECTED BEHAVIOUR - */ -open class TypeToken - -val case_1 = object : TypeToken<@Ann(unresolved_reference) String>() {} - -/* - * TESTCASE NUMBER: 2 - * UNEXPECTED BEHAVIOUR - */ -interface A - -val case_2 = object: @Ann(unresolved_reference) A {} diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/7.kt b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/7.kt index 10fcb3a938c..96481d956bf 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/7.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/annotations/type-annotations/neg/7.kt @@ -1,4 +1,4 @@ - +// FIR_IDENTICAL /* * KOTLIN DIAGNOSTICS NOT LINKED SPEC TEST (NEGATIVE) *