dokka icon indicating copy to clipboard operation
dokka copied to clipboard

Links to extensions with type parameters

Open vmishenev opened this issue 10 months ago • 1 comments

fun <T : Number> List<T>.foo() {}

interface MyListWithT<T> : List<T>

interface MyListWithTNumberBound<T : Number> : List<T>

interface MyListWithNumber : List<Number>

/**
 * 1 [List.foo]
 * 2 [MutableList.foo]
 * 3 [MyListWithT.foo]
 * 4 [MyListWithTNumberBound.foo]
 * 5 [MyListWithNumber.foo]
 */
fun usage() {}

In K1 - 1, 4 and 5 are resolved, but 2 and 3 are not. In K2 the easiest solution is implemented (without type inference) that resolves only 1.

Which references should be resolved?


This question has come from the review of https://youtrack.jetbrains.com/issue/KT-62695

can’t we approximate the type parameter’s type with its upper bound? This question is legal, of course Let’s look at some example:

fun <T : Number> List<T>.foo() {}

/**
 * [List.foo]
 */
fun usage() {}

If we take the List type and approximate it to List<*>, and List<T> to List<Number>, then we already have a problem: List<*> is not a subtype of List<Number>, so we should not resolve the foo extension at this point. But K1 implementation resolves that. That’s why my type comparison method does a simple equality check without any type bound Moving on to the next example:

fun <T : Number> List<T>.foo() {}

interface MyListWithT<T> : List<T>

interface MyListWithTNumberBound<T : Number> : List<T>

interface MyListWithNumber : List<Number>

/**
 * [MyListWithT.foo]
 * [MyListWithTNumberBound.foo]
 * [MyListWithNumber.foo]
 */
fun usage() {}

K1 does not resolve the first function, but it does not resolve the first one The question is - why? You can still call MyListWithT<Int>().foo() if you want to in your code. The fact that it does not have the correct bound does not imply that it is not possible to call foo on the receiver of that type. At the same time, it has some contradiction with the first example - why do we resolve List.foo, but do not resolve MyListWithT.foo? List also does not have a proper type bound I was trying to draw some meaningful system from the K1 behaviour (to be fair, I didn’t look into the implementation - only on the behaviour). I also anticipated the behaviour that you’ve proposed However, more complicated nature of the K1 behavior got me thinking about the lack of specification for that part. I decided not to try and replicate all the details of K1 implementation without knowing at least with some certainty that this is indeed correct and desired behaviour So my plan was to throw in some simple, non contrived implementation which is as simple as possible while still being useful, and modify it in the future as the specification becomes more fleshed out (edited)

vmishenev avatar Apr 06 '24 20:04 vmishenev

Blocking?

  • Testing: no
  • Beta: no
  • Release: No

The specification around this should be discussed to make a decision.

IgnatBeresnev avatar Apr 26 '24 12:04 IgnatBeresnev

Proposed expected behaviour could be found in KEEP: https://github.com/Kotlin/KEEP/blob/kdoc/extension-links/proposals/kdoc/links-to-extensions.md

whyoleg avatar Aug 20 '24 10:08 whyoleg