Unqualified type name emitted for a self-referential struct with an `_array` field of pointers to itself
- Dominant language
- Rust
- Stars
- 11
- Forks
- 1
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 47
Description
**Versions:** PAL `a9ebbed` · F\*/Pulse nightly `2026-08-27` · Clang 20.1.8
## Summary
When a struct is **self-referential** *and* has an **`_array` field whose element type is a pointer to that same struct**, PAL emits an **unqualified** type name into the generated typedef module, and F\* cannot resolve it.
Translation reports no errors; the failure appears in generated code.
## Minimal repro
```c
#include "pal.h"
/* 1: TRIGGERS THE BUG */
typedef struct node_t {
struct node_t *next;
_array struct node_t **to_nodes; /* array of pointers to the SAME struct */
int n;
} node_t;
int f1(node_t *p) _requires(p->to_nodes._length > 0) { return p->n; }
/* 2: control -- _array of a different type. VERIFIES */
typedef struct node2_t {
struct node2_t *next;
_array double **vals;
int n;
} node2_t;
int f2(node2_t *p) _requires(p->vals._length > 0) { return p->n; }
/* 3: control -- self-referential, no _array field. VERIFIES */
typedef struct node3_t {
struct node3_t *next;
int n;
} node3_t;
int f3(node3_t *p) { return p->n; }
```
```
$ pal --outdir out repro.c # no errors
$ run-fstar.sh --include out out/Func_f1.fst
Error 72 at out/Typedef_node_t.fst(15,36-15,49):
- Identifier not found: struct_node_t
$ run-fstar.sh --include out out/Func_f2.fst # Verified module: Func_f2
$ run-fstar.sh --include out out/Func_f3.fst # Verified module: Func_f3
```
Neither self-reference alone nor an `_array` field alone is enough — it is the combination.
## The generated code
`out/Typedef_node_t.fst`, as emitted:
```fstar
[@@pulse_eager_unfold] let predicate ty_node_t__uninit_pred
([@@@mkey] this: ty_node_t)
(val_this_0: (array_spec (ref struct_node_t))) <-- line 15, unqualified
(val_this_1: (array_spec (ref Pulse.Lib.C.float64)))
(val_this_2: (array_spec Pulse.Lib.C.float64)) =
((Struct_node_t.struct_node_t__uninit_pred this val_this_0 val_this_1 val_this_2))
```
Every other occurrence in the same file is correctly qualified as `Struct_node_t.struct_node_t`. Only the `array_spec (ref ...)` argument inside `__uninit_pred` is bare — this looks like a single missing module qualifier on the path that renders an `_array`-of-`ref`-to-self field type.
## Impact
We are using PAL to prove spatial memory safety (every array access in bounds) on the Olden and Ptrdist benchmark suites, holding the C source fixed and adding only annotations.
This is the natural C shape for a graph node. From `olden/em3d`'s `em3d.h:38-46`, unmodified:
```c
typedef struct node_t {
double *value;
struct node_t *next;
_array struct node_t **to_nodes; /* array of nodes pointed to */
_array double **from_values;
_array double *coeffs;
int from_count;
int from_length;
} node_t;
```
Because the failure is in the typedef module, it blocks **every** function that mentions the type — `compute_nodes`, `make_neighbors`, `fill_from_fields` — and with them **12 of em3d's 24** array-bounds obligations, none of which is otherwise problematic.
## Workaround
None from the annotation side: the failure is in generated code, before any user annotation is consulted.
## Suggested fix
Qualify the type name on the `array_spec (ref …)` rendering path inside `__uninit_pred`, as is already done everywhere else in the same generated file.
Happy to test a fix against the benchmark suite.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by running the minimal C reproduction with `pal --outdir out repro.c`, then inspect `out/Typedef_node_t.fst`, especially the `__uninit_pred` array_spec argument. Trace the `_array`-of-self-reference rendering path in PAL and compare it with the qualified occurrences elsewhere in that generated file. Done means the self-referential case resolves and the f1, f2, f3 commands verify successfully.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 70/100