swap!, reverse!, sort!, sort-by!, index-of, min-of, max-of, map!, reduce and filter, each written once over $t. Every call site in the corpus moves with them. min-of and max-of are not min and max because min and max are builtins over two or more numbers and nothing shadows a builtin. These reduce a slice, which is a different operation at a different arity. sort-bytes! did not collapse into sort!, and the reason is the point of the predicates: a [u8] is not ordered? and cannot be, because < is an instruction and comparing two slices lexicographically is a loop. It is sort-by! with bytes<? written in, one line, keeping its name and its stability note. sum-i32/sum-f32 and append-i64!/append-f64! stay for the reasons the spike gave. Not what the notes predicted: none of the ten collapses on a signature change alone. filter and reduce need copyable? because the checker demands it - reduce's accumulator at (Vec i32) is a double move - and the rest declare it because a slice of owning elements would have them duplicating headers.
54 lines
1.9 KiB
Plaintext
54 lines
1.9 KiB
Plaintext
;;;; Three edges of Reach's walk, each the only route to one function.
|
|
;;;;
|
|
;;;; A release build is pruned: a function nothing reachable from main or from
|
|
;;;; a global initialiser calls is not emitted at all. So an edge the walk
|
|
;;;; forgets does not produce a wrong answer — it produces a program that does
|
|
;;;; not link, with a message about a symbol nobody wrote. Each of the three
|
|
;;;; functions below is called from exactly one place, and that place is an
|
|
;;;; edge no other program in the corpus exercises:
|
|
;;;;
|
|
;;;; index-expr the index expression of a place, (set (at a (f)) v)
|
|
;;;; through a place under (addr ...), here a (deref ...) so that it is
|
|
;;;; the addr edge and not the index one again
|
|
;;;; placeholder a restart-case clause body, which is reached by a transfer
|
|
;;;; and never by a call the walk can see from the body
|
|
;;;;
|
|
;;;; Nothing here is about the values; the values are how the test notices that
|
|
;;;; the program was built and ran at all.
|
|
|
|
(defvar cells [4 i32])
|
|
(defvar slot i32)
|
|
|
|
(defstruct Nope [id i32])
|
|
|
|
(defn index-expr [] i32 2)
|
|
|
|
(defn through [] (Ptr i32) (addr slot))
|
|
|
|
(defn placeholder [] i32 42)
|
|
|
|
;;; Signals with nothing to return, so the clause body is the only way past.
|
|
(defn missing [] i32
|
|
(error (Nope {.id 1})))
|
|
|
|
(defn pick [] i32
|
|
(restart-case (missing)
|
|
(use-placeholder [] (placeholder))))
|
|
|
|
(defn main [] i32
|
|
;; The index of a place is an expression, and it can call.
|
|
(set (at cells (index-expr)) 10)
|
|
(print (at cells 2)) (println "")
|
|
|
|
;; (addr (deref p)) is p, so this is the addr edge over a place whose own
|
|
;; walk is Pderef rather than Pindex — the index case above cannot stand in
|
|
;; for it.
|
|
(let [q (addr (deref (through)))]
|
|
(set (deref q) 20))
|
|
(print slot) (println "")
|
|
|
|
;; The clause body, reached only because the handler transfers into it.
|
|
(handler-bind [(Nope [c] (invoke-restart 'use-placeholder))]
|
|
(print (pick)) (println ""))
|
|
0)
|