swc-project/swc · error
invalid syntax
Error message
invalid syntax
What it means
The React display_name pass scans object literals (e.g. options passed to forwardRef/memo/createReactClass-like calls) for a `displayName` key. While matching property keys it treats Prop::Assign as impossible: `{a = 1}` assignment shorthand is cover grammar that is only valid inside destructuring patterns, so an object literal expression containing it is invalid syntax, hence unreachable!("invalid syntax").
Source
Thrown at crates/swc_ecma_transforms_react/src/display_name/mod.rs:215
fn is_key_display_name(prop: &PropOrSpread) -> bool {
match *prop {
PropOrSpread::Prop(ref prop) => match **prop {
Prop::Shorthand(ref i) => i.sym == "displayName",
Prop::Method(MethodProp { ref key, .. })
| Prop::Getter(GetterProp { ref key, .. })
| Prop::Setter(SetterProp { ref key, .. })
| Prop::KeyValue(KeyValueProp { ref key, .. }) => match *key {
PropName::Ident(ref i) => i.sym == "displayName",
PropName::Str(ref s) => {
matches!(s.value.as_str(), Some(value) if value == "displayName")
}
PropName::Num(..) => false,
PropName::BigInt(..) => false,
PropName::Computed(..) => false,
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
},
Prop::Assign(..) => unreachable!("invalid syntax"),
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
},
_ => false,
// TODO(kdy1): maybe.. handle spread
}
}
View on GitHub (pinned to 5176682b65)
Solutions
- Normalize the AST before the React transform: convert Prop::Assign to Prop::KeyValue (and bare shorthand to key:value).
- Fix the generator/codemod that produced `{a = b}` in expression position — it is invalid JavaScript.
- Report to the producer tool, not swc, when the AST provably contains Prop::Assign in an expression.
Example fix
// before: cover-grammar node left in an object expression
// ast: ObjectLit { props: [Prop::Assign { key: displayName, value }) }] }
// after
// ast: ObjectLit { props: [Prop::KeyValue { key: displayName, value }) }] }
// source equivalent: ({ displayName: 'Foo' }) Defensive patterns
Strategy: type-guard
Validate before calling
use swc_ecma_ast::{ObjectLit, Prop, PropOrSpread};
fn no_assign_props(o: &ObjectLit) -> bool {
o.props.iter().all(|p| !matches!(p, PropOrSpread::Prop(p) if matches!(**p, Prop::Assign(_))))
} Type guard
fn is_plain_object_expr(o: &ObjectLit) -> bool {
o.props.iter().all(|p| match p {
PropOrSpread::Prop(p) => !matches!(**p, Prop::Assign(_)),
PropOrSpread::Spread(_) => true,
})
} Prevention
- Normalize cover-grammar nodes (Prop::Assign) to KeyValue when moving patterns into expressions.
- Validate third-party ASTs before React/Babel-compat passes.
- Remember `{a = 1}` only parses inside destructuring patterns.
When it happens
Trigger: Feeding the React display_name transform an object expression containing Prop::Assign nodes — produced by custom transforms that turn object/array patterns into object literals, by lenient parsers, or by hand-built ASTs. Not reproducible from normal parsed source because the parser rejects it.
Common situations: Codemods migrating destructuring patterns into object expressions; ESLint/AST tooling feeding modified ASTs back into swc; tests constructing ObjectLit props manually.
Related errors
- assignment property be removed before generator pass
- attr_to_prop(JSXEmptyExpr)
- failed to parse jsx option {}: '{}' is not an expression
- empty expression container
- Duplicate __source is found
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/84baa88ce628a3fd.
Report an issue: GitHub.