Skip to content

Latest commit

 

History

History
160 lines (126 loc) · 7.19 KB

CELLSCRIPT_PUBLIC_VALUE_GENERICS.md

File metadata and controls

160 lines (126 loc) · 7.19 KB

CellScript Public Value Generics

Status: accepted and implemented for the 0.30 development line

Decision owner: issue #23

Decision

CellScript selects issue #23 Proposal A: restricted public generics. Public generic value structs, fixed-width payload enums, and pure functions may be imported across package boundaries. The compiler specializes every concrete use in the template's owning module before IR, so CKB-VM artifacts contain only bounded concrete code and layouts.

This preserves the dependency-facing Edition 2026 capability already exercised by the cross-package generic library fixture. Selecting package-local-only generics would remove that supported capability and violate the 0.30 requirement to retain the Edition 2026 surface.

The decision does not add generic Cells, generic actions or locks, traits, dynamic dispatch, higher-kinded types, runtime type reflection, or runtime linkage. Cell lifecycle authority stays separate from value abilities.

Canonical source profile

fixed_value is the compact constraint profile for an ordinary fixed-width, serializable, non-Cell value:

public struct Pair<T: fixed_value> {
    left: T
    right: T
}

public fn first<T: fixed_value>(pair: Pair<T>) -> T {
    return pair.left
}

The parser expands fixed_value to this exact closed set and order:

copy + drop + store + fixed + serializable + non_linear

The profile is valid in a type-parameter constraint list. It is not a new ability and does not appear in canonical metadata. Combining it with one of its expanded abilities is a duplicate-constraint error. Combining cell and non_linear remains invalid.

The expanded spelling remains accepted. Compact and expanded source forms produce the same AST constraints, public interface, interface hash, typed instantiation evidence, IR, and artifact. The formatter preserves whether the source used the compact profile or expanded constraints, and retains explicit has clauses so formatting does not raise the minimum compiler version.

Visibility and layout boundary

  • public templates are dependency-facing and may be specialized by an importing package.
  • public(package) templates are visible only inside the declaring package.
  • private templates stay module-local.
  • Edition 2026 retains its historical public-by-default behavior, although new package APIs should spell visibility explicitly.

In edition 2027, every non-phantom parameter of a public generic struct or enum must declare at least fixed + serializable + non_linear. Use fixed_value when the parameter also supports copy, drop, and store. Missing public layout requirements fail with E2110 and point to fixed_value. Edition 2026 retains the 0.25 declaration contract, including unconstrained public templates; concrete specializations still undergo ability, layout, and hidden-Cell checks.

A phantom parameter contributes to canonical type identity and occupies no serialized bytes. Using a phantom parameter in a field remains E2110. Instantiating an ordinary generic layout with a resource, shared Cell, receipt, or transitively Cell-backed value remains E2111.

Structural ability derivation

When a generic struct or enum omits a redundant has clause, the compiler derives the abilities guaranteed for every permitted specialization by intersecting the guarantees of all serialized fields:

  • a type parameter contributes only its declared constraints;
  • fixed scalar, address, hash, and unit fields contribute fixed_value;
  • an array contributes its element guarantees;
  • a tuple contributes the intersection of its element guarantees;
  • a reference contributes copy + drop + non_linear;
  • String and Vec contribute copy + drop + store + serializable + non_linear, without fixed;
  • an empty value layout contributes fixed_value; and
  • a named field whose template guarantee cannot be proven locally contributes no inferred ability. Authors may use an explicit has clause, which is checked again for every concrete specialization.

cell is always removed from a derived ordinary-value ability set. The algorithm is closed and deterministic; source code cannot override its meaning. The formatter omits an explicit has clause when it exactly repeats the derived result.

Interface and compatibility contract

cellc interface INPUT prints the compact human view by default:

package tutorial::pairs
interface <ckb-blake2b-256>
runtime ckb
exports
  public struct Pair<T: fixed_value>  [layout <layout-identity>]
  public function first<T: fixed_value>(pair: Pair<T>) -> T

cellc interface INPUT --json and --output FILE retain the complete canonical machine record. JSON always contains expanded constraints, phantom flags, resulting abilities, layouts, ABI/profile identities, builder hashes, and deployment identity. Interface hashing uses that canonical expanded form.

Compatibility follows these rules:

Change Classification
Compact versus exactly equivalent expanded spelling Same semantic interface identity
Private/package-local instantiation change No public interface change
Add a public export Compatible; exact interface hash changes
Remove or rename a public export Breaking
Change parameter count, name, order, or phantom status Breaking
Tighten any public generic constraint Breaking
Relax a constraint Source-compatible only when layout, runtime ABI, effects/capabilities, builder, and deployment dimensions independently remain compatible
Change a resulting value ability or serialized layout Breaking in its corresponding dimension

The Rust compiler validates the canonical generic interface before accepting metadata. The Registry API applies the same canonical-order and public-layout checks before publication and mirrors the relax-versus-tighten upgrade rule. The parser-free artifact checker independently recomputes interface_hash, validates expanded public generic records, and retains the complete checked monomorphization identities in typed semantics.

Migration

The expanded 0.25 spelling remains source-compatible under edition 2026. cellc fmt preserves expanded constraints and explicit has clauses. Adopting fixed_value or removing an explicit ability clause is an intentional source migration requiring a compiler that supports those forms.

When opting into edition 2027, public generic layouts must add any missing fixed, serializable, or non_linear constraints, or change visibility to public(package)/private. Dependency templates use their owning package edition; the importer cannot silently select a stricter declaration contract.

Evidence boundary

The syntax-combination seed, cross-package resolver fixture, metadata and interface tests, CKB-VM generic value fixture, Registry tests, independent checker mutation, WASM Playground compile test, LSP hover/completion, and VS Code grammar/snippet validation exercise the same profile. The required dev, ci, and backend gates passed on 2026-09-08 at 69488316; the full backend audit included the clean-source CKB production/stateful acceptance harness. This closes the issue #23 decision and implementation boundary on the 0.30 branch.