Skip to content

Commit

Permalink
[K2] Fix typealiased type that leads to functional type (#3396)
Browse files Browse the repository at this point in the history
* [K2] Fix typealiased type to function

* Add check on emptiness
  • Loading branch information
vmishenev authored Dec 6, 2023
1 parent 81666e9 commit 3d8be6c
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal class TypeTranslator(
is KtTypeArgumentWithVariance -> toBoundFrom(typeProjection.type).wrapWithVariance(typeProjection.variance)
}

private fun KtAnalysisSession.toTypeConstructorFromTypeAliased(classType: KtUsualClassType): TypeAliased {
private fun KtAnalysisSession.toBoundFromTypeAliased(classType: KtNonErrorClassType): TypeAliased {
val classSymbol = classType.classSymbol
return if (classSymbol is KtTypeAliasSymbol)
TypeAliased(
Expand Down Expand Up @@ -77,7 +77,7 @@ internal class TypeTranslator(
fun KtAnalysisSession.toBoundFrom(type: KtType): Bound =
when (type) {
is KtUsualClassType -> {
if (type.classSymbol is KtTypeAliasSymbol) toTypeConstructorFromTypeAliased(type)
if (type.classSymbol is KtTypeAliasSymbol) toBoundFromTypeAliased(type)
else toTypeConstructorFrom(type)
}

Expand All @@ -92,16 +92,8 @@ internal class TypeTranslator(

is KtClassErrorType -> UnresolvedBound(type.toString())
is KtFunctionalType -> {
/**
* For example
* `typealias CompletionHandler = (cause: Throwable?) -> Unit`
* has functional type with no type arguments in K2
* In K1 we have a usual generic type
*/
if (type.ownTypeArguments.isEmpty())
toTypeConstructorFrom(type)
else
toFunctionalTypeConstructorFrom(type)
if (type.classSymbol is KtTypeAliasSymbol) toBoundFromTypeAliased(type)
else toFunctionalTypeConstructorFrom(type)
}
is KtDynamicType -> Dynamic
is KtDefinitelyNotNullType -> DefinitelyNonNullable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,12 @@ public class KotlinSignatureProvider(
type.projections

punctuation("(")
if(args.isEmpty()) {
contentBuilder.logger.warn("Functional type should have at least one argument in ${type.dri}")
text("ERROR CLASS: functional type should have at least one argument in ${type.dri}")
return@contentFor
}

args.subList(0, args.size - 1).forEachIndexed { i, arg ->
signatureForProjection(arg)
if (i < args.size - 2) punctuation(", ")
Expand Down
70 changes: 70 additions & 0 deletions dokka-subprojects/plugin-base/src/test/kotlin/model/TypesTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package model

import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.driOrNull
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.*
import utils.AbstractModelTest
import kotlin.test.Test
import kotlin.test.assertTrue

class TypesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "types") {

@Test
fun `type with typealias to functional type with parameter`() {
inlineModelTest(
"""
|typealias HttpExceptionCallback<T> = String.(T) -> String
|fun <T> exception(callback: HttpExceptionCallback<T>){}"""
) {
with((this / "types" / "HttpExceptionCallback").cast<DTypeAlias>()) {
name equals "HttpExceptionCallback"
assertTrue(type is GenericTypeConstructor)
(type as GenericTypeConstructor).projections counts 1
underlyingType.values.first().driOrNull equals DRI("kotlin", "Function2")
}
with((this / "types" / "exception").cast<DFunction>()) {
name equals "exception"
val parameterType = parameters.first().type
assertTrue(parameterType is TypeAliased)
with(parameterType) {
assertTrue(typeAlias is GenericTypeConstructor)
(typeAlias as GenericTypeConstructor).projections counts 1
assertTrue(inner is FunctionalTypeConstructor)
(inner as FunctionalTypeConstructor).dri equals DRI("kotlin", "Function2")
(inner as FunctionalTypeConstructor).projections counts 3
}
}
}
}

@Test
fun `type with typealias to functional type`() {
inlineModelTest(
"""
|typealias CompletionHandler = (cause: Throwable?) -> Unit
|fun exception(callback: CompletionHandler){}"""
) {
with((this / "types" / "CompletionHandler").cast<DTypeAlias>()) {
assertTrue(type is GenericTypeConstructor)
(type as GenericTypeConstructor).projections counts 0
name equals "CompletionHandler"
underlyingType.values.first().driOrNull equals DRI("kotlin", "Function1")
}
with((this / "types" / "exception").cast<DFunction>()) {
name equals "exception"
val parameterType = parameters.first().type
assertTrue(parameterType is TypeAliased)
with(parameterType) {
assertTrue(typeAlias is GenericTypeConstructor)
assertTrue(inner is FunctionalTypeConstructor)
(inner as FunctionalTypeConstructor).dri equals DRI("kotlin", "Function1")
(inner as FunctionalTypeConstructor).projections counts 2
}
}
}
}
}

0 comments on commit 3d8be6c

Please sign in to comment.