## Linked issue
n/a — small change
## At a glance
```prisma
types {
Email = String
}
model User {
id Int @id
email Email
slug Slug
}
types {
Slug = VarChar(191)
}
```
`prisma contract emit` accepts this schema: the named types from both
blocks are in the contract. If a name is bound in two `types` blocks,
the second one is reported as `PSL_DUPLICATE_DECLARATION` and the first
binding is kept.
## Summary
A schema has been able to contain several `types` blocks since the
legacy PSL parser was replaced by the symbol table in #851. The legacy
parser reported "Only one top-level `types` block is allowed per
document". `buildSymbolTable` instead reads every `types` block and
checks each binding name against the same set of names as models and
composite types. Nothing tested this. This PR adds tests at each level
and documents it in the psl-parser README. It does not change any
implementation code.
## Behavior changes & evidence
- **Bindings from several `types` blocks are merged into `namedTypes`.**
Implementation:
[`packages/1-framework/2-authoring/psl-parser/src/symbol-table.ts`](packages/1-framework/2-authoring/psl-parser/src/symbol-table.ts).
Evidence:
[`psl-parser/test/symbol-table.test.ts`](packages/1-framework/2-authoring/psl-parser/test/symbol-table.test.ts),
[`contract-psl/test/interpreter.types.test.ts`](packages/2-sql/2-authoring/contract-psl/test/interpreter.types.test.ts).
In the interpreter test, one block is declared after the model that uses
it.
- **A name bound in two `types` blocks is a duplicate declaration.** The
diagnostic points at the later name. Evidence: the same two unit test
files, plus the provider-level diagnostics fixture
[`test/integration/test/authoring/diagnostics/duplicate-named-type-across-types-blocks/`](test/integration/test/authoring/diagnostics/duplicate-named-type-across-types-blocks/).
- **`contract emit` succeeds on a schema with two `types` blocks.**
Evidence: `emits a psl schema with several types blocks` in
[`test/integration/test/cli.emit-command.test.ts`](test/integration/test/cli.emit-command.test.ts).
It runs the real CLI command and checks for exit code 0.
- **Docs:**
[`packages/1-framework/2-authoring/psl-parser/README.md`](packages/1-framework/2-authoring/psl-parser/README.md)
now says that a schema can have any number of `types` blocks.
## Testing performed
- `pnpm test` in `psl-parser` (`symbol-table.test.ts`, 61 tests) and
`contract-psl` (`interpreter.types.test.ts`)
- `pnpm test test/authoring/cli.emit-parity-fixtures.test.ts` in
`test/integration` (68 tests, includes the new diagnostics fixture)
- `pnpm test test/cli.emit-command.test.ts -t "several types blocks"` in
`test/integration`. I also checked that the test fails, with emit
exiting with code 2, when a name is repeated across the two blocks.
- `pnpm typecheck` and `pnpm lint` in the three touched packages
## Skill update
n/a — the PR changes no behavior; it adds tests and a README sentence
for behavior that already exists.
## Checklist
- [x] All commits are signed off (`git commit -s`) per the
[DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco).
- [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is
scoped to one logical concern.
- [x] Tests are updated.
- [ ] The PR title is in `TML-NNNN: <sentence-case title>` form. There
is no Linear ticket for this change.
- [x] The **Skill update** section above is filled in.
## Notes for the reviewer
The emit integration test checks only that emit finishes without errors.
The contents of the merged named types are covered by the interpreter
unit test.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Named types can now be declared across multiple `types {}` blocks in
the same schema or across files.
* **Bug Fixes**
* Duplicate names across `types {}` blocks are reported as
`PSL_DUPLICATE_DECLARATION`, with the diagnostic pointing to the later
declaration.
* **Documentation**
* Clarified that aliases can span multiple `types {}` blocks and that
duplicate names are not allowed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: Steven McClankerton <tatarintsev@prisma.io>
Co-authored-by: Steven McClankerton <tatarintsev@prisma.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>