-
-
Notifications
You must be signed in to change notification settings - Fork 833
Description
Would it be a pain if we merged AST Statement and Declaration types into one?
Currently:
pub enum Statement<'a> {
BlockStatement(Box<'a, BlockStatement<'a>>),
/* ... */
ModuleDeclaration(Box<'a, ModuleDeclaration<'a>>),
Declaration(Declaration<'a>),
}
pub enum Declaration<'a> {
VariableDeclaration(Box<'a, VariableDeclaration<'a>>),
/* ... */
TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>),
}Could we make it just 1 enum combining all the variants:
pub enum Statement<'a> {
// From `Statement`
BlockStatement(Box<'a, BlockStatement<'a>>),
/* ... */
ModuleDeclaration(Box<'a, ModuleDeclaration<'a>>),
// From `Declaration`
VariableDeclaration(Box<'a, VariableDeclaration<'a>>),
/* ... */
TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>),
}I'm asking because this would simplify #2409. It is still possible to make it work without this change, but it's a bit more brittle.
To explain:
For AST transfer, ideally we want all enums to be #[repr(u8)] so the byte value for each option's discriminant can be specified explicitly. Then they're completely locked and you can read the bytes representing a Statement in memory, and reliably interpret them.
But in this case, the compiler is cleverly merging the discriminants for Statement and Declaration using niche optimization, which means Statement is 16 bytes. If we make Statement #[repr(u8)], it disables the niche optimization, and Statement becomes 24 bytes. Not good!
There is a way around this without changing the types: Don't make Statement #[repr(u8)], and the compiler in practice is predictable in what discriminants it assigns. But the compiler makes no promise not to change that at any minute without warning, so while I don't think likely that it will break, it could break at any time.
To get to the point... It'd be simpler to sidestep the issue entirely by folding Declaration's variants into Statement. Question is how much of a pain would that be? So is it worth it?
NB: The same problem applies to a few other types (only ExportDefaultDeclarationKind and AssignmentTargetMaybeDefault that I'm aware of, but maybe there's a few more). But of course Statement is the one which gets used absolutely everywhere.