Posted 2021-05-17 18:44:42 GMT
コンパイラへの指示で、assertを無効にした時に消えてしまうのではなくて、unreachableに変化すると最適化のヒントになって良いのではないか、というのを目にしたので、Common Lispで似たようなことができないか試してみます。
Common Lispでは、assert
は継続エラーを出すという仕様なので最適化で消えたりはしませんが、ブロックから早期脱出するようにすれば、後続のコードが不達になって不達コードの警告を出すコンパイラもあると思います(SBCL等)
(ql:quickload 'policy-cond)(defun innermost-block (env)
(let ((blk (car #+sbcl (sb-c::lexenv-blocks env)
#+lispworks (compiler::environment-benv env))))
(values (car blk) (cdr blk)))))
(defmacro assert* (test-form &environment env)
(multiple-value-bind (name namep)
(innermost-block env)
(if (or name namep)
`(policy-cond:policy-if (eql 0 cl:safety)
(unless ,test-form (return-from ,name nil))
(assert ,test-form))
`(assert ,test-form))))
policy-condを利用してsafety 0
の時だけassert
が早期脱出のコードに変換されるようにしてみました。
(defun bar (n)
(declare ((integer 0 2) n))
(declare (optimize (safety 0)))
(assert* (= 3 n))
(list n))(bar 1)
→ nil
LispWorksあたりだと、早期脱出のコードに変換される程度ですが、SBCLでは不達コードの警告を出したりはできるようです。
とはいえ、残念ながらコンパイル時に判明している値レベルでしか判定できませんが。
(defun bar (n)
(assert* (= 3 4))
(print n)); processing (DEFUN BAR ...)
; file: /tmp/slimert9DD9
; in: DEFUN BAR
; (PRINT N)
; ==>
; N
;
; note: deleting unreachable code
;
; compilation unit finished
; printed 1 note
SBCLを始めとするPythonコンパイラ系では、型情報の伝搬や、不達コードの検出等の機能はそこそこありますが、一度どの程度のことをやってくれるのかまとめてみたいところです。
■
HTML generated by 3bmd in LispWorks 7.0.0