Skip to content

RFC proposal - derive vocab helper bindings from package public exports #759

@dannymeijer

Description

@dannymeijer

Use this issue to propose an RFC topic and get early alignment.
If accepted, we’ll typically ask for a PR adding an RFC document under docs/RFCs/ based on the RFC template.

RFCs are user-facing only (language features, documentation, CLI/tooling, runtime surface area).
If your proposal is about Rust internals/compiler architecture, please open a bug/chore/feature issue instead.

Area

  • Incan Language (syntax/semantics)
  • Tooling (CLI/formatter/test runner)
  • Documentation

Summary

Propose an RFC for vocab companions to derive helper-call bindings from a package's public export and metadata surface, instead of requiring each vocab companion to maintain a parallel Rust-side string list of helper names. The goal is for vocab desugarers to lower into ordinary package helper calls through the same manifest path that consumers use for pub::package imports.

Motivation

The concrete motivating package is InQL, whose query-block vocabulary is being finalized in InQL PR #59. The InQL query-block companion currently has to maintain an explicit helper list in vocab_companion/src/lib.rs that mirrors the public helper exports in src/lib.incn. Tests guard the drift, but the architecture is still split-brain: the Incan package facade and InQL function registry already know which helpers are public, while the vocab companion must repeat those names for query desugaring.

This is painful for library authors and easy to get wrong as packages grow. A package author should not have to update a Rust vocab manifest every time a public helper is added, renamed, aliased, or re-exported. The package's public Incan surface and checked metadata should be the source of truth.

Proposal sketch

Define a user-facing vocab/package manifest contract that lets a vocab companion resolve emitted helper calls through package public exports.

Possible direction:

VocabRegistration::new()
    .with_library_manifest(LibraryManifest::public_exports_for("inql"))

or an equivalent API that means: helper calls emitted by this desugarer are resolved against this package's public manifest.

The RFC should cover:

  • a namespaced helper-call AST or manifest form, e.g. HelperCall { package: "inql", name: "eq", args: [...] };
  • package-public helper discovery from .incnlib or equivalent public package metadata;
  • metadata-based eligibility so vocab expressions can include public expression helpers while excluding public inspection/configuration helpers;
  • alias and facade re-export behavior, so vocab helper resolution matches ordinary pub::package calls;
  • package-build validation that every helper a desugarer may emit resolves to an eligible public export;
  • diagnostics when a vocab companion emits an unknown or ineligible helper.

The desired InQL shape is that query desugaring can emit calls such as eq, sum, or desc without maintaining a second Rust-side list that duplicates src/lib.incn.

Alternatives considered

  • Keep explicit HelperBinding lists in each vocab companion. This works but duplicates package ownership and forces test guardrails to compensate for drift.
  • Generate the helper list with a build script. Better than hand-maintained strings, but still treats the symptom rather than giving vocab companions a first-class package metadata contract.
  • Let vocab desugarers emit bare names and rely on lexical imports. Rejected because vocab output should be package-stable and should not depend on accidental source imports in the consuming file.
  • Make every public export eligible in vocab expressions. Rejected because packages can export registry inspection helpers, configuration values, types, and other items that are public but not expression helpers.

Impact / compatibility

This should be additive. Existing vocab companions with explicit helper bindings should continue to work. Newer companions could opt into package-derived helper bindings once the manifest and eligibility model are available.

For packages like InQL, the migration path would be to move query-expression eligibility into helper-side metadata or export metadata, then remove the manual Rust helper list once build-time validation proves the vocab companion and package facade agree.

Implementation notes (optional)

Likely implementation areas:

  • public package manifest generation and loading;
  • vocab manifest API shape;
  • helper-call AST or desugarer output representation;
  • export metadata for vocab eligibility categories;
  • alias/facade re-export resolution at vocab helper boundaries;
  • package-build validation and diagnostics;
  • docs for authoring vocab companions that call package helpers.

Testing should include InQL as the motivating real package, plus a smaller synthetic package with ordinary helpers, aliases, facade re-exports, non-helper public exports, and a vocab companion that emits helper calls without a hand-maintained binding list.

Checklist

  • I checked for an existing RFC/issue covering this.
  • I can describe how this impacts existing code and how to migrate (if needed).

Metadata

Metadata

Assignees

No one assigned

    Labels

    RFCAdding or updating RFC documentsdocumentationImprovements or additions to documentationincan language semanticsSuggestions, features, or bugs related to the Incan Language itself (syntax and semantics)toolingSuggestions, features, or bugs related to the Tooling (CLI/formatter/test runner)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions