Skip to content

Develop - #34

Merged
fabriceHategekimana merged 56 commits into
mainfrom
develop
Oct 1, 2026
Merged

fabriceHategekimana merged 56 commits into
mainfrom
develop

Conversation

@fabriceHategekimana

Copy link
Copy Markdown
Collaborator

Ce que fait cette PR

Vérifications

  • cargo test --workspace passe en local
  • cargo fmt --all appliqué
  • typr case run ne montre aucun REGRESS

Si cette PR touche le parseur ou le typage

  • Un cas a été ajouté dans cases/ (typr case add) pour le comportement
    corrigé, ou une raison de ne pas en ajouter est donnée ci-dessous

Si cette PR est une RFC

  • Le fichier est rfcs/0000-<slug>.md (le numéro est attribué à la fusion,
    c'est celui de cette PR) et suit rfcs/0000-template.md

Une RFC ne se relit pas comme du code : les fils de commentaires se posent sur
les phrases. Évite de force-pusher par-dessus une relecture en cours. Voir
rfcs/README.md.

Si cette PR change une version

Les versions ne se modifient pas à la main : nu publish.nu bump <niveau> puis
nu publish.nu sync. Le job coherence échoue sinon. Voir RELEASING.md.

fabriceHategekimana and others added 20 commits September 12, 2026 09:09
Grounds each in the current compiler (0.5.12) instead of leaving them
open: Lang::RFunction carries no default values or `...` handling
today (so arity checking is exactly parameters.len(), no fallback
needed), the untyped-call result stays Any rather than Foreign<Any>,
and R { ... } blocks are explicitly out of scope since they already
type-check as Type::Empty, not Type::Any, with different unification
rules.

Opens the RFC for the review this repo's rfcs/README.md describes —
it previously landed on develop without going through that process.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETPqhgWqDMt7UaUQXdxJmN
Per rfcs/README.md: on acceptance the file is renamed to the PR's own
number and the header filled in. Tracking issue #29
opened for the implementation (J0 of registry.md's plan).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETPqhgWqDMt7UaUQXdxJmN
RFC 0000: resolve open questions on calling untyped R functions
`Lang::RFunction` (`function(a, b) { ... }`) now types as a real
`(Any, ..., Any) -> Any` function with n parameters, instead of the
0-ary `Type::UnknownFunction` placeholder that made any call with
arguments a type error. `Type::UnknownFunction` (used for preloaded
untyped base-R builtins like `Position`, `t`, `Reduce`) becomes
variadic for the same reason — fixing only `RFunction` would leave
the bug reachable through every untyped base-R name.

- `processes/type_checking/mod.rs`: `Lang::RFunction`'s typing rule
  builds a `Type::Function` with n `Any` params -> `Any`.
- `components/type/mod.rs` and `components/type/function_type.rs`:
  `Type::UnknownFunction`'s conversion to `FunctionType` is now a
  single variadic `Any` parameter -> `Any`.
- `components/error_message/type_error.rs`: new `TypeError::
  UntypedFunctionArity` (T044) replaces the confusing "no signature
  matches () -> UnknownFunction" message with the RFC's proposed
  wording when an untyped function is called with the wrong arity.
- `processes/type_checking/function_application.rs`: wires the new
  error in, using `FunctionType::is_r_function()` to detect the
  untyped-function shape.
- `cases/0062-0064`: regression cases for the callable case, the
  arity error message, and the preloaded-builtin case.

Bumps the `guard_any_type_call_count_is_tracked` baseline 19 -> 21:
two new `any_type()` calls in the `RFunction` typing arm, which is
the RFC's whole point, not a silent degradation.

Tracking issue: #29

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETPqhgWqDMt7UaUQXdxJmN
…unctions

Implement RFC 0028: make untyped R functions callable
Turns registry.md §5 (definition format), §7 (resolution/locking) and
§8.3 (conflict order) into a committed contract: typr-def.toml
manifests, since/until on FunctionMeta, external .ty loading gated by
a project-configured trust threshold that degrades to Any (never a
hard error), typr.lock, and typr types add/update/list/vendor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETPqhgWqDMt7UaUQXdxJmN
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETPqhgWqDMt7UaUQXdxJmN
Status: draft -> accepted, file renamed to its assigned PR number
(0031) per rfcs/README.md's process. Tracking issue to follow in a
separate commit once opened.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETPqhgWqDMt7UaUQXdxJmN
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETPqhgWqDMt7UaUQXdxJmN
First checklist item of rfcs/0031-external-type-definitions.md (J2,
#32): fix the manifest's shape as a real type instead of
a TOML example in prose, and enforce the format_version gate the RFC
requires ("the compiler reads old manifests it recognizes or refuses
the ones it doesn't — it never silently misparses one").

- crates/typr-cli/src/type_definition.rs: DefinitionManifest and its
  sections (package/definition/provider/capabilities), parse_manifest()
  checking format_version against a raw toml::Value before attempting
  the typed parse, so an unsupported version is reported as exactly
  that rather than as a confusing missing-field error.
- since/until added to FunctionMeta (typr-core's stdlib_meta.rs) and
  StdlibMeta (spg/model.rs), parsed identically to `ret`/`coercion` via
  the existing #! annotation parser — the per-entry override the RFC's
  reference section describes, kept a lossless mapping between the two
  structs.

Nothing here fetches a repository, resolves typr.lock, or loads a
definition into the type checker yet — those remain in #32.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETPqhgWqDMt7UaUQXdxJmN
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014brvdoSu1AUJnY3mFzSc8C
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014brvdoSu1AUJnY3mFzSc8C
registry.md §8.2 and we-data-ch/registry's definitions/README.md already
documented a `definitions/<pkg>/` monorepo path for long-tail Type
Definitions, indexed via `"repository": "we-data-ch/registry"` — but
RepoSpec/fetch only ever read `typr-def.toml` at a cloned repository's
root, so two packages sharing that one repository could never both
resolve (each `typr-def.toml` has exactly one `[package] name`). This
extends `github:owner/repo[/subdir][@rev]` with an optional subdir,
scopes fetch/digest/cache to that subdir when present, and widens the
registry JSON schema's `repository` pattern and `entry_spec` parsing to
match — unblocking J5's plan to land 30 generated definitions under one
registry repo instead of 30 external ones.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014brvdoSu1AUJnY3mFzSc8C
… J6)

Scoped-down implementation of "Add to Registry" — a CLI command that
shells out to the caller's own authenticated `gh`/`git` (fork, branch,
upsert packages/<pkg>.json, push, open PR) rather than the GitHub-App
web backend §12/D6 describes and defers as a separate project. Runs
the same checks as `typr types validate` first and refuses both a
failing definition and a no-op PR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014brvdoSu1AUJnY3mFzSc8C
fabriceHategekimana and others added 9 commits September 15, 2026 12:54
typr graph <file> [--format json|dot] [--focus <key>] [--projection deps|types]
exposes the typr-graph builder from the CLI. Adds BlockGraph::one_level
(the one-level view shared by DOT export and JSON --focus), BlockKey
helpers (from_raw/is_top_level/top_level_ancestor), the deps/types
projections from spec §8, and JSON/DOT exporters (DOT renders one level
at a time as Graphviz records with ports).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New post-pass (build/type_relations.rs) over the program's top-level
Lang::Alias declarations, run once every TypeDecl/Interface block
already exists:

- Satisfies: computed with typr-core's own
  interface_satisfaction::check_interface_satisfaction (not
  reimplemented), with per-method evidence pointing at the free
  function that provides it, or at the TypeDecl itself when the
  requirement is met structurally.
- DeclaredAs: detected directly on an alias's as-written target_type
  for a `Record & NamedInterface` intersection.
- Subtype: pairwise TypeSystem::is_subtype between declared type
  aliases (deliberately not a walk of Context.subtypes' internal tree,
  which only holds reduced/anonymous structural types and would need
  an unreliable reverse name lookup — see visualization_graph_v2.md
  §12 étape 3 for the full rationale).

Also factors discover_methods (TypeDecl's Q4 method discovery) out of
build_type_decl into a shared helper, since Satisfies evidence needs
the same lookup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fabriceHategekimana and others added 27 commits September 25, 2026 22:46
Exposes typr-graph's BlockGraph as JSON from WASM, for the playground's
upcoming Graph tab. Mirrors compile()'s pipeline (Compiler::new_wasm, parse,
with_recording around type_check) and typeCheck()'s error shape: when the
source has type errors, has_errors is set and graph_json is left empty,
since the builder's totality guarantee only holds for a program that
type-checks. Verified byte-for-byte identical (modulo the source filename)
against `typr graph --format json` on the spec's walkthrough example.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fills in the four block kinds reserved since étape 1 but never emitted until
now (they fell back to Opaque):

- Loop (ForLoop/WhileLoop/Loop): a for-loop's iterable feeds a port named
  after its own loop variable (mirroring a Function parameter); every outer
  variable reassigned directly in the loop's body gets a paired
  `{name}_in`/`{name}_out` port (spec §4.1 Q3).
- Match: one Scope-kind sub-block per branch, with whatever names its
  pattern binds exposed as that sub-block's own input ports (resolves the
  open question in spec §13 that way).
- Module: only `@pub` members get an output port; all members (public and
  private) stay in the body, since privacy is enforced solely by omitting
  the port, never by hiding the block.
- RCode (RBlock/RFunction/ExternBlock): a plain opaque boundary, no
  inputs/wires derived from the untouched R text, per spec §4.

Both Loop's state ports and a plain top-level `x <- expr;` (spec §4.1's
"Assign hors boucle", previously unhandled) needed the same fix: a bare
Assign now rebinds its target the same way a Let does, so later reads wire
from the reassignment rather than the original declaration.

cargo test --workspace and typr case run stay at the same pre-existing
regressions/flake (0004/0005/0006/0008-was-declared-as-a-public-function,
registry_validate::tests::formals_diff_flags_a_missing_export_and_an_arity_mismatch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…he graph spec

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wraps typr_graph::diff over two independently-built sources for the
playground's upcoming diff view: both sides are type-checked so callers see
every error, not just the first, and old/new graph JSON ride along with the
diff JSON since the diff itself only carries keys.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds §11 "Relations comme arêtes" — Ref-capture, TypePosition{0}, and
HasType drawn as colored, directed, independently toggleable edges on
top of the existing wire rendering, plus the implementation notes for
the playground-side complement to étape 4.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ajoute les deux installeurs du lot 1 du plan, avec leurs suites de tests et
les jobs de CI qui les gardent honnêtes.

install/install.sh est un sh POSIX de bout en bout : ni bash, ni jq, ni
python. Sur Linux il installe un binaire musl lié statiquement, qui démarre
sur Rocky 9, Debian 12, Ubuntu 22.04 et Alpine alike ; le binaire GNU n est
choisi que sur --gnu explicite, parce que le défaut mesuré sur v0.5.12 était
GLIBC_2.39 not found sur les trois premières distributions. Rien n est écrit
hors de $HOME/.local/bin, et le script n écrit dans aucun fichier de profil :
il affiche la ligne PATH à ajouter.

install/install.ps1 vise PowerShell 5.1 comme PowerShell 7, en .zip parce
que Expand-Archive est le seul extracteur présent sur un Windows sans rien
installer. Il pose le binaire dans %LOCALAPPDATA%\Programs\typr et met le
PATH à jour par registre, sans privilège administrateur.

Les deux résolvent la dernière stable par l en-tête Location de
/releases/latest et la dernière prerelease par releases.atom, sans
dépendance externe. Ils vérifient le SHA-256 avant d installer, et refusent
aussi bien un checksums.txt absent qu un SHA malformé : deux diagnostics
distincts, que les scripts nomment de la même façon.

Cinq défauts sont sortis des tests, tous invisibles à la lecture :
Try-Save-File rendait $null donc falsy sur un téléchargement réussi, et
chaque installation Windows échouait ; $input est une variable automatique
PowerShell ; le fichier sans BOM UTF-8 était lu en ANSI par PS 5.1, ce qui
casse chaque accent sur un Windows français ou allemand ; une ligne
checksums.txt malformée était signalée comme absente ; et le harnais perdait
les codes de retour, rendant le refus de tag (2) indiscernable du refus
d environnement (1).

59 assertions Unix et 49 PowerShell passent, shellcheck est propre sur les
deux scripts shell. Trois jobs : install (analyse et suites), install-windows
(le script sous Windows PowerShell 5.1 réel) et install-hosting (copie vers
typr.github.io/static/install/).

Le démarrage d un binaire Windows réel reste non vérifié : le runner n a pas
de VC++ Redistributable et la fixture n est pas un exécutable Windows. Le job
install-windows valide donc le script, pas le binaire.
Trois jobs pour garder les scripts d installation honnêtes. install lance
shellcheck sur les deux scripts shell, dash -n et bash -n, puis les deux
suites de tests. install-windows exécute install.ps1 sous Windows PowerShell
5.1 — le runtime le plus ancien encore présent sur une machine de bureau, et
celui que les tests sous Linux ne l'exercent pas. install-hosting copie les
deux scripts dans typr.github.io/static/install/, sur push vers main seulement :
une PR ne doit pas laisser une page d installation qui peut mentir.

Le job hosting pousse par commit normal plutôt que par contournement d une
branche protégée. Mieux vaut le voir échouer bruyamment qu écraser une
protection posée par un humain.

install_plan.md passe le lot 1 à « fait » et consigne les cinq défauts que les
tests ont tirés, avec la raison de chacun.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Parsing du suffixe @id (S018 si mal formé), normalisation de signature,
un rigide par id dans le corps (rigides imbriqués inclus), liaison des ids
au site d'appel (T049 si un id reçoit deux types), erreurs T047/T048,
R généré inchangé. Corrige PartialEq de Bounded (boucle dans hoist_aliases).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… unique

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… : caveats avant test

Le cache SUBTYPE_CACHE hache tous les génériques pareil et PartialEq les
juge égaux : __rigid_1 <: __rigid_0 pouvait être répondu par un T <: U
antérieur du même thread (test_bound_return_rejects_another_id, ~1,5 %).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ods in name order

They were read from a HashSet / unordered context, so the block order changed
between runs and the walkthrough snapshot failed intermittently in CI. The
snapshot is re-frozen in the (now stable) alphabetical order.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@fabriceHategekimana
fabriceHategekimana merged commit 47f53d4 into main Oct 1, 2026
22 checks passed
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