{"record":{"id":"6e0770eebadfc767","repo":"GraphiteEditor/Graphite","slug":"the-variant-type-message-should-be-defined-as","errorCode":null,"errorMessage":"The `{variant_type}` message should be defined as a struct-style (not tuple-style) enum variant to maintain consistent formatting across all editor messages.\nReplace `{field_types}` with named fields using {{curly braces}} instead of positional fields using (parentheses).","messagePattern":"The `(.+?)` message should be defined as a struct-style \\(not tuple-style\\) enum variant to maintain consistent formatting across all editor messages\\.\nReplace `(.+?)` with named fields using (.+?)\\} instead of positional fields using \\(parentheses\\)\\.","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"proc-macros/src/hierarchical_tree.rs","lineNumber":69,"sourceCode":"\t\t\t\t\t\tlet error_msg = match fields.unnamed.len() {\n\t\t\t\t\t\t\t0 => format!(\"Remove the unnecessary `()` from the `{variant_type}` message enum variant.\"),\n\t\t\t\t\t\t\t1 => {\n\t\t\t\t\t\t\t\tlet field_type = &fields.unnamed.first().unwrap().ty;\n\t\t\t\t\t\t\t\tformat!(\n\t\t\t\t\t\t\t\t\t\"The `{variant_type}` message should be defined as a struct-style (not tuple-style) enum variant to maintain consistent formatting across all editor messages.\\n\\\n\t\t\t\t\t\t\t\t\tReplace `{}` with a named field using {{curly braces}} instead of a positional field using (parentheses).\",\n\t\t\t\t\t\t\t\t\tfield_type.to_token_stream()\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_ => {\n\t\t\t\t\t\t\t\tlet field_types = fields.unnamed.iter().map(|f| f.ty.to_token_stream().to_string()).collect::<Vec<_>>().join(\", \");\n\t\t\t\t\t\t\t\tformat!(\n\t\t\t\t\t\t\t\t\t\"The `{variant_type}` message should be defined as a struct-style (not tuple-style) enum variant to maintain consistent formatting across all editor messages.\\n\\\n\t\t\t\t\t\t\t\t\tReplace `{field_types}` with named fields using {{curly braces}} instead of positional fields using (parentheses).\"\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tErr(syn::Error::new(Span::call_site(), error_msg))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tFields::Named(fields) => {\n\t\t\t\t\tlet names = fields.named.iter().map(|f| f.ident.as_ref().unwrap());\n\t\t\t\t\tlet ty = fields.named.iter().map(|f| clean_rust_type_syntax(f.ty.to_token_stream().to_string()));\n\t\t\t\t\tOk(quote! {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlet mut field_names = Vec::new();\n\t\t\t\t\t\t\t#(field_names.push(format!(\"{}: {}\",stringify!(#names), #ty));)*\n\t\t\t\t\t\t\tlet mut variant_tree = DebugMessageTree::new(stringify!(#variant_type));\n\t\t\t\t\t\t\tvariant_tree.add_fields(field_names);\n\t\t\t\t\t\t\tmessage_tree.add_variant(variant_tree);\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\t.collect();","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/proc-macros/src/hierarchical_tree.rs#L51-L87","documentation":"Every variant of a `HierarchicalTree`-derived enum must use named (struct-style) fields, not positional (tuple-style) fields. The macro renders each variant as a DebugMessageTree of `field_name: value` strings, and tuple variants have no field names to print — so the derive reports the offending variant and its positional field types and asks for curly-brace form.","triggerScenarios":"Declaring a variant like `AddLayer(u64, String)` inside an enum that derives `HierarchicalTree`. The `Fields::Unnamed` arm builds the error message listing the tuple field types.","commonSituations":"Adding a quick new message variant in tuple style (the ergonomic Rust default), or converting an existing enum to derive HierarchicalTree without restyling its variants. Note sibling macros such as editor_commands already enforce the named-field convention, so mixed codebases drift here first.","solutions":["Convert the offending variant to named fields: `AddLayer { id: u64, name: String }`.","Update construction sites to use `AddLayer { id, name }` struct-literal syntax (the compiler will list them all).","Scan the whole enum for other tuple-style variants — the macro reports one at a time."],"exampleFix":"// before\n#[derive(HierarchicalTree)]\nenum Message {\n\tAddLayer(u64, String),\n}\n\n// after\n#[derive(HierarchicalTree)]\nenum Message {\n\tAddLayer {\n\t\tid: u64,\n\t\tname: String,\n\t},\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize on struct-style (named-field) variants for all message enums.","Enable a clippy lint like `clippy::upper_case_acronyms`-style team convention or a custom lint pass to flag tuple variants in message crates.","Fix all variants in one pass after the first error — the macro reports them one at a time."],"tags":["rust","proc-macro","derive","enum-variants","named-fields"],"backgroundTag":"derive-macro-input-validation","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}