Skip to content

Commit b9703dc

Browse files
authored
Fix bug with enum code generation (#4137)
2 parents 1b0f2a6 + 1d1cf7f commit b9703dc

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

.changelog/unknown-debug.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
applies_to: ["client"]
3+
authors: ["landonxjames"]
4+
references: ["smithy-rs#4137"]
5+
breaking: false
6+
new_feature: false
7+
bug_fix: true
8+
---
9+
10+
Fix bug with enum codegen
11+
12+
When the first enum generated has the `@sensitive` trait the opaque type
13+
underlying the `UnknownVariant` inherits that sensitivity. This means that
14+
it does not derive `Debug`. Since the module is only generated once this
15+
causes a problem for non-sensitive enums that rely on the type deriving
16+
`Debug` so that they can also derive `Debug`. We manually add `Debug` to
17+
the module so it will always be there since the `UnknownVariant` is not
18+
modeled and cannot be `@sensitive`.

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)