Change default rules for declaration-site wildcards

Mostly this commit is about skipping wildcards that are redundant in some sense.
The motivation is that they looks `long` in Java code.

There are basically two important parts: return types and value parameters.

1. For return types default behaviour is skipping all declaration-site wildcards.
The intuition behind this rule is simple: return types are basically used in subtype position
(as an argument for another call), and here everything works well in case of 'out'-variance.
For example we have 'Out<Out<T>>>' as subtype both for 'Out<Out<T>>>' and 'Out<? extends Out<? extends T>>>',
so values of such type is more flexible in contrast to `Out<? extends Out<? extends T>>>` that could be used only
for the second case.

But we have choosen to treat `in`-variance in a different way: argument itself
should be rendered without wildcard while nested arguments are rendered by the rules
described further (see second part).

For example: 'In<Out<OpenClass>>' will have generic signature 'In<Out<? extends OpenClass>>'.
If we omit all wildcards here, then value of type 'In<Out<OpenClass>>'
will be impossible to use as argument for function expecting 'In<? super Out<? extends Derived>>'
where Derived <: OpenClass (you can check it manually :]).

And this exception should not be very inconvinient because in-variance is rather rare.

2. For value parameters we decided to skip wildcards if it doesn't make obtained signature weaker
in a sense of set of acceptable arguments.

More precisely:
    a. We write wildcard for 'Out<T>' iff T ``can have subtypes ignoring nullability''
    b. We write wildcard for 'In<T>' iff T is not equal to it's class upper bound (ignoring nullability again)

Definition of ``can have subtypes ignoring nullability'' is straightforward and you can see it in commit.

 #KT-9801 Fixed
 #KT-9890 Fixed
This commit is contained in:
Denis Zharkov
2015-11-23 19:45:48 +03:00
parent 1731cb8b40
commit 406e31f54a
29 changed files with 620 additions and 60 deletions
@@ -0,0 +1,25 @@
class Out<out T>
class OutPair<out X, out Y>
class In<in Z>
class Final
open class Open
// For value parameters we decided to skip wildcards if it doesn't make obtained signature weaker
// in a sense of set of acceptable arguments.
// More precisely:
//    a. We write wildcard for 'Out<T>' iff T ``can have subtypes ignoring nullability''
//    b. We write wildcard for 'In<T>' iff T is not equal to it's class upper bound (ignoring nullability again)
// Definition of ``can have subtypes ignoring nullability'' is straightforward and you can see it in commit.
fun openClassArgument(x: Out<Open>, y: In<Open>) {}
// method: ArgumentOverridabilityKt::openClassArgument
// generic signature: (LOut<+LOpen;>;LIn<-LOpen;>;)V
fun finalClassArgument(x: Out<Final>, y: In<Final>) {}
// method: ArgumentOverridabilityKt::finalClassArgument
// generic signature: (LOut<LFinal;>;LIn<-LFinal;>;)V
fun oneArgumentFinal(x: OutPair<Final, Open>) {}
// method: ArgumentOverridabilityKt::oneArgumentFinal
// generic signature: (LOutPair<LFinal;+LOpen;>;)V
@@ -0,0 +1,23 @@
class Inv<E>
class Out<out T>
class OutPair<out Final, out Y>
class In<in Z>
class Final
open class Open
fun arrayOfOutOpen(x: Array<Out<Open>>) {}
// method: ArraysKt::arrayOfOutOpen
// generic signature: ([LOut<+LOpen;>;)V
fun arrayOfOutFinal(x: Array<Out<Final>>) {}
// method: ArraysKt::arrayOfOutFinal
// generic signature: ([LOut<LFinal;>;)V
fun outOfArrayOpen(x: Out<Array<Open>>) {}
// method: ArraysKt::outOfArrayOpen
// generic signature: (LOut<[LOpen;>;)V
fun outOfArrayOutOpen(x: Out<Array<out Open>>) {}
// method: ArraysKt::outOfArrayOutOpen
// generic signature: (LOut<+[LOpen;>;)V
@@ -0,0 +1,12 @@
class Out<out T>
class In<in T : F?, F : CharSequence>
fun optimized(x: In<CharSequence, CharSequence>) {}
// method: ComplicatedInBoundsKt::optimized
// generic signature: (LIn<-Ljava/lang/CharSequence;Ljava/lang/CharSequence;>;)V
class In2<in T, F : In2<T, F>>
fun nonOptimized(x: In2<In2<*, *>, *>) {}
// method: ComplicatedInBoundsKt::nonOptimized
// generic signature: (LIn2<-LIn2<**>;*>;)V
@@ -0,0 +1,12 @@
class Out<out T>
class Final
open class Open
fun deepOpen(x: Out<Out<Out<Open>>>) {}
// method: DeepOutKt::deepOpen
// generic signature: (LOut<+LOut<+LOut<+LOpen;>;>;>;)V
fun deepFinal(x: Out<Out<Out<Final>>>) {}
// method: DeepOutKt::deepFinal
// generic signature: (LOut<LOut<LOut<LFinal;>;>;>;)V
@@ -0,0 +1,31 @@
class Out<out T>
class OutPair<out X, out Y>
class In<in Z>
class Inv<E>
open class Open
class Final
fun skipAllOutInvWildcards(): Inv<OutPair<Open, Out<Out<Open>>>> = null!!
// method: FinalReturnTypeKt::skipAllOutInvWildcards
// generic signature: ()LInv<LOutPair<LOpen;LOut<LOut<LOpen;>;>;>;>;
fun notDeepIn(): In<Final> = null!!
// method: FinalReturnTypeKt::notDeepIn
// generic signature: ()LIn<LFinal;>;
fun skipWildcardsUntilIn0(): Out<In<Out<Open>>> = null!!
// method: FinalReturnTypeKt::skipWildcardsUntilIn0
// generic signature: ()LOut<LIn<LOut<+LOpen;>;>;>;
fun skipWildcardsUntilIn1(): Out<In<Out<Final>>> = null!!
// method: FinalReturnTypeKt::skipWildcardsUntilIn1
// generic signature: ()LOut<LIn<LOut<LFinal;>;>;>;
fun skipWildcardsUntilIn2(): Out<In<OutPair<Final, Out<Open>>>> = null!!
// method: FinalReturnTypeKt::skipWildcardsUntilIn2
// generic signature: ()LOut<LIn<LOutPair<LFinal;+LOut<+LOpen;>;>;>;>;
fun skipWildcardsUntilInProjection(): Inv<in Out<Open>> = null!!
// method: FinalReturnTypeKt::skipWildcardsUntilInProjection
// generic signature: ()LInv<-LOut<+LOpen;>;>;
@@ -0,0 +1,12 @@
class Out<out T>
class In<in Z>
class Final
fun outIn(x: Out<In<Final>>) {}
// method: OutInKt::outIn
// generic signature: (LOut<+LIn<-LFinal;>;>;)V
fun outInAny(x: Out<In<Any?>>) {}
// method: OutInKt::outInAny
// generic signature: (LOut<LIn<Ljava/lang/Object;>;>;)V
@@ -0,0 +1,25 @@
class Inv<E>
class Out<out T>
class Final
open class Open
fun invInv(x: Out<Inv<Open>>) {}
// method: OutInvKt::invInv
// generic signature: (LOut<LInv<LOpen;>;>;)V
fun invOut(x: Out<Inv<out Open>>) {}
// method: OutInvKt::invOut
// generic signature: (LOut<+LInv<+LOpen;>;>;)V
fun invOutFinal(x: Out<Inv<out Final>>) {}
// method: OutInvKt::invOutFinal
// generic signature: (LOut<LInv<+LFinal;>;>;)V
fun invIn(x: Out<Inv<in Final>>) {}
// method: OutInvKt::invIn
// generic signature: (LOut<+LInv<-LFinal;>;>;)V
fun invInAny(x: Out<Inv<in Any>>) {}
// method: OutInvKt::invInAny
// generic signature: (LOut<LInv<-Ljava/lang/Object;>;>;)V
@@ -0,0 +1,15 @@
class In<in Z>
class Out<out T>
class Final
fun inFinal(x: In<Final>) {}
// method: TopLevelInKt::inFinal
// generic signature: (LIn<-LFinal;>;)V
fun inAny(x: In<Any>) {}
// method: TopLevelInKt::inAny
// generic signature: (LIn<Ljava/lang/Object;>;)V
fun inOutFinal(x: In<Out<Final>>) {}
// method: TopLevelInKt::inOutFinal
// generic signature: (LIn<-LOut<LFinal;>;>;)V
@@ -0,0 +1,24 @@
class Inv<X>
class Out<out T>
class Final
open class Open
fun invOpen(x: Inv<Open>) {}
// method: TopLevelInvKt::invOpen
// generic signature: (LInv<LOpen;>;)V
fun invFinal(x: Inv<Final>) {}
// method: TopLevelInvKt::invFinal
// generic signature: (LInv<LFinal;>;)V
fun invOutOpen(x: Inv<Out<Open>>) {}
// method: TopLevelInvKt::invOutOpen
// generic signature: (LInv<LOut<+LOpen;>;>;)V
fun invOutFinal(x: Inv<Out<Final>>) {}
// method: TopLevelInvKt::invOutFinal
// generic signature: (LInv<LOut<LFinal;>;>;)V
fun invOutProjectedOutFinal(x: Inv<out Out<Final>>) {}
// method: TopLevelInvKt::invOutProjectedOutFinal
// generic signature: (LInv<+LOut<LFinal;>;>;)V
@@ -0,0 +1,8 @@
class Out<out T>
class In<in Z>
class Final
fun <Q : Final> typeParameter(x: Out<Q>, y: In<Q>) {}
// method: TypeParameterKt::typeParameter
// generic signature: <Q:LFinal;>(LOut<+TQ;>;LIn<-TQ;>;)V