VisualBasic.Grammar.g4: required list children emitted as '*' instead of '+' (HandleList ignores optionality; C# generator honors MinCount)
help wantedLanguage-VBArea-Compilers
**Version Used:** `main` @ a213b74a81f3e66512c01d5e8f146cd05720cfe7 (file last regenerated in #47618)
**Area:** VisualBasicSyntaxGenerator, output file [`VisualBasic.Grammar.g4`](https://github.com/dotnet/roslyn/blob/a213b74a81f3e66512c01d5e8f146cd05720cfe7/src/Compilers/VisualBasic/Portable/Generated/VisualBasic.Grammar.g4)
### Summary
The VB grammar generator emits **every** plain (non-separated) list child as `*` (zero-or-more), ignoring whether the child is declared optional in `Syntax.xml`. The C# generator distinguishes these cases (`MinCount == 0 ? "*" : "+"`). As a result, eleven productions in the published VB grammar accept empty derivations the syntax model forbids, e.g.:
```antlr
array_type
: type array_rank_specifier* // an "array type" with no rank specifier is just `type`
;
xml_text
: xml_text_token* // an XML text node with no text
;
query_expression
: query_clause* // a query with no clauses — matches the empty string
;
```
Compare the C# grammar, generated from the equivalent model shape: [`array_type : type array_rank_specifier+`](https://github.com/dotnet/roslyn/blob/a213b74a81f3e66512c01d5e8f146cd05720cfe7/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4) (plus, not star; `ArrayTypeSyntax.RankSpecifiers` has `MinCount="1"` in the C# `Syntax.xml`).
### Root cause
[`HandleList`, `GrammarGenerator.vb` L205–L207](https://github.com/dotnet/roslyn/blob/a213b74a81f3e66512c01d5e8f146cd05720cfe7/src/Tools/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/Grammar/GrammarGenerator.vb#L205-L207):
```vb
Private Function HandleList(structureNode As ParseNodeStructure, child As ParseNodeChild) As Production
Return HandleChildKind(structureNode, child, child.ChildKind).Suffix("*")
End Function
```
`Suffix("*")` is unconditional. The VB syntax model *does* make the distinction the generator discards: optional lists carry `optional="true"` (e.g. [`ModifiedIdentifierSyntax.ArrayRankSpecifiers`, Syntax.xml L5571](https://github.com/dotnet/roslyn/blob/a213b74a81f3e66512c01d5e8f146cd05720cfe7/src/Compilers/VisualBasic/Portable/Syntax/Syntax.xml#L5571)) while required lists do not (e.g. [`ArrayTypeSyntax.RankSpecifiers`](https://github.com/dotnet/roslyn/blob/a213b74a81f3e66512c01d5e8f146cd05720cfe7/src/Compilers/VisualBasic/Portable/Syntax/Syntax.xml#L7405)). The sibling `HandleSeparatedList` (L196–L203) already honors `child.MinCount`; plain lists should analogously emit `+` when the child is not optional — `Suffix(If(child.IsOptional, "*", "+"))`.
Affected children (all plain-list, not `optional="true"`): `PropertyBlockSyntax.Accessors`, `EventBlockSyntax.Accessors`, `LocalDeclarationStatementSyntax.Modifiers`, `QueryExpressionSyntax.Clauses`, `XmlElementSyntax.Content`, `XmlTextSyntax.TextTokens`, `XmlCommentSyntax.TextTokens`, `XmlProcessingInstructionSyntax.TextTokens`, `XmlCDataSectionSyntax.TextTokens`, `ArrayTypeSyntax.RankSpecifiers`, `InterpolatedStringExpressionSyntax.Contents`.
One caveat: honoring the flag will also surface a few `Syntax.xml` annotations that look inaccurate themselves — e.g. `XmlElementSyntax.Content` is not marked optional, yet `<a></a>` is legal and produces an empty `Content` list. So the complete fix is generator + an audit of the eleven annotations; today the generator makes the two cases indistinguishable, so such model inconsistencies are invisible.
### Why it matters
Beyond fidelity, two of these make the grammar structurally degenerate for any consumer: `array_type : type array_rank_specifier*` lets `array_type` derive bare `type` (an epsilon unit-cycle inside the `type` hierarchy), and `query_expression`/`xml_text` matching the empty string produces empty-closure ambiguities everywhere they appear under `*`/`?` (ANTLR reports these as `error(153)`/`warning(154)` when the neighbouring issues are patched).
### Steps to Reproduce
```bash
curl -sLo vb.g4 https://raw.githubusercontent.com/dotnet/roslyn/main/src/Compilers/VisualBasic/Portable/Generated/VisualBasic.Grammar.g4
grep -A2 -E '^(array_type|xml_text|query_expression)$' vb.g4
```
### Expected Behavior
Required lists emitted as `+`; only `optional="true"` lists emitted as `*` — matching both the syntax model and the C# generator's behavior.
### Actual Behavior
All plain lists emitted as `*`.
Related: sibling reports from the same review: #84633; precedent #47594 / #47618.
0 条评论