Why can't type parameter in Kotlin have any other bounds if it's bounded by another type parameter?

uchuhimo :

Here is the minimal demo code that shows this problem:

interface A

fun <T1, T2> test() where T2 : T1, T2 : A {}

When I try to compile it, compiler will complain:

Error:(81, 25) Kotlin: Type parameter cannot have any other bounds if it's bounded by another type parameter

I read Kotlin Language Specification, but only find the following bound restriction:

A type-parameter cannot specify itself as its own bound, and several type-parameters cannot specify each other as a bound in a cyclic manner.

It doesn't explain the restriction I meet.

I explore Kotlin's issue tracker, and I find an issue about this restriction: Allow to inherit a type parameter from another type parameter and a class : KT-13768. However, this issue has been rejected by the following reason (update on May 6th, 2017: this issue has been reopened by Stanislav Erokhin):

I don't think we can compile the code correctly to JVM if we remove this restriction.

By Andrey Breslav

So the question is: why can't we compile the code correctly to JVM if we remove this restriction?

The same demo works in Scala:

trait A

def test[T1, T2 <: T1 with A](): Unit = {}

It indicates that Scala can compile the code correctly to JVM. Why can't Kotlin? Is it a restriction to guarantee a decidable subtyping in Kotlin (I guess. Subtyping is undecidable for Scala (Scala has a Turing-complete type system). Kotlin may want decidable subtyping like C#.)?

Update after answered by @erokhins (https://stackoverflow.com/a/43807444/7964561):

There are some subtle issues when supporting something forbidden by Java but allowed by JVM, especially in Java interoperability. I find an interesting issue when digging into bytecode generated by scalac. I modify Scala code in demo as follow:

trait A

trait B

def test[T1 <: B, T2 <: T1 with A](t1: T1, t2: T2): Unit = {}

class AB extends A with B

Scalac will generate the following signature:

// signature <T1::LB;T2:TT1;:LA;>(TT1;TT2;)V
// descriptor: (LB;LB;)V
public <T1 extends B, T2 extends T1 & A> void test(T1, T2);

Invoke test with test(new AB, new AB) in Scala will succeed, since Scalas invoke signature (LB;LB;)V; but invoke with test(new AB(), new AB()); in Java will fail, since Java invokes signature (LB;Ljava/lang/Object;)V, causing java.lang.NoSuchMethodError in runtime. It means scalac generates something cannot be invoked in Java after relaxing this restriction. Kotlin may meet the same issue after relaxing it.

erokhins :

This restrictions was made because java(language) has it:

  interface A {}
  // Error:(7, 26) java: a type variable may not be followed by other bounds
  <T1, T2 extends T1 & A> void test() {} 

And we suppose that this forbidden also in bytecode level. I dig into it and seems like it is allowed, and scalac generate the following signature:

  // access flags 0x1
  // signature <T1:Ljava/lang/Object;T2:TT1;:LA;>()V
  // declaration: void test<T1, T2T1 extends A>()
  public test()V

So, we probably can support such cases it in the future versions of kotlin.

P.S. As far as I know Kotlin has decidable subtyping, and decidability isn't affected by this.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Why can I use bounded wildcards for parameter and not for return type in a method?

Why can't I use a type argument in a type parameter with multiple bounds?

Why I can't use a Class type as a generic parameter in Kotlin?

Why can't a Java type parameter have a lower bound?

Bounded type as method parameter?

Why can't typescript infer generic type parameter when one type parameter depends on another?

Type parameter Bounds [T <: Comparable[_]] in guava's MinMaxPriorityQueue in Scala

Why Mockito can't mock a generic parameter type with number type in Kotlin?

Why do I have to cast to type parameter and can't use the constrained type?

Bounds for type parameter of FunctionK

Java: bounded wildcards or bounded type parameter?

Kotlin - Why do we have to explicit type parameter(s) for generic method?

Why can't a parameter of function type take an argument whose parameters implement the original parameter's interface?

Type T is not a valide Substitute for the bounded Parameter `<T extends Collection<?>>

Why this argument type can't be assigned to the parameter type?

Why can't Go functions return a type with a constrained type parameter?

Why there can be only one implementation of a typeclass for any given type parameter?

Set of WrappedArray: Type arguments [Int] do not conform to method empty's type parameter bounds [T <: AnyRef]

Can Java infer type arguments from type parameter bounds?

Why does `thread::JoinHandle<T>` have a type parameter?

Kotlin reified type parameter can't be used as type parameter in body of function

How do I annotate the type of a parameter of an abstractmethod, when the parameter can have any type derived from a specific base type?

The parameter can't have a value of 'null' because of its type in Dart

@require parameter '#' can't have a value of 'null' because of its type

The parameter 'id' can't have a value of 'null' because of its type?

Define bounded type parameter in method type parameter list or in method argument

Why I can't assign nullable type to Any in Kotlin?

Bounded type parameter vs plain base class

Add object to the list using bounded type parameter