Joseph Ferano b64770feb7 A generic crosses a package boundary, and a trial leaves one copy
The two compositions the milestone owed, pinned, and the record of the
whole lane.

A package whose exports are generic: pkgs/gen, imported by
pkg-generic.flan at three shapes. One generic at two element types.
One that calls another in its own package at its own variable, so the
transitive copy is generated from a call site two files away. And a
generic written in the program calling one written in the package at
its own $t, which only resolves once Load has flattened both bodies
into one namespace -- the thing that has to change the day a package
becomes a real compilation unit, because a copy is made from a body
and a body that did not cross cannot be copied. Plus the call-site
half of a bound written in another file, quoted here rather than
pointed at in a file the caller cannot change.

And the composition with the widening trial. A binary operator
re-checks its right operand at its left one's type inside a trial, so
a generic call written there is checked twice and once thrown away.
The discarded pass's instantiation does not go back out: instantiate
rewinds a copy whose *body* refused, which is a different event. It
does not have to, and the reason is this lane's own rule rather than
luck -- a generic call's instantiation is read off its arguments and
never off the ambient want, so both passes ask for the same types and
the second ask is a cache hit. Pinned by counting the copies in the
checked program.

The widening lane's note said that cache already rewinds itself. It
does not. Corrected in the comment and in FIX.org, in place.
2026-09-20 21:00:22 +07:00

34 lines
1.4 KiB
Plaintext

;;;; A package whose exports are generic.
;;;;
;;;; The spike's "no plan" bucket named this one, and named what makes it
;;;; work: Load flattens every import into one namespace *before* the checker
;;;; runs, so the generic's body is present at the call site the way a C++
;;;; template's is because it sits in a header. Nothing here crosses a real
;;;; compilation-unit boundary, and the day a package becomes one, this is the
;;;; thing that has to change — a copy is made from a body, and a body that
;;;; did not cross cannot be copied.
;;;;
;;;; What this package is for: a generic called from the program at two types,
;;;; a bounded generic whose {:where} has to be readable from outside the
;;;; file that wrote it, and a generic that calls another generic in its own
;;;; package at its own variable, so the transitive copy is generated from a
;;;; call site two files away.
(defn last-of [s [$t]] $t
(at s (- (len s) 1)))
;;; Calls last-of at its own variable: the copy of last-of is generated when
;;; this is instantiated, and this is instantiated from the program.
(defn ends [s [$t]] $t
(last-of s))
;;; The bound travels with the signature. A caller that passes a type the
;;; clause refuses is refused at the call, against a requirement written in
;;; another file.
(defn largest [s [$t]] $t
{:where (ordered? $t)}
(let [m (at s 0)]
(dotimes [i (len s)]
(set m (max m (at s i))))
m))