Skip to content

Fix/3412 enum negative - #76

Merged
fredbi merged 2 commits into
go-openapi:masterfrom
fredbi:fix/3412-enum-negative
Aug 1, 2026
Merged

Fix/3412 enum negative#76
fredbi merged 2 commits into
go-openapi:masterfrom
fredbi:fix/3412-enum-negative

Conversation

@fredbi

@fredbi fredbi commented Aug 1, 2026

Copy link
Copy Markdown
Member

Change type

Please select: 🆕 New feature or enhancement|🔧 Bug fix'|📃 Documentation update

Short description

This PR reworks how enums are identified and associated with a swagger type.

This allows for supported a wider range of valid go const constructs, including negative values, hex/octal literals,
redefined basic types, possibly bearing the "swagger:strfmt" annotation.

Adds a full tutorial to present the enhanced enum feature.

Fixes

  • Contributes go-swagger/go-swager#3412

Full description

Checklist

  • I have signed all my commits with my name and email (see DCO. This does not require a PGP-signed commit
  • I have rebased and squashed my work, so only one commit remains
  • I have added tests to cover my changes.
  • I have properly enriched go doc comments in code.
  • I have properly documented any breaking change.

Comment thread internal/builders/validations/const_values.go Dismissed
@fredbi

fredbi commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

Supersedes #75

fredbi and others added 2 commits August 1, 2026 14:10
Both the members of a swagger:enum and the type of the schema carrying them were
derived from the literal syntax of the const block. Neither survives that reading
intact: a constant's right-hand side is only incidentally a literal, and a value
carries no trace of the width it was declared with.

Members:
- a signed constant (-1) is a unary expression, not a literal, and was skipped,
  so an enum straddling zero lost half its members;
- the non-decimal forms (0x2a, 0b101010, 0o52) and digit separators failed a
  base-10 parse and reached the spec as a null member; a value above MaxInt64,
  legal for a uint64 enum, was dropped;
- iota, constant expressions, references to earlier members, rune literals,
  true/false and the raw string form were invisible, since their value is not in
  their syntax and inside an iota block only the first spec carries a type at
  all. Members now come from the type-checker, which evaluated them exactly, and
  membership is decided per name from the constant's own type — the package
  included, so a same-named imported type is not swallowed.

The literal reader survives as the fallback for a package that only partially
type-checks, where an annotated enum should still contribute what can be read.

Typing:
- type and format come from the declared Go type rather than from the first
  value's Go representation: an int8 enum is {integer, int8}, a float32 one
  {number, float}. Every width used to collapse, and the declaration order of
  the const block decided the type — a float enum whose first member was written
  `= 0` emitted {type: integer} carrying fractional members;
- each member is normalised to that type, and one that cannot be represented in
  it is reported and dropped rather than written against the schema's own type;
- a type declared over another named type (type Kind strfmt.UUID) keeps the
  format of the type it is written over, which Underlying() does not carry.

An enum built from iota, booleans or expressions used to emit nothing plus a "no
matching const values found" warning; it now emits its values.

A rune or byte enum is among those newly emitted, and it emits an integer enum:
`const LetterA Letter = 'a'` becomes {integer, int32} with the member 97. That
is likely not what its author pictured, and it is still the only faithful
answer — a scalar rune is an int32 on the wire, and encoding/json refuses to
unmarshal "a" into that field. Declaring the type over string is what changes
the wire, and with it the schema.

No existing golden changes: the corpus held no enum that was negative, sized,
iota-based or strfmt-backed, which is why none of this was visible.

Refers to go-swagger/go-swagger#3412.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
The enum section under "Model definitions" covered a string const block and
little else. Enums get their own page, next to it in the tutorial order: what
the scanner collects (any constant expression, iota included), what decides the
emitted type and format, the inline form parameters and headers take, and the
two shapes that do not work — a rune or byte enum, which emits code points
because that is what those types are on the wire, and an alias to a basic type,
which the type-checker erases before there is anything left to collect.

A new docs/examples/concepts/enums package backs the panes, one region per rule,
its fragments regenerated as goldens like the other tutorials.

Model definitions keeps its introductory pane and points at the new page; the
annotation index and the swagger:enum reference follow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
@fredbi
fredbi force-pushed the fix/3412-enum-negative branch from a915317 to 7afe0e3 Compare August 1, 2026 12:10
@fredbi
fredbi merged commit c37d503 into go-openapi:master Aug 1, 2026
24 checks passed
@fredbi
fredbi deleted the fix/3412-enum-negative branch August 1, 2026 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants