1 ;;;; tree-il.test --- test suite for compiling tree-il -*- scheme -*-
2 ;;;; Andy Wingo <wingo@pobox.com> --- May 2009
4 ;;;; Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
6 ;;;; This library is free software; you can redistribute it and/or
7 ;;;; modify it under the terms of the GNU Lesser General Public
8 ;;;; License as published by the Free Software Foundation; either
9 ;;;; version 3 of the License, or (at your option) any later version.
11 ;;;; This library is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;;;; Lesser General Public License for more details.
16 ;;;; You should have received a copy of the GNU Lesser General Public
17 ;;;; License along with this library; if not, write to the Free Software
18 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 (define-module (test-suite tree-il)
21 #:use-module (test-suite lib)
22 #:use-module (system base compile)
23 #:use-module (system base pmatch)
24 #:use-module (system base message)
25 #:use-module (language tree-il)
26 #:use-module (language tree-il primitives)
27 #:use-module (language glil)
28 #:use-module (srfi srfi-13))
30 ;; Of course, the GLIL that is emitted depends on the source info of the
31 ;; input. Here we're not concerned about that, so we strip source
32 ;; information from the incoming tree-il.
34 (define (strip-source x)
35 (post-order! (lambda (x) (set! (tree-il-src x) #f))
38 (define-syntax assert-tree-il->glil
39 (syntax-rules (with-partial-evaluation without-partial-evaluation
41 ((_ with-partial-evaluation in pat test ...)
42 (assert-tree-il->glil with-options (#:partial-eval? #t)
44 ((_ without-partial-evaluation in pat test ...)
45 (assert-tree-il->glil with-options (#:partial-eval? #f)
47 ((_ with-options opts in pat test ...)
50 (let ((glil (unparse-glil
51 (compile (strip-source (parse-tree-il exp))
52 #:from 'tree-il #:to 'glil
55 (pat (guard test ...) #t)
58 (assert-tree-il->glil with-partial-evaluation
61 (define-syntax pass-if-tree-il->scheme
64 (assert-scheme->tree-il->scheme in pat #t))
67 (pmatch (tree-il->scheme
68 (compile 'in #:from 'scheme #:to 'tree-il))
69 (pat (guard guard-exp) #t)
73 ;; The partial evaluator.
74 (@@ (language tree-il optimize) peval))
76 (define-syntax pass-if-peval
77 (syntax-rules (resolve-primitives)
80 (compile 'in #:from 'scheme #:to 'tree-il)))
81 ((_ resolve-primitives in pat)
85 (compile 'in #:from 'scheme #:to 'tree-il)
89 (let ((evaled (unparse-tree-il (peval code))))
92 (_ (pk 'peval-mismatch)
93 ((@ (ice-9 pretty-print) pretty-print)
96 ((@ (ice-9 pretty-print) pretty-print)
99 ((@ (ice-9 pretty-print) pretty-print)
105 (with-test-prefix "tree-il->scheme"
106 (pass-if-tree-il->scheme
107 (case-lambda ((a) a) ((b c) (list b c)))
108 (case-lambda ((,a) ,a1) ((,b ,c) (list ,b1 ,c1)))
109 (and (eq? a a1) (eq? b b1) (eq? c c1))))
111 (with-test-prefix "void"
112 (assert-tree-il->glil
114 (program () (std-prelude 0 0 #f) (label _) (void) (call return 1)))
115 (assert-tree-il->glil
116 (begin (void) (const 1))
117 (program () (std-prelude 0 0 #f) (label _) (const 1) (call return 1)))
118 (assert-tree-il->glil
119 (apply (primitive +) (void) (const 1))
120 (program () (std-prelude 0 0 #f) (label _) (void) (call add1 1) (call return 1))))
122 (with-test-prefix "application"
123 (assert-tree-il->glil
124 (apply (toplevel foo) (const 1))
125 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (const 1) (call tail-call 1)))
126 (assert-tree-il->glil
127 (begin (apply (toplevel foo) (const 1)) (void))
128 (program () (std-prelude 0 0 #f) (label _) (call new-frame 0) (toplevel ref foo) (const 1) (mv-call 1 ,l1)
129 (call drop 1) (branch br ,l2)
130 (label ,l3) (mv-bind 0 #f)
132 (void) (call return 1))
133 (and (eq? l1 l3) (eq? l2 l4)))
134 (assert-tree-il->glil
135 (apply (toplevel foo) (apply (toplevel bar)))
136 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call new-frame 0) (toplevel ref bar) (call call 0)
137 (call tail-call 1))))
139 (with-test-prefix "conditional"
140 (assert-tree-il->glil
141 (if (toplevel foo) (const 1) (const 2))
142 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1)
143 (const 1) (call return 1)
144 (label ,l2) (const 2) (call return 1))
147 (assert-tree-il->glil without-partial-evaluation
148 (begin (if (toplevel foo) (const 1) (const 2)) (const #f))
149 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1) (branch br ,l2)
150 (label ,l3) (label ,l4) (const #f) (call return 1))
151 (eq? l1 l3) (eq? l2 l4))
153 (assert-tree-il->glil
154 (apply (primitive null?) (if (toplevel foo) (const 1) (const 2)))
155 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1)
156 (const 1) (branch br ,l2)
157 (label ,l3) (const 2) (label ,l4)
158 (call null? 1) (call return 1))
159 (eq? l1 l3) (eq? l2 l4)))
161 (with-test-prefix "primitive-ref"
162 (assert-tree-il->glil
164 (program () (std-prelude 0 0 #f) (label _) (toplevel ref +) (call return 1)))
166 (assert-tree-il->glil
167 (begin (primitive +) (const #f))
168 (program () (std-prelude 0 0 #f) (label _) (const #f) (call return 1)))
170 (assert-tree-il->glil
171 (apply (primitive null?) (primitive +))
172 (program () (std-prelude 0 0 #f) (label _) (toplevel ref +) (call null? 1)
175 (with-test-prefix "lexical refs"
176 (assert-tree-il->glil without-partial-evaluation
177 (let (x) (y) ((const 1)) (lexical x y))
178 (program () (std-prelude 0 1 #f) (label _)
179 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
180 (lexical #t #f ref 0) (call return 1)
183 (assert-tree-il->glil without-partial-evaluation
184 (let (x) (y) ((const 1)) (begin (lexical x y) (const #f)))
185 (program () (std-prelude 0 1 #f) (label _)
186 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
187 (const #f) (call return 1)
190 (assert-tree-il->glil without-partial-evaluation
191 (let (x) (y) ((const 1)) (apply (primitive null?) (lexical x y)))
192 (program () (std-prelude 0 1 #f) (label _)
193 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
194 (lexical #t #f ref 0) (call null? 1) (call return 1)
197 (with-test-prefix "lexical sets"
198 (assert-tree-il->glil
199 ;; unreferenced sets may be optimized away -- make sure they are ref'd
200 (let (x) (y) ((const 1))
201 (set! (lexical x y) (apply (primitive 1+) (lexical x y))))
202 (program () (std-prelude 0 1 #f) (label _)
203 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
204 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0)
205 (void) (call return 1)
208 (assert-tree-il->glil
209 (let (x) (y) ((const 1))
210 (begin (set! (lexical x y) (apply (primitive 1+) (lexical x y)))
212 (program () (std-prelude 0 1 #f) (label _)
213 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
214 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0)
215 (lexical #t #t ref 0) (call return 1)
218 (assert-tree-il->glil
219 (let (x) (y) ((const 1))
220 (apply (primitive null?)
221 (set! (lexical x y) (apply (primitive 1+) (lexical x y)))))
222 (program () (std-prelude 0 1 #f) (label _)
223 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
224 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0) (void)
225 (call null? 1) (call return 1)
228 (with-test-prefix "module refs"
229 (assert-tree-il->glil
231 (program () (std-prelude 0 0 #f) (label _)
232 (module public ref (foo) bar)
235 (assert-tree-il->glil
236 (begin (@ (foo) bar) (const #f))
237 (program () (std-prelude 0 0 #f) (label _)
238 (module public ref (foo) bar) (call drop 1)
239 (const #f) (call return 1)))
241 (assert-tree-il->glil
242 (apply (primitive null?) (@ (foo) bar))
243 (program () (std-prelude 0 0 #f) (label _)
244 (module public ref (foo) bar)
245 (call null? 1) (call return 1)))
247 (assert-tree-il->glil
249 (program () (std-prelude 0 0 #f) (label _)
250 (module private ref (foo) bar)
253 (assert-tree-il->glil
254 (begin (@@ (foo) bar) (const #f))
255 (program () (std-prelude 0 0 #f) (label _)
256 (module private ref (foo) bar) (call drop 1)
257 (const #f) (call return 1)))
259 (assert-tree-il->glil
260 (apply (primitive null?) (@@ (foo) bar))
261 (program () (std-prelude 0 0 #f) (label _)
262 (module private ref (foo) bar)
263 (call null? 1) (call return 1))))
265 (with-test-prefix "module sets"
266 (assert-tree-il->glil
267 (set! (@ (foo) bar) (const 2))
268 (program () (std-prelude 0 0 #f) (label _)
269 (const 2) (module public set (foo) bar)
270 (void) (call return 1)))
272 (assert-tree-il->glil
273 (begin (set! (@ (foo) bar) (const 2)) (const #f))
274 (program () (std-prelude 0 0 #f) (label _)
275 (const 2) (module public set (foo) bar)
276 (const #f) (call return 1)))
278 (assert-tree-il->glil
279 (apply (primitive null?) (set! (@ (foo) bar) (const 2)))
280 (program () (std-prelude 0 0 #f) (label _)
281 (const 2) (module public set (foo) bar)
282 (void) (call null? 1) (call return 1)))
284 (assert-tree-il->glil
285 (set! (@@ (foo) bar) (const 2))
286 (program () (std-prelude 0 0 #f) (label _)
287 (const 2) (module private set (foo) bar)
288 (void) (call return 1)))
290 (assert-tree-il->glil
291 (begin (set! (@@ (foo) bar) (const 2)) (const #f))
292 (program () (std-prelude 0 0 #f) (label _)
293 (const 2) (module private set (foo) bar)
294 (const #f) (call return 1)))
296 (assert-tree-il->glil
297 (apply (primitive null?) (set! (@@ (foo) bar) (const 2)))
298 (program () (std-prelude 0 0 #f) (label _)
299 (const 2) (module private set (foo) bar)
300 (void) (call null? 1) (call return 1))))
302 (with-test-prefix "toplevel refs"
303 (assert-tree-il->glil
305 (program () (std-prelude 0 0 #f) (label _)
309 (assert-tree-il->glil without-partial-evaluation
310 (begin (toplevel bar) (const #f))
311 (program () (std-prelude 0 0 #f) (label _)
312 (toplevel ref bar) (call drop 1)
313 (const #f) (call return 1)))
315 (assert-tree-il->glil
316 (apply (primitive null?) (toplevel bar))
317 (program () (std-prelude 0 0 #f) (label _)
319 (call null? 1) (call return 1))))
321 (with-test-prefix "toplevel sets"
322 (assert-tree-il->glil
323 (set! (toplevel bar) (const 2))
324 (program () (std-prelude 0 0 #f) (label _)
325 (const 2) (toplevel set bar)
326 (void) (call return 1)))
328 (assert-tree-il->glil
329 (begin (set! (toplevel bar) (const 2)) (const #f))
330 (program () (std-prelude 0 0 #f) (label _)
331 (const 2) (toplevel set bar)
332 (const #f) (call return 1)))
334 (assert-tree-il->glil
335 (apply (primitive null?) (set! (toplevel bar) (const 2)))
336 (program () (std-prelude 0 0 #f) (label _)
337 (const 2) (toplevel set bar)
338 (void) (call null? 1) (call return 1))))
340 (with-test-prefix "toplevel defines"
341 (assert-tree-il->glil
342 (define bar (const 2))
343 (program () (std-prelude 0 0 #f) (label _)
344 (const 2) (toplevel define bar)
345 (void) (call return 1)))
347 (assert-tree-il->glil
348 (begin (define bar (const 2)) (const #f))
349 (program () (std-prelude 0 0 #f) (label _)
350 (const 2) (toplevel define bar)
351 (const #f) (call return 1)))
353 (assert-tree-il->glil
354 (apply (primitive null?) (define bar (const 2)))
355 (program () (std-prelude 0 0 #f) (label _)
356 (const 2) (toplevel define bar)
357 (void) (call null? 1) (call return 1))))
359 (with-test-prefix "constants"
360 (assert-tree-il->glil
362 (program () (std-prelude 0 0 #f) (label _)
363 (const 2) (call return 1)))
365 (assert-tree-il->glil
366 (begin (const 2) (const #f))
367 (program () (std-prelude 0 0 #f) (label _)
368 (const #f) (call return 1)))
370 (assert-tree-il->glil
371 ;; This gets simplified by `peval'.
372 (apply (primitive null?) (const 2))
373 (program () (std-prelude 0 0 #f) (label _)
374 (const #f) (call return 1))))
376 (with-test-prefix "letrec"
377 ;; simple bindings -> let
378 (assert-tree-il->glil without-partial-evaluation
379 (letrec (x y) (x1 y1) ((const 10) (const 20))
380 (apply (toplevel foo) (lexical x x1) (lexical y y1)))
381 (program () (std-prelude 0 2 #f) (label _)
382 (const 10) (const 20)
383 (bind (x #f 0) (y #f 1))
384 (lexical #t #f set 1) (lexical #t #f set 0)
386 (lexical #t #f ref 0) (lexical #t #f ref 1)
390 ;; complex bindings -> box and set! within let
391 (assert-tree-il->glil without-partial-evaluation
392 (letrec (x y) (x1 y1) ((apply (toplevel foo)) (apply (toplevel bar)))
393 (apply (primitive +) (lexical x x1) (lexical y y1)))
394 (program () (std-prelude 0 4 #f) (label _)
395 (void) (void) ;; what are these?
396 (bind (x #t 0) (y #t 1))
397 (lexical #t #t box 1) (lexical #t #t box 0)
398 (call new-frame 0) (toplevel ref foo) (call call 0)
399 (call new-frame 0) (toplevel ref bar) (call call 0)
400 (bind (x #f 2) (y #f 3)) (lexical #t #f set 3) (lexical #t #f set 2)
401 (lexical #t #f ref 2) (lexical #t #t set 0)
402 (lexical #t #f ref 3) (lexical #t #t set 1)
403 (void) (lexical #t #f set 2) (void) (lexical #t #f set 3) ;; clear bindings
405 (lexical #t #t ref 0) (lexical #t #t ref 1)
406 (call add 2) (call return 1) (unbind)))
408 ;; complex bindings in letrec* -> box and set! in order
409 (assert-tree-il->glil without-partial-evaluation
410 (letrec* (x y) (x1 y1) ((apply (toplevel foo)) (apply (toplevel bar)))
411 (apply (primitive +) (lexical x x1) (lexical y y1)))
412 (program () (std-prelude 0 2 #f) (label _)
413 (void) (void) ;; what are these?
414 (bind (x #t 0) (y #t 1))
415 (lexical #t #t box 1) (lexical #t #t box 0)
416 (call new-frame 0) (toplevel ref foo) (call call 0)
417 (lexical #t #t set 0)
418 (call new-frame 0) (toplevel ref bar) (call call 0)
419 (lexical #t #t set 1)
420 (lexical #t #t ref 0)
421 (lexical #t #t ref 1)
422 (call add 2) (call return 1) (unbind)))
424 ;; simple bindings in letrec* -> equivalent to letrec
425 (assert-tree-il->glil without-partial-evaluation
426 (letrec* (x y) (xx yy) ((const 1) (const 2))
428 (program () (std-prelude 0 1 #f) (label _)
430 (bind (y #f 0)) ;; X is removed, and Y is unboxed
431 (lexical #t #f set 0)
432 (lexical #t #f ref 0)
433 (call return 1) (unbind))))
435 (with-test-prefix "lambda"
436 (assert-tree-il->glil
438 (lambda-case (((x) #f #f #f () (y)) (const 2)) #f))
439 (program () (std-prelude 0 0 #f) (label _)
440 (program () (std-prelude 1 1 #f)
441 (bind (x #f 0)) (label _)
442 (const 2) (call return 1) (unbind))
445 (assert-tree-il->glil
447 (lambda-case (((x y) #f #f #f () (x1 y1))
450 (program () (std-prelude 0 0 #f) (label _)
451 (program () (std-prelude 2 2 #f)
452 (bind (x #f 0) (y #f 1)) (label _)
453 (const 2) (call return 1)
457 (assert-tree-il->glil
459 (lambda-case ((() #f x #f () (y)) (const 2))
461 (program () (std-prelude 0 0 #f) (label _)
462 (program () (opt-prelude 0 0 0 1 #f)
463 (bind (x #f 0)) (label _)
464 (const 2) (call return 1)
468 (assert-tree-il->glil
470 (lambda-case (((x) #f x1 #f () (y y1)) (const 2))
472 (program () (std-prelude 0 0 #f) (label _)
473 (program () (opt-prelude 1 0 1 2 #f)
474 (bind (x #f 0) (x1 #f 1)) (label _)
475 (const 2) (call return 1)
479 (assert-tree-il->glil
481 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x y))
483 (program () (std-prelude 0 0 #f) (label _)
484 (program () (opt-prelude 1 0 1 2 #f)
485 (bind (x #f 0) (x1 #f 1)) (label _)
486 (lexical #t #f ref 0) (call return 1)
490 (assert-tree-il->glil
492 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x1 y1))
494 (program () (std-prelude 0 0 #f) (label _)
495 (program () (opt-prelude 1 0 1 2 #f)
496 (bind (x #f 0) (x1 #f 1)) (label _)
497 (lexical #t #f ref 1) (call return 1)
501 (assert-tree-il->glil
503 (lambda-case (((x) #f #f #f () (x1))
505 (lambda-case (((y) #f #f #f () (y1))
509 (program () (std-prelude 0 0 #f) (label _)
510 (program () (std-prelude 1 1 #f)
511 (bind (x #f 0)) (label _)
512 (program () (std-prelude 1 1 #f)
513 (bind (y #f 0)) (label _)
514 (lexical #f #f ref 0) (call return 1)
516 (lexical #t #f ref 0)
517 (call make-closure 1)
522 (with-test-prefix "sequence"
523 (assert-tree-il->glil
524 (begin (begin (const 2) (const #f)) (const #t))
525 (program () (std-prelude 0 0 #f) (label _)
526 (const #t) (call return 1)))
528 (assert-tree-il->glil
529 ;; This gets simplified by `peval'.
530 (apply (primitive null?) (begin (const #f) (const 2)))
531 (program () (std-prelude 0 0 #f) (label _)
532 (const #f) (call return 1))))
534 (with-test-prefix "values"
535 (assert-tree-il->glil
536 (apply (primitive values)
537 (apply (primitive values) (const 1) (const 2)))
538 (program () (std-prelude 0 0 #f) (label _)
539 (const 1) (call return 1)))
541 (assert-tree-il->glil
542 (apply (primitive values)
543 (apply (primitive values) (const 1) (const 2))
545 (program () (std-prelude 0 0 #f) (label _)
546 (const 1) (const 3) (call return/values 2)))
548 (assert-tree-il->glil
550 (apply (primitive values) (const 1) (const 2)))
551 (program () (std-prelude 0 0 #f) (label _)
552 (const 1) (call return 1)))
554 ;; Testing `(values foo)' in push context with RA.
555 (assert-tree-il->glil without-partial-evaluation
556 (apply (primitive cdr)
557 (letrec (lp) (#{lp ~V9KrhVD4PFEL6oCTrLg3A}#)
558 ((lambda ((name . lp))
559 (lambda-case ((() #f #f #f () ())
560 (apply (toplevel values) (const (one two)))))))
561 (apply (lexical lp #{lp ~V9KrhVD4PFEL6oCTrLg3A}#))))
562 (program () (std-prelude 0 0 #f) (label _)
563 (branch br _) ;; entering the fix, jump to :2
564 ;; :1 body of lp, jump to :3
565 (label _) (bind) (const (one two)) (branch br _) (unbind)
566 ;; :2 initial call of lp, jump to :1
567 (label _) (bind) (branch br _) (label _) (unbind)
568 ;; :3 the push continuation
569 (call cdr 1) (call return 1))))
571 ;; FIXME: binding info for or-hacked locals might bork the disassembler,
572 ;; and could be tightened in any case
573 (with-test-prefix "the or hack"
574 (assert-tree-il->glil without-partial-evaluation
575 (let (x) (y) ((const 1))
578 (let (a) (b) ((const 2))
580 (program () (std-prelude 0 1 #f) (label _)
581 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
582 (lexical #t #f ref 0) (branch br-if-not ,l1)
583 (lexical #t #f ref 0) (call return 1)
585 (const 2) (bind (a #f 0)) (lexical #t #f set 0)
586 (lexical #t #f ref 0) (call return 1)
591 ;; second bound var is unreferenced
592 (assert-tree-il->glil without-partial-evaluation
593 (let (x) (y) ((const 1))
596 (let (a) (b) ((const 2))
598 (program () (std-prelude 0 1 #f) (label _)
599 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
600 (lexical #t #f ref 0) (branch br-if-not ,l1)
601 (lexical #t #f ref 0) (call return 1)
603 (lexical #t #f ref 0) (call return 1)
607 (with-test-prefix "apply"
608 (assert-tree-il->glil
609 (apply (primitive @apply) (toplevel foo) (toplevel bar))
610 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (toplevel ref bar) (call tail-apply 2)))
611 (assert-tree-il->glil
612 (begin (apply (primitive @apply) (toplevel foo) (toplevel bar)) (void))
613 (program () (std-prelude 0 0 #f) (label _)
614 (call new-frame 0) (toplevel ref apply) (toplevel ref foo) (toplevel ref bar) (mv-call 2 ,l1)
615 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
617 (void) (call return 1))
618 (and (eq? l1 l3) (eq? l2 l4)))
619 (assert-tree-il->glil
620 (apply (toplevel foo) (apply (toplevel @apply) (toplevel bar) (toplevel baz)))
621 (program () (std-prelude 0 0 #f) (label _)
623 (call new-frame 0) (toplevel ref bar) (toplevel ref baz) (call apply 2)
624 (call tail-call 1))))
626 (with-test-prefix "call/cc"
627 (assert-tree-il->glil
628 (apply (primitive @call-with-current-continuation) (toplevel foo))
629 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call tail-call/cc 1)))
630 (assert-tree-il->glil
631 (begin (apply (primitive @call-with-current-continuation) (toplevel foo)) (void))
632 (program () (std-prelude 0 0 #f) (label _)
633 (call new-frame 0) (toplevel ref call-with-current-continuation) (toplevel ref foo) (mv-call 1 ,l1)
634 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
636 (void) (call return 1))
637 (and (eq? l1 l3) (eq? l2 l4)))
638 (assert-tree-il->glil
639 (apply (toplevel foo)
640 (apply (toplevel @call-with-current-continuation) (toplevel bar)))
641 (program () (std-prelude 0 0 #f) (label _)
643 (toplevel ref bar) (call call/cc 1)
644 (call tail-call 1))))
647 (with-test-prefix "labels allocation"
648 (pass-if "http://debbugs.gnu.org/9769"
649 ((compile '(lambda ()
650 (let ((fail (lambda () #f)))
651 (let ((test (lambda () (fail))))
654 ;; Prevent inlining. We're testing analyze.scm's
655 ;; labels allocator here, and inlining it will
656 ;; reduce the entire thing to #t.
657 #:opts '(#:partial-eval? #f)))))
660 (with-test-prefix "partial evaluation"
663 ;; First order, primitive.
664 (let ((x 1) (y 2)) (+ x y))
668 ;; First order, thunk.
670 (let ((f (lambda () (+ x y))))
674 (pass-if-peval resolve-primitives
675 ;; First order, let-values (requires primitive expansion for
676 ;; `call-with-values'.)
679 (lambda () (if (zero? x) (values 1 2) (values 3 4)))
684 (pass-if-peval resolve-primitives
685 ;; First order, multiple values.
688 (apply (primitive values) (const 1) (const 2)))
690 (pass-if-peval resolve-primitives
691 ;; First order, multiple values truncated.
692 (let ((x (values 1 'a)) (y 2))
694 (apply (primitive values) (const 1) (const 2)))
696 (pass-if-peval resolve-primitives
697 ;; First order, multiple values truncated.
702 ;; First order, coalesced, mutability preserved.
703 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
704 (apply (primitive list)
705 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
708 ;; First order, coalesced, immutability preserved.
709 (cons 0 (cons 1 (cons 2 '(3 4 5))))
710 (apply (primitive cons) (const 0)
711 (apply (primitive cons) (const 1)
712 (apply (primitive cons) (const 2)
715 ;; These two tests doesn't work any more because we changed the way we
716 ;; deal with constants -- now the algorithm will see a construction as
717 ;; being bound to the lexical, so it won't propagate it. It can't
718 ;; even propagate it in the case that it is only referenced once,
721 ;; (let ((x (cons 1 2))) (lambda () x))
723 ;; is not the same as
725 ;; (lambda () (cons 1 2))
727 ;; Perhaps if we determined that not only was it only referenced once,
728 ;; it was not closed over by a lambda, then we could propagate it, and
729 ;; re-enable these two tests.
733 ;; First order, mutability preserved.
734 (let loop ((i 3) (r '()))
737 (loop (1- i) (cons (cons i i) r))))
738 (apply (primitive list)
739 (apply (primitive cons) (const 1) (const 1))
740 (apply (primitive cons) (const 2) (const 2))
741 (apply (primitive cons) (const 3) (const 3))))
746 ;; First order, evaluated.
751 (loop (1- i) (cons i r))))
754 ;; Instead here are tests for what happens for the above cases: they
755 ;; unroll but they don't fold.
757 (let loop ((i 3) (r '()))
760 (loop (1- i) (cons (cons i i) r))))
762 ((apply (primitive list)
763 (apply (primitive cons) (const 3) (const 3))))
765 ((apply (primitive cons)
766 (apply (primitive cons) (const 2) (const 2))
768 (apply (primitive cons)
769 (apply (primitive cons) (const 1) (const 1))
778 (loop (1- i) (cons i r))))
780 ((apply (primitive list) (const 4)))
782 ((apply (primitive cons)
786 ((apply (primitive cons)
790 ((apply (primitive cons)
793 (apply (primitive car)
798 (let loop ((l '(1 2 3 4)) (sum 0))
801 (loop (cdr l) (+ sum (car l)))))
804 (pass-if-peval resolve-primitives
816 (string->chars "yo"))
817 (apply (primitive list) (const #\y) (const #\o)))
820 ;; Primitives in module-refs are resolved (the expansion of `pmatch'
821 ;; below leads to calls to (@@ (system base pmatch) car) and
822 ;; similar, which is what we want to be inlined.)
824 (use-modules (system base pmatch))
833 ;; Mutability preserved.
834 ((lambda (x y z) (list x y z)) 1 2 3)
835 (apply (primitive list) (const 1) (const 2) (const 3)))
838 ;; Don't propagate effect-free expressions that operate on mutable
844 (let (x) (_) ((apply (primitive list) (const 1)))
845 (let (y) (_) ((apply (primitive car) (lexical x _)))
847 (apply (toplevel set-car!) (lexical x _) (const 0))
851 ;; Don't propagate effect-free expressions that operate on objects we
856 (let (y) (_) ((apply (primitive car) (toplevel x)))
858 (apply (toplevel set-car!) (toplevel x) (const 0))
862 ;; Infinite recursion
863 ((lambda (x) (x x)) (lambda (x) (x x)))
868 (apply (lexical x _) (lexical x _))))))
869 (apply (lexical x _) (lexical x _))))
872 ;; First order, aliased primitive.
873 (let* ((x *) (y (x 1 2))) y)
877 ;; First order, shadowed primitive.
879 (define (+ x y) (pk x y))
885 (((x y) #f #f #f () (_ _))
886 (apply (toplevel pk) (lexical x _) (lexical y _))))))
887 (apply (toplevel +) (const 1) (const 2))))
890 ;; First-order, effects preserved.
895 (apply (toplevel do-something!))
899 ;; First order, residual bindings removed.
902 (apply (primitive *) (const 5) (toplevel z)))
905 ;; First order, with lambda.
907 (define (bar z) (* z z))
912 (((x) #f #f #f () (_))
913 (apply (primitive +) (lexical x _) (const 9)))))))
916 ;; First order, with lambda inlined & specialized twice.
917 (let ((f (lambda (x y)
926 (apply (primitive +) ; (f 2 3)
931 (let (x) (_) ((toplevel something)) ; (f something 2)
932 ;; `something' is not const, so preserve order of
933 ;; effects with a lexical binding.
941 ;; First order, with lambda inlined & specialized 3 times.
942 (let ((f (lambda (x y) (if (> x 0) y x))))
949 (const -1) ; (f -1 0)
951 (begin (toplevel y) (const -1)) ; (f -1 y)
952 (toplevel y) ; (f 2 y)
953 (let (x y) (_ _) ((toplevel z) (toplevel y)) ; (f z y)
954 (if (apply (primitive >) (lexical x _) (const 0))
959 ;; First order, conditional.
967 (((x) #f #f #f () (_))
968 (apply (toplevel display) (lexical x _))))))
971 ;; First order, recursive procedure.
972 (letrec ((fibo (lambda (n)
981 ;; Don't propagate toplevel references, as intervening expressions
982 ;; could alter their bindings.
986 (let (x) (_) ((toplevel top))
988 (apply (toplevel foo))
994 (f (* (car x) (cadr x))))
1001 ;; Higher order with optional argument (default value).
1002 ((lambda* (f x #:optional (y 0))
1003 (+ y (f (* (car x) (cadr x)))))
1010 ;; Higher order with optional argument (caller-supplied value).
1011 ((lambda* (f x #:optional (y 0))
1012 (+ y (f (* (car x) (cadr x)))))
1020 ;; Higher order with optional argument (side-effecting default
1022 ((lambda* (f x #:optional (y (foo)))
1023 (+ y (f (* (car x) (cadr x)))))
1027 (let (y) (_) ((apply (toplevel foo)))
1028 (apply (primitive +) (lexical y _) (const 7))))
1031 ;; Higher order with optional argument (caller-supplied value).
1032 ((lambda* (f x #:optional (y (foo)))
1033 (+ y (f (* (car x) (cadr x)))))
1042 ((lambda (f) (f x)) (lambda (x) x))
1047 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
1048 (let ((fold (lambda (f g) (f (g top)))))
1049 (fold 1+ (lambda (x) x)))
1050 (apply (primitive 1+) (toplevel top)))
1053 ;; Procedure not inlined when residual code contains recursive calls.
1054 ;; <http://debbugs.gnu.org/9542>
1055 (letrec ((fold (lambda (f x3 b null? car cdr)
1058 (f (car x3) (fold f (cdr x3) b null? car cdr))))))
1059 (fold * x 1 zero? (lambda (x1) x1) (lambda (x2) (- x2 1))))
1060 (letrec (fold) (_) (_)
1061 (apply (lexical fold _)
1068 (((x1) #f #f #f () (_))
1072 (((x2) #f #f #f () (_))
1073 (apply (primitive -) (lexical x2 _) (const 1))))))))
1075 (pass-if "inlined lambdas are alpha-renamed"
1076 ;; In this example, `make-adder' is inlined more than once; thus,
1077 ;; they should use different gensyms for their arguments, because
1078 ;; the various optimization passes assume uniquely-named variables.
1081 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html> and
1082 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00029.html>.
1083 (pmatch (unparse-tree-il
1086 (lambda (x) (lambda (y) (+ x y)))))
1087 (cons (make-adder 1) (make-adder 2)))
1089 ((apply (primitive cons)
1092 (((y) #f #f #f () (,gensym1))
1093 (apply (primitive +)
1095 (lexical y ,ref1)))))
1098 (((y) #f #f #f () (,gensym2))
1099 (apply (primitive +)
1101 (lexical y ,ref2))))))
1102 (and (eq? gensym1 ref1)
1104 (not (eq? gensym1 gensym2))))
1108 ;; Unused letrec bindings are pruned.
1109 (letrec ((a (lambda () (b)))
1116 ;; Unused letrec bindings are pruned.
1121 (begin (apply (toplevel foo!))
1125 ;; Higher order, mutually recursive procedures.
1126 (letrec ((even? (lambda (x)
1131 (and (even? 4) (odd? 7)))
1135 ;; Memv with constants.
1140 ;; Memv with non-constant list. It could fold but doesn't
1142 (memv 1 (list 3 2 1))
1143 (apply (primitive memv)
1145 (apply (primitive list) (const 3) (const 2) (const 1))))
1148 ;; Memv with non-constant key, constant list, test context
1152 (let (key) (_) ((toplevel foo))
1153 (if (if (apply (primitive eqv?) (lexical key _) (const 3))
1155 (if (apply (primitive eqv?) (lexical key _) (const 2))
1157 (apply (primitive eqv?) (lexical key _) (const 1))))
1162 ;; Memv with non-constant key, empty list, test context. Currently
1163 ;; doesn't fold entirely.
1167 (begin (toplevel foo) (const b)))
1170 ;; Below are cases where constant propagation should bail out.
1174 ;; Non-constant lexical is not propagated.
1175 (let ((v (make-vector 6 #f)))
1177 (vector-set! v n n)))
1179 ((apply (toplevel make-vector) (const 6) (const #f)))
1182 (((n) #f #f #f () (_))
1183 (apply (toplevel vector-set!)
1184 (lexical v _) (lexical n _) (lexical n _)))))))
1187 ;; Mutable lexical is not propagated.
1188 (let ((v (vector 1 2 3)))
1192 ((apply (primitive vector) (const 1) (const 2) (const 3)))
1195 ((() #f #f #f () ())
1199 ;; Lexical that is not provably pure is not inlined nor propagated.
1200 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
1203 (let (x) (_) ((if (apply (primitive >) (toplevel p) (toplevel q))
1204 (apply (toplevel frob!))
1205 (apply (toplevel display) (const chbouib))))
1206 (let (y) (_) ((apply (primitive *) (lexical x _) (const 2)))
1207 (apply (primitive +)
1208 (lexical x _) (lexical x _) (lexical y _)))))
1211 ;; Non-constant arguments not propagated to lambdas.
1219 (let (x y z) (_ _ _)
1220 ((apply (primitive vector) (const 1) (const 2) (const 3))
1221 (apply (toplevel make-list) (const 10))
1222 (apply (primitive list) (const 1) (const 2) (const 3)))
1224 (apply (toplevel vector-set!)
1225 (lexical x _) (const 0) (const 0))
1226 (apply (toplevel set-car!)
1227 (lexical y _) (const 0))
1228 (apply (toplevel set-cdr!)
1229 (lexical z _) (const ())))))
1232 (let ((foo top-foo) (bar top-bar))
1233 (let* ((g (lambda (x y) (+ x y)))
1234 (f (lambda (g x) (g x x))))
1235 (+ (f g foo) (f g bar))))
1236 (let (foo bar) (_ _) ((toplevel top-foo) (toplevel top-bar))
1237 (apply (primitive +)
1238 (apply (primitive +) (lexical foo _) (lexical foo _))
1239 (apply (primitive +) (lexical bar _) (lexical bar _)))))
1242 ;; Fresh objects are not turned into constants, nor are constants
1243 ;; turned into fresh objects.
1248 (let (x) (_) ((apply (primitive cons) (const 1) (const (2 3))))
1249 (apply (primitive cons) (const 0) (lexical x _))))
1252 ;; Bindings mutated.
1256 (let (x) (_) ((const 2))
1258 (set! (lexical x _) (const 3))
1262 ;; Bindings mutated.
1267 (frob f) ; may mutate `x'
1269 (letrec (x) (_) ((const 0))
1271 (apply (toplevel frob) (lambda _ _))
1275 ;; Bindings mutated.
1276 (letrec ((f (lambda (x)
1277 (set! f (lambda (_) x))
1283 ;; Bindings possibly mutated.
1284 (let ((x (make-foo)))
1285 (frob! x) ; may mutate `x'
1287 (let (x) (_) ((apply (toplevel make-foo)))
1289 (apply (toplevel frob!) (lexical x _))
1293 ;; Inlining stops at recursive calls with dynamic arguments.
1295 (if (< x 0) x (loop (1- x))))
1296 (letrec (loop) (_) ((lambda (_)
1298 (((x) #f #f #f () (_))
1300 (apply (lexical loop _)
1301 (apply (primitive 1-)
1302 (lexical x _))))))))
1303 (apply (lexical loop _) (toplevel x))))
1306 ;; Recursion on the 2nd argument is fully evaluated.
1308 (let loop ((x x) (y 10))
1312 (let (x) (_) ((apply (toplevel top)))
1313 (apply (toplevel foo) (lexical x _) (const 0))))
1316 ;; Inlining aborted when residual code contains recursive calls.
1318 ;; <http://debbugs.gnu.org/9542>
1319 (let loop ((x x) (y 0))
1321 (loop (1- x) (1- y))
1324 (loop (1+ x) (1+ y)))))
1325 (letrec (loop) (_) ((lambda (_)
1327 (((x y) #f #f #f () (_ _))
1328 (if (apply (primitive >)
1329 (lexical y _) (const 0))
1331 (apply (lexical loop _) (toplevel x) (const 0))))
1334 ;; Infinite recursion: `peval' gives up and leaves it as is.
1335 (letrec ((f (lambda (x) (g (1- x))))
1336 (g (lambda (x) (h (1+ x))))
1337 (h (lambda (x) (f x))))
1342 ;; Infinite recursion: all the arguments to `loop' are static, but
1343 ;; unrolling it would lead `peval' to enter an infinite loop.
1347 (letrec (loop) (_) ((lambda . _))
1348 (apply (lexical loop _) (const 0))))
1351 ;; This test checks that the `start' binding is indeed residualized.
1352 ;; See the `referenced?' procedure in peval's `prune-bindings'.
1354 (set! pos 1) ;; Cause references to `pos' to residualize.
1355 (let ((here (let ((start pos)) (lambda () start))))
1357 (let (pos) (_) ((const 0))
1359 (set! (lexical pos _) (const 1))
1361 (apply (lexical here _))))))
1364 ;; FIXME: should this one residualize the binding?
1370 ;; This is a fun one for peval to handle.
1373 (letrec (a) (_) ((lexical a _))
1377 ;; Another interesting recursive case.
1378 (letrec ((a b) (b a))
1380 (letrec (a) (_) ((lexical a _))
1384 ;; Another pruning case, that `a' is residualized.
1385 (letrec ((a (lambda () (a)))
1391 ;; "b c a" is the current order that we get with unordered letrec,
1392 ;; but it's not important to this test, so if it changes, just adapt
1394 (letrec (b c a) (_ _ _)
1397 ((() #f #f #f () ())
1398 (apply (lexical a _)))))
1401 (((x) #f #f #f () (_))
1405 ((() #f #f #f () ())
1406 (apply (lexical a _))))))
1409 ((apply (toplevel foo) (lexical b _)))
1410 (apply (lexical c _)
1414 ;; In this case, we can prune the bindings. `a' ends up being copied
1415 ;; because it is only referenced once in the source program. Oh
1417 (letrec* ((a (lambda (x) (top x)))
1420 (apply (toplevel foo)
1423 (((x) #f #f #f () (_))
1424 (apply (toplevel top) (lexical x _)))))
1427 (((x) #f #f #f () (_))
1428 (apply (toplevel top) (lexical x _)))))))
1431 ;; Constant folding: cons of #nil does not make list
1433 (apply (primitive cons) (const 1) (const '#nil)))
1436 ;; Constant folding: cons
1437 (begin (cons 1 2) #f)
1441 ;; Constant folding: cons
1442 (begin (cons (foo) 2) #f)
1443 (begin (apply (toplevel foo)) (const #f)))
1446 ;; Constant folding: cons
1451 ;; Constant folding: car+cons
1456 ;; Constant folding: cdr+cons
1461 ;; Constant folding: car+cons, impure
1462 (car (cons 1 (bar)))
1463 (begin (apply (toplevel bar)) (const 1)))
1466 ;; Constant folding: cdr+cons, impure
1467 (cdr (cons (bar) 0))
1468 (begin (apply (toplevel bar)) (const 0)))
1471 ;; Constant folding: car+list
1476 ;; Constant folding: cdr+list
1478 (apply (primitive list) (const 0)))
1481 ;; Constant folding: car+list, impure
1482 (car (list 1 (bar)))
1483 (begin (apply (toplevel bar)) (const 1)))
1486 ;; Constant folding: cdr+list, impure
1487 (cdr (list (bar) 0))
1488 (begin (apply (toplevel bar)) (apply (primitive list) (const 0))))
1492 ;; Non-constant guards get lexical bindings.
1493 (dynamic-wind foo (lambda () bar) baz)
1494 (let (pre post) (_ _) ((toplevel foo) (toplevel baz))
1495 (dynwind (lexical pre _) (toplevel bar) (lexical post _))))
1499 ;; Constant guards don't need lexical bindings.
1500 (dynamic-wind (lambda () foo) (lambda () bar) (lambda () baz))
1504 ((() #f #f #f () ()) (toplevel foo))))
1508 ((() #f #f #f () ()) (toplevel baz))))))
1512 ;; Prompt is removed if tag is unreferenced
1513 (let ((tag (make-prompt-tag)))
1514 (call-with-prompt tag
1516 (lambda args args)))
1521 ;; Prompt is removed if tag is unreferenced, with explicit stem
1522 (let ((tag (make-prompt-tag "foo")))
1523 (call-with-prompt tag
1525 (lambda args args)))
1528 ;; Handler lambda inlined
1531 (call-with-prompt tag
1534 (prompt (toplevel tag)
1537 (((k x) #f #f #f () (_ _))
1540 ;; Handler toplevel not inlined
1543 (call-with-prompt tag
1546 (let (handler) (_) ((toplevel handler))
1547 (prompt (toplevel tag)
1550 ((() #f args #f () (_))
1551 (apply (primitive @apply)
1553 (lexical args _)))))))
1557 ;; `while' without `break' or `continue' has no prompts and gets its
1558 ;; condition folded. Unfortunately the outer `lp' does not yet get
1564 ((() #f #f #f () ())
1568 ((() #f #f #f () ())
1569 (apply (lexical loop _))))))
1570 (apply (lexical loop _)))))))
1571 (apply (lexical lp _))))
1576 (apply (lambda (x y) (+ x y))
1580 (((x y) #f #f #f () (_ _))
1583 (pass-if-peval resolve-primitives
1584 ((@ (guile) car) '(1 2))
1587 (pass-if-peval resolve-primitives
1588 ((@@ (guile) car) '(1 2))
1593 (with-test-prefix "tree-il-fold"
1595 (pass-if "empty tree"
1596 (let ((leaf? #f) (up? #f) (down? #f) (mark (list 'mark)))
1598 (tree-il-fold (lambda (x y) (set! leaf? #t) y)
1599 (lambda (x y) (set! down? #t) y)
1600 (lambda (x y) (set! up? #t) y)
1607 (pass-if "lambda and application"
1608 (let* ((leaves '()) (ups '()) (downs '())
1609 (result (tree-il-fold (lambda (x y)
1610 (set! leaves (cons x leaves))
1613 (set! downs (cons x downs))
1616 (set! ups (cons x ups))
1622 (((x y) #f #f #f () (x1 y1))
1627 (and (equal? (map strip-source leaves)
1628 (list (make-lexical-ref #f 'y 'y1)
1629 (make-lexical-ref #f 'x 'x1)
1630 (make-toplevel-ref #f '+)))
1631 (= (length downs) 3)
1632 (equal? (reverse (map strip-source ups))
1633 (map strip-source downs))))))
1640 ;; Make sure we get English messages.
1641 (setlocale LC_ALL "C")
1643 (define (call-with-warnings thunk)
1644 (let ((port (open-output-string)))
1645 (with-fluids ((*current-warning-port* port)
1646 (*current-warning-prefix* ""))
1648 (let ((warnings (get-output-string port)))
1649 (string-tokenize warnings
1650 (char-set-complement (char-set #\newline))))))
1652 (define %opts-w-unused
1653 '(#:warnings (unused-variable)))
1655 (define %opts-w-unused-toplevel
1656 '(#:warnings (unused-toplevel)))
1658 (define %opts-w-unbound
1659 '(#:warnings (unbound-variable)))
1661 (define %opts-w-arity
1662 '(#:warnings (arity-mismatch)))
1664 (define %opts-w-format
1665 '(#:warnings (format)))
1668 (with-test-prefix "warnings"
1670 (pass-if "unknown warning type"
1671 (let ((w (call-with-warnings
1673 (compile #t #:opts '(#:warnings (does-not-exist)))))))
1674 (and (= (length w) 1)
1675 (number? (string-contains (car w) "unknown warning")))))
1677 (with-test-prefix "unused-variable"
1680 (null? (call-with-warnings
1682 (compile '(lambda (x y) (+ x y))
1683 #:opts %opts-w-unused)))))
1685 (pass-if "let/unused"
1686 (let ((w (call-with-warnings
1688 (compile '(lambda (x)
1691 #:opts %opts-w-unused)))))
1692 (and (= (length w) 1)
1693 (number? (string-contains (car w) "unused variable `y'")))))
1695 (pass-if "shadowed variable"
1696 (let ((w (call-with-warnings
1698 (compile '(lambda (x)
1702 #:opts %opts-w-unused)))))
1703 (and (= (length w) 1)
1704 (number? (string-contains (car w) "unused variable `y'")))))
1707 (null? (call-with-warnings
1709 (compile '(lambda ()
1710 (letrec ((x (lambda () (y)))
1711 (y (lambda () (x))))
1713 #:opts %opts-w-unused)))))
1715 (pass-if "unused argument"
1716 ;; Unused arguments should not be reported.
1717 (null? (call-with-warnings
1719 (compile '(lambda (x y z) #t)
1720 #:opts %opts-w-unused)))))
1722 (pass-if "special variable names"
1723 (null? (call-with-warnings
1725 (compile '(lambda ()
1726 (let ((_ 'underscore)
1727 (#{gensym name}# 'ignore-me))
1730 #:opts %opts-w-unused))))))
1732 (with-test-prefix "unused-toplevel"
1734 (pass-if "used after definition"
1735 (null? (call-with-warnings
1737 (let ((in (open-input-string
1738 "(define foo 2) foo")))
1739 (read-and-compile in
1741 #:opts %opts-w-unused-toplevel))))))
1743 (pass-if "used before definition"
1744 (null? (call-with-warnings
1746 (let ((in (open-input-string
1747 "(define (bar) foo) (define foo 2) (bar)")))
1748 (read-and-compile in
1750 #:opts %opts-w-unused-toplevel))))))
1752 (pass-if "unused but public"
1753 (let ((in (open-input-string
1754 "(define-module (test-suite tree-il x) #:export (bar))
1755 (define (bar) #t)")))
1756 (null? (call-with-warnings
1758 (read-and-compile in
1760 #:opts %opts-w-unused-toplevel))))))
1762 (pass-if "unused but public (more)"
1763 (let ((in (open-input-string
1764 "(define-module (test-suite tree-il x) #:export (bar))
1765 (define (bar) (baz))
1766 (define (baz) (foo))
1767 (define (foo) #t)")))
1768 (null? (call-with-warnings
1770 (read-and-compile in
1772 #:opts %opts-w-unused-toplevel))))))
1774 (pass-if "unused but define-public"
1775 (null? (call-with-warnings
1777 (compile '(define-public foo 2)
1779 #:opts %opts-w-unused-toplevel)))))
1781 (pass-if "used by macro"
1782 ;; FIXME: See comment about macros at `unused-toplevel-analysis'.
1785 (null? (call-with-warnings
1787 (let ((in (open-input-string
1788 "(define (bar) 'foo)
1790 (syntax-rules () ((_) (bar))))")))
1791 (read-and-compile in
1793 #:opts %opts-w-unused-toplevel))))))
1796 (let ((w (call-with-warnings
1798 (compile '(define foo 2)
1800 #:opts %opts-w-unused-toplevel)))))
1801 (and (= (length w) 1)
1802 (number? (string-contains (car w)
1803 (format #f "top-level variable `~A'"
1806 (pass-if "unused recursive"
1807 (let ((w (call-with-warnings
1809 (compile '(define (foo) (foo))
1811 #:opts %opts-w-unused-toplevel)))))
1812 (and (= (length w) 1)
1813 (number? (string-contains (car w)
1814 (format #f "top-level variable `~A'"
1817 (pass-if "unused mutually recursive"
1818 (let* ((in (open-input-string
1819 "(define (foo) (bar)) (define (bar) (foo))"))
1820 (w (call-with-warnings
1822 (read-and-compile in
1824 #:opts %opts-w-unused-toplevel)))))
1825 (and (= (length w) 2)
1826 (number? (string-contains (car w)
1827 (format #f "top-level variable `~A'"
1829 (number? (string-contains (cadr w)
1830 (format #f "top-level variable `~A'"
1833 (pass-if "special variable names"
1834 (null? (call-with-warnings
1836 (compile '(define #{gensym name}# 'ignore-me)
1838 #:opts %opts-w-unused-toplevel))))))
1840 (with-test-prefix "unbound variable"
1843 (null? (call-with-warnings
1845 (compile '+ #:opts %opts-w-unbound)))))
1849 (w (call-with-warnings
1853 #:opts %opts-w-unbound)))))
1854 (and (= (length w) 1)
1855 (number? (string-contains (car w)
1856 (format #f "unbound variable `~A'"
1861 (w (call-with-warnings
1863 (compile `(set! ,v 7)
1865 #:opts %opts-w-unbound)))))
1866 (and (= (length w) 1)
1867 (number? (string-contains (car w)
1868 (format #f "unbound variable `~A'"
1871 (pass-if "module-local top-level is visible"
1872 (let ((m (make-module))
1874 (beautify-user-module! m)
1875 (compile `(define ,v 123)
1876 #:env m #:opts %opts-w-unbound)
1877 (null? (call-with-warnings
1882 #:opts %opts-w-unbound))))))
1884 (pass-if "module-local top-level is visible after"
1885 (let ((m (make-module))
1887 (beautify-user-module! m)
1888 (null? (call-with-warnings
1890 (let ((in (open-input-string
1893 (define chbouib 5)")))
1894 (read-and-compile in
1896 #:opts %opts-w-unbound)))))))
1898 (pass-if "optional arguments are visible"
1899 (null? (call-with-warnings
1901 (compile '(lambda* (x #:optional y z) (list x y z))
1902 #:opts %opts-w-unbound
1905 (pass-if "keyword arguments are visible"
1906 (null? (call-with-warnings
1908 (compile '(lambda* (x #:key y z) (list x y z))
1909 #:opts %opts-w-unbound
1912 (pass-if "GOOPS definitions are visible"
1913 (let ((m (make-module))
1915 (beautify-user-module! m)
1916 (module-use! m (resolve-interface '(oop goops)))
1917 (null? (call-with-warnings
1919 (let ((in (open-input-string
1920 "(define-class <foo> ()
1921 (bar #:getter foo-bar))
1922 (define z (foo-bar (make <foo>)))")))
1923 (read-and-compile in
1925 #:opts %opts-w-unbound))))))))
1927 (with-test-prefix "arity mismatch"
1930 (null? (call-with-warnings
1932 (compile '(cons 'a 'b) #:opts %opts-w-arity)))))
1934 (pass-if "direct application"
1935 (let ((w (call-with-warnings
1937 (compile '((lambda (x y) (or x y)) 1 2 3 4 5)
1938 #:opts %opts-w-arity
1940 (and (= (length w) 1)
1941 (number? (string-contains (car w)
1942 "wrong number of arguments to")))))
1944 (let ((w (call-with-warnings
1946 (compile '(let ((f (lambda (x y) (+ x y))))
1948 #:opts %opts-w-arity
1950 (and (= (length w) 1)
1951 (number? (string-contains (car w)
1952 "wrong number of arguments to")))))
1955 (let ((w (call-with-warnings
1957 (compile '(cons 1 2 3 4)
1958 #:opts %opts-w-arity
1960 (and (= (length w) 1)
1961 (number? (string-contains (car w)
1962 "wrong number of arguments to")))))
1964 (pass-if "alias to global"
1965 (let ((w (call-with-warnings
1967 (compile '(let ((f cons)) (f 1 2 3 4))
1968 #:opts %opts-w-arity
1970 (and (= (length w) 1)
1971 (number? (string-contains (car w)
1972 "wrong number of arguments to")))))
1974 (pass-if "alias to lexical to global"
1975 (let ((w (call-with-warnings
1977 (compile '(let ((f number?))
1980 #:opts %opts-w-arity
1982 (and (= (length w) 1)
1983 (number? (string-contains (car w)
1984 "wrong number of arguments to")))))
1986 (pass-if "alias to lexical"
1987 (let ((w (call-with-warnings
1989 (compile '(let ((f (lambda (x y z) (+ x y z))))
1992 #:opts %opts-w-arity
1994 (and (= (length w) 1)
1995 (number? (string-contains (car w)
1996 "wrong number of arguments to")))))
1999 (let ((w (call-with-warnings
2001 (compile '(letrec ((odd? (lambda (x) (even? (1- x))))
2006 #:opts %opts-w-arity
2008 (and (= (length w) 1)
2009 (number? (string-contains (car w)
2010 "wrong number of arguments to")))))
2012 (pass-if "case-lambda"
2013 (null? (call-with-warnings
2015 (compile '(let ((f (case-lambda
2022 #:opts %opts-w-arity
2025 (pass-if "case-lambda with wrong number of arguments"
2026 (let ((w (call-with-warnings
2028 (compile '(let ((f (case-lambda
2032 #:opts %opts-w-arity
2034 (and (= (length w) 1)
2035 (number? (string-contains (car w)
2036 "wrong number of arguments to")))))
2038 (pass-if "case-lambda*"
2039 (null? (call-with-warnings
2041 (compile '(let ((f (case-lambda*
2042 ((x #:optional y) 1)
2044 ((x y #:key z) 3))))
2049 #:opts %opts-w-arity
2052 (pass-if "case-lambda* with wrong arguments"
2053 (let ((w (call-with-warnings
2055 (compile '(let ((f (case-lambda*
2056 ((x #:optional y) 1)
2058 ((x y #:key z) 3))))
2061 #:opts %opts-w-arity
2063 (and (= (length w) 2)
2064 (null? (filter (lambda (w)
2068 w "wrong number of arguments to"))))
2071 (pass-if "local toplevel-defines"
2072 (let ((w (call-with-warnings
2074 (let ((in (open-input-string "
2075 (define (g x) (f x))
2077 (read-and-compile in
2078 #:opts %opts-w-arity
2079 #:to 'assembly))))))
2080 (and (= (length w) 1)
2081 (number? (string-contains (car w)
2082 "wrong number of arguments to")))))
2084 (pass-if "global toplevel alias"
2085 (let ((w (call-with-warnings
2087 (let ((in (open-input-string "
2089 (define (g) (f))")))
2090 (read-and-compile in
2091 #:opts %opts-w-arity
2092 #:to 'assembly))))))
2093 (and (= (length w) 1)
2094 (number? (string-contains (car w)
2095 "wrong number of arguments to")))))
2097 (pass-if "local toplevel overrides global"
2098 (null? (call-with-warnings
2100 (let ((in (open-input-string "
2102 (define (foo x) (cons))")))
2103 (read-and-compile in
2104 #:opts %opts-w-arity
2105 #:to 'assembly))))))
2107 (pass-if "keyword not passed and quiet"
2108 (null? (call-with-warnings
2110 (compile '(let ((f (lambda* (x #:key y) y)))
2112 #:opts %opts-w-arity
2115 (pass-if "keyword passed and quiet"
2116 (null? (call-with-warnings
2118 (compile '(let ((f (lambda* (x #:key y) y)))
2120 #:opts %opts-w-arity
2123 (pass-if "keyword passed to global and quiet"
2124 (null? (call-with-warnings
2126 (let ((in (open-input-string "
2127 (use-modules (system base compile))
2128 (compile '(+ 2 3) #:env (current-module))")))
2129 (read-and-compile in
2130 #:opts %opts-w-arity
2131 #:to 'assembly))))))
2133 (pass-if "extra keyword"
2134 (let ((w (call-with-warnings
2136 (compile '(let ((f (lambda* (x #:key y) y)))
2138 #:opts %opts-w-arity
2140 (and (= (length w) 1)
2141 (number? (string-contains (car w)
2142 "wrong number of arguments to")))))
2144 (pass-if "extra keywords allowed"
2145 (null? (call-with-warnings
2147 (compile '(let ((f (lambda* (x #:key y #:allow-other-keys)
2150 #:opts %opts-w-arity
2151 #:to 'assembly))))))
2153 (with-test-prefix "format"
2155 (pass-if "quiet (no args)"
2156 (null? (call-with-warnings
2158 (compile '(format #t "hey!")
2159 #:opts %opts-w-format
2162 (pass-if "quiet (1 arg)"
2163 (null? (call-with-warnings
2165 (compile '(format #t "hey ~A!" "you")
2166 #:opts %opts-w-format
2169 (pass-if "quiet (2 args)"
2170 (null? (call-with-warnings
2172 (compile '(format #t "~A ~A!" "hello" "world")
2173 #:opts %opts-w-format
2176 (pass-if "wrong port arg"
2177 (let ((w (call-with-warnings
2179 (compile '(format 10 "foo")
2180 #:opts %opts-w-format
2182 (and (= (length w) 1)
2183 (number? (string-contains (car w)
2184 "wrong port argument")))))
2186 (pass-if "non-literal format string"
2187 (let ((w (call-with-warnings
2189 (compile '(format #f fmt)
2190 #:opts %opts-w-format
2192 (and (= (length w) 1)
2193 (number? (string-contains (car w)
2194 "non-literal format string")))))
2196 (pass-if "non-literal format string using gettext"
2197 (null? (call-with-warnings
2199 (compile '(format #t (gettext "~A ~A!") "hello" "world")
2200 #:opts %opts-w-format
2203 (pass-if "non-literal format string using gettext as _"
2204 (null? (call-with-warnings
2206 (compile '(format #t (_ "~A ~A!") "hello" "world")
2207 #:opts %opts-w-format
2210 (pass-if "non-literal format string using ngettext"
2211 (null? (call-with-warnings
2213 (compile '(format #t
2214 (ngettext "~a thing" "~a things" n "dom") n)
2215 #:opts %opts-w-format
2218 (pass-if "non-literal format string using ngettext as N_"
2219 (null? (call-with-warnings
2221 (compile '(format #t (N_ "~a thing" "~a things" n) n)
2222 #:opts %opts-w-format
2225 (pass-if "non-literal format string with (define _ gettext)"
2226 (null? (call-with-warnings
2231 (format #t (_ "~A ~A!") "hello" "world")))
2232 #:opts %opts-w-format
2235 (pass-if "wrong format string"
2236 (let ((w (call-with-warnings
2238 (compile '(format #f 'not-a-string)
2239 #:opts %opts-w-format
2241 (and (= (length w) 1)
2242 (number? (string-contains (car w)
2243 "wrong format string")))))
2245 (pass-if "wrong number of args"
2246 (let ((w (call-with-warnings
2248 (compile '(format "shbweeb")
2249 #:opts %opts-w-format
2251 (and (= (length w) 1)
2252 (number? (string-contains (car w)
2253 "wrong number of arguments")))))
2255 (pass-if "~%, ~~, ~&, ~t, ~_, and ~\\n"
2256 (null? (call-with-warnings
2258 (compile '((@ (ice-9 format) format) some-port
2259 "~&~3_~~ ~\n~12they~%")
2260 #:opts %opts-w-format
2263 (pass-if "one missing argument"
2264 (let ((w (call-with-warnings
2266 (compile '(format some-port "foo ~A~%")
2267 #:opts %opts-w-format
2269 (and (= (length w) 1)
2270 (number? (string-contains (car w)
2271 "expected 1, got 0")))))
2273 (pass-if "one missing argument, gettext"
2274 (let ((w (call-with-warnings
2276 (compile '(format some-port (gettext "foo ~A~%"))
2277 #:opts %opts-w-format
2279 (and (= (length w) 1)
2280 (number? (string-contains (car w)
2281 "expected 1, got 0")))))
2283 (pass-if "two missing arguments"
2284 (let ((w (call-with-warnings
2286 (compile '((@ (ice-9 format) format) #f
2287 "foo ~10,2f and bar ~S~%")
2288 #:opts %opts-w-format
2290 (and (= (length w) 1)
2291 (number? (string-contains (car w)
2292 "expected 2, got 0")))))
2294 (pass-if "one given, one missing argument"
2295 (let ((w (call-with-warnings
2297 (compile '(format #t "foo ~A and ~S~%" hey)
2298 #:opts %opts-w-format
2300 (and (= (length w) 1)
2301 (number? (string-contains (car w)
2302 "expected 2, got 1")))))
2304 (pass-if "too many arguments"
2305 (let ((w (call-with-warnings
2307 (compile '(format #t "foo ~A~%" 1 2)
2308 #:opts %opts-w-format
2310 (and (= (length w) 1)
2311 (number? (string-contains (car w)
2312 "expected 1, got 2")))))
2315 (null? (call-with-warnings
2317 (compile '((@ (ice-9 format) format) #t
2318 "foo ~h ~a~%" 123.4 'bar)
2319 #:opts %opts-w-format
2322 (pass-if "~:h with locale object"
2323 (null? (call-with-warnings
2325 (compile '((@ (ice-9 format) format) #t
2326 "foo ~:h~%" 123.4 %global-locale)
2327 #:opts %opts-w-format
2330 (pass-if "~:h without locale object"
2331 (let ((w (call-with-warnings
2333 (compile '((@ (ice-9 format) format) #t "foo ~,2:h" 123.4)
2334 #:opts %opts-w-format
2336 (and (= (length w) 1)
2337 (number? (string-contains (car w)
2338 "expected 2, got 1")))))
2340 (with-test-prefix "conditionals"
2342 (null? (call-with-warnings
2344 (compile '((@ (ice-9 format) format) #f "~A ~[foo~;bar~;baz~;~] ~10,2f"
2346 #:opts %opts-w-format
2349 (pass-if "literals with selector"
2350 (let ((w (call-with-warnings
2352 (compile '((@ (ice-9 format) format) #f "~2[foo~;bar~;baz~;~] ~A"
2354 #:opts %opts-w-format
2356 (and (= (length w) 1)
2357 (number? (string-contains (car w)
2358 "expected 1, got 2")))))
2360 (pass-if "escapes (exact count)"
2361 (let ((w (call-with-warnings
2363 (compile '((@ (ice-9 format) format) #f "~[~a~;~a~]")
2364 #:opts %opts-w-format
2366 (and (= (length w) 1)
2367 (number? (string-contains (car w)
2368 "expected 2, got 0")))))
2370 (pass-if "escapes with selector"
2371 (let ((w (call-with-warnings
2373 (compile '((@ (ice-9 format) format) #f "~1[chbouib~;~a~]")
2374 #:opts %opts-w-format
2376 (and (= (length w) 1)
2377 (number? (string-contains (car w)
2378 "expected 1, got 0")))))
2380 (pass-if "escapes, range"
2381 (let ((w (call-with-warnings
2383 (compile '((@ (ice-9 format) format) #f "~[chbouib~;~a~;~2*~a~]")
2384 #:opts %opts-w-format
2386 (and (= (length w) 1)
2387 (number? (string-contains (car w)
2388 "expected 1 to 4, got 0")))))
2391 (let ((w (call-with-warnings
2393 (compile '((@ (ice-9 format) format) #f "~@[temperature=~d~]")
2394 #:opts %opts-w-format
2396 (and (= (length w) 1)
2397 (number? (string-contains (car w)
2398 "expected 1, got 0")))))
2401 (let ((w (call-with-warnings
2403 (compile '((@ (ice-9 format) format) #f "~:[~[hey~;~a~;~va~]~;~3*~]")
2404 #:opts %opts-w-format
2406 (and (= (length w) 1)
2407 (number? (string-contains (car w)
2408 "expected 2 to 4, got 0")))))
2410 (pass-if "unterminated"
2411 (let ((w (call-with-warnings
2413 (compile '((@ (ice-9 format) format) #f "~[unterminated")
2414 #:opts %opts-w-format
2416 (and (= (length w) 1)
2417 (number? (string-contains (car w)
2418 "unterminated conditional")))))
2420 (pass-if "unexpected ~;"
2421 (let ((w (call-with-warnings
2423 (compile '((@ (ice-9 format) format) #f "foo~;bar")
2424 #:opts %opts-w-format
2426 (and (= (length w) 1)
2427 (number? (string-contains (car w)
2430 (pass-if "unexpected ~]"
2431 (let ((w (call-with-warnings
2433 (compile '((@ (ice-9 format) format) #f "foo~]")
2434 #:opts %opts-w-format
2436 (and (= (length w) 1)
2437 (number? (string-contains (car w)
2441 (null? (call-with-warnings
2443 (compile '((@ (ice-9 format) format) #f "~A ~{~S~} ~A"
2444 'hello '("ladies" "and")
2446 #:opts %opts-w-format
2449 (pass-if "~{...~}, too many args"
2450 (let ((w (call-with-warnings
2452 (compile '((@ (ice-9 format) format) #f "~{~S~}" 1 2 3)
2453 #:opts %opts-w-format
2455 (and (= (length w) 1)
2456 (number? (string-contains (car w)
2457 "expected 1, got 3")))))
2460 (null? (call-with-warnings
2462 (compile '((@ (ice-9 format) format) #f "~@{~S~}" 1 2 3)
2463 #:opts %opts-w-format
2466 (pass-if "~@{...~}, too few args"
2467 (let ((w (call-with-warnings
2469 (compile '((@ (ice-9 format) format) #f "~A ~@{~S~}")
2470 #:opts %opts-w-format
2472 (and (= (length w) 1)
2473 (number? (string-contains (car w)
2474 "expected at least 1, got 0")))))
2476 (pass-if "unterminated ~{...~}"
2477 (let ((w (call-with-warnings
2479 (compile '((@ (ice-9 format) format) #f "~{")
2480 #:opts %opts-w-format
2482 (and (= (length w) 1)
2483 (number? (string-contains (car w)
2487 (null? (call-with-warnings
2489 (compile '((@ (ice-9 format) format) #f "~:@(~A ~A~)" 'foo 'bar)
2490 #:opts %opts-w-format
2494 (let ((w (call-with-warnings
2496 (compile '((@ (ice-9 format) format) #f "~v_foo")
2497 #:opts %opts-w-format
2499 (and (= (length w) 1)
2500 (number? (string-contains (car w)
2501 "expected 1, got 0")))))
2503 (null? (call-with-warnings
2505 (compile '((@ (ice-9 format) format) #f "~v:@y" 1 123)
2506 #:opts %opts-w-format
2511 (let ((w (call-with-warnings
2513 (compile '((@ (ice-9 format) format) #f "~2*~a" 'a 'b)
2514 #:opts %opts-w-format
2516 (and (= (length w) 1)
2517 (number? (string-contains (car w)
2518 "expected 3, got 2")))))
2521 (null? (call-with-warnings
2523 (compile '((@ (ice-9 format) format) #f "~?" "~d ~d" '(1 2))
2524 #:opts %opts-w-format
2527 (pass-if "complex 1"
2528 (let ((w (call-with-warnings
2530 (compile '((@ (ice-9 format) format) #f
2531 "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
2533 #:opts %opts-w-format
2535 (and (= (length w) 1)
2536 (number? (string-contains (car w)
2537 "expected 4, got 6")))))
2539 (pass-if "complex 2"
2540 (let ((w (call-with-warnings
2542 (compile '((@ (ice-9 format) format) #f
2543 "~:(~A~) Commands~:[~; [abbrev]~]:~2%"
2545 #:opts %opts-w-format
2547 (and (= (length w) 1)
2548 (number? (string-contains (car w)
2549 "expected 2, got 4")))))
2551 (pass-if "complex 3"
2552 (let ((w (call-with-warnings
2554 (compile '((@ (ice-9 format) format) #f "~9@a~:[~*~3_~;~3d~] ~v:@y~%")
2555 #:opts %opts-w-format
2557 (and (= (length w) 1)
2558 (number? (string-contains (car w)
2559 "expected 5, got 0")))))
2561 (pass-if "ice-9 format"
2562 (let ((w (call-with-warnings
2564 (let ((in (open-input-string
2565 "(use-modules ((ice-9 format)
2566 #:renamer (symbol-prefix-proc 'i9-)))
2567 (i9-format #t \"yo! ~A\" 1 2)")))
2568 (read-and-compile in
2569 #:opts %opts-w-format
2570 #:to 'assembly))))))
2571 (and (= (length w) 1)
2572 (number? (string-contains (car w)
2573 "expected 1, got 2")))))
2575 (pass-if "not format"
2576 (null? (call-with-warnings
2578 (compile '(let ((format chbouib))
2579 (format #t "not ~A a format string"))
2580 #:opts %opts-w-format
2583 (with-test-prefix "simple-format"
2586 (null? (call-with-warnings
2588 (compile '(simple-format #t "foo ~a bar ~s ~%~~" 1 2)
2589 #:opts %opts-w-format
2592 (pass-if "wrong number of args"
2593 (let ((w (call-with-warnings
2595 (compile '(simple-format #t "foo ~a ~s~%" 'one-missing)
2596 #:opts %opts-w-format
2598 (and (= (length w) 1)
2599 (number? (string-contains (car w) "wrong number")))))
2601 (pass-if "unsupported"
2602 (let ((w (call-with-warnings
2604 (compile '(simple-format #t "foo ~x~%" 16)
2605 #:opts %opts-w-format
2607 (and (= (length w) 1)
2608 (number? (string-contains (car w) "unsupported format option")))))
2610 (pass-if "unsupported, gettext"
2611 (let ((w (call-with-warnings
2613 (compile '(simple-format #t (gettext "foo ~2f~%") 3.14)
2614 #:opts %opts-w-format
2616 (and (= (length w) 1)
2617 (number? (string-contains (car w) "unsupported format option")))))
2619 (pass-if "unsupported, ngettext"
2620 (let ((w (call-with-warnings
2622 (compile '(simple-format #t (ngettext "s ~x" "p ~x" x) x)
2623 #:opts %opts-w-format
2625 (and (= (length w) 1)
2626 (number? (string-contains (car w) "unsupported format option"))))))))