compiler.test 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. ;;;; compiler.test --- tests for the compiler -*- scheme -*-
  2. ;;;; Copyright (C) 2008-2014, 2018 Free Software Foundation, Inc.
  3. ;;;;
  4. ;;;; This library is free software; you can redistribute it and/or
  5. ;;;; modify it under the terms of the GNU Lesser General Public
  6. ;;;; License as published by the Free Software Foundation; either
  7. ;;;; version 3 of the License, or (at your option) any later version.
  8. ;;;;
  9. ;;;; This library is distributed in the hope that it will be useful,
  10. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;;; Lesser General Public License for more details.
  13. ;;;;
  14. ;;;; You should have received a copy of the GNU Lesser General Public
  15. ;;;; License along with this library; if not, write to the Free Software
  16. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. (define-module (tests compiler)
  18. #:use-module (test-suite lib)
  19. #:use-module (test-suite guile-test)
  20. #:use-module (system base compile)
  21. #:use-module ((system vm loader) #:select (load-thunk-from-memory))
  22. #:use-module ((system vm program) #:select (program-sources source:addr)))
  23. (define read-and-compile
  24. (@@ (system base compile) read-and-compile))
  25. (with-test-prefix "basic"
  26. (pass-if "compile to value"
  27. (equal? (compile 1) 1)))
  28. (with-test-prefix "psyntax"
  29. (pass-if "compile uses a fresh module by default"
  30. (begin
  31. (compile '(define + -))
  32. (eq? (compile '+) +)))
  33. (pass-if "compile-time definitions are isolated"
  34. (begin
  35. (compile '(define foo-bar #t))
  36. (not (module-variable (current-module) 'foo-bar))))
  37. (pass-if "compile in current module"
  38. (let ((o (begin
  39. (compile '(define-macro (foo) 'bar)
  40. #:env (current-module))
  41. (compile '(let ((bar 'ok)) (foo))
  42. #:env (current-module)))))
  43. (and (macro? (module-ref (current-module) 'foo))
  44. (eq? o 'ok))))
  45. (pass-if "compile in fresh module"
  46. (let* ((m (let ((m (make-module)))
  47. (beautify-user-module! m)
  48. m))
  49. (o (begin
  50. (compile '(define-macro (foo) 'bar) #:env m)
  51. (compile '(let ((bar 'ok)) (foo)) #:env m))))
  52. (and (module-ref m 'foo)
  53. (eq? o 'ok))))
  54. (pass-if "redefinition"
  55. ;; In this case the locally-bound `round' must have the same value as the
  56. ;; imported `round'. See the same test in `syntax.test' for details.
  57. (let ((m (make-module)))
  58. (beautify-user-module! m)
  59. (compile '(define round round) #:env m)
  60. (eq? round (module-ref m 'round)))))
  61. (with-test-prefix "current-reader"
  62. (pass-if "default compile-time current-reader differs"
  63. (not (eq? (compile 'current-reader)
  64. current-reader)))
  65. (pass-if "compile-time changes are honored and isolated"
  66. ;; Make sure changing `current-reader' as the side-effect of a defmacro
  67. ;; actually works.
  68. (let ((r (fluid-ref current-reader))
  69. (input (open-input-string
  70. "(define-macro (install-reader!)
  71. ;;(format #t \"current-reader = ~A~%\" current-reader)
  72. (fluid-set! current-reader
  73. (let ((first? #t))
  74. (lambda args
  75. (if first?
  76. (begin
  77. (set! first? #f)
  78. ''ok)
  79. (read (open-input-string \"\"))))))
  80. #f)
  81. (install-reader!)
  82. this-should-be-ignored")))
  83. (and (eq? ((load-thunk-from-memory (read-and-compile input)))
  84. 'ok)
  85. (eq? r (fluid-ref current-reader)))))
  86. (pass-if "with eval-when"
  87. (let ((r (fluid-ref current-reader)))
  88. (compile '(eval-when (compile eval)
  89. (fluid-set! current-reader (lambda args 'chbouib))))
  90. (eq? (fluid-ref current-reader) r))))
  91. (with-test-prefix "procedure-name"
  92. (pass-if "program"
  93. (let ((m (make-module)))
  94. (beautify-user-module! m)
  95. (compile '(define (foo x) x) #:env m)
  96. (eq? (procedure-name (module-ref m 'foo)) 'foo)))
  97. (pass-if "program with lambda"
  98. (let ((m (make-module)))
  99. (beautify-user-module! m)
  100. (compile '(define foo (lambda (x) x)) #:env m)
  101. (eq? (procedure-name (module-ref m 'foo)) 'foo)))
  102. (pass-if "subr"
  103. (eq? (procedure-name waitpid) 'waitpid)))
  104. (with-test-prefix "program-sources"
  105. (with-test-prefix "source info associated with IP 0"
  106. ;; Tools like `(system vm coverage)' like it when source info is associated
  107. ;; with IP 0 of a VM program, which corresponds to the entry point. See
  108. ;; also <http://savannah.gnu.org/bugs/?29817> for details.
  109. (pass-if "lambda"
  110. (let ((s (program-sources (compile '(lambda (x) x)))))
  111. (not (not (memv 0 (map source:addr s))))))
  112. (pass-if "lambda*"
  113. (let ((s (program-sources
  114. (compile '(lambda* (x #:optional y) x)))))
  115. (not (not (memv 0 (map source:addr s))))))
  116. (pass-if "case-lambda"
  117. (let ((s (program-sources
  118. (compile '(case-lambda (() #t)
  119. ((y) y)
  120. ((y z) (list y z)))))))
  121. (not (not (memv 0 (map source:addr s))))))))
  122. (with-test-prefix "case-lambda"
  123. (pass-if "self recursion to different clause"
  124. (equal? (with-output-to-string
  125. (lambda ()
  126. (let ()
  127. (define t
  128. (case-lambda
  129. ((x)
  130. (t x 'y))
  131. ((x y)
  132. (display (list x y))
  133. (list x y))))
  134. (display (t 'x)))))
  135. "(x y)(x y)")))
  136. (with-test-prefix "limits"
  137. (define (arg n)
  138. (string->symbol (format #f "arg~a" n)))
  139. ;; Cons and vector-set! take uint8 arguments, so this triggers the
  140. ;; shuffling case. Also there is the case where more than 252
  141. ;; arguments causes shuffling.
  142. (pass-if "300 arguments"
  143. (equal? (apply (compile `(lambda ,(map arg (iota 300))
  144. 'foo))
  145. (iota 300))
  146. 'foo))
  147. (pass-if "300 arguments with list"
  148. (equal? (apply (compile `(lambda ,(map arg (iota 300))
  149. (list ,@(reverse (map arg (iota 300))))))
  150. (iota 300))
  151. (reverse (iota 300))))
  152. (pass-if "300 arguments with vector"
  153. (equal? (apply (compile `(lambda ,(map arg (iota 300))
  154. (vector ,@(reverse (map arg (iota 300))))))
  155. (iota 300))
  156. (list->vector (reverse (iota 300)))))
  157. (pass-if "0 arguments with list of 300 elements"
  158. (equal? ((compile `(lambda ()
  159. (list ,@(map (lambda (n) `(identity ,n))
  160. (iota 300))))))
  161. (iota 300)))
  162. (pass-if "0 arguments with vector of 300 elements"
  163. (equal? ((compile `(lambda ()
  164. (vector ,@(map (lambda (n) `(identity ,n))
  165. (iota 300))))))
  166. (list->vector (iota 300)))))
  167. (with-test-prefix "regression tests"
  168. (pass-if-equal "#18583" 1
  169. (compile
  170. '(begin
  171. (define x (list 1))
  172. (define x (car x))
  173. x)))
  174. (pass-if "Chained comparisons"
  175. (not (compile
  176. '(false-if-exception (< 'not-a-number))))))
  177. (with-test-prefix "prompt body slot allocation"
  178. (define test-code
  179. '(begin
  180. (use-modules (ice-9 control))
  181. (define (foo k) (k))
  182. (define (qux k) 42)
  183. (define (test)
  184. (let lp ((i 0))
  185. (when (< i 5)
  186. (let/ec cancel (let lp () (qux cancel) (foo cancel) (lp)))
  187. (lp (1+ i)))))
  188. test))
  189. (define test-proc #f)
  190. (pass-if "compiling test works"
  191. (begin
  192. (set! test-proc (compile test-code))
  193. (procedure? test-proc)))
  194. (pass-if "test terminates without error"
  195. (begin
  196. (test-proc)
  197. #t)))
  198. (with-test-prefix "flonum inference"
  199. (define test-code
  200. '(lambda (x) (let ((y (if x 0.0 0.0+0.0i))) (+ y 0.0))))
  201. (define test-proc #f)
  202. (pass-if "compiling test works"
  203. (begin
  204. (set! test-proc (compile test-code))
  205. (procedure? test-proc)))
  206. (pass-if-equal "test flonum" 0.0 (test-proc #t))
  207. (pass-if-equal "test complex" 0.0+0.0i (test-proc #f)))
  208. (with-test-prefix "null? and nil? inference"
  209. (pass-if-equal "nil? after null?"
  210. '((f . f) ; 3
  211. (f . f) ; #t
  212. (f . t) ; #f
  213. (t . t) ; #nil
  214. (t . t)) ; ()
  215. (map (compile '(lambda (x)
  216. (if (null? x)
  217. (cons 't (if (nil? x) 't 'f))
  218. (cons 'f (if (nil? x) 't 'f)))))
  219. '(3 #t #f #nil ())))
  220. (pass-if-equal "nil? after truth test"
  221. '((t . f) ; 3
  222. (t . f) ; #t
  223. (f . t) ; #f
  224. (f . t) ; #nil
  225. (t . t)) ; ()
  226. (map (compile '(lambda (x)
  227. (if x
  228. (cons 't (if (nil? x) 't 'f))
  229. (cons 'f (if (nil? x) 't 'f)))))
  230. '(3 #t #f #nil ())))
  231. (pass-if-equal "null? after nil?"
  232. '((f . f) ; 3
  233. (f . f) ; #t
  234. (t . f) ; #f
  235. (t . t) ; #nil
  236. (t . t)) ; ()
  237. (map (compile '(lambda (x)
  238. (if (nil? x)
  239. (cons 't (if (null? x) 't 'f))
  240. (cons 'f (if (null? x) 't 'f)))))
  241. '(3 #t #f #nil ())))
  242. (pass-if-equal "truth test after nil?"
  243. '((f . t) ; 3
  244. (f . t) ; #t
  245. (t . f) ; #f
  246. (t . f) ; #nil
  247. (t . t)) ; ()
  248. (map (compile '(lambda (x)
  249. (if (nil? x)
  250. (cons 't (if x 't 'f))
  251. (cons 'f (if x 't 'f)))))
  252. '(3 #t #f #nil ()))))
  253. (with-test-prefix "cse auxiliary definitions"
  254. (define test-code
  255. '(begin
  256. (define count 1)
  257. (set! count count) ;; Avoid inlining
  258. (define (main)
  259. (define (trampoline thunk)
  260. (let loop ((i 0) (result #f))
  261. (cond
  262. ((< i 1)
  263. (loop (+ i 1) (thunk)))
  264. (else
  265. (unless (= result 42) (error "bad result" result))
  266. (newline)
  267. result))))
  268. (define (test n)
  269. (let ((matrix (make-vector n)))
  270. (let loop ((i (- n 1)))
  271. (when (>= i 0)
  272. (vector-set! matrix i (make-vector n 42))
  273. (loop (- i 1))))
  274. (vector-ref (vector-ref matrix 0) 0)))
  275. (trampoline (lambda () (test count))))
  276. main))
  277. (define test-proc #f)
  278. (pass-if "compiling test works"
  279. (begin
  280. (set! test-proc (compile test-code))
  281. (procedure? test-proc)))
  282. (pass-if-equal "test terminates without error" 42
  283. (test-proc)))