{"record":{"id":"c7e107216281fbae","repo":"astral-sh/ruff","slug":"t-is-unsupported-use-box-t-rule","errorCode":null,"errorMessage":"`&T*` is unsupported; use `Box<[T]>`: {rule}","messagePattern":"`&T\\*` is unsupported; use `Box<\\[T\\]>`: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"crates/ruff_python_ast/generate.py","lineNumber":241,"sourceCode":"    if open_bracket_index == -1:\n        return rust_type_str\n    close_bracket_index = rust_type_str.rfind(\">\")\n    if close_bracket_index == -1 or close_bracket_index <= open_bracket_index:\n        raise ValueError(f\"Brackets are not balanced for type {rust_type_str}\")\n    inner_type = rust_type_str[open_bracket_index + 1 : close_bracket_index].strip()\n    inner_type = inner_type.replace(\"crate::\", \"\")\n    return inner_type\n\n\nclass SequenceKind(Enum):\n    VEC = \"vec\"\n    BOXED_SLICE = \"boxed_slice\"\n    THIN_VEC = \"thin_vec\"\n\n\ndef split_sequence_type(rule: str) -> tuple[SequenceKind | None, str]:\n    if \"&\" in rule:\n        raise ValueError(f\"`&T*` is unsupported; use `Box<[T]>`: {rule}\")\n\n    if \"*\" in rule:\n        if rule.endswith(\"*\") and rule.count(\"*\") == 1:\n            return SequenceKind.VEC, rule[:-1]\n        raise ValueError(f\"`*` must be at the end: {rule}\")\n\n    for prefix, suffix, sequence_kind in (\n        (\"Vec<\", \">\", SequenceKind.VEC),\n        (\"ThinVec<\", \">\", SequenceKind.THIN_VEC),\n        (\"Box<[\", \"]>\", SequenceKind.BOXED_SLICE),\n    ):\n        if rule.startswith(prefix):\n            if not rule.endswith(suffix):\n                raise ValueError(f\"Unclosed collection type: {rule}\")\n            return sequence_kind, rule[len(prefix) : -len(suffix)]\n\n    return None, rule\n","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/astral-sh/ruff/blob/d1087a4b9e03d253a88703f34e0869ee4b805456/crates/ruff_python_ast/generate.py#L223-L259","documentation":"split_sequence_type() maps AST DSL sequence rules to Rust collection kinds. A '&' in a rule denotes a reference type (e.g. '&Token*'), which the generated AST cannot own, so the generator rejects it outright and points to the supported owned spelling Box<[T]>.","triggerScenarios":"Writing an AST field rule that contains '&', such as 'names: &Token*' or 'keywords: &str*', then running the generate.py script.","commonSituations":"Porting a hand-written AST struct that stored borrowed slices; attempting to avoid boxing by storing references in a node; refactoring old ruff_python_ast code into the DSL.","solutions":["Replace the reference-sequence rule with the owned slice form Box<[T]>.","For a single owned value use Box<T>; for a growable sequence use Vec<T> or the T* shorthand.","Re-run the generator and review the output."],"exampleFix":"# before\nnames: &Token*\n\n# after\nnames: Box<[Token]>","handlingStrategy":"validation","validationCode":"def rule_ok(rule: str) -> bool:\n    return '&' not in rule  # reference types are rejected; use Box<[T]>","typeGuard":null,"tryCatchPattern":null,"preventionTips":["AST nodes own their children; never introduce '&' into field rules.","Use Box<[T]> for owned slices and the T* shorthand for Vec<T>."],"tags":["codegen","rust-ast","ownership","developer-tooling"],"backgroundTag":"codegen-dsl-parse-error","analyzedSha":"d1087a4b9e03d253a88703f34e0869ee4b805456","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}