diff --git a/SKIE/acceptance-tests b/SKIE/acceptance-tests index 93a96fdfe..7bc9c780d 160000 --- a/SKIE/acceptance-tests +++ b/SKIE/acceptance-tests @@ -1 +1 @@ -Subproject commit 93a96fdfeedee53d61a3228817af0a358ca819bf +Subproject commit 7bc9c780d442b3f98bc4db2f80c27dc9306ab800 diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/kir/type/SupportedFlow.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/kir/type/SupportedFlow.kt index 3b0a7ef46..e89c80760 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/kir/type/SupportedFlow.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/kir/type/SupportedFlow.kt @@ -31,6 +31,8 @@ enum class SupportedFlow(private val directParent: SupportedFlow?) { val kotlinClassFqName: String + val swiftSimpleName: String + val kind: SupportedFlow fun getCoroutinesKirClass(kirProvider: KirProvider): KirClass = @@ -40,6 +42,9 @@ enum class SupportedFlow(private val directParent: SupportedFlow?) { fun getSwiftClass(sirProvider: SirProvider): SirClass + context(SirPhase.Context) + fun getCoroutinesKirClass(): KirClass = getCoroutinesKirClass(kirProvider) + context(SirPhase.Context) fun getKotlinKirClass(): KirClass = getKotlinKirClass(kirProvider) @@ -52,11 +57,13 @@ enum class SupportedFlow(private val directParent: SupportedFlow?) { override val kotlinClassFqName: String = "co.touchlab.skie.runtime.coroutines.flow.SkieKotlin${kind.name}" + override val swiftSimpleName: String = "SkieSwift${kind.name}" + override fun getKotlinKirClass(kirProvider: KirProvider): KirClass = kirProvider.getClassByFqName(kotlinClassFqName) override fun getSwiftClass(sirProvider: SirProvider): SirClass = - sirProvider.getClassByFqName(SirFqName(sirProvider.skieModule, "SkieSwift${kind.name}")) + sirProvider.getClassByFqName(SirFqName(sirProvider.skieModule, swiftSimpleName)) override fun isCastableTo(variant: Variant): Boolean { return kind.isSelfOrChildOf(variant.kind) @@ -67,11 +74,13 @@ enum class SupportedFlow(private val directParent: SupportedFlow?) { override val kotlinClassFqName: String = "co.touchlab.skie.runtime.coroutines.flow.SkieKotlinOptional${kind.name}" + override val swiftSimpleName: String = "SkieSwiftOptional${kind.name}" + override fun getKotlinKirClass(kirProvider: KirProvider): KirClass = kirProvider.getClassByFqName(kotlinClassFqName) override fun getSwiftClass(sirProvider: SirProvider): SirClass = - sirProvider.getClassByFqName(SirFqName(sirProvider.skieModule, "SkieSwiftOptional${kind.name}")) + sirProvider.getClassByFqName(SirFqName(sirProvider.skieModule, swiftSimpleName)) override fun isCastableTo(variant: Variant): Boolean { if (variant is Required) return false diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/CustomMembersPassthroughGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/CustomMembersPassthroughGenerator.kt new file mode 100644 index 000000000..a4fd5c836 --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/CustomMembersPassthroughGenerator.kt @@ -0,0 +1,155 @@ +package co.touchlab.skie.phases.bridging + +import co.touchlab.skie.phases.SirPhase +import co.touchlab.skie.sir.element.* +import co.touchlab.skie.util.swift.addFunctionDeclarationBodyWithErrorTypeHandling +import io.outfoxx.swiftpoet.CodeBlock +import io.outfoxx.swiftpoet.Modifier +import io.outfoxx.swiftpoet.joinToCode + +object CustomMembersPassthroughGenerator { + context(SirPhase.Context) + fun generatePassthroughForDeclarations( + targetBridge: SirClass, + declarations: List, + delegateAccessor: CodeBlock, + ) { + declarations.forEach { + targetBridge.addPassthroughForDeclaration(it, delegateAccessor) + } + } + + context(SirPhase.Context) + private fun SirClass.addPassthroughForDeclaration(declaration: CustomPassthroughDeclaration, delegateAccessor: CodeBlock) { + when (declaration) { + is CustomPassthroughDeclaration.SimpleFunction -> addPassthroughForFunction(declaration, delegateAccessor) + is CustomPassthroughDeclaration.Property -> addPassthroughForProperty(declaration, delegateAccessor) + } + } + + + context(SirPhase.Context) + private fun SirClass.addPassthroughForFunction(function: CustomPassthroughDeclaration.SimpleFunction, delegateAccessor: CodeBlock) { + SirSimpleFunction( + identifier = function.identifier, + returnType = function.returnType, + visibility = function.visibility, + scope = function.scope, + isAsync = function.isAsync, + throws = function.throws, + ).apply { + function.valueParameters.forEach { parameter -> + SirValueParameter( + name = parameter.name, + label = parameter.label, + type = parameter.type, + ) + } + + addFunctionBody(function, delegateAccessor) + } + } + + private fun SirSimpleFunction.addFunctionBody(function: CustomPassthroughDeclaration.SimpleFunction, delegateAccessor: CodeBlock) { + this.addFunctionDeclarationBodyWithErrorTypeHandling(this) { + addCode( + function.transformBody( + CodeBlock.of( + "%L%L%L.%L", + if (function.throws) "try " else "", + if (function.isAsync) "await " else "", + delegateAccessor, + function.call(), + ) + ) + ) + } + } + + private fun CustomPassthroughDeclaration.SimpleFunction.call(): CodeBlock { + val argumentsWithLabels = valueParameters.map { parameter -> + if (parameter.label == "_") { + parameter.transformAccess(CodeBlock.of("%L", parameter.name)) + } else { + CodeBlock.of( + "%N: %L", + parameter.label ?: parameter.name, + parameter.transformAccess(CodeBlock.of("%L", parameter.name)), + ) + } + }.joinToCode(", ") + + return CodeBlock.of( + "%L(%L)", + identifier, + argumentsWithLabels, + ) + } + + context(SirPhase.Context) + private fun SirClass.addPassthroughForProperty(property: CustomPassthroughDeclaration.Property, delegateAccessor: CodeBlock) { + SirProperty( + identifier = property.identifier, + type = property.type, + visibility = property.visibility, + scope = property.scope, + ).apply { + addGetter(property, delegateAccessor) + addSetter(property, delegateAccessor) + } + } + + private fun SirProperty.addGetter(property: CustomPassthroughDeclaration.Property, delegateAccessor: CodeBlock) { + SirGetter().apply { + this.addFunctionDeclarationBodyWithErrorTypeHandling(this@addGetter) { + addCode( + property.transformGetter( + CodeBlock.of( + "%L.%N", + delegateAccessor, + property.identifier, + ) + ) + ) + } + } + } + + private fun SirProperty.addSetter(property: CustomPassthroughDeclaration.Property, delegateAccessor: CodeBlock) { + val setter = property.setter ?: return + val parent = parent + + SirSetter( + modifiers = listOfNotNull(Modifier.NONMUTATING.takeIf { parent is SirClass && parent.kind != SirClass.Kind.Class }), + ).addSetterBody(property, setter, delegateAccessor) + } + + private fun SirSetter.addSetterBody( + property: CustomPassthroughDeclaration.Property, + setter: CustomPassthroughDeclaration.Property.Setter, + delegateAccessor: CodeBlock, + ) { + this.addFunctionDeclarationBodyWithErrorTypeHandling(this.property) { + // TODO Remove this once SKIE generates custom header + when (setter) { + CustomPassthroughDeclaration.Property.Setter.MutableProperty -> { + addStatement( + "%L.%N = value", + delegateAccessor, + property.identifier, + ) + } + is CustomPassthroughDeclaration.Property.Setter.SimpleFunction -> { + addStatement( + "%L.%N(%L)", + delegateAccessor, + setter.identifier, + setter.parameterLabel?.let { + CodeBlock.of("%N: value", it) + } ?: CodeBlock.of("value"), + ) + } + } + } + } +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/CustomPassthroughDeclaration.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/CustomPassthroughDeclaration.kt new file mode 100644 index 000000000..c1e3a83ec --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/CustomPassthroughDeclaration.kt @@ -0,0 +1,44 @@ +package co.touchlab.skie.phases.bridging + +import co.touchlab.skie.sir.element.SirScope +import co.touchlab.skie.sir.element.SirVisibility +import co.touchlab.skie.sir.type.SirType +import io.outfoxx.swiftpoet.CodeBlock + +sealed interface CustomPassthroughDeclaration { + data class Property( + val identifier: String, + val type: SirType, + val visibility: SirVisibility = SirVisibility.Public, + val scope: SirScope = SirScope.Member, + val transformGetter: (CodeBlock) -> CodeBlock = { it }, + val setter: Setter? = null, + ): CustomPassthroughDeclaration { + sealed interface Setter { + object MutableProperty: Setter + + data class SimpleFunction( + val identifier: String, + val parameterLabel: String? = null, + ): Setter + } + } + + data class SimpleFunction( + val identifier: String, + val returnType: SirType, + val visibility: SirVisibility = SirVisibility.Public, + val scope: SirScope = SirScope.Member, + val isAsync: Boolean = false, + val throws: Boolean = false, + val valueParameters: List = emptyList(), + val transformBody: (CodeBlock) -> CodeBlock = { it }, + ): CustomPassthroughDeclaration { + data class ValueParameter( + val label: String? = null, + val name: String, + val type: SirType, + val transformAccess: (CodeBlock) -> CodeBlock = { it }, + ) + } +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/DirectMembersPassthroughGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/DirectMembersPassthroughGenerator.kt new file mode 100644 index 000000000..a9a7ee524 --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/DirectMembersPassthroughGenerator.kt @@ -0,0 +1,141 @@ +package co.touchlab.skie.phases.bridging + +import co.touchlab.skie.kir.element.* +import co.touchlab.skie.phases.SirPhase +import co.touchlab.skie.sir.element.* +import co.touchlab.skie.util.swift.addFunctionDeclarationBodyWithErrorTypeHandling +import io.outfoxx.swiftpoet.CodeBlock +import io.outfoxx.swiftpoet.Modifier + +object DirectMembersPassthroughGenerator { + private val unsupportedFunctionNames = listOf("compareTo(other:)", "hash()", "description()", "isEqual(_:)") + + private val SirSimpleFunction.isSupported: Boolean + get() = this.name !in unsupportedFunctionNames + + context(SirPhase.Context) + fun generatePassthroughForMembers( + targetBridge: SirClass, + bridgedKirClass: KirClass, + delegateAccessor: CodeBlock, + ) { + bridgedKirClass.callableDeclarations + .forEach { + targetBridge.addPassthroughForMember(it, delegateAccessor) + } + } + + context(SirPhase.Context) + private fun SirClass.addPassthroughForMember(member: KirCallableDeclaration<*>, delegateAccessor: CodeBlock) { + when (member) { + is KirConstructor -> { + // Constructors do not need passthrough + } + is KirSimpleFunction -> addPassthroughForFunction(member, delegateAccessor) + is KirProperty -> addPassthroughForProperty(member, delegateAccessor) + } + } + + context(SirPhase.Context) + private fun SirClass.addPassthroughForFunction(function: KirSimpleFunction, delegateAccessor: CodeBlock) { + function.forEachAssociatedExportedSirDeclaration { + addPassthroughForFunction(it, delegateAccessor) + } + } + + private fun SirClass.addPassthroughForFunction(function: SirSimpleFunction, delegateAccessor: CodeBlock) { + if (!function.isSupported) { + return + } + + function.shallowCopy(parent = this, isFakeOverride = false).apply { + copyValueParametersFrom(function) + + addFunctionBody(function, delegateAccessor) + } + } + + private fun SirSimpleFunction.addFunctionBody(function: SirSimpleFunction, delegateAccessor: CodeBlock) { + this.addFunctionDeclarationBodyWithErrorTypeHandling(function) { + addStatement( + "return %L%L%L.%L", + if (function.throws) "try " else "", + if (function.isAsync) "await " else "", + delegateAccessor, + function.call(function.valueParameters), + ) + } + } + + context(SirPhase.Context) + private fun SirClass.addPassthroughForProperty(property: KirProperty, delegateAccessor: CodeBlock) { + property.forEachAssociatedExportedSirDeclaration { + addPassthroughForProperty(it, delegateAccessor) + } + } + + private fun SirClass.addPassthroughForProperty(property: SirProperty, delegateAccessor: CodeBlock) { + property.shallowCopy( + parent = this, + isFakeOverride = false, + ).apply { + addGetter(property, delegateAccessor) + addSetter(property, delegateAccessor) + } + } + + private fun SirProperty.addGetter(property: SirProperty, delegateAccessor: CodeBlock) { + val getter = property.getter ?: return + + SirGetter( + throws = getter.throws, + ).addGetterBody(property, getter, delegateAccessor) + } + + private fun SirGetter.addGetterBody(property: SirProperty, getter: SirGetter, delegateAccessor: CodeBlock) { + this.addFunctionDeclarationBodyWithErrorTypeHandling(property) { + addStatement( + "return %L%L.%N", + if (getter.throws) "try " else "", + delegateAccessor, + property.reference, + ) + } + } + + private fun SirProperty.addSetter(property: SirProperty, delegateAccessor: CodeBlock) { + val setter = property.setter ?: return + val parent = parent + + SirSetter( + throws = setter.throws, + modifiers = listOfNotNull(Modifier.NONMUTATING.takeIf { parent is SirClass && parent.kind != SirClass.Kind.Class }), + ).addSetterBody(property, setter, delegateAccessor) + } + + private fun SirSetter.addSetterBody( + property: SirProperty, + setter: SirSetter, + delegateAccessor: CodeBlock, + ) { + this.addFunctionDeclarationBodyWithErrorTypeHandling(property) { + // TODO Remove this filter once SKIE generates custom header + val isParentProtocol = (property.parent as? SirClass)?.kind == SirClass.Kind.Protocol + if (property.isOverriddenFromReadOnlyProperty && isParentProtocol) { + addStatement( + "%L%L.%N(value)", + if (setter.throws) "try " else "", + delegateAccessor, + "set" + property.reference.replaceFirstChar { it.uppercase() }, + ) + } else { + addStatement( + "%L%L.%N = value", + if (setter.throws) "try " else "", + delegateAccessor, + property.reference, + ) + } + } + } +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/ObjCBridgeableGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/ObjCBridgeableGenerator.kt new file mode 100644 index 000000000..d0edad114 --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/bridging/ObjCBridgeableGenerator.kt @@ -0,0 +1,154 @@ +package co.touchlab.skie.phases.bridging + +import co.touchlab.skie.phases.SirPhase +import co.touchlab.skie.sir.element.* +import co.touchlab.skie.sir.type.SirDeclaredSirType +import co.touchlab.skie.sir.type.SirType +import co.touchlab.skie.sir.type.SpecialSirType +import co.touchlab.skie.sir.type.toNullable +import io.outfoxx.swiftpoet.CodeBlock + +object ObjCBridgeableGenerator { + + /** + * @param unwrapObjectiveCSource Whether to add `guard let` to crash on `nil` source in `fromObjectiveC`. + */ + context(SirPhase.Context) + fun addObjcBridgeableImplementation( + target: SirClass, + bridgedType: SirType, + bridgeToObjectiveC: CodeBlock.Builder.() -> Unit, + bridgeFromObjectiveC: CodeBlock.Builder.() -> Unit, + unwrapObjectiveCSource: Boolean = true, + ) = with(target) { + addObjectiveCTypeAlias(bridgedType) + addForceBridgeFromObjectiveC(bridgedType) + addConditionallyBridgeFromObjectiveC(bridgedType) + addUnconditionallyBridgeFromObjectiveC(bridgedType) + addBridgeToObjectiveC(bridgedType, bridgeToObjectiveC) + addFromObjectiveC(bridgedType, unwrapObjectiveCSource, bridgeFromObjectiveC) + } + + private val SirClass.toTypeWithGenericParameters: SirDeclaredSirType + get() = this.toType(this.typeParameters.map { it.toTypeParameterUsage() }) + + context(SirPhase.Context) + private fun SirClass.addObjectiveCTypeAlias(bridgedType: SirType) { + SirTypeAlias( + baseName = sirBuiltins.Swift._ObjectiveCBridgeable.typeParameters.first().name, + ) { + bridgedType + } + } + + context(SirPhase.Context) + private fun SirClass.addForceBridgeFromObjectiveC(bridgedType: SirType) { + SirSimpleFunction( + identifier = "_forceBridgeFromObjectiveC", + returnType = sirBuiltins.Swift.Void.defaultType, + scope = SirScope.Static, + ).apply { + SirValueParameter( + label = "_", + name = "source", + type = bridgedType, + ) + + SirValueParameter( + name = "result", + type = toTypeWithGenericParameters.toNullable(), + inout = true, + ) + + bodyBuilder.add { + addStatement("result = fromObjectiveC(source)") + } + } + } + + context(SirPhase.Context) + private fun SirClass.addConditionallyBridgeFromObjectiveC(bridgedType: SirType) { + SirSimpleFunction( + identifier = "_conditionallyBridgeFromObjectiveC", + returnType = sirBuiltins.Swift.Bool.defaultType, + scope = SirScope.Static, + ).apply { + SirValueParameter( + label = "_", + name = "source", + type = bridgedType, + ) + + SirValueParameter( + name = "result", + type = toTypeWithGenericParameters.toNullable(), + inout = true, + ) + + bodyBuilder.add { + addStatement("result = fromObjectiveC(source)") + addStatement("return true") + } + } + } + + private fun SirClass.addUnconditionallyBridgeFromObjectiveC(bridgedType: SirType) { + SirSimpleFunction( + identifier = "_unconditionallyBridgeFromObjectiveC", + returnType = SpecialSirType.Self, + scope = SirScope.Static, + ).apply { + SirValueParameter( + label = "_", + name = "source", + type = bridgedType.toNullable(), + ) + + bodyBuilder.add { + addStatement("return fromObjectiveC(source)") + } + } + } + + private fun SirClass.addBridgeToObjectiveC(bridgedType: SirType, body: CodeBlock.Builder.() -> Unit) { + SirSimpleFunction( + identifier = "_bridgeToObjectiveC", + returnType = bridgedType, + ).apply { + bodyBuilder.add { + addCode(CodeBlock.Builder().apply(body).build()) + } + } + } + + private fun SirClass.addFromObjectiveC( + bridgedType: SirType, + unwrapObjectiveCSource: Boolean, + body: CodeBlock.Builder.() -> Unit, + ) { + SirSimpleFunction( + identifier = "fromObjectiveC", + returnType = SpecialSirType.Self, + scope = SirScope.Static, + visibility = SirVisibility.Private, + ).apply { + SirValueParameter( + label = "_", + name = "source", + type = bridgedType.toNullable(), + ) + + bodyBuilder.add { + if (unwrapObjectiveCSource) { + beginControlFlow("guard", "let source = source else") + addCode(fatalErrorFromObjectiveC(this@addFromObjectiveC)) + endControlFlow("guard") + } + addCode(CodeBlock.Builder().apply(body).build()) + } + } + } + + fun fatalErrorFromObjectiveC(sirClass: SirClass): CodeBlock = + CodeBlock.of("""fatalError("Couldn't map value of \(Swift.String(describing: source)) to ${sirClass.publicName}")""") +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsGenerator.kt index 2f314463e..38ef9db74 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsGenerator.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsGenerator.kt @@ -94,7 +94,7 @@ private fun createBridgingEnum(enumKirClass: KirClass): SirClass = attributes.add("frozen") ExhaustiveEnumsMembersPassthroughGenerator.generatePassthroughForMembers(enumKirClass, this) - addObjcBridgeableImplementation(enumKirClass) + ExhaustiveEnumsObjectiveCBridgeableGenerator.addObjcBridgeableImplementation(enumKirClass, this) doInPhase(ExhaustiveEnumsGenerator.NestedTypeDeclarationsPhase) { addNestedClassTypeAliases(enumKirClass) diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsMembersPassthroughGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsMembersPassthroughGenerator.kt index 067ce0e49..58f7dc3a2 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsMembersPassthroughGenerator.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsMembersPassthroughGenerator.kt @@ -1,133 +1,18 @@ package co.touchlab.skie.phases.features.enums -import co.touchlab.skie.kir.element.KirCallableDeclaration import co.touchlab.skie.kir.element.KirClass -import co.touchlab.skie.kir.element.KirConstructor -import co.touchlab.skie.kir.element.KirProperty -import co.touchlab.skie.kir.element.KirSimpleFunction -import co.touchlab.skie.kir.element.forEachAssociatedExportedSirDeclaration import co.touchlab.skie.phases.SirPhase +import co.touchlab.skie.phases.bridging.DirectMembersPassthroughGenerator import co.touchlab.skie.sir.element.SirClass -import co.touchlab.skie.sir.element.SirGetter -import co.touchlab.skie.sir.element.SirProperty -import co.touchlab.skie.sir.element.SirSetter -import co.touchlab.skie.sir.element.SirSimpleFunction -import co.touchlab.skie.sir.element.call -import co.touchlab.skie.sir.element.copyValueParametersFrom -import co.touchlab.skie.sir.element.shallowCopy -import co.touchlab.skie.util.swift.addFunctionDeclarationBodyWithErrorTypeHandling -import io.outfoxx.swiftpoet.Modifier +import io.outfoxx.swiftpoet.CodeBlock object ExhaustiveEnumsMembersPassthroughGenerator { - - private val unsupportedFunctionNames = listOf("compareTo(other:)", "hash()", "description()", "isEqual(_:)") - - private val SirSimpleFunction.isSupported: Boolean - get() = this.name !in unsupportedFunctionNames - context(SirPhase.Context) fun generatePassthroughForMembers(enumKirClass: KirClass, bridgedEnum: SirClass) { - enumKirClass.callableDeclarations - .forEach { - bridgedEnum.addPassthroughForMember(it) - } - } - - context(SirPhase.Context) - private fun SirClass.addPassthroughForMember(member: KirCallableDeclaration<*>) { - when (member) { - is KirConstructor -> { - // Constructors do not need passthrough - } - is KirSimpleFunction -> addPassthroughForFunction(member) - is KirProperty -> addPassthroughForProperty(member) - } - } - - context(SirPhase.Context) - private fun SirClass.addPassthroughForFunction(function: KirSimpleFunction) { - function.forEachAssociatedExportedSirDeclaration { - addPassthroughForFunction(it) - } - } - - private fun SirClass.addPassthroughForFunction(function: SirSimpleFunction) { - if (!function.isSupported) { - return - } - - function.shallowCopy(parent = this, isFakeOverride = false).apply { - copyValueParametersFrom(function) - - addFunctionBody(function) - } - } - - private fun SirSimpleFunction.addFunctionBody(function: SirSimpleFunction) { - this.addFunctionDeclarationBodyWithErrorTypeHandling(function) { - addStatement( - "return %L%L(self as _ObjectiveCType).%L", - if (function.throws) "try " else "", - if (function.isAsync) "await " else "", - function.call(function.valueParameters), - ) - } - } - - context(SirPhase.Context) - private fun SirClass.addPassthroughForProperty(property: KirProperty) { - property.forEachAssociatedExportedSirDeclaration { - addPassthroughForProperty(it) - } - } - - private fun SirClass.addPassthroughForProperty(property: SirProperty) { - property.shallowCopy( - parent = this, - isFakeOverride = false, - ).apply { - addGetter(property) - addSetter(property) - } - } - - private fun SirProperty.addGetter(property: SirProperty) { - val getter = property.getter ?: return - - SirGetter( - throws = getter.throws, - ).addGetterBody(property, getter) - } - - private fun SirGetter.addGetterBody(property: SirProperty, getter: SirGetter) { - this.addFunctionDeclarationBodyWithErrorTypeHandling(property) { - addStatement( - "return %L(self as _ObjectiveCType).%N", - if (getter.throws) "try " else "", - property.reference, - ) - } - } - - private fun SirProperty.addSetter(property: SirProperty) { - val setter = property.setter ?: return - - SirSetter( - throws = setter.throws, - modifiers = listOf(Modifier.NONMUTATING), - ).addSetterBody(property, setter) - } - - private fun SirSetter.addSetterBody( - property: SirProperty, - setter: SirSetter, - ) { - this.addFunctionDeclarationBodyWithErrorTypeHandling(property) { - addStatement( - "%L(self as _ObjectiveCType).%N = value", - if (setter.throws) "try " else "", - property.reference, - ) - } + DirectMembersPassthroughGenerator.generatePassthroughForMembers( + targetBridge = bridgedEnum, + bridgedKirClass = enumKirClass, + delegateAccessor = CodeBlock.of("(self as _ObjectiveCType)") + ) } } diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsObjectiveCBridgeableGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsObjectiveCBridgeableGenerator.kt new file mode 100644 index 000000000..4e1b43c7f --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ExhaustiveEnumsObjectiveCBridgeableGenerator.kt @@ -0,0 +1,86 @@ +package co.touchlab.skie.phases.features.enums + +import co.touchlab.skie.kir.element.KirClass +import co.touchlab.skie.kir.element.KirEnumEntry +import co.touchlab.skie.phases.SirPhase +import co.touchlab.skie.phases.bridging.ObjCBridgeableGenerator +import co.touchlab.skie.phases.bridging.ObjCBridgeableGenerator.fatalErrorFromObjectiveC +import co.touchlab.skie.sir.element.SirClass +import io.outfoxx.swiftpoet.CodeBlock +import io.outfoxx.swiftpoet.joinToCode + +object ExhaustiveEnumsObjectiveCBridgeableGenerator { + context(SirPhase.Context) + fun addObjcBridgeableImplementation(enumKirClass: KirClass, bridgedEnum: SirClass) { + ObjCBridgeableGenerator.addObjcBridgeableImplementation( + target = bridgedEnum, + bridgedType = enumKirClass.enum.defaultType, + bridgeToObjectiveC = { + addBridgeToObjectiveCBody(enumKirClass) + }, + bridgeFromObjectiveC = { + addNonEmptyFromObjectiveCBody(enumKirClass) + }, + ) + } + + private val KirClass.enum: SirClass + get() = this.originalSirClass + + private fun CodeBlock.Builder.addBridgeToObjectiveCBody(enumKirClass: KirClass) { + beginControlFlow("switch", "self") + add( + enumKirClass.enumEntries.map { it.getSwiftBridgeCase(enumKirClass.enum) }.joinToCode("\n", suffix = "\n"), + ) + endControlFlow("switch") + } + + private fun KirEnumEntry.getSwiftBridgeCase(enum: SirClass): CodeBlock { + val typeName = enum.defaultType.evaluate().swiftPoetTypeName + + return CodeBlock.of( + "case .%N: return %T.%N as %T", + sirEnumEntry.name, + typeName, + sirEnumEntry.name, + typeName, + ) + } + + private fun CodeBlock.Builder.addNonEmptyFromObjectiveCBody( + enumKirClass: KirClass, + ) { + val enum = enumKirClass.enum + + if (enumKirClass.enumEntries.isNotEmpty()) { + enumKirClass.enumEntries.forEachIndexed { index, entry -> + addFromObjectiveCBodyCase(entry, enum, index) + } + + nextControlFlow("else") + addStatement("%L", fatalErrorFromObjectiveC(enum)) + endControlFlow("if") + } else { + add(fatalErrorFromObjectiveC(enum)) + } + } + + private fun CodeBlock.Builder.addFromObjectiveCBodyCase( + entry: KirEnumEntry, + enum: SirClass, + index: Int, + ) { + val typeName = enum.defaultType.evaluate().swiftPoetTypeName + + val controlFlowCode = "source == %T.%N as %T" + val controlFlowArguments = arrayOf(typeName, entry.sirEnumEntry.name, typeName) + + if (index == 0) { + beginControlFlow("if", controlFlowCode, *controlFlowArguments) + } else { + nextControlFlow("else if", controlFlowCode, *controlFlowArguments) + } + + addStatement("return .%N", entry.sirEnumEntry.name) + } +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ObjCBridgeable.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ObjCBridgeable.kt deleted file mode 100644 index f945fa955..000000000 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/features/enums/ObjCBridgeable.kt +++ /dev/null @@ -1,212 +0,0 @@ -package co.touchlab.skie.phases.features.enums - -import co.touchlab.skie.kir.element.KirClass -import co.touchlab.skie.kir.element.KirEnumEntry -import co.touchlab.skie.phases.SirPhase -import co.touchlab.skie.sir.element.SirClass -import co.touchlab.skie.sir.element.SirScope -import co.touchlab.skie.sir.element.SirSimpleFunction -import co.touchlab.skie.sir.element.SirTypeAlias -import co.touchlab.skie.sir.element.SirValueParameter -import co.touchlab.skie.sir.element.SirVisibility -import co.touchlab.skie.sir.type.SpecialSirType -import co.touchlab.skie.sir.type.toNullable -import io.outfoxx.swiftpoet.CodeBlock -import io.outfoxx.swiftpoet.joinToCode - -context(SirPhase.Context) -fun SirClass.addObjcBridgeableImplementation(enumKirClass: KirClass) { - addObjectiveCTypeAlias(enumKirClass.enum) - addForceBridgeFromObjectiveC(enumKirClass.enum) - addConditionallyBridgeFromObjectiveC(enumKirClass.enum) - addUnconditionallyBridgeFromObjectiveC(enumKirClass.enum) - addBridgeToObjectiveC(enumKirClass) - addFromObjectiveC(enumKirClass) -} - -private val KirClass.enum: SirClass - get() = this.originalSirClass - -context(SirPhase.Context) -private fun SirClass.addObjectiveCTypeAlias(enum: SirClass) { - SirTypeAlias( - baseName = sirBuiltins.Swift._ObjectiveCBridgeable.typeParameters.first().name, - ) { - enum.defaultType - } -} - -context(SirPhase.Context) -private fun SirClass.addForceBridgeFromObjectiveC(enum: SirClass) { - SirSimpleFunction( - identifier = "_forceBridgeFromObjectiveC", - returnType = sirBuiltins.Swift.Void.defaultType, - scope = SirScope.Static, - ).apply { - SirValueParameter( - label = "_", - name = "source", - type = enum.defaultType, - ) - - SirValueParameter( - name = "result", - type = SpecialSirType.Self.toNullable(), - inout = true, - ) - - bodyBuilder.add { - addStatement("result = fromObjectiveC(source)") - } - } -} - -context(SirPhase.Context) -private fun SirClass.addConditionallyBridgeFromObjectiveC(enum: SirClass) { - SirSimpleFunction( - identifier = "_conditionallyBridgeFromObjectiveC", - returnType = sirBuiltins.Swift.Bool.defaultType, - scope = SirScope.Static, - ).apply { - SirValueParameter( - label = "_", - name = "source", - type = enum.defaultType, - ) - - SirValueParameter( - name = "result", - type = SpecialSirType.Self.toNullable(), - inout = true, - ) - - bodyBuilder.add { - addStatement("result = fromObjectiveC(source)") - addStatement("return true") - } - } -} - -private fun SirClass.addUnconditionallyBridgeFromObjectiveC(enum: SirClass) { - SirSimpleFunction( - identifier = "_unconditionallyBridgeFromObjectiveC", - returnType = SpecialSirType.Self, - scope = SirScope.Static, - ).apply { - SirValueParameter( - label = "_", - name = "source", - type = enum.defaultType.toNullable(), - ) - - bodyBuilder.add { - addStatement("return fromObjectiveC(source)") - } - } -} - -private fun SirClass.addBridgeToObjectiveC(enumKirClass: KirClass) { - SirSimpleFunction( - identifier = "_bridgeToObjectiveC", - returnType = enumKirClass.enum.defaultType, - ).apply { - addBridgeToObjectiveCBody(enumKirClass) - } -} - -private fun SirSimpleFunction.addBridgeToObjectiveCBody(enumKirClass: KirClass) { - bodyBuilder.add { - addCode( - CodeBlock.builder() - .beginControlFlow("switch", "self") - .add( - enumKirClass.enumEntries.map { it.getSwiftBridgeCase(enumKirClass.enum) }.joinToCode("\n", suffix = "\n"), - ) - .endControlFlow("switch") - .build(), - ) - } -} - -private fun KirEnumEntry.getSwiftBridgeCase(enum: SirClass): CodeBlock { - val typeName = enum.defaultType.evaluate().swiftPoetTypeName - - return CodeBlock.of( - "case .%N: return %T.%N as %T", - sirEnumEntry.name, - typeName, - sirEnumEntry.name, - typeName, - ) -} - -private fun SirClass.addFromObjectiveC(enumKirClass: KirClass) { - SirSimpleFunction( - identifier = "fromObjectiveC", - returnType = SpecialSirType.Self, - scope = SirScope.Static, - visibility = SirVisibility.Private, - ).apply { - SirValueParameter( - label = "_", - name = "source", - type = enumKirClass.enum.defaultType.toNullable(), - ) - - addFromObjectiveCBody(enumKirClass) - } -} - -private fun SirSimpleFunction.addFromObjectiveCBody(enumKirClass: KirClass) { - bodyBuilder.add { - addCode( - CodeBlock.builder() - .apply { - addNonEmptyFromObjectiveCBody(enumKirClass) - } - .build(), - ) - } -} - -private fun CodeBlock.Builder.addNonEmptyFromObjectiveCBody( - enumKirClass: KirClass, -) { - val enum = enumKirClass.enum - - if (enumKirClass.enumEntries.isNotEmpty()) { - addStatement("guard let source = source else { %L }", enum.fatalErrorFromObjectiveC) - - enumKirClass.enumEntries.forEachIndexed { index, entry -> - addFromObjectiveCBodyCase(entry, enum, index) - } - - nextControlFlow("else") - addStatement("%L", enum.fatalErrorFromObjectiveC) - endControlFlow("if") - } else { - add(enum.fatalErrorFromObjectiveC) - } -} - -private fun CodeBlock.Builder.addFromObjectiveCBodyCase( - entry: KirEnumEntry, - enum: SirClass, - index: Int, -) { - val typeName = enum.defaultType.evaluate().swiftPoetTypeName - - val controlFlowCode = "source == %T.%N as %T" - val controlFlowArguments = arrayOf(typeName, entry.sirEnumEntry.name, typeName) - - if (index == 0) { - beginControlFlow("if", controlFlowCode, *controlFlowArguments) - } else { - nextControlFlow("else if", controlFlowCode, *controlFlowArguments) - } - - addStatement("return .%N", entry.sirEnumEntry.name) -} - -private val SirClass.fatalErrorFromObjectiveC: CodeBlock - get() = CodeBlock.of("""fatalError("Couldn't map value of \(Swift.String(describing: source)) to $publicName")""") diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SkieSwiftFlowIteratorGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SkieSwiftFlowIteratorGenerator.kt new file mode 100644 index 000000000..558763331 --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SkieSwiftFlowIteratorGenerator.kt @@ -0,0 +1,113 @@ +package co.touchlab.skie.phases.runtime + +import co.touchlab.skie.kir.type.SupportedFlow +import co.touchlab.skie.phases.SirPhase +import co.touchlab.skie.sir.element.* + +object SkieSwiftFlowIteratorGenerator { + + context(SirPhase.Context) + fun generate(): SirClass { + return namespaceProvider.getSkieNamespaceFile("SkieSwiftFlowIterator").run { + SirClass( + baseName = "SkieSwiftFlowIterator", + superTypes = listOf( + sirBuiltins._Concurrency.AsyncIteratorProtocol.defaultType, + ), + ).apply { + val tParameter = SirTypeParameter("T") + val elementAlias = SirTypeAlias("Element") { + tParameter.toTypeParameterUsage() + } + + addIteratorProperty() + addInternalConstructor() + addNextFunction(elementAlias) + addCancelTaskFunction() + addDeinit() + } + } + } + + context(SirPhase.Context) + private fun SirClass.addIteratorProperty() { + val skieColdFlowIterator = kirProvider + .getClassByFqName("co.touchlab.skie.runtime.coroutines.flow.SkieColdFlowIterator") + .originalSirClass + + SirProperty( + identifier = "iterator", + type = skieColdFlowIterator.toType(sirBuiltins.Swift.AnyObject.defaultType), + visibility = SirVisibility.Private, + ) + } + + context(SirPhase.Context) + private fun SirClass.addInternalConstructor() { + SirConstructor( + visibility = SirVisibility.Internal, + ).apply { + SirValueParameter( + name = "flow", + type = SupportedFlow.Flow.getCoroutinesKirClass().originalSirClass.defaultType, + ) + + bodyBuilder.add { + addCode("iterator = .init(flow: flow)") + } + } + } + + context(SirPhase.Context) + private fun SirClass.addNextFunction(elementAlias: SirTypeAlias) { + SirSimpleFunction( + identifier = "next", + returnType = sirBuiltins.Swift.Optional.toType(elementAlias.type), + isAsync = true, + ).apply { + bodyBuilder.add { + addCode(""" + do { + let hasNext = try await skie(iterator).hasNext() + + if hasNext.boolValue { + return .some(iterator.next() as! Element) + } else { + return nil + } + } catch is _Concurrency.CancellationError { + await cancelTask() + + return nil + } catch { + Swift.fatalError("Unexpected error: \(error)") + } + """.trimIndent()) + } + } + } + + context(SirPhase.Context) + private fun SirClass.addCancelTaskFunction() { + SirSimpleFunction( + identifier = "cancelTask", + returnType = sirBuiltins.Swift.Void.defaultType, + visibility = SirVisibility.Private, + isAsync = true, + ).apply { + bodyBuilder.add { + addCode(""" + _Concurrency.withUnsafeCurrentTask { task in + task?.cancel() + } + """.trimIndent()) + } + } + } + + private fun SirClass.addDeinit() { + deinitBuilder.add { + addCode("iterator.cancel()") + } + } +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SupportedFlowRuntimeGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SupportedFlowRuntimeGenerator.kt new file mode 100644 index 000000000..e1201f4d4 --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SupportedFlowRuntimeGenerator.kt @@ -0,0 +1,236 @@ +package co.touchlab.skie.phases.runtime + +import co.touchlab.skie.kir.type.SupportedFlow +import co.touchlab.skie.phases.SirPhase +import co.touchlab.skie.phases.bridging.CustomMembersPassthroughGenerator +import co.touchlab.skie.phases.bridging.CustomPassthroughDeclaration +import co.touchlab.skie.phases.bridging.ObjCBridgeableGenerator +import co.touchlab.skie.sir.SirFqName +import co.touchlab.skie.sir.element.* +import co.touchlab.skie.sir.type.SirType +import co.touchlab.skie.sir.type.toNullable +import io.outfoxx.swiftpoet.CodeBlock + +object SupportedFlowRuntimeGenerator { + + context(SirPhase.Context) + fun generate(skieSwiftFlowIterator: SirClass) { + val classesForVariants = SupportedFlow.allVariants.associateWith { flowVariant -> + createSwiftFlowClass(flowVariant) + } + + classesForVariants.forEach { (flowVariant, sirClass) -> + sirClass.addSwiftFlowMembers(flowVariant, skieSwiftFlowIterator) + } + } + + context(SirPhase.Context) + private fun createSwiftFlowClass(flowVariant: SupportedFlow.Variant): SirClass { + return namespaceProvider.getSkieNamespaceFile(flowVariant.swiftSimpleName).run { + SirClass( + baseName = flowVariant.swiftSimpleName, + superTypes = listOf( + sirBuiltins._Concurrency.AsyncSequence.defaultType, + sirBuiltins.Swift._ObjectiveCBridgeable.defaultType, + ), + modality = SirModality.Final, + ) + } + } + + context(SirPhase.Context) + private fun SirClass.addSwiftFlowMembers( + flowVariant: SupportedFlow.Variant, + skieSwiftFlowIterator: SirClass, + ) { + val flowKirClass = flowVariant.getCoroutinesKirClass() + val flowClass = flowKirClass.originalSirClass + + val tParameter = SirTypeParameter("T") + val elementType = tParameter.toTypeParameterUsage().toNullable(flowVariant is SupportedFlow.Variant.Optional) + + val asyncIteratorAlias = SirTypeAlias("AsyncIterator") { + skieSwiftFlowIterator.toType(elementType) + } + + val elementTypeAlias = SirTypeAlias("Element") { + elementType + } + + addDelegateProperty(flowClass) + + addInternalConstructor(flowClass) + + addPassthroughMembers(flowVariant, elementTypeAlias) + + addObjCBridgeableImplementation(flowVariant.getKotlinKirClass().originalSirClass) + + addMakeAsyncIteratorFunction(asyncIteratorAlias) + } + + private fun SirClass.addDelegateProperty( + flowClass: SirClass, + ) { + SirProperty( + identifier = "delegate", + type = flowClass.defaultType, + visibility = SirVisibility.Internal, + ) + } + + private fun SirClass.addInternalConstructor( + flowClass: SirClass, + ) { + SirConstructor( + visibility = SirVisibility.Internal, + ).apply { + SirValueParameter( + name = "flow", + label = "internal", + type = flowClass.defaultType, + ) + + bodyBuilder.add { + addCode("delegate = flow") + } + } + } + + context(SirPhase.Context) + private fun SirClass.addPassthroughMembers( + flowVariant: SupportedFlow.Variant, + elementTypeAlias: SirTypeAlias, + ) { + CustomMembersPassthroughGenerator.generatePassthroughForDeclarations( + targetBridge = this, + declarations = flowVariant.kind.passthroughDeclarations(elementTypeAlias.type), + delegateAccessor = CodeBlock.of("delegate"), + ) + } + + context(SirPhase.Context) + private fun SirClass.addObjCBridgeableImplementation(bridgedClass: SirClass) { + ObjCBridgeableGenerator.addObjcBridgeableImplementation( + target = this, + bridgedType = bridgedClass.toType(sirBuiltins.Swift.AnyObject.defaultType), + bridgeToObjectiveC = { + addStatement("return ${bridgedClass.fqName}(delegate)") + }, + bridgeFromObjectiveC = { + addStatement("return .init(internal: source)") + } + ) + } + + private fun SirClass.addMakeAsyncIteratorFunction(asyncIteratorAlias: SirTypeAlias) { + SirSimpleFunction( + identifier = "makeAsyncIterator", + returnType = asyncIteratorAlias.type, + ).apply { + bodyBuilder.add { + addCode("return SkieSwiftFlowIterator(flow: delegate)") + } + } + } + + context(SirPhase.Context) + private fun SupportedFlow.passthroughDeclarations(elementType: SirType): List { + val directParents = when (this) { + SupportedFlow.Flow -> emptyList() + SupportedFlow.SharedFlow -> listOf(SupportedFlow.Flow) + SupportedFlow.MutableSharedFlow -> listOf(SupportedFlow.SharedFlow) + SupportedFlow.StateFlow -> listOf(SupportedFlow.SharedFlow) + SupportedFlow.MutableStateFlow -> listOf(SupportedFlow.StateFlow, SupportedFlow.MutableSharedFlow) + } + val parentDeclarations = directParents.flatMap { + it.passthroughDeclarations(elementType) + }.distinct() + + val declarations = when (this) { + SupportedFlow.Flow -> emptyList() + SupportedFlow.SharedFlow -> listOf( + CustomPassthroughDeclaration.Property( + identifier = "replayCache", + type = sirBuiltins.Swift.Array.toType(elementType), + transformGetter = { + CodeBlock.of("%L as! [%T]", it, elementType.evaluate().swiftPoetTypeName) + } + ), + ) + SupportedFlow.MutableSharedFlow -> listOf( + CustomPassthroughDeclaration.Property( + identifier = "subscriptionCount", + type = sirProvider.getClassByFqName(SirFqName(sirProvider.skieModule, "SkieSwiftStateFlow")).toType(kirBuiltins.nsNumberDeclarationsByFqName["kotlin.Int"]!!.originalSirClass.defaultType), + ), + CustomPassthroughDeclaration.SimpleFunction( + identifier = "emit", + returnType = sirBuiltins.Swift.Void.defaultType, + isAsync = true, + throws = true, + valueParameters = listOf( + CustomPassthroughDeclaration.SimpleFunction.ValueParameter( + name = "value", + type = elementType, + ) + ), + ), + CustomPassthroughDeclaration.SimpleFunction( + identifier = "tryEmit", + returnType = sirBuiltins.Swift.Bool.defaultType, + valueParameters = listOf( + CustomPassthroughDeclaration.SimpleFunction.ValueParameter( + name = "value", + type = elementType, + ) + ), + ), + CustomPassthroughDeclaration.SimpleFunction( + identifier = "resetReplayCache", + returnType = sirBuiltins.Swift.Void.defaultType, + ), + ) + SupportedFlow.StateFlow -> listOf( + CustomPassthroughDeclaration.Property( + identifier = "value", + type = elementType, + transformGetter = { + CodeBlock.of("%L as! %T", it, elementType.evaluate().swiftPoetTypeName) + }, + ) + ) + SupportedFlow.MutableStateFlow -> listOf( + CustomPassthroughDeclaration.Property( + identifier = "value", + type = elementType, + transformGetter = { + CodeBlock.of("%L as! %T", it, elementType.evaluate().swiftPoetTypeName) + }, + setter = CustomPassthroughDeclaration.Property.Setter.SimpleFunction( + identifier = "setValue", + ), + ), + CustomPassthroughDeclaration.SimpleFunction( + identifier = "compareAndSet", + returnType = sirBuiltins.Swift.Bool.defaultType, + valueParameters = listOf( + CustomPassthroughDeclaration.SimpleFunction.ValueParameter( + name = "expect", + type = elementType, + ), + CustomPassthroughDeclaration.SimpleFunction.ValueParameter( + name = "update", + type = elementType, + ), + ), + ) + ) + } + + return (declarations + parentDeclarations).distinctBy { declaration -> + when (declaration) { + is CustomPassthroughDeclaration.Property -> declaration.identifier + is CustomPassthroughDeclaration.SimpleFunction -> declaration.identifier + } + } + } +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SwiftRuntimeGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SwiftRuntimeGenerator.kt index 0b0a09b82..947acb129 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SwiftRuntimeGenerator.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/runtime/SwiftRuntimeGenerator.kt @@ -16,6 +16,9 @@ object SwiftRuntimeGenerator : SirPhase { namespaceProvider.getSkieNamespaceWrittenSourceFile(it.swiftFileName).content = "// $GeneratedBySkieComment\n\n$baseFileContent" } + + val skieSwiftFlowIterator = SkieSwiftFlowIteratorGenerator.generate() + SupportedFlowRuntimeGenerator.generate(skieSwiftFlowIterator) } private fun getSwiftRuntimeFiles(): List = diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/swift/SirCodeGenerator.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/swift/SirCodeGenerator.kt index 641ba4661..a750799f0 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/swift/SirCodeGenerator.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/phases/swift/SirCodeGenerator.kt @@ -6,13 +6,16 @@ import co.touchlab.skie.sir.element.SirConditionalConstraint import co.touchlab.skie.sir.element.SirConstructor import co.touchlab.skie.sir.element.SirDeclaration import co.touchlab.skie.sir.element.SirDeclarationWithScope +import co.touchlab.skie.sir.element.SirDeclarationWithVisibility import co.touchlab.skie.sir.element.SirElementWithAttributes import co.touchlab.skie.sir.element.SirElementWithFunctionBodyBuilder +import co.touchlab.skie.sir.element.SirElementWithModality import co.touchlab.skie.sir.element.SirElementWithModifiers import co.touchlab.skie.sir.element.SirEnumCase import co.touchlab.skie.sir.element.SirExtension import co.touchlab.skie.sir.element.SirFunction import co.touchlab.skie.sir.element.SirIrFile +import co.touchlab.skie.sir.element.SirModality import co.touchlab.skie.sir.element.SirOverridableDeclaration import co.touchlab.skie.sir.element.SirProperty import co.touchlab.skie.sir.element.SirScope @@ -103,15 +106,27 @@ object SirCodeGenerator { name = typeAlias.simpleName, type = typeAlias.type.toSwiftPoetTypeName(), ) - .addVisibility(typeAlias.visibility) + .addVisibility(typeAlias) .addTypeParameters(typeAlias) .build(), ) } - private fun T.addVisibility(visibility: SirVisibility): T = + private fun T.addVisibilityAndModality( + element: E, + ): T where E: SirElementWithModality, E: SirDeclarationWithVisibility = apply { - val visibilityModifier = visibility.toSwiftPoetVisibility() + if (!element.shouldHaveOpenModifier()) { + addVisibility(element) + } + addModifiers(*element.toSwiftPoetModality().toTypedArray()) + } + + private fun T.addVisibility( + declaration: SirDeclarationWithVisibility + ): T = + apply { + val visibilityModifier = declaration.visibility.toSwiftPoetVisibility() val defaultVisibilityModifier = SirVisibility.Internal.toSwiftPoetVisibility() if (visibilityModifier == defaultVisibilityModifier) { @@ -129,6 +144,25 @@ object SirCodeGenerator { SirVisibility.Removed -> error("Removed declarations should not be generated and must be filtered out sooner.") } + private fun E.shouldHaveOpenModifier(): Boolean where E: SirElementWithModality, E: SirDeclarationWithVisibility = + modality == SirModality.Open && visibility == SirVisibility.Public && (parent as? SirClass)?.modality == SirModality.Open + + private fun SirElementWithModality.shouldHaveFinalModifier(): Boolean = + when (this) { + is SirClass -> kind == SirClass.Kind.Class && modality == SirModality.Final + is SirSimpleFunction -> { + val parent = parent + modality == SirModality.Final && parent is SirClass && parent.modality != SirModality.Final && scope != SirScope.Static + } + is SirProperty -> false + } + + private fun E.toSwiftPoetModality(): Set where E: SirElementWithModality, E: SirDeclarationWithVisibility = + setOfNotNull( + Modifier.FINAL.takeIf { shouldHaveFinalModifier() }, + Modifier.OPEN.takeIf { shouldHaveOpenModifier() }, + ) + private fun T.addTypeParameters(parent: SirTypeParameterParent) = apply { parent.typeParameters.forEach { addTypeParameter(it) @@ -192,12 +226,14 @@ object SirCodeGenerator { addType( TypeSpec.Builder(sirClass.swiftPoetKind, sirClass.simpleName) - .addVisibility(sirClass.visibility) + .addVisibilityAndModality(sirClass) .addSuperTypes(sirClass.superTypes.map { it.toSwiftPoetTypeName() }) .addAttributes(sirClass) .addTypeParameters(sirClass) .addClassDeclarations(sirClass) .addEnumCases(sirClass) + .addDeinit(sirClass) + .addVisibilityAndModality(sirClass) .build(), ) } @@ -224,6 +260,23 @@ object SirCodeGenerator { } } + private fun TypeSpec.Builder.addDeinit(sirClass: SirClass): TypeSpec.Builder = + apply { + if (sirClass.deinitBuilder.isEmpty()) { + return@apply + } + + addFunction( + FunctionSpec.deinitializerBuilder() + .apply { + sirClass.deinitBuilder.forEach { + it() + } + } + .build(), + ) + } + private fun TypeSpec.Builder.addClassDeclaration(declaration: SirDeclaration) { when (declaration) { is SirTypeAlias -> generateTypeAlias(declaration) @@ -259,6 +312,7 @@ object SirCodeGenerator { .addOverrideIfNeeded(function) .addScope(function) .addTypeParameters(function) + .addVisibilityAndModality(function) .async(function.isAsync) .returns(function.returnType.toSwiftPoetTypeName()) .build(), @@ -277,6 +331,7 @@ object SirCodeGenerator { .addScope(property) .addGetter(property) .addSetter(property) + .addVisibilityAndModality(property) .build(), ) } @@ -318,6 +373,7 @@ object SirCodeGenerator { FunctionSpec.constructorBuilder() .addFunctionProperties(constructor) .applyIf(constructor.isConvenience) { addModifiers(Modifier.CONVENIENCE) } + .addVisibility(constructor) .build(), ) } @@ -333,7 +389,6 @@ object SirCodeGenerator { private fun T.addCallableDeclarationProperties(callableDeclaration: SirCallableDeclaration): T where T : BuilderWithModifiers, T : AttributedSpec.Builder<*> = this.apply { - addVisibility(callableDeclaration.visibility) addAttributes(callableDeclaration) addModifiers(callableDeclaration) } diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/builtin/SirBuiltin.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/builtin/SirBuiltin.kt index 4f66401ad..762c5eaca 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/builtin/SirBuiltin.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/builtin/SirBuiltin.kt @@ -26,6 +26,8 @@ class SirBuiltins( val Skie = Modules.Skie(globalConfiguration, sirProvider.skieModule) + val _Concurrency = Modules._Concurrency(sirProvider, Swift) + object Modules { class Swift(sirProvider: SirProvider) : ModuleBase() { @@ -104,56 +106,34 @@ class SirBuiltins( val unichar by TypeAlias { swift.UInt16.defaultType } } - class Skie( - private val globalConfiguration: GlobalConfiguration, - val module: SirModule.Skie, - ) : ModuleBase() { - - override val declarationParent: SirDeclarationParent = module.builtInFile - - override val origin: SirClass.Origin = SirClass.Origin.Generated - - // The SkieSwiftFlow classes are only stubs (correct super types, and content are currently not needed) - - val SkieSwiftFlow by RuntimeClass { - SirTypeParameter("T") - } - - val SkieSwiftSharedFlow by RuntimeClass { - SirTypeParameter("T") - } - - val SkieSwiftMutableSharedFlow by RuntimeClass { - SirTypeParameter("T") - } + class _Concurrency(sirProvider: SirProvider, swift: Swift) : ModuleBase() { + override val declarationParent = sirProvider.getExternalModule("_Concurrency").builtInFile - val SkieSwiftStateFlow by RuntimeClass { - SirTypeParameter("T") - } + override val origin = SirClass.Origin.ExternalSwiftFramework - val SkieSwiftMutableStateFlow by RuntimeClass { - SirTypeParameter("T") + val AsyncIteratorProtocol by Protocol { + SirTypeParameter("Element") } - val SkieSwiftOptionalFlow by RuntimeClass { - SirTypeParameter("T") + val AsyncSequence by Protocol { + SirTypeParameter("AsyncIterator", AsyncIteratorProtocol) + // TODO: Element is `==` bound to `AsyncIterator.Element`, how to represent it? + SirTypeParameter("Element") } - val SkieSwiftOptionalSharedFlow by RuntimeClass { - SirTypeParameter("T") - } + val CancellationError by Struct( + superTypes = listOf(swift.Error.defaultType) + ) + } - val SkieSwiftOptionalMutableSharedFlow by RuntimeClass { - SirTypeParameter("T") - } + class Skie( + private val globalConfiguration: GlobalConfiguration, + val module: SirModule.Skie, + ) : ModuleBase() { - val SkieSwiftOptionalStateFlow by RuntimeClass { - SirTypeParameter("T") - } + override val declarationParent: SirDeclarationParent = module.builtInFile - val SkieSwiftOptionalMutableStateFlow by RuntimeClass { - SirTypeParameter("T") - } + override val origin: SirClass.Origin = SirClass.Origin.Generated private fun RuntimeClass( superTypes: List = emptyList(), diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirClass.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirClass.kt index c769f2a1c..f06584270 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirClass.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirClass.kt @@ -6,12 +6,14 @@ import co.touchlab.skie.oir.element.kirClassOrNull import co.touchlab.skie.sir.SirFqName import co.touchlab.skie.sir.element.util.sirDeclarationParent import co.touchlab.skie.sir.type.SirDeclaredSirType +import io.outfoxx.swiftpoet.FunctionSpec class SirClass( override var baseName: String, parent: SirDeclarationParent, // Class requires explicit declaration of inheritance from AnyObject var kind: Kind, + override var modality: SirModality = coerceModalityForClass(kind), override var visibility: SirVisibility = SirVisibility.Public, override var isReplaced: Boolean = false, override var isHidden: Boolean = false, @@ -22,7 +24,7 @@ class SirClass( var isInherentlyHashable: Boolean = false, var isAlwaysAReference: Boolean = false, val origin: Origin = Origin.Generated, -) : SirTypeDeclaration, SirDeclarationNamespace, SirTypeParameterParent, SirElementWithAttributes { +) : SirTypeDeclaration, SirDeclarationNamespace, SirTypeParameterParent, SirElementWithAttributes, SirElementWithModality { // TODO If modality is added update [SirHierarchyCache.canTheoreticallyInheritFrom] @@ -51,6 +53,8 @@ class SirClass( val enumCases: MutableList = mutableListOf() + val deinitBuilder = mutableListOf Unit>() + /** * Actual fully qualified name (including module) of the declaration. Used by SKIE to generate code if possible. */ @@ -111,6 +115,7 @@ class SirClass( baseName: String, kind: Kind = Kind.Class, visibility: SirVisibility = SirVisibility.Public, + modality: SirModality = coerceModalityForClass(kind), isReplaced: Boolean = false, isHidden: Boolean = false, superTypes: List = emptyList(), @@ -124,6 +129,7 @@ class SirClass( baseName = baseName, parent = this@SirDeclarationParent, kind = kind, + modality = modality, visibility = visibility, isReplaced = isReplaced, isHidden = isHidden, @@ -178,3 +184,11 @@ val SirClass.oirClassOrNull: OirClass? val SirClass.kirClassOrNull: KirClass? get() = oirClassOrNull?.kirClassOrNull + +fun coerceModalityForClass(kind: SirClass.Kind): SirModality { + return when (kind) { + SirClass.Kind.Class -> SirModality.ModuleLimited + SirClass.Kind.Enum, SirClass.Kind.Struct -> SirModality.Final + SirClass.Kind.Protocol -> SirModality.Open + } +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirElementWithModality.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirElementWithModality.kt new file mode 100644 index 000000000..cfe4ffd1f --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirElementWithModality.kt @@ -0,0 +1,5 @@ +package co.touchlab.skie.sir.element + +sealed interface SirElementWithModality { + var modality: SirModality +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirModality.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirModality.kt new file mode 100644 index 000000000..dc90a9c74 --- /dev/null +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirModality.kt @@ -0,0 +1,7 @@ +package co.touchlab.skie.sir.element + +enum class SirModality { + Final, + ModuleLimited, + Open, +} diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirProperty.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirProperty.kt index 8f69394c5..4033793f7 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirProperty.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirProperty.kt @@ -12,6 +12,7 @@ class SirProperty( parent: SirDeclarationParent, var type: SirType, override var visibility: SirVisibility = SirVisibility.Public, + override var modality: SirModality = parent.coerceModalityForSimpleFunctionOrProperty(), override var isReplaced: Boolean = false, override var isHidden: Boolean = false, override var scope: SirScope = parent.coerceScope(SirScope.Member), @@ -19,7 +20,7 @@ class SirProperty( override val isFakeOverride: Boolean = false, attributes: List = emptyList(), modifiers: List = emptyList(), -) : SirOverridableDeclaration, SirCallableDeclaration { +) : SirOverridableDeclaration, SirCallableDeclaration, SirElementWithModality { override val parent: SirDeclarationParent by sirDeclarationParent(parent) @@ -84,6 +85,7 @@ class SirProperty( identifier: String, type: SirType, visibility: SirVisibility = SirVisibility.Public, + modality: SirModality = coerceModalityForSimpleFunctionOrProperty(), isReplaced: Boolean = false, isHidden: Boolean = false, scope: SirScope = coerceScope(SirScope.Member), @@ -97,6 +99,7 @@ class SirProperty( parent = this@SirDeclarationParent, type = type, visibility = visibility, + modality = modality, isReplaced = isReplaced, isHidden = isHidden, scope = scope, @@ -113,6 +116,7 @@ fun SirProperty.shallowCopy( parent: SirDeclarationParent = this.parent, type: SirType = this.type, visibility: SirVisibility = this.visibility, + modality: SirModality = parent.coerceModalityForSimpleFunctionOrProperty(this.modality), isReplaced: Boolean = this.isReplaced, isHidden: Boolean = this.isHidden, scope: SirScope = parent.coerceScope(this.scope), @@ -126,6 +130,7 @@ fun SirProperty.shallowCopy( parent = parent, type = type, visibility = visibility, + modality = modality, isReplaced = isReplaced, isHidden = isHidden, scope = scope, @@ -134,3 +139,6 @@ fun SirProperty.shallowCopy( attributes = attributes, modifiers = modifiers, ) + +val SirProperty.isOverriddenFromReadOnlyProperty: Boolean + get() = overriddenDeclarations.any { it.setter == null || it.isOverriddenFromReadOnlyProperty } diff --git a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirSimpleFunction.kt b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirSimpleFunction.kt index a3b464302..7927a5f61 100644 --- a/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirSimpleFunction.kt +++ b/SKIE/kotlin-compiler/core/src/commonMain/kotlin/co/touchlab/skie/sir/element/SirSimpleFunction.kt @@ -12,6 +12,7 @@ class SirSimpleFunction( parent: SirDeclarationParent, var returnType: SirType, override var visibility: SirVisibility = SirVisibility.Public, + override var modality: SirModality = parent.coerceModalityForSimpleFunctionOrProperty(), override var isReplaced: Boolean = false, override var isHidden: Boolean = false, override var scope: SirScope = parent.coerceScope(SirScope.Member), @@ -21,7 +22,7 @@ class SirSimpleFunction( var isAsync: Boolean = false, override var throws: Boolean = false, override val deprecationLevel: DeprecationLevel = DeprecationLevel.None, -) : SirFunction(attributes.toMutableList(), modifiers.toMutableList()), SirTypeParameterParent, SirOverridableDeclaration { +) : SirFunction(attributes.toMutableList(), modifiers.toMutableList()), SirTypeParameterParent, SirOverridableDeclaration, SirElementWithModality { override val identifierAfterVisibilityChange: String get() = if (isReplaced) "__$identifier" else identifier @@ -69,6 +70,7 @@ class SirSimpleFunction( identifier: String, returnType: SirType, visibility: SirVisibility = SirVisibility.Public, + modality: SirModality = coerceModalityForSimpleFunctionOrProperty(), isReplaced: Boolean = false, isHidden: Boolean = false, scope: SirScope = coerceScope(SirScope.Member), @@ -102,6 +104,7 @@ fun SirSimpleFunction.shallowCopy( parent: SirDeclarationParent = this.parent, returnType: SirType = this.returnType, visibility: SirVisibility = this.visibility, + modality: SirModality = parent.coerceModalityForSimpleFunctionOrProperty(this.modality), isReplaced: Boolean = this.isReplaced, isHidden: Boolean = this.isHidden, scope: SirScope = parent.coerceScope(this.scope), @@ -117,6 +120,7 @@ fun SirSimpleFunction.shallowCopy( parent = parent, returnType = returnType, visibility = visibility, + modality = modality, isReplaced = isReplaced, isHidden = isHidden, scope = scope, @@ -127,3 +131,13 @@ fun SirSimpleFunction.shallowCopy( throws = throws, deprecationLevel = deprecationLevel, ) + +fun SirDeclarationParent.coerceModalityForSimpleFunctionOrProperty(modality: SirModality = SirModality.ModuleLimited): SirModality { + return when (this) { + is SirClass -> when (this.modality) { + SirModality.Final -> SirModality.Final + SirModality.ModuleLimited, SirModality.Open -> modality + } + is SirExtension, SirDeclarationParent.None, is SirBuiltInFile, is SirIrFile -> SirModality.Final + } +} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftFlow.swift deleted file mode 100644 index 06ffa4b62..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftFlow.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Foundation - -public final class SkieSwiftFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T - - public typealias _ObjectiveCType = SkieKotlinFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.Flow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.Flow.__Kotlin) { - delegate = flow - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftFlow { - return SkieSwiftFlow(internal: source!) - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftFlowIterator.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftFlowIterator.swift deleted file mode 100644 index 43fb7b648..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftFlowIterator.swift +++ /dev/null @@ -1,40 +0,0 @@ -import Foundation - -public class SkieSwiftFlowIterator: _Concurrency.AsyncIteratorProtocol { - - public typealias Element = T - - private let iterator: SkieColdFlowIterator - - init(flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.Flow.__Kotlin) { - iterator = SkieColdFlowIterator(flow: flow) - } - - deinit { - iterator.cancel() - } - - public func next() async -> Element? { - do { - let hasNext = try await skie(iterator).hasNext() - - if (hasNext.boolValue) { - return .some(iterator.next() as! Element) - } else { - return nil - } - } catch is _Concurrency.CancellationError { - await cancelTask() - - return nil - } catch { - Swift.fatalError("Unexpected error: \(error)") - } - } - - private func cancelTask() async { - _Concurrency.withUnsafeCurrentTask { task in - task?.cancel() - } - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftMutableSharedFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftMutableSharedFlow.swift deleted file mode 100644 index 4b574e692..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftMutableSharedFlow.swift +++ /dev/null @@ -1,69 +0,0 @@ -import Foundation - -public final class SkieSwiftMutableSharedFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T - - public typealias _ObjectiveCType = SkieKotlinMutableSharedFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.MutableSharedFlow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.MutableSharedFlow.__Kotlin) { - delegate = flow - } - - public var replayCache: [T] { - return delegate.replayCache as! [T] - } - - public func emit(value: T) async throws { - try await delegate.emit(value: value) - } - - public func tryEmit(value: T) -> Bool { - return delegate.tryEmit(value: value) - } - - public var subscriptionCount: SkieSwiftStateFlow { - return bridgeSubscriptionCount(delegate.subscriptionCount) - } - - public func resetReplayCache() { - delegate.resetReplayCache() - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinMutableSharedFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftMutableSharedFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftMutableSharedFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftMutableSharedFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftMutableSharedFlow { - return SkieSwiftMutableSharedFlow(internal: source!) - } -} - -internal func bridgeSubscriptionCount(_ subscriptionCount: SkieSwiftStateFlow) -> SkieSwiftStateFlow { - return subscriptionCount -} - -internal func bridgeSubscriptionCount(_ subscriptionCount: any Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.StateFlow.__Kotlin) -> SkieSwiftStateFlow { - return SkieSwiftStateFlow(internal: subscriptionCount) -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftMutableStateFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftMutableStateFlow.swift deleted file mode 100644 index 3747ee24b..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftMutableStateFlow.swift +++ /dev/null @@ -1,70 +0,0 @@ -import Foundation - -public final class SkieSwiftMutableStateFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T - - public typealias _ObjectiveCType = SkieKotlinMutableStateFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.MutableStateFlow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.MutableStateFlow.__Kotlin) { - delegate = flow - } - - public var replayCache: [T] { - return delegate.replayCache as! [T] - } - - public func emit(value: T) async throws { - try await delegate.emit(value: value) - } - - public func tryEmit(value: T) -> Bool { - return delegate.tryEmit(value: value) - } - - public var subscriptionCount: SkieSwiftStateFlow { - return bridgeSubscriptionCount(delegate.subscriptionCount) - } - - public var value: T { - get { - return delegate.value as! T - } - set { - delegate.setValue(newValue) - } - } - - public func compareAndSet(expect: T, update: T) -> Bool { - return delegate.compareAndSet(expect: expect, update: update) - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinMutableStateFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftMutableStateFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftMutableStateFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftMutableStateFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftMutableStateFlow { - return SkieSwiftMutableStateFlow(internal: source!) - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalFlow.swift deleted file mode 100644 index 3f7921f49..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalFlow.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Foundation - -public final class SkieSwiftOptionalFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T? - - public typealias _ObjectiveCType = SkieKotlinOptionalFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.Flow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.Flow.__Kotlin) { - delegate = flow - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinOptionalFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalFlow { - return SkieSwiftOptionalFlow(internal: source!) - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalMutableSharedFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalMutableSharedFlow.swift deleted file mode 100644 index f3041869d..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalMutableSharedFlow.swift +++ /dev/null @@ -1,61 +0,0 @@ -import Foundation - -public final class SkieSwiftOptionalMutableSharedFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T? - - public typealias _ObjectiveCType = SkieKotlinOptionalMutableSharedFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.MutableSharedFlow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.MutableSharedFlow.__Kotlin) { - delegate = flow - } - - public var replayCache: [T?] { - return delegate.replayCache as! [T?] - } - - public func emit(value: T?) async throws { - try await delegate.emit(value: value) - } - - public func tryEmit(value: T?) -> Bool { - return delegate.tryEmit(value: value) - } - - public var subscriptionCount: SkieSwiftStateFlow { - return bridgeSubscriptionCount(delegate.subscriptionCount) - } - - public func resetReplayCache() { - delegate.resetReplayCache() - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinOptionalMutableSharedFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalMutableSharedFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalMutableSharedFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalMutableSharedFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalMutableSharedFlow { - return SkieSwiftOptionalMutableSharedFlow(internal: source!) - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalMutableStateFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalMutableStateFlow.swift deleted file mode 100644 index 6c2e5cbae..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalMutableStateFlow.swift +++ /dev/null @@ -1,70 +0,0 @@ -import Foundation - -public final class SkieSwiftOptionalMutableStateFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T? - - public typealias _ObjectiveCType = SkieKotlinOptionalMutableStateFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.MutableStateFlow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.MutableStateFlow.__Kotlin) { - delegate = flow - } - - public var replayCache: [T?] { - return delegate.replayCache as! [T?] - } - - public func emit(value: T?) async throws { - try await delegate.emit(value: value) - } - - public func tryEmit(value: T?) -> Bool { - return delegate.tryEmit(value: value) - } - - public var subscriptionCount: SkieSwiftStateFlow { - return bridgeSubscriptionCount(delegate.subscriptionCount) - } - - public var value: T? { - get { - return delegate.value as! T? - } - set { - delegate.setValue(newValue) - } - } - - public func compareAndSet(expect: T?, update: T?) -> Bool { - return delegate.compareAndSet(expect: expect, update: update) - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinOptionalMutableStateFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalMutableStateFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalMutableStateFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalMutableStateFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalMutableStateFlow { - return SkieSwiftOptionalMutableStateFlow(internal: source!) - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalSharedFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalSharedFlow.swift deleted file mode 100644 index 9c166a4ac..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalSharedFlow.swift +++ /dev/null @@ -1,45 +0,0 @@ -import Foundation - -public final class SkieSwiftOptionalSharedFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T? - - public typealias _ObjectiveCType = SkieKotlinOptionalSharedFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.SharedFlow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.SharedFlow.__Kotlin) { - delegate = flow - } - - public var replayCache: [T?] { - return delegate.replayCache as! [T?] - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinOptionalSharedFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalSharedFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalSharedFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalSharedFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalSharedFlow { - return SkieSwiftOptionalSharedFlow(internal: source!) - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalStateFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalStateFlow.swift deleted file mode 100644 index 4ab5a1b16..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftOptionalStateFlow.swift +++ /dev/null @@ -1,49 +0,0 @@ -import Foundation - -public final class SkieSwiftOptionalStateFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T? - - public typealias _ObjectiveCType = SkieKotlinOptionalStateFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.StateFlow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.StateFlow.__Kotlin) { - delegate = flow - } - - public var replayCache: [T?] { - return delegate.replayCache as! [T?] - } - - public var value: T? { - return delegate.value as! T? - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinOptionalStateFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalStateFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftOptionalStateFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalStateFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftOptionalStateFlow { - return SkieSwiftOptionalStateFlow(internal: source!) - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftSharedFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftSharedFlow.swift deleted file mode 100644 index 0e4735e1f..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftSharedFlow.swift +++ /dev/null @@ -1,45 +0,0 @@ -import Foundation - -public final class SkieSwiftSharedFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T - - public typealias _ObjectiveCType = SkieKotlinSharedFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.SharedFlow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.SharedFlow.__Kotlin) { - delegate = flow - } - - public var replayCache: [T] { - return delegate.replayCache as! [T] - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinSharedFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftSharedFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftSharedFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftSharedFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftSharedFlow { - return SkieSwiftSharedFlow(internal: source!) - } -} diff --git a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftStateFlow.swift b/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftStateFlow.swift deleted file mode 100644 index 251973f99..000000000 --- a/SKIE/runtime/swift/src/main/resources/co/touchlab/skie/runtime/coroutines/flow/SkieSwiftStateFlow.swift +++ /dev/null @@ -1,49 +0,0 @@ -import Foundation - -public final class SkieSwiftStateFlow: _Concurrency.AsyncSequence, Swift._ObjectiveCBridgeable { - - public typealias AsyncIterator = SkieSwiftFlowIterator - - public typealias Element = T - - public typealias _ObjectiveCType = SkieKotlinStateFlow - - internal let delegate: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.StateFlow.__Kotlin - - internal init(internal flow: Skie.org_jetbrains_kotlinx__kotlinx_coroutines_core.StateFlow.__Kotlin) { - delegate = flow - } - - public var replayCache: [T] { - return delegate.replayCache as! [T] - } - - public var value: T { - return delegate.value as! T - } - - public func makeAsyncIterator() -> SkieSwiftFlowIterator { - return SkieSwiftFlowIterator(flow: delegate) - } - - public func _bridgeToObjectiveC() -> _ObjectiveCType { - return SkieKotlinStateFlow(delegate) - } - - public static func _forceBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftStateFlow?) { - result = fromObjectiveC(source) - } - - public static func _conditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType, result: inout SkieSwiftStateFlow?) -> Bool { - result = fromObjectiveC(source) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftStateFlow { - return fromObjectiveC(source) - } - - private static func fromObjectiveC(_ source: _ObjectiveCType?) -> SkieSwiftStateFlow { - return SkieSwiftStateFlow(internal: source!) - } -}