From 771fde27b213fb80765e716cae3608f0ba1cc648 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 19 Feb 2018 15:14:11 +0300 Subject: [PATCH 1/4] Add initial proposal state for jvm-meta-annotations-artifact --- proposals/jvm-meta-annotations-artifact.md | 160 +++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 proposals/jvm-meta-annotations-artifact.md diff --git a/proposals/jvm-meta-annotations-artifact.md b/proposals/jvm-meta-annotations-artifact.md new file mode 100644 index 000000000..614264edf --- /dev/null +++ b/proposals/jvm-meta-annotations-artifact.md @@ -0,0 +1,160 @@ +# Artifact with meta-annotations for Java types enhancement + +* **Type**: Design proposal +* **Author**: Denis Zharkov +* **Contributors**: Andrey Breslav +* **Status**: Submitted +* **Prototype**: Not started +* **Discussion**: [KEEP-99](https://github.com/Kotlin/KEEP/issues/99) +* **Related proposals**: [JSR-305 custom nullability qualifiers](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md) + +## Summary + +Add a separate artifact containing meta-annotations similar to ones from [JSR-305](https://jcp.org/en/jsr/detail?id=305). + +## Motivation + +- We need to put somewhere `@ApplyToTypeArgumentsAnnotation` meta-annotation (see the [discussion](https://github.com/Kotlin/KEEP/issues/79#issuecomment-336905480)). +- There is a [modules-related issue](https://blog.codefx.org/java/jsr-305-java-9/) with JSR-305 and Java 9. +- It's worth simplifying the way how JSR-305 nullability meta-annotations are being used +and integrating them with Kotlin-specific meta annotations. Namely, `@UnderMigration` and `@ApplyToTypeArguments`. + +## Description + +This section describes proposed semantics of the new annotations and partly the layout of resulting artifact. + +### Root package +Root package for this artifact will be `kotlin.annotations.jvm`. +All classes/packages names are assumed to be placed in the package and only their +relative names are mentioned below. + +### Built-in qualifiers +In JSR-305, there is [`@TypeQualifier`](https://aalmiray.github.io/jsr-305/apidocs/javax/annotation/meta/TypeQualifier.html) +annotation that allows to introduce custom qualifiers (like `@Nonnull`). +But that kind of meta-meta level seems to be unnecessary to our needs (at least for now), +the Kotlin compiler supports only nullability qualifier +(and in the nearest future mutability might be supported as well). + +So, there will only be fixed number of built-in qualifier annotations: +- `nullability.Nullable` +- `nullability.NotNull` +- `mutability.Mutable` +- `mutability.ReadOnly` + +Their target set would be the following: +ElementType.METHOD, ElementType.FIELD, +ElementType.PARAMETER, ElementType.LOCAL_VARIABLE + +And semantics when being applied to types is just the same as for analogue +from `org.jetbrains.annotations` (see [more](https://github.com/JetBrains/kotlin/blob/master/spec-docs/flexible-java-types.md#more-precise-type-information-from-annotations) about types enhancement) + +### Alias annotation +This proposal suggests to introduce `meta.Alias` annotation which would affect the compiler +in a similar way that `@TypeQualifierNickname` [does](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#type-qualifier-nicknames). + +In a basic version its declaration may look like +```kotlin +package kotlin.annotations.jvm.meta + +@Target(AnnotationTarget.ANNOTATION_CLASS) +annotation class Alias(val qualifier: KClass<*>) +``` + +and its usages is supposed to look like: +```kotlin +@Alias(kotlin.annotations.jvm.nullability.Nullable::class) +annotation class MyNullable +``` + +Thus, applying `@MyNullable` should have the same effect as `@Nullable` itself has. +Beside it, `@MyNullable` may have `@UnderMigration` annotation on it that would change its +[migration status](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#undermigration-annotation). + +### Default qualifiers options +This proposal has two options how +[default qualifiers](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#type-qualifier-default) +semantics can be introduced. + +And both of them are assume using special enum class instead of `ElementType` +that is used as a parameter type for JSR-305 `@TypeQualifierDefault`. +It might look like: +```kotlin +enum class ApplicabilityKind { + RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE, TYPE_ARGUMENT +} +``` + +All elements should work just the same as relevant entries from `ElementType` do for `@TypeQualifierDefault`, +beside `TYPE_ARGUMENT`. +The latter one should have the following effect: if a default qualifier is determined +to be applied to some top-level type (using the same logic as for `@TypeQualifierDefault`) +and the set of applicability kinds contain `TYPE_ARGUMENT` then this qualifier should also be applied +to all of it's type arguments (recursively). + +#### Parameter in @Alias (Option 1) +The first option is adding `propagateTo: Array` parameter to `meta.Alias` annotation. + +Thus, declaration of `AllParametersAreNullableByDefault` would look like this: +```kotlin +@Alias(Nullable::class, propagateTo=[ApplicabilityKind.VALUE_PARAMETER]) +annotation class AllParametersAreNullableByDefault +``` + +*Known pros:* +- It's nice to have one annotation for all issues. +- Probably, for someone such form of default qualifiers would look nicer than one suggested by JSR-305. + +*Known cons:* +- It would look a little weird when it's used in cases like the one below: +```kotlin +@Alias(Nullable::class) +@UnderMigration(...) +annotation class MyNullable + +@Alias(MyNullable::class, propagateTo=[ApplicabilityKind.PARAMETER]) +annotation class MyAllParametersAreNullableByDefault +``` +- Also it might be confusing when one alias (probably with non-empty `propagateTo`) +references another alias with non-trivial `propagateTo` argument + +#### Separate annotation (Option 2) +Another option would be a separate annotation `meta.ApplyByDefault` with vararg-parameter +of type `DefaultApplicabilityType`: +```kotlin +@Target(AnnotationTarget.ANNOTATION_CLASS) +annotation class ApplyByDefault(val qualifier: KClass<*>, vararg val elements: ApplicabilityKind) +``` + +Basically, it should work just the same as `@TypeQualifierDefault`, e.g. it might be used like: +```kotlin +@ApplyByDefault(MyNullable::class) +annotation class MyAllParametersAreNullableByDefault +``` + +### Avoidance of @UnderMigration annotation +After revisiting design for meta-annotations it looks like a natural thing to set up +a migration status for an annotation with its argument instead of another meta-annotation. + +Thus, the idea is to add `migrationStatus` parameter to `meta.Alias` +(and to `meta.ApplyByDefault` if we decide to introduce the latter) with default value to be `STRICT`. + +This argument should be processed by the compiler in the same way as for [`@UnderMigration`](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#undermigration-annotation) annotation +having the same argument value. + +### Details on artifact + +There is already an artifact called [kotlin-annotations-jvm](https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-annotations-jvm) +that might be the best candidate where the new meta annotations may be placed. + +Probably, the annotations that are already there should be moved to a different packages: + +- `kotlin.annotations.jvm.MigrationStatus` -> `kotlin.annotations.jvm.meta` +- `kotlin.annotations.jvm.Mutable`, `kotlin.annotations.jvm.ReadOnly` -> `kotlin.annotations.jvm.collections` + +## Remaining questions +- Should aliasing JSR-305 qualifiers like `javax.annotation.Nonnull` be allowed? +- What option is the best to choose for supporting [default qualifiers](#default-qualifiers)? +- Should there be a `migrationStatus` parameter in `@Alias` or migration status +should be tracked through `@UnderMigration` annotation? +- What is the best name for `ApplicabilityKind` enum class? +Would it be better to place it inside the `ApplyByDefault` annotation class (if it will be there) From cea482b2a4faa27743a8723bf27b402657cb6201 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 10 Apr 2018 15:54:23 +0300 Subject: [PATCH 2/4] Strip whitespaces before end-of-line --- proposals/jvm-meta-annotations-artifact.md | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/proposals/jvm-meta-annotations-artifact.md b/proposals/jvm-meta-annotations-artifact.md index 614264edf..773973df6 100644 --- a/proposals/jvm-meta-annotations-artifact.md +++ b/proposals/jvm-meta-annotations-artifact.md @@ -16,23 +16,23 @@ Add a separate artifact containing meta-annotations similar to ones from [JSR-30 - We need to put somewhere `@ApplyToTypeArgumentsAnnotation` meta-annotation (see the [discussion](https://github.com/Kotlin/KEEP/issues/79#issuecomment-336905480)). - There is a [modules-related issue](https://blog.codefx.org/java/jsr-305-java-9/) with JSR-305 and Java 9. -- It's worth simplifying the way how JSR-305 nullability meta-annotations are being used +- It's worth simplifying the way how JSR-305 nullability meta-annotations are being used and integrating them with Kotlin-specific meta annotations. Namely, `@UnderMigration` and `@ApplyToTypeArguments`. ## Description This section describes proposed semantics of the new annotations and partly the layout of resulting artifact. -### Root package -Root package for this artifact will be `kotlin.annotations.jvm`. -All classes/packages names are assumed to be placed in the package and only their +### Root package +Root package for this artifact will be `kotlin.annotations.jvm`. +All classes/packages names are assumed to be placed in the package and only their relative names are mentioned below. -### Built-in qualifiers -In JSR-305, there is [`@TypeQualifier`](https://aalmiray.github.io/jsr-305/apidocs/javax/annotation/meta/TypeQualifier.html) +### Built-in qualifiers +In JSR-305, there is [`@TypeQualifier`](https://aalmiray.github.io/jsr-305/apidocs/javax/annotation/meta/TypeQualifier.html) annotation that allows to introduce custom qualifiers (like `@Nonnull`). -But that kind of meta-meta level seems to be unnecessary to our needs (at least for now), -the Kotlin compiler supports only nullability qualifier +But that kind of meta-meta level seems to be unnecessary to our needs (at least for now), +the Kotlin compiler supports only nullability qualifier (and in the nearest future mutability might be supported as well). So, there will only be fixed number of built-in qualifier annotations: @@ -42,10 +42,10 @@ So, there will only be fixed number of built-in qualifier annotations: - `mutability.ReadOnly` Their target set would be the following: -ElementType.METHOD, ElementType.FIELD, +ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE -And semantics when being applied to types is just the same as for analogue +And semantics when being applied to types is just the same as for analogue from `org.jetbrains.annotations` (see [more](https://github.com/JetBrains/kotlin/blob/master/spec-docs/flexible-java-types.md#more-precise-type-information-from-annotations) about types enhancement) ### Alias annotation @@ -67,15 +67,15 @@ annotation class MyNullable ``` Thus, applying `@MyNullable` should have the same effect as `@Nullable` itself has. -Beside it, `@MyNullable` may have `@UnderMigration` annotation on it that would change its +Beside it, `@MyNullable` may have `@UnderMigration` annotation on it that would change its [migration status](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#undermigration-annotation). ### Default qualifiers options This proposal has two options how -[default qualifiers](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#type-qualifier-default) +[default qualifiers](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#type-qualifier-default) semantics can be introduced. -And both of them are assume using special enum class instead of `ElementType` +And both of them are assume using special enum class instead of `ElementType` that is used as a parameter type for JSR-305 `@TypeQualifierDefault`. It might look like: ```kotlin @@ -100,7 +100,7 @@ Thus, declaration of `AllParametersAreNullableByDefault` would look like this: annotation class AllParametersAreNullableByDefault ``` -*Known pros:* +*Known pros:* - It's nice to have one annotation for all issues. - Probably, for someone such form of default qualifiers would look nicer than one suggested by JSR-305. @@ -135,10 +135,10 @@ annotation class MyAllParametersAreNullableByDefault After revisiting design for meta-annotations it looks like a natural thing to set up a migration status for an annotation with its argument instead of another meta-annotation. -Thus, the idea is to add `migrationStatus` parameter to `meta.Alias` +Thus, the idea is to add `migrationStatus` parameter to `meta.Alias` (and to `meta.ApplyByDefault` if we decide to introduce the latter) with default value to be `STRICT`. -This argument should be processed by the compiler in the same way as for [`@UnderMigration`](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#undermigration-annotation) annotation +This argument should be processed by the compiler in the same way as for [`@UnderMigration`](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#undermigration-annotation) annotation having the same argument value. ### Details on artifact @@ -156,5 +156,5 @@ Probably, the annotations that are already there should be moved to a different - What option is the best to choose for supporting [default qualifiers](#default-qualifiers)? - Should there be a `migrationStatus` parameter in `@Alias` or migration status should be tracked through `@UnderMigration` annotation? -- What is the best name for `ApplicabilityKind` enum class? +- What is the best name for `ApplicabilityKind` enum class? Would it be better to place it inside the `ApplyByDefault` annotation class (if it will be there) From dae9cdb5b8526a13e67a889ed727860e7e610827 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 10 Apr 2018 16:21:20 +0300 Subject: [PATCH 3/4] Add some refinements to proposal jvm-meta-annotations-artifact --- proposals/jvm-meta-annotations-artifact.md | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/proposals/jvm-meta-annotations-artifact.md b/proposals/jvm-meta-annotations-artifact.md index 773973df6..ef6242c2b 100644 --- a/proposals/jvm-meta-annotations-artifact.md +++ b/proposals/jvm-meta-annotations-artifact.md @@ -10,7 +10,7 @@ ## Summary -Add a separate artifact containing meta-annotations similar to ones from [JSR-305](https://jcp.org/en/jsr/detail?id=305). +Add a separate artifact containing meta-annotations covering use cases of ones from [JSR-305](https://jcp.org/en/jsr/detail?id=305). ## Motivation @@ -92,7 +92,7 @@ and the set of applicability kinds contain `TYPE_ARGUMENT` then this qualifier s to all of it's type arguments (recursively). #### Parameter in @Alias (Option 1) -The first option is adding `propagateTo: Array` parameter to `meta.Alias` annotation. +The first option is adding `propagateTo: Array` parameter to `meta.Alias` annotation. Thus, declaration of `AllParametersAreNullableByDefault` would look like this: ```kotlin @@ -119,7 +119,7 @@ references another alias with non-trivial `propagateTo` argument #### Separate annotation (Option 2) Another option would be a separate annotation `meta.ApplyByDefault` with vararg-parameter -of type `DefaultApplicabilityType`: +of type `ApplicabilityKind`: ```kotlin @Target(AnnotationTarget.ANNOTATION_CLASS) annotation class ApplyByDefault(val qualifier: KClass<*>, vararg val elements: ApplicabilityKind) @@ -127,8 +127,21 @@ annotation class ApplyByDefault(val qualifier: KClass<*>, vararg val elements: A Basically, it should work just the same as `@TypeQualifierDefault`, e.g. it might be used like: ```kotlin -@ApplyByDefault(MyNullable::class) +@ApplyByDefault(MyNullable::class, ApplicabilityKind.PARAMETER) annotation class MyAllParametersAreNullableByDefault + +@ApplyByDefault(MyNonnull::class, ApplicabilityKind.PARAMETER) +annotation class MyAllParametersAreNonNullByDefault + +@ApplyByDefault(MyNullable::class, ApplicabilityKind.PARAMETER) +annotation class MyAllParametersAreNullableByDefault + +@ApplyByDefault( + MyNonnull::class, + ApplicabilityKind.RETURN_TYPE, ApplicabilityKind.VALUE_PARAMETER, + ApplicabilityKind.FIELD, ApplicabilityKind.TYPE_ARGUMENT +) +annotation class MyApiNonNullByDefault ``` ### Avoidance of @UnderMigration annotation @@ -148,7 +161,7 @@ that might be the best candidate where the new meta annotations may be placed. Probably, the annotations that are already there should be moved to a different packages: -- `kotlin.annotations.jvm.MigrationStatus` -> `kotlin.annotations.jvm.meta` +- `kotlin.annotations.jvm.UnderMigration`, `kotlin.annotations.jvm.MigrationStatus` -> `kotlin.annotations.jvm.meta` - `kotlin.annotations.jvm.Mutable`, `kotlin.annotations.jvm.ReadOnly` -> `kotlin.annotations.jvm.collections` ## Remaining questions From c7adfc4b301fff8213f4bfdae1d8b126c131a8ac Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 17 Apr 2018 15:51:59 +0300 Subject: [PATCH 4/4] Add updates to jvm-meta-annotations-artifact proposal - Leave the single option for default qualifiers - Get rid of section about avoidance of @UnderMigration - Update "Remaining questions" section --- proposals/jvm-meta-annotations-artifact.md | 62 +++++++--------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/proposals/jvm-meta-annotations-artifact.md b/proposals/jvm-meta-annotations-artifact.md index ef6242c2b..c6a0d82f1 100644 --- a/proposals/jvm-meta-annotations-artifact.md +++ b/proposals/jvm-meta-annotations-artifact.md @@ -45,6 +45,9 @@ Their target set would be the following: ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE +*NB:* Having ElementType.TYPE_USE among their target is questionable since it's unknown how that would work with bytecode +version 50.0 (JDK 1.6). + And semantics when being applied to types is just the same as for analogue from `org.jetbrains.annotations` (see [more](https://github.com/JetBrains/kotlin/blob/master/spec-docs/flexible-java-types.md#more-precise-type-information-from-annotations) about types enhancement) @@ -70,12 +73,13 @@ Thus, applying `@MyNullable` should have the same effect as `@Nullable` itself h Beside it, `@MyNullable` may have `@UnderMigration` annotation on it that would change its [migration status](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#undermigration-annotation). -### Default qualifiers options -This proposal has two options how -[default qualifiers](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#type-qualifier-default) +### Default qualifiers +This section describes the way how the concept similar to +[JSR-305 default qualifiers](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#type-qualifier-default) semantics can be introduced. -And both of them are assume using special enum class instead of `ElementType` +#### Using ApplicabilityKind instead of ElementType +We suggest to use a special enum class instead of `ElementType` that is used as a parameter type for JSR-305 `@TypeQualifierDefault`. It might look like: ```kotlin @@ -91,34 +95,8 @@ to be applied to some top-level type (using the same logic as for `@TypeQualifie and the set of applicability kinds contain `TYPE_ARGUMENT` then this qualifier should also be applied to all of it's type arguments (recursively). -#### Parameter in @Alias (Option 1) -The first option is adding `propagateTo: Array` parameter to `meta.Alias` annotation. - -Thus, declaration of `AllParametersAreNullableByDefault` would look like this: -```kotlin -@Alias(Nullable::class, propagateTo=[ApplicabilityKind.VALUE_PARAMETER]) -annotation class AllParametersAreNullableByDefault -``` - -*Known pros:* -- It's nice to have one annotation for all issues. -- Probably, for someone such form of default qualifiers would look nicer than one suggested by JSR-305. - -*Known cons:* -- It would look a little weird when it's used in cases like the one below: -```kotlin -@Alias(Nullable::class) -@UnderMigration(...) -annotation class MyNullable - -@Alias(MyNullable::class, propagateTo=[ApplicabilityKind.PARAMETER]) -annotation class MyAllParametersAreNullableByDefault -``` -- Also it might be confusing when one alias (probably with non-empty `propagateTo`) -references another alias with non-trivial `propagateTo` argument - -#### Separate annotation (Option 2) -Another option would be a separate annotation `meta.ApplyByDefault` with vararg-parameter +#### @ApplyByDefault +We suggest to introduce a separate annotation `meta.ApplyByDefault` with vararg-parameter of type `ApplicabilityKind`: ```kotlin @Target(AnnotationTarget.ANNOTATION_CLASS) @@ -144,15 +122,15 @@ annotation class MyAllParametersAreNullableByDefault annotation class MyApiNonNullByDefault ``` -### Avoidance of @UnderMigration annotation -After revisiting design for meta-annotations it looks like a natural thing to set up -a migration status for an annotation with its argument instead of another meta-annotation. +*NB:* When `module-info` classes are annotated with a default qualifiers it should work just like being applied to all +classes in the modules. + +### @UnderMigration applicability -Thus, the idea is to add `migrationStatus` parameter to `meta.Alias` -(and to `meta.ApplyByDefault` if we decide to introduce the latter) with default value to be `STRICT`. +To simplify its semantics, we suggest to restrict applicability of [`@UnderMigration`](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#undermigration-annotation) +only to qualifier aliases (i.e. to annotations that are meta-annotated with `meta.Alias`). -This argument should be processed by the compiler in the same way as for [`@UnderMigration`](https://github.com/Kotlin/KEEP/blob/master/proposals/jsr-305-custom-nullability-qualifiers.md#undermigration-annotation) annotation -having the same argument value. +Thus, when being applied to a default qualifier `@UnderMigration` should be effectively ignored. ### Details on artifact @@ -166,8 +144,8 @@ Probably, the annotations that are already there should be moved to a different ## Remaining questions - Should aliasing JSR-305 qualifiers like `javax.annotation.Nonnull` be allowed? -- What option is the best to choose for supporting [default qualifiers](#default-qualifiers)? -- Should there be a `migrationStatus` parameter in `@Alias` or migration status -should be tracked through `@UnderMigration` annotation? - What is the best name for `ApplicabilityKind` enum class? Would it be better to place it inside the `ApplyByDefault` annotation class (if it will be there) +- What bytecode version should all those annotations have? +On one side, we'd like to have compatibility with 1.6, on the other, we'd like them to have `ElementType.TYPE_USE` among their targets +- Do we need to add built-in default qualifiers (like `@AllParametersAreNotNullByDefault` or `@NotNullAPI`)?