papsign / Ktor-OpenAPI-Generator

Ktor OpenAPI/Swagger 3 Generator
Apache License 2.0
243 stars 42 forks source link

make Nothing provider provide nullable Nothing #27

Closed SerVB closed 4 years ago

SerVB commented 4 years ago

Follow up of #26.

Thank you, but you variant puts java.lang.Void in the map so my kotlin.Nothing? isn't its subtype. I've made some changes and they work for me. Could you accept them to the main repo?

Wicpar commented 4 years ago

The type has to be non nullable, because Nothing is not a subtype of Nothing?, but the opposite is true. Can you change that ?

SerVB commented 4 years ago

Nothing is not a subtype of Nothing?

Nothing is a subtype of Nothing?. Like T is a subtype of T?.

So if I change it to Nothing here, map.firstOrNull { type isSubtypeOf it } won't give NothingSchemaProvider for Nothing? so my code won't work.

The type has to be non nullable

Are you sure? On the screenshots from https://github.com/papsign/Ktor-OpenAPI-Generator/issues/26#issuecomment-605528988, I see there are many nullable keys in the map...

Wicpar commented 4 years ago

The map you see is the cache of the types that have already been built. Subtype and Supertype are quite confusing indeed. It is indeed correct to use the non nullable type, all current builders are configured like this. All nullable types are subtypes to their non nullable counterpart but not the opposite, so:

map.firstOrNull { type isSubtypeOf it }

type is the type being matched, it is one of the registered handler types. Nothing? isSubtypeOf Nothing == true Nothing isSubtypeOf Nothing? == false If you try to match Nothing to a handler with a registered type of Nothing? it will fail and fallback to the next non nullable type.

SerVB commented 4 years ago

Subtype and Supertype are quite confusing indeed.

I strongly agree but I believe here that I am not mistaken.

There is what running shows:

import kotlin.reflect.full.createType
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.full.withNullability

object NothingWrapper {
    private val nothing: Nothing get() = TODO("Nothing can't be ever assigned or returned")
    val typeOfNothing = this::nothing.returnType
}

fun main() {
    val nonNullableAny = Any::class.createType(nullable = false)
    val nullableAny = Any::class.createType(nullable = true)

    println(nonNullableAny)                           // kotlin.Any
    println(nullableAny)                              // kotlin.Any?
    println(nullableAny.isSubtypeOf(nonNullableAny))  // false
    println(nonNullableAny.isSubtypeOf(nullableAny))  // true

    val nonNullableNothing = NothingWrapper.typeOfNothing
    val nullableNothing = nonNullableNothing.withNullability(true)

    println(nonNullableNothing)                               // kotlin.Nothing
    println(nullableNothing)                                  // kotlin.Nothing?
    println(nullableNothing.isSubtypeOf(nonNullableNothing))  // false
    println(nonNullableNothing.isSubtypeOf(nullableNothing))  // true
}

So

Nothing? isSubtypeOf Nothing == false
Nothing isSubtypeOf Nothing? == true
Wicpar commented 4 years ago

Yeah, i just tested it myself. This nomenclature is so confusing. You are indeed right. It was a stroke of luck that the system worked when i tested it... I should have registered all types as nullable, i'm doing the appropriate changes.

Wicpar commented 4 years ago

The changes have been made, turns out only the Enum handler was wrong, which of course i used to create the nothing type... Thank you.