Skip to content

Commit eaf5deb

Browse files
committed
Fix bug with enum codegen
When the first enum generated has the @sensitive trait the opaque type underlying the Unknown variant inherits that sensitivity. This means that it does not derive Debug. Since the module is only generated once this causes a problem for non-sensitive enums that rely on the type deriving Debug so that they can also derive Debug.
1 parent 1b0f2a6 commit eaf5deb

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,12 @@ data class InfallibleEnumType(
194194
This is not intended to be used directly.
195195
""".trimIndent(),
196196
)
197-
context.enumMeta.render(this)
197+
198+
// The UnknownVariant's underlying opaque type should always derive `Debug`. If this isn't explicitly
199+
// added and the first enum to render this module has the `@sensitive` trait then the UnknownVariant
200+
// inherits that sensitivity and does not derive `Debug`. This leads to issues deriving `Debug` for
201+
// all enum variants that are not marked `@sensitive`.
202+
context.enumMeta.withDerives(RuntimeType.Debug).render(this)
198203
rustTemplate("struct $UNKNOWN_VARIANT_VALUE(pub(crate) #{String});", *preludeScope)
199204
rustBlock("impl $UNKNOWN_VARIANT_VALUE") {
200205
// The generated as_str is not pub as we need to prevent users from calling it on this opaque struct.

codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGeneratorTest.kt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,55 @@ class ClientEnumGeneratorTest {
106106
project.compileAndTest()
107107
}
108108

109+
// The idempotency of RustModules paired with Smithy's alphabetic order shape iteration meant that
110+
// if an @sensitive enum was the first enum generated that the opaque type underlying the Unknown
111+
// variant would not derive Debug, breaking all non-@sensitive enums
112+
@Test
113+
fun `sensitive enum in earlier alphabetic order does not break non-sensitive enums`() {
114+
val model =
115+
"""
116+
namespace test
117+
118+
@sensitive
119+
@enum([
120+
{ name: "Foo", value: "Foo" },
121+
{ name: "Bar", value: "Bar" },
122+
])
123+
string FooA
124+
125+
@enum([
126+
{ name: "Baz", value: "Baz" },
127+
{ name: "Ahh", value: "Ahh" },
128+
])
129+
string FooB
130+
""".asSmithyModel()
131+
132+
val shapeA = model.lookup<StringShape>("test#FooA")
133+
val shapeB = model.lookup<StringShape>("test#FooB")
134+
val context = testClientCodegenContext(model)
135+
val project = TestWorkspace.testProject(context.symbolProvider)
136+
project.moduleFor(shapeA) {
137+
ClientEnumGenerator(context, shapeA).render(this)
138+
}
139+
project.moduleFor(shapeB) {
140+
ClientEnumGenerator(context, shapeB).render(this)
141+
unitTest(
142+
"impl_debug_for_non_sensitive_enum_should_implement_the_derived_debug_trait",
143+
"""
144+
assert_eq!(format!("{:?}", FooB::Baz), "Baz");
145+
assert_eq!(format!("{:?}", FooB::Ahh), "Ahh");
146+
assert_eq!(format!("{}", FooB::Baz), "Baz");
147+
assert_eq!(FooB::Ahh.to_string(), "Ahh");
148+
assert_eq!(
149+
format!("{:?}", FooB::from("Bar")),
150+
"Unknown(UnknownVariantValue(\"Bar\"))"
151+
);
152+
""",
153+
)
154+
}
155+
project.compileAndTest()
156+
}
157+
109158
@Test
110159
fun `it escapes the Unknown variant if the enum has an unknown value in the model`() {
111160
val model =

0 commit comments

Comments
 (0)