Skip to content

added 1) -Wimplicit-rettype warning, 2) explicitly annotated most of the standard library#34

Merged
vpisarev merged 8 commits into
masterfrom
annotate-2
Jul 9, 2026
Merged

added 1) -Wimplicit-rettype warning, 2) explicitly annotated most of the standard library#34
vpisarev merged 8 commits into
masterfrom
annotate-2

Conversation

@vpisarev

@vpisarev vpisarev commented Jul 9, 2026

Copy link
Copy Markdown
Owner

What & why

Extends annotate-1 (return annotations on all 106 generic stdlib operators)
to functions, and adds the compiler's first non-fatal warning subsystem.
A generic function's return annotation is a load-bearing viability filter in
overload resolution (the resolve-2 near-miss: a free return type unifies with
any expected type and lets a candidate invade foreign contexts). Explicit
signatures are also the firewall for future type-error recovery, LSP, and
interface-only compilation. Design: docs/language_changes_brief.md §1.7;
full write-up: docs/annotate2_report.md.

WP-1 — warning subsystem + -Wimplicit-rettype

  • compile_warning is now counted; the driver prints an end-of-run
    N warning(s) generated summary, and -Werror folds a nonzero count into a
    failing exit. Seed for session-2's multiple-errors-per-run work.
  • Flags: -Wimplicit-rettype, -Wimplicit-rettype=all, -Wall, -Werror.
  • The check fires once per source DefFun, detecting a missing annotation at the
    signature level (a fresh TypVar(ref None) captured before typechecking),
    so it covers generic templates too. Exempts nested funcs, lambdas,
    @ccode, and auto-generated constructors.
  • Scope: default = all USER modules (everything outside <ficus_root>/lib) —
    a whole multi-file project, not just the file on the command line;
    =all also covers stdlib (how the stdlib self-gates).

WP-2 — the sweep (559 functions, 24 stdlib files)

Every module-level function in lib/ except the application libraries NN/,
Onnx/, Protobuf/, OpenCV.fx now spells its return type. Method: the compiler
is the oracle (tools/retann.py — read the inferred type the warning prints,
re-spell it, insert ): <type>); a wrong annotation fails typecheck, so behavior
can't silently change.

Resolution-neutral: -pr-resolve census over compiler/fx.fx stays
351/344/7/0 with the (name|winner|outcome) multiset identical to the WP-1
baseline. Return annotations erase in K-form → the bootstrap regen touched no
stdlib module
(byte-identical generated C).

WP-3 — CI gate

tools/rettype_gate.sh (gcc/ubuntu leg) gates the annotated stdlib
(-Wimplicit-rettype=all -Werror) and the test suite. Supersedes
lint_op_returns.py --funs (which false-positives on nested generics like
Map.mem_); the operator lint stays as a separate guard. Compiler sources are
not gated yet — 340 functions for a future annotate-3.

Also in this PR

  • test/ cleaned & gated (~30 fns: interface methods, operators, resolution
    helpers). test_resolve still passes with 0 failures.
  • @NN gensyms stripped from the warning's inferred type (copy-paste fix),
    via Re.replace — the compiler now depends on Re (+1 tiny bootstrap module).
  • K_remove_unused: no longer warns about an unused auto-generated
    constructor (e.g. a variant case) — only explicit local functions warn.
  • Docs: a proposal to revise the uniform-container zoo (vector/rrbvec/Dynvec).

Verification

make && test_all (136 pass) · fxtest all · determinism · sanitize ·
bootstrap fixpoint holds · census unchanged. Fenced findings for review:
FB-018 (Array.diag(d:'t[]) uses a before it's defined), FB-019
(floor/ceil/trunc/round return int, contra CLAUDE.md — design question).

vpisarev and others added 8 commits July 9, 2026 20:32
Bootstraps the compiler's first non-fatal diagnostic path (seed for
session-2's multiple-errors-per-run work) and adds an opt-in warning for
module-level functions whose return type is left to inference -- a
load-bearing viability filter in overload resolution (resolve-2 near-miss).

- Ast.fx: compile_warning now counts into all_compile_warns (reset in
  init_all); the pre-existing unused-value/@parallel warnings fold in too.
- Compiler.fx: end-of-run "N warning(s) generated" summary; under -Werror a
  nonzero count fails process_all's exit path.
- Options.fx: -Wimplicit-rettype, -Wall (umbrella), -Werror. (options_t
  layout propagates into 9 bootstrap modules, as with print_resolve.)
- Ast_typecheck.fx: the check fires once per source DefFun, detecting a
  missing annotation signature-level (fresh TypVar(ref None) captured before
  check_deffun resolves it) so it also covers generic templates, which are
  never body-checked at their definition site. Root modules only; exempts
  nested funcs, lambdas, @ccode, and auto-generated constructors.

test/negative/220_implicit_rettype locks the message format + the -Werror
promotion (new `// flags:` header in the T3 harness lets a warning case
exercise the required nonzero exit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… files)

Explicit return types on every module-level function in the annotated stdlib
scope -- all of lib/ except the application libraries NN/, Onnx/, Protobuf/,
OpenCV.fx (Vadim's call). Method: the compiler is the oracle -- compile with
-Wall, re-spell the inferred type it prints (only transform: strip the @NNN
gensym), insert `): <type>` (tools/retann.py). A wrong annotation fails
typecheck, so behavior cannot silently change; the -pr-resolve census guards
overload resolution.

248 concrete inferred types inserted mechanically; 310 generics annotated by
family convention (string->string, print->void, predicates->bool, size->int,
pass-throughs-> the bound var, conversions-> fixed element type, numeric folds
-> the type the body computes). Judgment cases (see docs/annotate2_report.md):
the width-varying Builtins tuple-norms get a fresh scalar var ': 't3' (safe --
arg-pinned); floor/ceil/trunc/round return int (FB-019).

Census unchanged: 351/344/7/0, (name|winner|outcome) multiset identical to the
WP-1 baseline -- resolution-neutral. Bootstrap regen touches NO stdlib module
(return annotations erase in K-form -> byte-identical C). test/negative/212
golden refreshed: the __negate__ candidate now prints 't [+] not <unknown>.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- tools/rettype_gate.sh: compile every in-scope stdlib file as a root with
  -Wall -Werror (-no-c, a few seconds), wired into ci.yml on the gcc leg
  beside the operator lint. The compiler-based gate supersedes
  lint_op_returns.py --funs, which false-positives on nested generics
  (Map.mem_) it cannot see; no parked-by-decision allowlist was needed.
  Compiler sources are NOT gated yet -- 340 functions for annotate-3.
- docs/annotate2_report.md: scope decision, WP-1 design (root-only), family
  conventions, judgment cases, per-commit census verdicts, annotate-3 data.
- found_bugs.md: FB-018 (Array.diag uses `a` before it is defined -> unusable,
  only errors on instantiation), FB-019 (floor/ceil/trunc/round return int,
  contra CLAUDE.md -- design question).
- CLAUDE.md: -W flags + gate; return-annotation spellings ((void -> T),
  module-self-type, (int...), fresh-var norms); census location-normalization;
  corrected the floor/ceil note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Revises WP-1's root-only scope. With stdlib now annotated, root-only
under-warns: it misses the user's OWN non-root modules (e.g. running
test_all.fx flagged only test_all.fx, not the imported test_oop.fx). The
useful distinction is stdlib vs user code, not root vs imported.

- Ast.fx: `ficus_std_path` (the <ficus_root>/lib dir), set in
  Compiler.process_all; a module is stdlib iff its path is under it.
- Ast_typecheck.has_implicit_rettype: default scope = every USER module
  (path not under stdlib) -- the whole project transitively; `=all` also
  covers stdlib.
- Options.fx: `-Wimplicit-rettype=all` flag (+ W_implicit_rettype_all).
- rettype_gate.sh: switched to `-Wimplicit-rettype=all -Werror` (a stdlib
  file compiled as root is otherwise skipped, since it IS stdlib).

Proven: with one stdlib annotation removed, plain -Wimplicit-rettype stays
silent while =all flags it. Ladder green (136 tests, fxtest all, determinism,
sanitize), fixpoint holds, census 351/344/7/0 unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The inferred type in the warning is meant to be copy-pasted, but typ2str
appends `@NN` gensym suffixes to module-qualified type names
(`test_oop.IClone@22`, `(bool, Date.t@11)`). Strip them with a regex --
`Re.replace(Re.compile("@[0-9]+"), s, "")` -- which correctly handles
compound types (a single truncate at the first '@' would drop the trailing
`)`). This makes the compiler depend on Re (tiny wrapper over the runtime
regex; +one bootstrap module Re.c). CLAUDE.md: prefer String.fx/Re.fx over
hand-rolled string loops. Fixpoint holds; full ladder green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cleans test/ under the new user-code default scope (which covers a test
module and its imported user helpers). ~30 functions: interface methods
(`fun Rect.name(): string`), operator overloads, and the resolution-edge-case
helpers. CplxHelper's mixed operators get the fresh-var `'t3 cplx` (matching
Complex.fx); test_resolve still runs with 0 failures, so the annotations did
not perturb what it exercises. Includes Vadim's test_all.fx annotation.

retann.py: broadened DECL_RE to match methods (`fun T.m(`) and operators, with
a capture group so scan_decls lands on the parameter '(' (not a later one in
the body); get_warnings now filters to the file being processed (the default
scope emits warnings for imported user modules too).

rettype_gate.sh: added a test-suite leg. It greps for the warning instead of
using -Werror, since test files legitimately trip an unused-local warning and
a couple do not compile standalone (test_gencmp needs -I compiler; test_re2
has an unrelated pre-existing error).

fxtest all + test_resolve(0 fails) + full gate green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An unused variant-case constructor (e.g. `B` of a locally-declared
`type ('a,'b) ct = A | B | C` in test_basic.fx) tripped the "local function
'B' is declared but not used" warning. It is compiler-generated, not a
function the user wrote, so the warning is noise. Skip it when
is_constructor(kf_flags) holds; genuine unused local functions still warn.
Fixpoint holds; full ladder green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vpisarev vpisarev merged commit 2db464b into master Jul 9, 2026
3 checks passed
@vpisarev vpisarev deleted the annotate-2 branch July 9, 2026 19:07
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