Skip to content

Commit

Permalink
Revert "[compiler] Add Enum.KNOWN__ as an intermediary interface (#6248
Browse files Browse the repository at this point in the history
…)"

This reverts commit b136060.
  • Loading branch information
martinbonnin committed Jan 9, 2025
1 parent e731692 commit fa4b540
Show file tree
Hide file tree
Showing 124 changed files with 1,531 additions and 209 deletions.
4 changes: 4 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
<<<<<<< HEAD
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
=======
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
>>>>>>> parent of b13606094f ([compiler] Add Enum.KNOWN__ as an intermediary interface (#6248))
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
3 changes: 0 additions & 3 deletions libraries/apollo-annotations/api/apollo-annotations.api
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ public abstract interface annotation class com/apollographql/apollo/annotations/
public abstract interface annotation class com/apollographql/apollo/annotations/ApolloInternal : java/lang/annotation/Annotation {
}

public abstract interface annotation class com/apollographql/apollo/annotations/ApolloPrivateEnumConstructor : java/lang/annotation/Annotation {
}

public abstract interface annotation class com/apollographql/apollo/annotations/ApolloRequiresOptIn : java/lang/annotation/Annotation {
}

4 changes: 0 additions & 4 deletions libraries/apollo-annotations/api/apollo-annotations.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ open annotation class com.apollographql.apollo.annotations/ApolloInternal : kotl
constructor <init>() // com.apollographql.apollo.annotations/ApolloInternal.<init>|<init>(){}[0]
}

open annotation class com.apollographql.apollo.annotations/ApolloPrivateEnumConstructor : kotlin/Annotation { // com.apollographql.apollo.annotations/ApolloPrivateEnumConstructor|null[0]
constructor <init>() // com.apollographql.apollo.annotations/ApolloPrivateEnumConstructor.<init>|<init>(){}[0]
}

open annotation class com.apollographql.apollo.annotations/ApolloRequiresOptIn : kotlin/Annotation { // com.apollographql.apollo.annotations/ApolloRequiresOptIn|null[0]
constructor <init>() // com.apollographql.apollo.annotations/ApolloRequiresOptIn.<init>|<init>(){}[0]
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ internal object Identifier {
const val copy = "copy"
const val Data = "Data"

const val cacheKeyForObject = "cacheKeyForObject"
const val field = "field"
const val __map = "__map"
const val __path = "__path"
const val __fields = "__fields"

Expand All @@ -58,16 +60,11 @@ internal object Identifier {
const val knownValues = "knownValues"
const val knownEntries = "knownEntries"

/**
* UNKNOWN__ and KNOWN__ should probably have been __UNKNOWN because GraphQL reserves the leading __ but it's too late now.
*
* All in all it's not too bad because typing 'U', 'N', ... is usually more intuitive and in the very unlikely event that
* there is a name clash, it can always be resolved with `@targetName`
*/
// extra underscores at the end to prevent potential name clashes
const val UNKNOWN__ = "UNKNOWN__"
const val KNOWN__ = "KNOWN__"
const val rawValue = "rawValue"
const val types = "types"
const val testResolver = "testResolver"
const val block = "block"
const val resolver = "resolver"
const val newBuilder = "newBuilder"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.apollographql.apollo.compiler.codegen.kotlin.operations.OperationSele
import com.apollographql.apollo.compiler.codegen.kotlin.operations.OperationVariablesAdapterBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.CustomScalarAdaptersBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumAsEnumBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumAsSealedInterfaceBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumAsSealedBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumResponseAdapterBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.InputObjectAdapterBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.InputObjectBuilder
Expand All @@ -49,6 +49,7 @@ import com.apollographql.apollo.compiler.generateMethodsKotlin
import com.apollographql.apollo.compiler.ir.DefaultIrSchema
import com.apollographql.apollo.compiler.ir.IrOperations
import com.apollographql.apollo.compiler.ir.IrSchema
import com.apollographql.apollo.compiler.ir.IrTargetObject
import com.apollographql.apollo.compiler.maybeTransform
import com.apollographql.apollo.compiler.operationoutput.OperationOutput
import com.apollographql.apollo.compiler.operationoutput.findOperationId
Expand Down Expand Up @@ -178,7 +179,7 @@ internal object KotlinCodegen {
}
irSchema.irEnums.forEach { irEnum ->
if (sealedClassesForEnumsMatching.any { Regex(it).matches(irEnum.name) }) {
builders.add(EnumAsSealedInterfaceBuilder(context, irEnum))
builders.add(EnumAsSealedBuilder(context, irEnum))
} else {
builders.add(EnumAsEnumBuilder(context, irEnum, addUnknownForEnums))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
* Symbols can be [ClassName] or [MemberName]
*/
internal object KotlinSymbols {
val ExecutableSchemaBuilder = ClassName(ClassNames.apolloExecutionPackageName, "ExecutableSchema", "Builder")
val Resolver = ClassName(ClassNames.apolloExecutionPackageName, "Resolver")
val ResolveInfo = ClassName(ClassNames.apolloExecutionPackageName, "ResolveInfo")
val Roots = ClassName(ClassNames.apolloExecutionPackageName, "Roots")
val Schema = ClassName(ClassNames.apolloAstPackageName, "Schema")
val ObjectType = ClassNames.ObjectType.toKotlinPoetClassName()
val ObjectTypeBuilder = ClassNames.ObjectTypeBuilder.toKotlinPoetClassName()
Expand Down Expand Up @@ -101,7 +105,6 @@ internal object KotlinSymbols {

val ApolloAdaptableWith = ClassName(ClassNames.apolloAnnotationsPackageName, "ApolloAdaptableWith")
val ApolloExperimental = ClassName(ClassNames.apolloAnnotationsPackageName, "ApolloExperimental")
val ApolloPrivateEnumConstructor = ClassName(ClassNames.apolloAnnotationsPackageName, "ApolloPrivateEnumConstructor")

val JsExport = ClassName("kotlin.js", "JsExport")

Expand All @@ -111,6 +114,7 @@ internal object KotlinSymbols {
val errorAware = MemberName(apolloApiPackageName, "errorAware")
val readTypename = MemberName(apolloApiJsonPackageName, "readTypename")
val buildData = MemberName(apolloApiPackageName, "buildData")
val GlobalBuilder = MemberName(apolloApiPackageName, "GlobalBuilder")
val assertOneOf = MemberName(apolloApiPackageName, "assertOneOf")
val missingField = MemberName(apolloApiPackageName, "missingField")
val FieldResult = ClassNames.FieldResult.toKotlinPoetClassName()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package com.apollographql.apollo.compiler.codegen.kotlin.schema

import com.apollographql.apollo.compiler.codegen.Identifier
import com.apollographql.apollo.compiler.codegen.Identifier.KNOWN__
import com.apollographql.apollo.compiler.codegen.Identifier.UNKNOWN__
import com.apollographql.apollo.compiler.codegen.Identifier.rawValue
import com.apollographql.apollo.compiler.codegen.Identifier.safeValueOf
import com.apollographql.apollo.compiler.codegen.kotlin.CgFile
import com.apollographql.apollo.compiler.codegen.kotlin.CgFileBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.KotlinSchemaContext
Expand All @@ -18,20 +14,18 @@ import com.apollographql.apollo.compiler.codegen.kotlin.schema.util.typeProperty
import com.apollographql.apollo.compiler.codegen.typePackageName
import com.apollographql.apollo.compiler.internal.escapeKotlinReservedWordInSealedClass
import com.apollographql.apollo.compiler.ir.IrEnum
import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.ParameterSpec
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.buildCodeBlock
import com.squareup.kotlinpoet.joinToCode
import com.squareup.kotlinpoet.withIndent

internal class EnumAsSealedInterfaceBuilder(
internal class EnumAsSealedBuilder(
private val context: KotlinSchemaContext,
private val enum: IrEnum,
) : CgFileBuilder {
Expand All @@ -56,23 +50,20 @@ internal class EnumAsSealedInterfaceBuilder(
return CgFile(
packageName = packageName,
fileName = simpleName,
typeSpecs = listOf(enum.toSealedInterfaceTypeSpec())
typeSpecs = listOf(enum.toSealedClassTypeSpec(), enum.unknownClassTypeSpec())
)
}

private fun IrEnum.toSealedInterfaceTypeSpec(): TypeSpec {
private fun IrEnum.toSealedClassTypeSpec(): TypeSpec {
return TypeSpec.interfaceBuilder(simpleName)
.maybeAddDescription(description)
// XXX: can an enum be made deprecated (and not only its values) ?
.addModifiers(KModifier.SEALED)
.addProperty(
PropertySpec.builder(rawValue, KotlinSymbols.String)
.build()
)
.addProperty(rawValuePropertySpec)
.addType(companionTypeSpec())
.addTypes(values.map { value ->
value.toObjectTypeSpec()
value.toObjectTypeSpec(selfClassName)
})
.addType(knownValueTypeSpec())
.addType(unknownValueTypeSpec())
.build()
}
Expand All @@ -85,12 +76,12 @@ internal class EnumAsSealedInterfaceBuilder(
.build()
}

private fun IrEnum.Value.toObjectTypeSpec(): TypeSpec {
private fun IrEnum.Value.toObjectTypeSpec(superClass: TypeName): TypeSpec {
return TypeSpec.objectBuilder(targetName.escapeKotlinReservedWordInSealedClass())
.maybeAddDeprecation(deprecationReason)
.maybeAddDescription(description)
.maybeAddRequiresOptIn(context.resolver, optInFeature)
.addSuperinterface(selfClassName.nestedClass(KNOWN__))
.addSuperinterface(superClass)
.addProperty(
PropertySpec.builder("rawValue", KotlinSymbols.String)
.addModifiers(KModifier.OVERRIDE)
Expand All @@ -100,99 +91,71 @@ internal class EnumAsSealedInterfaceBuilder(
.build()
}

private fun IrEnum.knownValueTypeSpec(): TypeSpec {
return TypeSpec.interfaceBuilder(KNOWN__)
.addKdoc("An enum value that is known at build time.")
private fun IrEnum.unknownValueTypeSpec(): TypeSpec {
return TypeSpec.interfaceBuilder("UNKNOWN__")
.addKdoc("An enum value that wasn't known at compile time.")
.addSuperinterface(selfClassName)
.addProperty(
PropertySpec.builder(rawValue, KotlinSymbols.String)
.addModifiers(KModifier.OVERRIDE)
.build()
)
.addModifiers(KModifier.SEALED)
.addAnnotation(AnnotationSpec.builder(KotlinSymbols.Suppress).addMember("%S", "ClassName").build())
.addProperty(unknownValueRawValuePropertySpec)
.build()
}

private fun IrEnum.unknownValueTypeSpec(): TypeSpec {
return TypeSpec.classBuilder(UNKNOWN__)
.addKdoc("An enum value that isn't known at build time.")
.addSuperinterface(selfClassName)
.primaryConstructor(
FunSpec.constructorBuilder()
.addAnnotation(AnnotationSpec.builder(KotlinSymbols.ApolloPrivateEnumConstructor).build())
.addParameter(rawValue, KotlinSymbols.String)
.build()
)
.addProperty(
PropertySpec.builder(rawValue, KotlinSymbols.String)
.addModifiers(KModifier.OVERRIDE)
.initializer(rawValue)
.build()
)
.addAnnotation(AnnotationSpec.builder(KotlinSymbols.Suppress).addMember("%S", "ClassName").build())
private fun IrEnum.unknownClassTypeSpec(): TypeSpec {
return TypeSpec.classBuilder("UNKNOWN__${simpleName}")
.addSuperinterface(unknownValueInterfaceName())
.primaryConstructor(unknownValuePrimaryConstructorSpec)
.addProperty(unknownValueRawValuePropertySpecWithInitializer)
.addModifiers(KModifier.PRIVATE)
.addFunction(
FunSpec.builder("equals")
.addModifiers(KModifier.OVERRIDE)
.addParameter(ParameterSpec("other", KotlinSymbols.Any.copy(nullable = true)))
.returns(KotlinSymbols.Boolean)
.addCode("if (other !is $UNKNOWN__) return false\n",)
.addCode("return this.$rawValue == other.rawValue")
.addCode("if (other !is %T) return false\n", unknownValueClassName())
.addCode("return this.rawValue == other.rawValue")
.build()
)
.addFunction(
FunSpec.builder("hashCode")
.addModifiers(KModifier.OVERRIDE)
.returns(KotlinSymbols.Int)
.addCode("return this.$rawValue.hashCode()")
.addCode("return this.rawValue.hashCode()")
.build()
)
.addFunction(
FunSpec.builder("toString")
.addModifiers(KModifier.OVERRIDE)
.returns(KotlinSymbols.String)
.addCode("return \"$UNKNOWN__(${'$'}$rawValue)\"")
.addCode("return \"UNKNOWN__(${'$'}rawValue)\"")
.build()
)
.build()
}

private fun IrEnum.safeValueOfFunSpec(): FunSpec {
return FunSpec.builder(safeValueOf)
return FunSpec.builder(Identifier.safeValueOf)
.addKdoc(
"""
Returns an instance of [%T] representing [$rawValue].
The returned value may be an instance of [$UNKNOWN__] if the enum value is not known at build time.
You may want to update your schema instead of calling this function directly.
""".trimIndent(),
"Returns the [%T] that represents the specified [rawValue].\n" +
"Note: unknown values of [rawValue] will return [UNKNOWN__]. You may want to update your schema instead of calling this function directly.\n",
selfClassName
)
.addSuppressions(enum.values.any { it.deprecationReason != null })
.maybeAddOptIn(context.resolver, enum.values)
.addParameter(rawValue, KotlinSymbols.String)
.addParameter("rawValue", KotlinSymbols.String)
.returns(selfClassName)
.beginControlFlow("return when($rawValue)")
.beginControlFlow("return when(rawValue)")
.addCode(
values
.map { CodeBlock.of("%S -> %T", it.name, it.valueClassName()) }
.joinToCode(separator = "\n", suffix = "\n")
)
.addCode(buildCodeBlock {
add("else -> {\n")
withIndent {
add("@%T(%T::class)\n", KotlinSymbols.OptIn, KotlinSymbols.ApolloPrivateEnumConstructor)
add("$UNKNOWN__($rawValue)\n")
}
add("}\n")
})
.addCode("else -> %T(rawValue)\n", unknownValueClassName())
.endControlFlow()
.build()
}

private fun IrEnum.knownValuesFunSpec(): FunSpec {
return FunSpec.builder(Identifier.knownValues)
.addKdoc("Returns all [%T] known at build time", selfClassName)
.addKdoc("Returns all [%T] known at compile time", selfClassName)
.addSuppressions(enum.values.any { it.deprecationReason != null })
.maybeAddOptIn(context.resolver, enum.values)
.returns(KotlinSymbols.Array.parameterizedBy(selfClassName))
Expand All @@ -216,4 +179,31 @@ internal class EnumAsSealedInterfaceBuilder(
return ClassName(selfClassName.packageName, selfClassName.simpleName, targetName.escapeKotlinReservedWordInSealedClass())
}

private fun unknownValueInterfaceName(): ClassName {
return ClassName(selfClassName.packageName, selfClassName.simpleName, "UNKNOWN__")
}

private fun unknownValueClassName(): ClassName {
return ClassName(selfClassName.packageName, "UNKNOWN__${selfClassName.simpleName}")
}

private val unknownValuePrimaryConstructorSpec =
FunSpec.constructorBuilder()
.addParameter("rawValue", KotlinSymbols.String)
.build()

private val unknownValueRawValuePropertySpec =
PropertySpec.builder("rawValue", KotlinSymbols.String)
.addModifiers(KModifier.OVERRIDE)
.build()

private val unknownValueRawValuePropertySpecWithInitializer =
PropertySpec.builder("rawValue", KotlinSymbols.String)
.addModifiers(KModifier.OVERRIDE)
.initializer("rawValue")
.build()

private val rawValuePropertySpec =
PropertySpec.builder("rawValue", KotlinSymbols.String)
.build()
}
Loading

0 comments on commit fa4b540

Please sign in to comment.