Skip to content

feat(desugar): a qualified constructor takes its arguments (E7, part 2) - #430

Merged
hyperpolymath merged 2 commits into
mainfrom
claude/e2e-language-pass-ow72tj
Nov 10, 2026
Merged

hyperpolymath merged 2 commits into
mainfrom
claude/e2e-language-pass-ow72tj

Conversation

@hyperpolymath

@hyperpolymath hyperpolymath commented Nov 10, 2026 •

Copy link
Copy Markdown
Owner

Summary

M.Ctor(x) now builds a value of a data type of the imported module M. This is the M.Ctor(x) item of rung E7 in the v2 plan. A second commit fixes a late review finding on #429.

The defect

lib2.MkBox(9) parses as a call of the member lib2.MkBox. The desugarer read the member alone as a constructor with no arguments. A constructor with fields was then an arity error:

Desugar error in app2.eph: constructor `MkBox` expects 1 arguments, got 0

The change

  • src/ephapax-desugar/src/lib.rs: the desugarer reads the full call. When the head of a call is M.Ctor and M is an imported module, the arguments of the call are the arguments of the constructor (qualified_ctor_call).
  • M.Ctor() is the constructor with no arguments, as Ctor() is.
  • An unknown qualifier and a wrong number of arguments keep their errors.

Review finding on #429 (second commit)

The type checker refused a generic main in each module. Only the main of the root module is an entry point, so a program that imported a module with a generic main was a type error. The driver now makes this check, on the root module only (check_program). The error is the same TypeError::GenericMain.

Not in this change

  • The qualifier still resolves unqualified, as M.f does.
  • Constructor visibility is unchanged (owner decision: later).
  • Qualified constructor patterns (| M.Ctor(v) => ...) are not in the gate.

Verification

  • Gate of the plan: the probe qa/app2 checks, compiles and runs (9), as wasm and in the interpreter. The 4 qa/app2 rows of tests/probes/expectations.tsv now have the target as baseline.
  • New test a_qualified_constructor_takes_its_arguments (src/ephapax-cli/tests/run_wasm.rs): constructors with 0, 1 and 2 fields, 2 inputs each, on both engines; the 2 load errors.
  • New test a_generic_main_of_an_imported_module_is_not_an_entry_point (src/ephapax-cli/tests/generics.rs).
  • cargo test --workspace: 610 passed, 0 failed.
  • cargo fmt --all --check and cargo clippy --workspace --all-targets: clean.
  • scripts/status-gate.sh: 607 all-target tests.
  • scripts/probe-battery.sh: 51 SAME, 7 SKIP (the SKIP rows need the wasmtime CLI).

🤖 Generated with Claude Code

https://claude.ai/code/session_0136P7ZmKrYLDC4WHi2yt11u

`M.Ctor(x)` parses as a call of the member `M.Ctor`. The desugarer read
the member alone as a constructor with no arguments, so a constructor
with fields was an arity error ("expects 1 arguments, got 0").

The desugarer now reads the full call: when the head of a call is
`M.Ctor` and `M` is an imported module, the arguments of the call are
the arguments of the constructor. `M.Ctor()` is the constructor with no
arguments, as `Ctor()` is.

An unknown qualifier and a wrong number of arguments keep their errors.
The qualifier still resolves unqualified, as `M.f` does.

Gate: the probe `qa/app2` checks, compiles and runs (9), as wasm and in
the interpreter. Tests: 606 all-target.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZmKrYLDC4WHi2yt11u
@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 18 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: da0f91b0-a6e4-40fe-80a0-7086f447f947
Commits

Reviewing files that changed from the base of the PR and between 6a422f6 and 0966fdc.

Files ignored due to path filters: 1

  • tests/probes/expectations.tsv is excluded by !**/*.tsv
Files selected for processing: 6

  • TEST-NEEDS.adoc
  • src/ephapax-cli/tests/generics.rs
  • src/ephapax-cli/tests/run_wasm.rs
  • src/ephapax-desugar/src/lib.rs
  • src/ephapax-driver/src/lib.rs
  • src/ephapax-typing/src/lib.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

The type checker refused a generic `main` in each module. A `main` of
an imported module is not an entry point: `run` starts the `main` of
the root, and an imported `main` without type parameters was already a
function like any other. A program that imported a module with a
generic `main` was a type error.

The driver now makes this check, on the root module only. The error is
the same `TypeError::GenericMain`. Review finding on #429.

Tests: 607 all-target.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZmKrYLDC4WHi2yt11u
@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath marked this pull request as ready for review November 10, 2026 15:37
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-10T15:41:28.741275Z 0966fdc Draft marked ready
🔒 Security Review ❌ Failed 2026-11-10T15:37:09.133445Z
We couldn’t complete this review. Comment @codex security review to try again.
0966fdc Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@hyperpolymath
hyperpolymath merged commit d343f0e into main Nov 10, 2026
48 checks passed
@hyperpolymath
hyperpolymath deleted the claude/e2e-language-pass-ow72tj branch November 10, 2026 15:37

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0966fdc079

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +631 to +635
if nullary
&& matches!(
args[..],
[SurfaceExpr {
kind: SurfaceExprKind::Lit(Literal::Unit),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve empty calls separately from unit arguments

This heuristic cannot distinguish M.Dot() from M.Dot(()), because parse_postfix_expr represents both as App(M.Dot, Lit(Unit)). Consequently, for data T = Dot, the explicitly supplied argument in M.Dot(()) is silently discarded instead of producing an arity error; conversely, for data T = Wrap(Unit), M.Wrap() is accepted as though one argument were supplied, unlike the equivalent unqualified Wrap(). The parser or surface AST needs to preserve whether the call's argument list was actually empty before constructor arity is checked.

Useful? React with 👍 / 👎.

hyperpolymath pushed a commit that referenced this pull request Nov 10, 2026
`M.Ctor(x)` works as an expression since #430. The same form in a match
pattern did not parse: `| shapes.Rect(w, h) => ...`.

- Grammar: `constructor_pattern` takes an optional `pattern_qualifier`
  and a `.` before the constructor name.
- The surface parser keeps the qualifier in the name (`M.Ctor`). The
  desugarer checks that `M` is an import of the module, and finds
  `Ctor` in the scope of the module. So the visibility rule of #431
  holds: a private type is "unknown constructor".
- The core parser fallback has no list of imports: it does not check
  the module there.

Part 1 of spec/ephapax-v2-grammar.ebnf is written again from the
grammar.

Tests: 2 programs on both engines (with and without a guard) and 2
refused programs. 618 all-target.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZmKrYLDC4WHi2yt11u
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.

3 participants