google / google/pdl

[Rust Generator] Packet specialization match arms sorted alphabetically instead of preserving declaration order or specificity

Open
#184 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
86
Forks
18
Avg merge
20h 49m
Merged PRs (30d)
1

Description

### Description
In the Rust code generator (`pdlc --output-format rust`), child packet specialization match arms in `specialize()` / `decode()` are generated in alphabetical order of the packet struct names rather than preserving declaration order or ordering by specificity (e.g. evaluating child packets with more discriminant constraints before generic base/intermediate packets).

When a more specific child packet's name alphabetically follows a more generic sibling or parent packet's name, the generic match arm is evaluated first and greedily matches the buffer, masking the specific child packet and dropping child-specific fields.

---

### Minimal Reproducible Example

Consider the following mock PDL definitions:

```pdl
enum MessageType : 8 {
CONTROL = 1,
DATA = 2,
}

enum Subtype : 8 {
DEFAULT = 0,
EXTENDED = 1,
}

packet Message {
msg_type: MessageType,
subtype: Subtype,
_payload_,
}

// 1. Generic base child (matches any CONTROL message)
packet GenericControlMessage : Message (msg_type = CONTROL) {
}

// 2. Specific child with an additional constraint and extra fields
packet SpecificControlMessage : Message (msg_type = CONTROL, subtype = EXTENDED) {
extended_param: 8,
}
```

### Observed Behavior
Because the generated Rust parser orders match arms alphabetically:
1. `GenericControlMessage` ('G') is placed **before** `SpecificControlMessage` ('S').
2. When parsing a buffer for `SpecificControlMessage` (`msg_type = CONTROL`, `subtype = EXTENDED`, `extended_param = 0x42`):
- The parser evaluates `GenericControlMessage` first.
- Because `GenericControlMessage` only checks `msg_type = CONTROL`, the match succeeds.
- `extended_param` is swallowed into unparsed trailing payload rather than decoding into `SpecificControlMessage`.
- `SpecificControlMessage` is never reached.

*Note: If the specific packet were renamed to `ASpecificControlMessage`, it would match correctly simply because `'A' < 'G'`.*

---

### Expected Behavior
The Rust backend should generate specialization match arms either:
1. **Preserving declaration order** as written in the `.pdl` file (allowing authors to declare specific variants before generic fallback variants).
2. **Ordering by constraint specificity** (child packets with more discriminant constraints evaluated before variants with fewer constraints).

---

### Environment
* PDL Compiler: `pdlc --output-format rust`
* Target Language: Rust

Contributor guide

Open the contributing guide

Research direction

Start by running the minimal PDL example with `pdlc --output-format rust` and inspect the generated `specialize()` and `decode()` match arms. Trace where child packet arms are ordered, then determine whether declaration order or discriminant specificity is the intended rule. Done means a specific child is evaluated before a generic matching sibling and its child-specific fields are decoded rather than treated as trailing payload.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.