Skip to content

Commit

Permalink
Convert SwiftUI Flow Observing generating to SIR.
Browse files Browse the repository at this point in the history
  • Loading branch information
TadeasKriz committed Aug 11, 2024
1 parent b78dd55 commit 9d5a489
Show file tree
Hide file tree
Showing 51 changed files with 1,717 additions and 580 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import co.touchlab.skie.sir.element.SirIrFile
import co.touchlab.skie.sir.element.SirSimpleFunction
import co.touchlab.skie.sir.element.SirTypeParameter
import co.touchlab.skie.sir.element.SirValueParameter
import co.touchlab.skie.sir.element.toConformanceBound
import co.touchlab.skie.sir.element.toTypeParameterUsage
import co.touchlab.skie.sir.type.SirType
import co.touchlab.skie.sir.type.TypeParameterUsageSirType
Expand Down Expand Up @@ -119,7 +120,7 @@ class FlowConversionConstructorsGenerator(

SirConditionalConstraint(
typeParameter = typeParameter,
bounds = listOf(typeBound),
bounds = listOf(typeBound.toConformanceBound()),
)

bodyFactory(typeParameter)
Expand Down Expand Up @@ -155,7 +156,7 @@ class FlowConversionConstructorsGenerator(
).apply {
val typeParameter = SirTypeParameter(
name = "T",
bounds = listOf(typeBound),
bounds = listOf(typeBound.toConformanceBound()),
)

val flowTypeArgument = flowTypeArgumentFactory(typeParameter.toTypeParameterUsage())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import co.touchlab.skie.sir.element.SirTypeParameter
import co.touchlab.skie.sir.element.SirValueParameter
import co.touchlab.skie.sir.element.call
import co.touchlab.skie.sir.element.copyTypeParametersFrom
import co.touchlab.skie.sir.element.toConformanceBound
import co.touchlab.skie.sir.element.toTypeFromEnclosingTypeParameters
import co.touchlab.skie.sir.element.toTypeParameterUsage
import co.touchlab.skie.sir.type.SirType
Expand Down Expand Up @@ -63,7 +64,7 @@ class SealedFunctionGeneratorDelegate(
val sealedTypeParameter = SirTypeParameter(
name = "__Sealed",
bounds = listOf(
kirClass.originalSirClass.toTypeFromEnclosingTypeParameters(typeParameters),
kirClass.originalSirClass.toTypeFromEnclosingTypeParameters(typeParameters).toConformanceBound(),
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private fun SirClass.addSkieClassConstructor(suspendFunctionOwner: KirClass) {
SirValueParameter(
label = "_",
name = SkieClassSuspendGenerator.kotlinObjectVariableName,
type = suspendFunctionOwner.originalSirClass.toTypeFromEnclosingTypeParameters(typeParameters),
type = suspendFunctionOwner.originalSirClass.toTypeFromEnclosingTypeParameters(this@SirClass.typeParameters),
)

bodyBuilder.add {
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ object PropagateSirVisibilityToMembersPhase : SirPhase {
sirFunction.returnType.visibilityConstraint,
) +
sirFunction.valueParameters.map { it.type.visibilityConstraint } +
sirFunction.typeParameters.flatMap { typeParameter -> typeParameter.bounds.map { it.visibilityConstraint } }
sirFunction.typeParameters.flatMap { typeParameter -> typeParameter.bounds.map { it.type.visibilityConstraint } }

sirFunction.visibility = allConstraints.minimumVisibility()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import co.touchlab.skie.sir.SirFqName
import co.touchlab.skie.sir.element.SirClass
import co.touchlab.skie.sir.element.SirDeclarationParent
import co.touchlab.skie.sir.element.SirTypeParameter
import co.touchlab.skie.sir.element.toConformanceBound
import co.touchlab.skie.sir.element.toSirKind
import co.touchlab.skie.util.toSirVisibility

Expand Down Expand Up @@ -82,7 +83,7 @@ class CreateKotlinSirTypesPhase : SirPhase {
typeParameter.sirTypeParameter = SirTypeParameter(
name = typeParameter.name,
parent = sirClass,
bounds = listOf(sirBuiltins.Swift.AnyObject.defaultType),
bounds = listOf(sirBuiltins.Swift.AnyObject.defaultType.toConformanceBound()),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ object PropagateSirVisibilityToClassesPhase : SirPhase {
sirClass.namespace?.classDeclaration,
(sirClass.kirClassOrNull?.parent as? KirClass)?.originalSirClass,
) +
sirClass.typeParameters.flatMap { typeParameter -> typeParameter.bounds.flatMap { it.referencedClasses } }.toSet() +
sirClass.typeParameters.flatMap { typeParameter -> typeParameter.bounds.flatMap { it.type.referencedClasses } }.toSet() +
getSuperTypesDependencies()

private fun getSuperTypesDependencies(): List<SirClass> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ object PropagateSirVisibilityToTypeAliasesPhase : SirPhase {
sirTypeAlias.namespace?.classDeclaration?.visibility,
) +
sirTypeAlias.type.visibilityConstraint +
sirTypeAlias.typeParameters.flatMap { typeParameter -> typeParameter.bounds.map { it.visibilityConstraint } }
sirTypeAlias.typeParameters.flatMap { typeParameter -> typeParameter.bounds.map { it.type.visibilityConstraint } }

sirTypeAlias.visibility = allConstraints.minimumVisibility()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package co.touchlab.skie.phases.swift

import co.touchlab.skie.phases.swift.SirCodeGenerator.addSuperTypes
import co.touchlab.skie.phases.swift.SirCodeGenerator.addTypeParameters
import co.touchlab.skie.phases.swift.SirCodeGenerator.addTypeParametersOrAssociatedTypes
import co.touchlab.skie.phases.swift.SirCodeGenerator.toSwiftPoetTypeName
import co.touchlab.skie.sir.element.SirCallableDeclaration
import co.touchlab.skie.sir.element.SirClass
import co.touchlab.skie.sir.element.SirConditionalConstraint
import co.touchlab.skie.sir.element.SirConditionalConstraintParent
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.SirDeclarationWithSuperTypes
import co.touchlab.skie.sir.element.SirDeclarationWithVisibility
import co.touchlab.skie.sir.element.SirElementWithAttributes
import co.touchlab.skie.sir.element.SirElementWithFunctionBodyBuilder
Expand All @@ -30,6 +36,7 @@ import co.touchlab.skie.sir.type.SirType
import co.touchlab.skie.util.GeneratedBySkieComment
import io.outfoxx.swiftpoet.AttributeSpec
import io.outfoxx.swiftpoet.AttributedSpec
import io.outfoxx.swiftpoet.CodeBlock
import io.outfoxx.swiftpoet.ExtensionSpec
import io.outfoxx.swiftpoet.FileSpec
import io.outfoxx.swiftpoet.FunctionSpec
Expand All @@ -41,8 +48,12 @@ import io.outfoxx.swiftpoet.TypeAliasSpec
import io.outfoxx.swiftpoet.TypeName
import io.outfoxx.swiftpoet.TypeSpec
import io.outfoxx.swiftpoet.TypeVariableName
import io.outfoxx.swiftpoet.builder.BuilderWithAssociatedTypes
import io.outfoxx.swiftpoet.builder.BuilderWithConditionalConstraints
import io.outfoxx.swiftpoet.builder.BuilderWithDocs
import io.outfoxx.swiftpoet.builder.BuilderWithMembers
import io.outfoxx.swiftpoet.builder.BuilderWithModifiers
import io.outfoxx.swiftpoet.builder.BuilderWithSuperTypes
import io.outfoxx.swiftpoet.builder.BuilderWithTypeParameters
import io.outfoxx.swiftpoet.builder.BuilderWithTypeSpecs

Expand Down Expand Up @@ -106,12 +117,23 @@ object SirCodeGenerator {
name = typeAlias.simpleName,
type = typeAlias.type.toSwiftPoetTypeName(),
)
.addDoc(typeAlias)
.addVisibility(typeAlias)
.addTypeParameters(typeAlias)
.build(),
)
}

private fun <T: BuilderWithDocs<T>, E> T.addDoc(
element: E,
): T where E: SirDeclaration = apply {
if (element.documentation.isNotBlank()) {
addDoc(
CodeBlock.of("%L", element.documentation)
)
}
}

private fun <T : BuilderWithModifiers, E> T.addVisibilityAndModality(
element: E,
): T where E : SirElementWithModality, E : SirDeclarationWithVisibility =
Expand Down Expand Up @@ -163,38 +185,73 @@ object SirCodeGenerator {
Modifier.OPEN.takeIf { shouldHaveOpenModifier() },
)

private fun <B: BuilderWithAssociatedTypes<B>> B.addTypeParametersOrAssociatedTypes(parent: SirClass) = apply {
if (parent.kind == SirClass.Kind.Protocol) {
parent.typeParameters.forEach {
addAssociatedType(it)
}
} else {
this.addTypeParameters(parent)
}
}

private fun <B: BuilderWithAssociatedTypes<B>> B.addAssociatedType(typeDeclaration: SirTypeParameter) {
val bounds = typeDeclaration.bounds.map { it.toSwiftPoetTypeVariableNameBound() }

addAssociatedType(
TypeVariableName.typeVariable(typeDeclaration.name, bounds)
)

if (typeDeclaration.isPrimaryAssociatedType) {
addTypeVariable(
TypeVariableName.typeVariable(typeDeclaration.name)
)
}
}

private fun <T : BuilderWithTypeParameters> T.addTypeParameters(parent: SirTypeParameterParent) = apply {
parent.typeParameters.forEach {
addTypeParameter(it)
}
}

private fun BuilderWithTypeParameters.addTypeParameter(typeDeclaration: SirTypeParameter) {
val bounds = typeDeclaration.bounds.map { it.toSwiftPoetTypeName() }.map { TypeVariableName.Bound(it) }
val bounds = typeDeclaration.bounds.map { it.toSwiftPoetTypeVariableNameBound() }

addTypeVariable(
TypeVariableName.typeVariable(typeDeclaration.name, bounds),
)
}

private fun SirTypeParameter.Bound.toSwiftPoetTypeVariableNameBound(): TypeVariableName.Bound {
val constraint = when (this) {
is SirTypeParameter.Bound.Conformance -> TypeVariableName.Bound.Constraint.CONFORMS_TO
is SirTypeParameter.Bound.Equality -> TypeVariableName.Bound.Constraint.SAME_TYPE
}
return TypeVariableName.bound(constraint, type.toSwiftPoetTypeName())
}

private fun FileSpec.Builder.generateExtension(extension: SirExtension) {
addExtension(
ExtensionSpec.builder(extension.classDeclaration.internalName.toSwiftPoetDeclaredTypeName())
.addDoc(extension)
.addAttributes(extension)
.addConditionalConstraints(extension)
.addExtensionDeclarations(extension)
.addSuperTypes(extension)
.build(),
)
}

private fun ExtensionSpec.Builder.addConditionalConstraints(extension: SirExtension): ExtensionSpec.Builder =
private fun <B: BuilderWithConditionalConstraints<B>> B.addConditionalConstraints(parent: SirConditionalConstraintParent): B =
apply {
extension.conditionalConstraints.forEach {
parent.conditionalConstraints.forEach {
addConditionalConstraint(it)
}
}

private fun ExtensionSpec.Builder.addConditionalConstraint(conditionalConstraint: SirConditionalConstraint) {
val bounds = conditionalConstraint.bounds.map { it.toSwiftPoetTypeName() }.map { TypeVariableName.Bound(it) }
private fun <B: BuilderWithConditionalConstraints<B>> B.addConditionalConstraint(conditionalConstraint: SirConditionalConstraint) {
val bounds = conditionalConstraint.bounds.map { it.toSwiftPoetTypeVariableNameBound() }

addConditionalConstraint(
TypeVariableName.typeVariable(conditionalConstraint.typeParameter.name, bounds),
Expand Down Expand Up @@ -226,10 +283,11 @@ object SirCodeGenerator {

addType(
TypeSpec.Builder(sirClass.swiftPoetKind, sirClass.simpleName)
.addDoc(sirClass)
.addVisibilityAndModality(sirClass)
.addSuperTypes(sirClass.superTypes.map { it.toSwiftPoetTypeName() })
.addSuperTypes(sirClass)
.addAttributes(sirClass)
.addTypeParameters(sirClass)
.addTypeParametersOrAssociatedTypes(sirClass)
.addClassDeclarations(sirClass)
.addEnumCases(sirClass)
.addDeinit(sirClass)
Expand All @@ -238,6 +296,11 @@ object SirCodeGenerator {
)
}

private fun <B: BuilderWithSuperTypes<B>> B.addSuperTypes(sirDeclarationWithSuperTypes: SirDeclarationWithSuperTypes) =
apply {
addSuperTypes(sirDeclarationWithSuperTypes.superTypes.map { it.toSwiftPoetTypeName() })
}

private val SirClass.swiftPoetKind: TypeSpec.Kind
get() = when (kind) {
SirClass.Kind.Class -> TypeSpec.Kind.Class()
Expand Down Expand Up @@ -309,10 +372,12 @@ object SirCodeGenerator {

addFunction(
FunctionSpec.builder(function.identifierAfterVisibilityChange)
.addDoc(function)
.addFunctionProperties(function)
.addOverrideIfNeeded(function)
.addScope(function)
.addTypeParameters(function)
.addConditionalConstraints(function)
.addVisibilityAndModality(function)
.async(function.isAsync)
.returns(function.returnType.toSwiftPoetTypeName())
Expand All @@ -327,12 +392,14 @@ object SirCodeGenerator {

addProperty(
PropertySpec.builder(property.identifierAfterVisibilityChange, property.type.toSwiftPoetTypeName())
.addDoc(property)
.addCallableDeclarationProperties(property)
.addOverrideIfNeeded(property)
.addScope(property)
.addGetter(property)
.addSetter(property)
.addVisibilityAndModality(property)
.mutable(property.isMutable)
.build(),
)
}
Expand Down Expand Up @@ -372,8 +439,11 @@ object SirCodeGenerator {

addFunction(
FunctionSpec.constructorBuilder()
.addDoc(constructor)
.addFunctionProperties(constructor)
.applyIf(constructor.isConvenience) { addModifiers(Modifier.CONVENIENCE) }
.addTypeParameters(constructor)
.addConditionalConstraints(constructor)
.addVisibility(constructor)
.build(),
)
Expand All @@ -398,8 +468,12 @@ object SirCodeGenerator {
elementWithSwiftPoetBuilderModifications: SirElementWithFunctionBodyBuilder,
): FunctionSpec.Builder =
apply {
elementWithSwiftPoetBuilderModifications.bodyBuilder.forEach {
it(this)
if (elementWithSwiftPoetBuilderModifications.bodyBuilder.isNotEmpty()) {
elementWithSwiftPoetBuilderModifications.bodyBuilder.forEach {
it(this)
}
} else {
abstract = true
}
}

Expand Down Expand Up @@ -430,10 +504,14 @@ object SirCodeGenerator {

private fun FunctionSpec.Builder.addValueParameter(valueParameter: SirValueParameter) {
val builder = ParameterSpec.builder(valueParameter.label, valueParameter.name, valueParameter.type.toSwiftPoetTypeName())
.addAttributes(valueParameter)

if (valueParameter.inout) {
builder.addModifiers(Modifier.INOUT)
}
valueParameter.defaultValue?.let {
builder.defaultValue(it)
}

addParameter(builder.build())
}
Expand Down
Loading

0 comments on commit 9d5a489

Please sign in to comment.