[K/N] KT-53069: Guard against recursive generic type argument constraints during objc export

Merge-request: KT-MR-7872
Merged-by: Gleb Lukianets <Gleb.Lukianets@jetbrains.com>
This commit is contained in:
Gleb Lukianets
2022-12-08 14:03:45 +00:00
committed by Space Team
parent 96e1ba045c
commit a3e396e7e4
8 changed files with 173 additions and 46 deletions
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.DataClassResolver
import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
@@ -261,7 +260,7 @@ internal class ObjCExportTranslatorImpl(
val name = referenceClass(classDescriptor).objCName
val members = buildMembers {
translatePlainMembers(declarations, ObjCNoneExportScope)
translatePlainMembers(declarations, ObjCRootExportScope)
}
return ObjCInterfaceImpl(name, categoryName = "Extensions", members = members)
}
@@ -271,7 +270,7 @@ internal class ObjCExportTranslatorImpl(
// TODO: stop inheriting KotlinBase.
val members = buildMembers {
translatePlainMembers(declarations, ObjCNoneExportScope)
translatePlainMembers(declarations, ObjCRootExportScope)
}
return objCInterface(
name,
@@ -342,7 +341,7 @@ internal class ObjCExportTranslatorImpl(
?.forEach {
val selector = getSelector(it)
if (selector !in presentConstructors) {
add { buildMethod(it, it, ObjCNoneExportScope, unavailable = true) }
add { buildMethod(it, it, ObjCRootExportScope, unavailable = true) }
if (selector == "init") {
add { ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable")) }
@@ -383,7 +382,7 @@ internal class ObjCExportTranslatorImpl(
}
}
ClassKind.ENUM_CLASS -> {
val type = mapType(descriptor.defaultType, ReferenceBridge, ObjCNoneExportScope)
val type = mapType(descriptor.defaultType, ReferenceBridge, ObjCRootExportScope)
descriptor.enumEntries.forEach {
val entryName = namer.getEnumEntrySelector(it)
@@ -434,9 +433,9 @@ internal class ObjCExportTranslatorImpl(
}
internal fun createGenericExportScope(descriptor: ClassDescriptor): ObjCExportScope = if (objcGenerics) {
ObjCClassExportScope(descriptor, namer)
ObjCRootExportScope.deriveForClass(descriptor, namer)
} else {
ObjCNoneExportScope
ObjCRootExportScope
}
private fun buildThrowableAsErrorMethod(): ObjCMethod {
@@ -560,7 +559,7 @@ internal class ObjCExportTranslatorImpl(
}
}
translatePlainMembers(methods, properties, ObjCNoneExportScope)
translatePlainMembers(methods, properties, ObjCRootExportScope)
}
private fun StubBuilder<Stub<*>>.translatePlainMembers(members: List<CallableMemberDescriptor>, objCExportScope: ObjCExportScope) {
@@ -922,12 +921,18 @@ internal class ObjCExportTranslatorImpl(
}
mostSpecificMatches.firstOrNull()?.let {
return it.mapper.mapType(it.type, this, objCExportScope)
try {
return it.mapper.mapType(it.type, this, objCExportScope.deriveForType(it.type))
} catch (e: ObjCExportScope.RecursionBreachException) {
return ObjCIdType
}
}
if(objcGenerics && kotlinType.isTypeParameter()){
val genericTypeUsage = objCExportScope.getGenericTypeUsage(TypeUtils.getTypeParameterDescriptorOrNull(kotlinType))
if(genericTypeUsage != null)
if (objcGenerics && kotlinType.isTypeParameter()) {
val genericTypeUsage = objCExportScope
.nearestScopeOfType<ObjCClassExportScope>()
?.getGenericTypeUsage(TypeUtils.getTypeParameterDescriptorOrNull(kotlinType))
if (genericTypeUsage != null)
return genericTypeUsage
}
@@ -1014,7 +1019,9 @@ internal class ObjCExportTranslatorImpl(
} else {
mapReferenceType(functionType.getReturnTypeFromFunctionType(), objCExportScope)
},
parameterTypes.map { mapReferenceType(it, objCExportScope) }
parameterTypes.map {
mapReferenceType(it, objCExportScope)
}
)
}
@@ -1369,36 +1376,8 @@ internal fun ObjCExportNamer.ClassOrProtocolName.toNameAttributes(): List<String
private fun swiftNameAttribute(swiftName: String) = "swift_name(\"$swiftName\")"
private fun objcRuntimeNameAttribute(name: String) = "objc_runtime_name(\"$name\")"
interface ObjCExportScope{
fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage?
}
internal class ObjCClassExportScope constructor(container:DeclarationDescriptor, val namer: ObjCExportNamer): ObjCExportScope {
private val typeNames = if(container is ClassDescriptor && !container.isInterface) {
container.typeConstructor.parameters
} else {
emptyList<TypeParameterDescriptor>()
}
override fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage? {
val localTypeParam = typeNames.firstOrNull {
typeParameterDescriptor != null &&
(it == typeParameterDescriptor || (it.isCapturedFromOuterDeclaration && it.original == typeParameterDescriptor))
}
return if(localTypeParam == null) {
null
} else {
ObjCGenericTypeParameterUsage(localTypeParam, namer)
}
}
}
internal object ObjCNoneExportScope: ObjCExportScope{
override fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage? = null
}
private fun computeSuperClassType(descriptor: ClassDescriptor): KotlinType? = descriptor.typeConstructor.supertypes.filter { !it.isInterface() }.firstOrNull()
private fun computeSuperClassType(descriptor: ClassDescriptor): KotlinType? =
descriptor.typeConstructor.supertypes.firstOrNull { !it.isInterface() }
internal const val OBJC_SUBCLASSING_RESTRICTED = "objc_subclassing_restricted"
@@ -1415,7 +1394,6 @@ internal fun ClassDescriptor.needCompanionObjectProperty(namer: ObjCExportNamer,
return true
}
private fun DeprecationInfo.toDeprecationAttribute(): String {
val attribute = when (deprecationLevel) {
DeprecationLevelValue.WARNING -> "deprecated"
@@ -1457,4 +1435,4 @@ private fun quoteAsCStringLiteral(str: String): String = buildString {
}
}
append('"')
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.konan.objcexport
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.types.KotlinType
interface ObjCExportScope {
class RecursionBreachException : Exception {
constructor(type: KotlinType) : super("$type was already encountered during type mapping process.")
}
val parent: ObjCExportScope?
get() = null
fun deriveForType(kotlinType: KotlinType): ObjCTypeExportScope = ObjCTypeExportScopeImpl(kotlinType, this)
fun deriveForClass(container: DeclarationDescriptor, namer: ObjCExportNamer): ObjCClassExportScope =
ObjCClassExportScopeImpl(container, namer, this)
}
internal inline fun <reified T : ObjCExportScope> ObjCExportScope.nearestScopeOfType(): T? {
var parent: ObjCExportScope? = this
while (parent != null) {
if (parent is T) {
return parent
}
parent = this.parent
}
return null
}
internal object ObjCRootExportScope : ObjCExportScope
interface ObjCClassExportScope : ObjCExportScope {
fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage?
}
private class ObjCClassExportScopeImpl constructor(
container: DeclarationDescriptor,
val namer: ObjCExportNamer,
override val parent: ObjCExportScope?,
) : ObjCClassExportScope {
private val typeParameterNames: List<TypeParameterDescriptor> =
if (container is ClassDescriptor && !container.isInterface) {
container.typeConstructor.parameters
} else {
emptyList<TypeParameterDescriptor>()
}
override fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage? {
return typeParameterDescriptor?.let { descriptor ->
typeParameterNames.firstOrNull {
it == descriptor || it.isCapturedFromOuterDeclaration && it.original == descriptor
}?.let {
ObjCGenericTypeParameterUsage(it, namer)
}
}
}
}
interface ObjCTypeExportScope : ObjCExportScope {
val kotlinType: KotlinType
}
private class ObjCTypeExportScopeImpl(override val kotlinType: KotlinType, override val parent: ObjCExportScope?) : ObjCTypeExportScope {
init {
var parent = this.parent
while (parent != null && parent is ObjCTypeExportScope) {
if (parent.kotlinType == kotlinType)
throw ObjCExportScope.RecursionBreachException(kotlinType)
parent = parent.parent
}
}
}
@@ -18,7 +18,7 @@ class ObjCExportTranslatorMobile internal constructor(private val delegate: ObjC
fun translateBaseFunction(descriptor: FunctionDescriptor): ObjCMethod {
val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor
val scope = classDescriptor?.let { delegate.createGenericExportScope(it) } ?: ObjCNoneExportScope
val scope = classDescriptor?.let { delegate.createGenericExportScope(it) } ?: ObjCRootExportScope
return delegate.buildMethod(descriptor, descriptor, scope)
}
}
@@ -1462,6 +1462,20 @@ __attribute__((swift_name("OverrideMethodsOfAnyKt")))
+ (BOOL)testObj:(id)obj other:(id)other swift:(BOOL)swift error:(NSError * _Nullable * _Nullable)error __attribute__((swift_name("test(obj:other:swift:)")));
@end
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("RecList")))
@interface KtRecList<T> : KtBase
- (instancetype)initWithValue:(NSArray<id> *)value __attribute__((swift_name("init(value:)"))) __attribute__((objc_designated_initializer));
@property (readonly) NSArray<id> *value __attribute__((swift_name("value")));
@end
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("RecFunc")))
@interface KtRecFunc<T> : KtBase
- (instancetype)initWithValue:(id (^)(void))value __attribute__((swift_name("init(value:)"))) __attribute__((objc_designated_initializer));
@property (readonly) id (^value)(void) __attribute__((swift_name("value")));
@end
__attribute__((swift_name("RefinedClassA")))
@interface KtRefinedClassA : KtBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
@@ -1397,6 +1397,20 @@ __attribute__((swift_name("OverrideMethodsOfAnyKt")))
+ (BOOL)testObj:(id)obj other:(id)other swift:(BOOL)swift error:(NSError * _Nullable * _Nullable)error __attribute__((swift_name("test(obj:other:swift:)")));
@end
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("RecList")))
@interface KtRecList<T> : KtBase
- (instancetype)initWithValue:(NSArray<id> *)value __attribute__((swift_name("init(value:)"))) __attribute__((objc_designated_initializer));
@property (readonly) NSArray<id> *value __attribute__((swift_name("value")));
@end
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("RecFunc")))
@interface KtRecFunc<T> : KtBase
- (instancetype)initWithValue:(id (^)(void))value __attribute__((swift_name("init(value:)"))) __attribute__((objc_designated_initializer));
@property (readonly) id (^value)(void) __attribute__((swift_name("value")));
@end
__attribute__((swift_name("RefinedClassA")))
@interface KtRefinedClassA : KtBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
@@ -1397,6 +1397,20 @@ __attribute__((swift_name("OverrideMethodsOfAnyKt")))
+ (BOOL)testObj:(id)obj other:(id)other swift:(BOOL)swift error:(NSError * _Nullable * _Nullable)error __attribute__((swift_name("test(obj:other:swift:)")));
@end
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("RecList")))
@interface KtRecList : KtBase
- (instancetype)initWithValue:(NSArray<id> *)value __attribute__((swift_name("init(value:)"))) __attribute__((objc_designated_initializer));
@property (readonly) NSArray<id> *value __attribute__((swift_name("value")));
@end
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("RecFunc")))
@interface KtRecFunc : KtBase
- (instancetype)initWithValue:(id (^)(void))value __attribute__((swift_name("init(value:)"))) __attribute__((objc_designated_initializer));
@property (readonly) id (^value)(void) __attribute__((swift_name("value")));
@end
__attribute__((swift_name("RefinedClassA")))
@interface KtRefinedClassA : KtBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package recursiveGenericArguments
class RecList<T: List<T>>(val value: T)
class RecFunc<T : () -> T>(val value: T)
@@ -0,0 +1,17 @@
import Kt
#if !NO_GENERICS
private func testRecursiveGenericArguments() throws {
try assertTrue(type(of: RecList<NSArray>(value: []).value) == [Any].self)
}
#endif
class RecursiveGenericArgumentsTests : SimpleTestProvider {
override init() {
super.init()
#if !NO_GENERICS
test("TestRecursiveGenericArguments", testRecursiveGenericArguments)
#endif
}
}