Three from a review of the commit before this one, and the first is a dev loop defect. Naming the widening thunk thick/<count so far> put traversal order into a symbol, and Session.compatible compares a reload's functions against the running program's by name -- so swapping two calls in a body renamed nothing the programmer can see and reported "thick/0 changes signature, from [i32] i32 to [i64] i64. Restart to change it." The name is the signature again, written by thick_enc: every type self-delimiting, an atom as its length and then its spelling, so the boundaries mangle_ty loses are in the string rather than inferred from the separators. mangle_ty is untouched -- it is load-bearing for the instantiation names a backtrace, a Reach edge and a dev cell show -- and the memo stays keyed on the types. fn-thunk-reload.flan is the pair of widenings and test_session reorders them. The second was a silent miscompile. bind_ty's Fn-pattern-against-CFn-argument arm was structural, so it matched nested function positions too, and the catch-up pass that builds the thunk compares the whole substituted parameter list -- false when the mismatch is inside one, and the fallthrough handed the argument over unchanged: one word where the instance declares two, 255 on both backends with nothing said anywhere. The widening is a value the caller builds around the whole argument and there is nowhere inside one to build it, so the arm is admitted at the top of an argument's type and nowhere else, and the catch-up arm is total over the pair rather than guarded -- bind_ty's fallthrough is Types.fits, which admits Never, so a binding can still succeed over a pair the two words cannot bridge. fn-generic-nested.flan is the parameter position and fn-generic-nested-return.flan the return one. And the third closes the hole the escaping inversion was for. A match arm binds the case's fields to slots and the store that fills them is inside the branch, not in any form escape_check reads as a binding, so (match o (Some f) f ...) handed back through a name what a case-field read cannot hand back at all -- sound only because Some_ denies suspects. An arm's slots of function type are suspect now, for the same reason the read itself is.
16 lines
502 B
Plaintext
16 lines
502 B
Plaintext
;; The same line drawn in return position, which is the half that is easy to
|
|
;; miss: a (Fn [] (Fn [] $t)) parameter handed a (CFn [] (CFn [] i32)) needs
|
|
;; the inner widening built by whatever calls the *argument*, and that is the
|
|
;; generic's own body, which was compiled against the parameter's type and not
|
|
;; against this caller's.
|
|
|
|
(defn inner [] i32 3)
|
|
|
|
(defn outer [] (CFn [] i32) inner)
|
|
|
|
(defn call-twice [g (Fn [] (Fn [] $t))] $t ((g)))
|
|
|
|
(defn main [] i32
|
|
(println (call-twice outer))
|
|
0)
|