Summary
The generated impl From<u16> for Tcl falls back to Self::Error — the Tcl
error keyword (discriminant 13, display "error") — instead of the
tree-sitter ERROR sentinel, which the generator renamed to Tcl::Error2
(discriminant 120, display "ERROR"). Every other language module's From<u16>
fallback correctly points to the ERROR sentinel.
Location
src/languages/language_tcl.rs:263-268 (generated From<u16> impl)
- Root cause:
enums/templates/rust.rs:30 (hardcoded Self::Error) +
enums/src/common.rs:170-184 (ERROR-sentinel rename logic)
Evidence
The Tcl grammar (tree-sitter-tcl =1.1.0, vendored) has two distinct
Error-named symbols after camel-casing:
anon_sym_error = 13 -> the Tcl error command keyword (display "error")
- the appended tree-sitter ERROR sentinel (display
"ERROR")
The generator anticipates exactly this collision and renames the sentinel
(enums/src/common.rs:171-184):
// The tree-sitter ERROR sentinel is appended last. If the grammar already
// defines an "error" keyword that camel-cased to "Error", increment the
// counter so this sentinel gets a unique name (e.g. "Error2").
let error_name = match name_count.entry("Error".to_string()) { ... };
names.push((error_name, false, "ERROR".to_string()));
So the enum correctly emits both variants:
Error = 13, // => "error"
...
Error2 = 120, // => "ERROR"
But the From<u16> template body is hardcoded and never consumes
error_name (enums/templates/rust.rs:30):
num_traits::FromPrimitive::from_u16(x).unwrap_or(Self::Error)
Result in the generated file (language_tcl.rs:263-268):
impl From<u16> for Tcl {
fn from(x: u16) -> Self {
num_traits::FromPrimitive::from_u16(x).unwrap_or(Self::Error) // id 13, the keyword
}
}
Cross-module comparison (every other module's fallback == its ERROR sentinel;
Tcl is the lone outlier):
language_python.rs ERROR_sentinel=Error(id=274) fallback=Self::Error(id=274)
language_rust.rs ERROR_sentinel=Error(id=355) fallback=Self::Error(id=355)
...
language_tcl.rs ERROR_sentinel=Error2(id=120) fallback=Self::Error(id=13) <-- wrong
Tcl is uniquely affected: it is the only vendored grammar whose keyword set
includes error (irules, the other Tcl dialect, has no such keyword and is
unaffected).
Expected Behavior
From<u16> for an out-of-range symbol id (e.g. the real tree-sitter ERROR
symbol) should map to the ERROR sentinel variant Tcl::Error2 (display
"ERROR"), matching the contract every other language module upholds.
Actual Behavior
Out-of-range / unknown symbol ids map to Tcl::Error — the Tcl error
command keyword (display "error") — silently misclassifying an
error/unknown node as a valid error command token.
Impact
Currently latent: no metric, checker, getter, or alterator pattern-matches
on Tcl::Error or Tcl::Error2 (both appear only in the generated
From<Tcl> for &str impl), and is_error uses tree-sitter's node.has_error()
directly rather than the enum. So there is no observable behavioral effect today.
The risk is forward-looking: any future code that matches Tcl::Error2 to
detect error nodes, or that relies on From<u16> of an unknown id yielding the
ERROR sentinel, would silently misbehave for Tcl only — the kind of
single-language divergence the mirrored-module design is meant to prevent. The
generated artifact already diverges from the invariant all sibling modules hold.
Generator-only fix
language_tcl.rs is machine-generated (Code generated; DO NOT EDIT.); do not
hand-edit it. The fix belongs in the enums/ generator/template.
Summary
The generated
impl From<u16> for Tclfalls back toSelf::Error— the Tclerrorkeyword (discriminant 13, display"error") — instead of thetree-sitter
ERRORsentinel, which the generator renamed toTcl::Error2(discriminant 120, display
"ERROR"). Every other language module'sFrom<u16>fallback correctly points to the ERROR sentinel.
Location
src/languages/language_tcl.rs:263-268(generatedFrom<u16>impl)enums/templates/rust.rs:30(hardcodedSelf::Error) +enums/src/common.rs:170-184(ERROR-sentinel rename logic)Evidence
The Tcl grammar (
tree-sitter-tcl=1.1.0, vendored) has two distinctError-named symbols after camel-casing:anon_sym_error = 13-> the Tclerrorcommand keyword (display"error")"ERROR")The generator anticipates exactly this collision and renames the sentinel
(
enums/src/common.rs:171-184):So the enum correctly emits both variants:
But the
From<u16>template body is hardcoded and never consumeserror_name(enums/templates/rust.rs:30):Result in the generated file (
language_tcl.rs:263-268):Cross-module comparison (every other module's fallback == its ERROR sentinel;
Tcl is the lone outlier):
Tcl is uniquely affected: it is the only vendored grammar whose keyword set
includes
error(irules, the other Tcl dialect, has no such keyword and isunaffected).
Expected Behavior
From<u16>for an out-of-range symbol id (e.g. the real tree-sitter ERRORsymbol) should map to the ERROR sentinel variant
Tcl::Error2(display"ERROR"), matching the contract every other language module upholds.Actual Behavior
Out-of-range / unknown symbol ids map to
Tcl::Error— the Tclerrorcommand keyword (display
"error") — silently misclassifying anerror/unknown node as a valid
errorcommand token.Impact
Currently latent: no metric, checker, getter, or alterator pattern-matches
on
Tcl::ErrororTcl::Error2(both appear only in the generatedFrom<Tcl> for &strimpl), andis_erroruses tree-sitter'snode.has_error()directly rather than the enum. So there is no observable behavioral effect today.
The risk is forward-looking: any future code that matches
Tcl::Error2todetect error nodes, or that relies on
From<u16>of an unknown id yielding theERROR sentinel, would silently misbehave for Tcl only — the kind of
single-language divergence the mirrored-module design is meant to prevent. The
generated artifact already diverges from the invariant all sibling modules hold.
Generator-only fix
language_tcl.rsis machine-generated (Code generated; DO NOT EDIT.); do nothand-edit it. The fix belongs in the
enums/generator/template.