[JS] Don't fail on recursive upper bounds while resolving JsExports
Fixes https://youtrack.jetbrains.com/issue/KT-42112
This commit is contained in:
+45
-33
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||
import org.jetbrains.kotlin.resolve.inline.isInlineWithReified
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjection
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
|
||||
@@ -30,7 +29,7 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
||||
|
||||
fun checkTypeParameter(descriptor: TypeParameterDescriptor) {
|
||||
for (upperBound in descriptor.upperBounds) {
|
||||
if (!isTypeExportable(upperBound, bindingContext)) {
|
||||
if (!upperBound.isExportable(bindingContext)) {
|
||||
val typeParameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)!!
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(typeParameterDeclaration, "upper bound", upperBound))
|
||||
}
|
||||
@@ -38,7 +37,7 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
fun checkValueParameter(descriptor: ValueParameterDescriptor) {
|
||||
if (!isTypeExportable(descriptor.type, bindingContext)) {
|
||||
if (!descriptor.type.isExportable(bindingContext)) {
|
||||
val valueParameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)!!
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(valueParameterDeclaration, "parameter", descriptor.type))
|
||||
}
|
||||
@@ -86,7 +85,7 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
descriptor.returnType?.let { returnType ->
|
||||
if (!isTypeExportable(returnType, bindingContext, true)) {
|
||||
if (!returnType.isExportableReturn(bindingContext)) {
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(declaration, "return", returnType))
|
||||
}
|
||||
}
|
||||
@@ -98,7 +97,7 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
||||
reportWrongExportedDeclaration("extension property")
|
||||
return
|
||||
}
|
||||
if (!isTypeExportable(descriptor.type, bindingContext)) {
|
||||
if (!descriptor.type.isExportable(bindingContext)) {
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(declaration, "property", descriptor.type))
|
||||
}
|
||||
}
|
||||
@@ -122,7 +121,7 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
for (superType in descriptor.defaultType.supertypes()) {
|
||||
if (!isTypeExportable(superType, bindingContext)) {
|
||||
if (!superType.isExportable(bindingContext)) {
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(declaration, "super", superType))
|
||||
}
|
||||
}
|
||||
@@ -130,45 +129,58 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType.isExportableReturn(bindingContext: BindingContext, currentlyProcessed: MutableSet<KotlinType> = mutableSetOf()) =
|
||||
isUnit() || isExportable(bindingContext, currentlyProcessed)
|
||||
|
||||
private fun isTypeExportable(type: KotlinType, bindingContext: BindingContext, isReturnType: Boolean = false): Boolean {
|
||||
if (isReturnType && type.isUnit())
|
||||
private fun KotlinType.isExportable(
|
||||
bindingContext: BindingContext,
|
||||
currentlyProcessed: MutableSet<KotlinType> = mutableSetOf()
|
||||
): Boolean {
|
||||
if (!currentlyProcessed.add(this)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (type.isFunctionType) {
|
||||
val arguments = type.arguments
|
||||
val argumentsSize = type.arguments.size - 1
|
||||
for (i in 0 until argumentsSize) {
|
||||
if (!isTypeExportable(arguments[i].type, bindingContext))
|
||||
currentlyProcessed.add(this)
|
||||
|
||||
if (isFunctionType) {
|
||||
for (i in 0 until arguments.lastIndex) {
|
||||
if (!arguments[i].type.isExportable(bindingContext, currentlyProcessed)) {
|
||||
currentlyProcessed.remove(this)
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (!isTypeExportable(arguments.last().type, bindingContext, isReturnType = true))
|
||||
return false
|
||||
|
||||
return true
|
||||
currentlyProcessed.remove(this)
|
||||
return arguments.last().type.isExportableReturn(bindingContext, currentlyProcessed)
|
||||
}
|
||||
|
||||
for (argument: TypeProjection in type.arguments) {
|
||||
if (!isTypeExportable(argument.type, bindingContext))
|
||||
for (argument in arguments) {
|
||||
if (!argument.type.isExportable(bindingContext, currentlyProcessed)) {
|
||||
currentlyProcessed.remove(this)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
val nonNullable = type.makeNotNullable()
|
||||
currentlyProcessed.remove(this)
|
||||
|
||||
// Is primitive exportable type
|
||||
if (nonNullable.isAnyOrNullableAny() ||
|
||||
nonNullable.isDynamic() ||
|
||||
nonNullable.isBoolean() ||
|
||||
KotlinBuiltIns.isThrowableOrNullableThrowable(nonNullable) ||
|
||||
KotlinBuiltIns.isString(nonNullable) ||
|
||||
(nonNullable.isPrimitiveNumberOrNullableType() && !nonNullable.isLong()) ||
|
||||
nonNullable.isNothingOrNullableNothing() ||
|
||||
(KotlinBuiltIns.isArray(type)) ||
|
||||
KotlinBuiltIns.isPrimitiveArray(type)
|
||||
) return true
|
||||
val nonNullable = makeNotNullable()
|
||||
|
||||
val descriptor = type.constructor.declarationDescriptor ?: return false
|
||||
return descriptor is MemberDescriptor && descriptor.isEffectivelyExternal() ||
|
||||
AnnotationsUtils.isExportedObject(descriptor, bindingContext)
|
||||
val isPrimitiveExportableType = nonNullable.isAnyOrNullableAny() ||
|
||||
nonNullable.isDynamic() ||
|
||||
nonNullable.isBoolean() ||
|
||||
KotlinBuiltIns.isThrowableOrNullableThrowable(nonNullable) ||
|
||||
KotlinBuiltIns.isString(nonNullable) ||
|
||||
(nonNullable.isPrimitiveNumberOrNullableType() && !nonNullable.isLong()) ||
|
||||
nonNullable.isNothingOrNullableNothing() ||
|
||||
KotlinBuiltIns.isArray(this) ||
|
||||
KotlinBuiltIns.isPrimitiveArray(this)
|
||||
|
||||
if (isPrimitiveExportableType) return true
|
||||
|
||||
val descriptor = constructor.declarationDescriptor
|
||||
|
||||
if (descriptor !is MemberDescriptor) return false
|
||||
|
||||
return descriptor.isEffectivelyExternal() || AnnotationsUtils.isExportedObject(descriptor, bindingContext)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user