Skip to content

fix: type enum-case parameter defaults as the enum, not the backing scalar#468

Open
chadmandoo wants to merge 2 commits into
illegalstudio:mainfrom
chadmandoo:upstream-pr/enum-case-param-defaults
Open

fix: type enum-case parameter defaults as the enum, not the backing scalar#468
chadmandoo wants to merge 2 commits into
illegalstudio:mainfrom
chadmandoo:upstream-pr/enum-case-param-defaults

Conversation

@chadmandoo

Copy link
Copy Markdown
Contributor

A parameter default of an enum case (function f(Level $l = Level::Low)) was typed as the case's BACKING scalar, so the declared enum parameter type rejected its own default. Resolve the default's type as the enum object. Byte-parity vs PHP 8.5 (defaulted + explicit call) + regression test.

chadmandoo added a commit to chadmandoo/elephc that referenced this pull request Jul 10, 2026
….1 (R6/#595)

Three v0.26.0 enum/parser fixes, survey-driven (79% → 85%, 241 → 262/307):

- ENUM-CASE PARAM DEFAULT (illegalstudio#468, declarations.rs): `E $x = E::Case` — an
  enum-case default has the enum object type, but syntactic inference types
  every `::` access as Str. When the declared type is Object(E) and the
  default is a scoped access naming E, accept it (the semantic pass validates
  the case exists). Clears the Badge/Button `$variant expects Object, got Str`
  family (9).
- KEYWORD ENUM-CASE NAMES (body.rs): PHP 8 allows semi-reserved keywords as
  enum-case names (`case Default;`, `case String;`, `case Float;`) — every one
  but `class` (reserved for `Foo::class`). Clears CardVariant/LogicalType/
  HeadAssetMode `Expected case name after 'case'` (10).
- USE CONST/FUNCTION IMPORTS (illegalstudio#473/EC-10/illegalstudio#493, namespace_use.rs): the lexer
  eagerly tokenizes `PHP_INT_MAX` etc., so the use-declaration parser must
  accept those dedicated tokens as import names (`use const PHP_INT_MAX;`).
  Clears RegionEntry `Expected imported name after 'use'` (2).

Deferred (not survey-visible on v0.26.1): illegalstudio#469 keyword-case access, illegalstudio#472 clone.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chadmandoo and others added 2 commits July 11, 2026 09:04
…calar

A parameter default that is an enum-case access (`function f(E $x =
E::Case)`) has the enum object type. elephc's default-value validation
inferred the default's type purely syntactically, and syntactic
inference types every `::` access as Str (it has no class table, and
enum cases are populated only after the schema pass runs). So an
enum-typed parameter with an enum-case default was rejected: "Method
parameter $x expects Object(E), got Str".

When the declared parameter type is an object type and the default is a
scoped-constant access naming that same type, accept it in
validate_declared_default_type; the later semantic pass still validates
that the named case exists. The check is ordering-independent (a name
comparison, not an enum-table lookup) and falls through to the existing
syntactic check for every other default.

Discovered compiling a real strict-types codebase: a constructor
`public HeadAssetMode $mode = HeadAssetMode::Default` would not compile.

Test: an enum-case default flows through ->value both when the default
is taken and when an explicit case is passed.

(cherry picked from commit e3ab062)
(cherry picked from commit 95cd867)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chadmandoo chadmandoo force-pushed the upstream-pr/enum-case-param-defaults branch from 0c83c63 to a7144e6 Compare July 11, 2026 14:06
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.

1 participant