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 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 (primcall + (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 (call (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 (call (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 (call (toplevel foo) (call (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 (primcall 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 (primcall 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)) (primcall 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) (primcall 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) (primcall 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))
221 (set! (lexical x y) (primcall 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 (primcall 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 (primcall 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 (primcall 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 (primcall 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 (primcall 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 (primcall 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 (primcall 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 (primcall 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 (call (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) ((call (toplevel foo)) (call (toplevel bar)))
393 (primcall + (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) (unbind)
403 (lexical #t #t ref 0) (lexical #t #t ref 1)
404 (call add 2) (call return 1) (unbind)))
406 ;; complex bindings in letrec* -> box and set! in order
407 (assert-tree-il->glil without-partial-evaluation
408 (letrec* (x y) (x1 y1) ((call (toplevel foo)) (call (toplevel bar)))
409 (primcall + (lexical x x1) (lexical y y1)))
410 (program () (std-prelude 0 2 #f) (label _)
411 (void) (void) ;; what are these?
412 (bind (x #t 0) (y #t 1))
413 (lexical #t #t box 1) (lexical #t #t box 0)
414 (call new-frame 0) (toplevel ref foo) (call call 0)
415 (lexical #t #t set 0)
416 (call new-frame 0) (toplevel ref bar) (call call 0)
417 (lexical #t #t set 1)
418 (lexical #t #t ref 0)
419 (lexical #t #t ref 1)
420 (call add 2) (call return 1) (unbind)))
422 ;; simple bindings in letrec* -> equivalent to letrec
423 (assert-tree-il->glil without-partial-evaluation
424 (letrec* (x y) (xx yy) ((const 1) (const 2))
426 (program () (std-prelude 0 1 #f) (label _)
428 (bind (y #f 0)) ;; X is removed, and Y is unboxed
429 (lexical #t #f set 0)
430 (lexical #t #f ref 0)
431 (call return 1) (unbind))))
433 (with-test-prefix "lambda"
434 (assert-tree-il->glil
436 (lambda-case (((x) #f #f #f () (y)) (const 2)) #f))
437 (program () (std-prelude 0 0 #f) (label _)
438 (program () (std-prelude 1 1 #f)
439 (bind (x #f 0)) (label _)
440 (const 2) (call return 1) (unbind))
443 (assert-tree-il->glil
445 (lambda-case (((x y) #f #f #f () (x1 y1))
448 (program () (std-prelude 0 0 #f) (label _)
449 (program () (std-prelude 2 2 #f)
450 (bind (x #f 0) (y #f 1)) (label _)
451 (const 2) (call return 1)
455 (assert-tree-il->glil
457 (lambda-case ((() #f x #f () (y)) (const 2))
459 (program () (std-prelude 0 0 #f) (label _)
460 (program () (opt-prelude 0 0 0 1 #f)
461 (bind (x #f 0)) (label _)
462 (const 2) (call return 1)
466 (assert-tree-il->glil
468 (lambda-case (((x) #f x1 #f () (y y1)) (const 2))
470 (program () (std-prelude 0 0 #f) (label _)
471 (program () (opt-prelude 1 0 1 2 #f)
472 (bind (x #f 0) (x1 #f 1)) (label _)
473 (const 2) (call return 1)
477 (assert-tree-il->glil
479 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x y))
481 (program () (std-prelude 0 0 #f) (label _)
482 (program () (opt-prelude 1 0 1 2 #f)
483 (bind (x #f 0) (x1 #f 1)) (label _)
484 (lexical #t #f ref 0) (call return 1)
488 (assert-tree-il->glil
490 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x1 y1))
492 (program () (std-prelude 0 0 #f) (label _)
493 (program () (opt-prelude 1 0 1 2 #f)
494 (bind (x #f 0) (x1 #f 1)) (label _)
495 (lexical #t #f ref 1) (call return 1)
499 (assert-tree-il->glil
501 (lambda-case (((x) #f #f #f () (x1))
503 (lambda-case (((y) #f #f #f () (y1))
507 (program () (std-prelude 0 0 #f) (label _)
508 (program () (std-prelude 1 1 #f)
509 (bind (x #f 0)) (label _)
510 (program () (std-prelude 1 1 #f)
511 (bind (y #f 0)) (label _)
512 (lexical #f #f ref 0) (call return 1)
514 (lexical #t #f ref 0)
515 (call make-closure 1)
520 (with-test-prefix "sequence"
521 (assert-tree-il->glil
522 (begin (begin (const 2) (const #f)) (const #t))
523 (program () (std-prelude 0 0 #f) (label _)
524 (const #t) (call return 1)))
526 (assert-tree-il->glil
527 ;; This gets simplified by `peval'.
528 (primcall null? (begin (const #f) (const 2)))
529 (program () (std-prelude 0 0 #f) (label _)
530 (const #f) (call return 1))))
532 (with-test-prefix "values"
533 (assert-tree-il->glil
535 (primcall values (const 1) (const 2)))
536 (program () (std-prelude 0 0 #f) (label _)
537 (const 1) (call return 1)))
539 (assert-tree-il->glil
541 (primcall values (const 1) (const 2))
543 (program () (std-prelude 0 0 #f) (label _)
544 (const 1) (const 3) (call return/values 2)))
546 (assert-tree-il->glil
548 (primcall values (const 1) (const 2)))
549 (program () (std-prelude 0 0 #f) (label _)
550 (const 1) (call return 1))))
552 ;; FIXME: binding info for or-hacked locals might bork the disassembler,
553 ;; and could be tightened in any case
554 (with-test-prefix "the or hack"
555 (assert-tree-il->glil without-partial-evaluation
556 (let (x) (y) ((const 1))
559 (let (a) (b) ((const 2))
561 (program () (std-prelude 0 1 #f) (label _)
562 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
563 (lexical #t #f ref 0) (branch br-if-not ,l1)
564 (lexical #t #f ref 0) (call return 1)
566 (const 2) (bind (a #f 0)) (lexical #t #f set 0)
567 (lexical #t #f ref 0) (call return 1)
572 ;; second bound var is unreferenced
573 (assert-tree-il->glil without-partial-evaluation
574 (let (x) (y) ((const 1))
577 (let (a) (b) ((const 2))
579 (program () (std-prelude 0 1 #f) (label _)
580 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
581 (lexical #t #f ref 0) (branch br-if-not ,l1)
582 (lexical #t #f ref 0) (call return 1)
584 (lexical #t #f ref 0) (call return 1)
588 (with-test-prefix "apply"
589 (assert-tree-il->glil
590 (primcall @apply (toplevel foo) (toplevel bar))
591 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (toplevel ref bar) (call tail-apply 2)))
592 (assert-tree-il->glil
593 (begin (primcall @apply (toplevel foo) (toplevel bar)) (void))
594 (program () (std-prelude 0 0 #f) (label _)
595 (call new-frame 0) (toplevel ref apply) (toplevel ref foo) (toplevel ref bar) (mv-call 2 ,l1)
596 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
598 (void) (call return 1))
599 (and (eq? l1 l3) (eq? l2 l4)))
600 (assert-tree-il->glil
601 (call (toplevel foo) (call (toplevel @apply) (toplevel bar) (toplevel baz)))
602 (program () (std-prelude 0 0 #f) (label _)
604 (call new-frame 0) (toplevel ref bar) (toplevel ref baz) (call apply 2)
605 (call tail-call 1))))
607 (with-test-prefix "call/cc"
608 (assert-tree-il->glil
609 (primcall @call-with-current-continuation (toplevel foo))
610 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call tail-call/cc 1)))
611 (assert-tree-il->glil
612 (begin (primcall @call-with-current-continuation (toplevel foo)) (void))
613 (program () (std-prelude 0 0 #f) (label _)
614 (call new-frame 0) (toplevel ref call-with-current-continuation) (toplevel ref foo) (mv-call 1 ,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
621 (call (toplevel @call-with-current-continuation) (toplevel bar)))
622 (program () (std-prelude 0 0 #f) (label _)
624 (toplevel ref bar) (call call/cc 1)
625 (call tail-call 1))))
628 (with-test-prefix "labels allocation"
629 (pass-if "http://debbugs.gnu.org/9769"
630 ((compile '(lambda ()
631 (let ((fail (lambda () #f)))
632 (let ((test (lambda () (fail))))
635 ;; Prevent inlining. We're testing analyze.scm's
636 ;; labels allocator here, and inlining it will
637 ;; reduce the entire thing to #t.
638 #:opts '(#:partial-eval? #f)))))
641 (with-test-prefix "partial evaluation"
644 ;; First order, primitive.
645 (let ((x 1) (y 2)) (+ x y))
649 ;; First order, thunk.
651 (let ((f (lambda () (+ x y))))
655 (pass-if-peval resolve-primitives
656 ;; First order, let-values (requires primitive expansion for
657 ;; `call-with-values'.)
660 (lambda () (if (zero? x) (values 1 2) (values 3 4)))
666 ;; First order, coalesced, mutability preserved.
667 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
669 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
672 ;; First order, coalesced, mutability preserved.
673 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
674 ;; This must not be a constant.
676 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
679 ;; First order, coalesced, immutability preserved.
680 (cons 0 (cons 1 (cons 2 '(3 4 5))))
681 (primcall cons (const 0)
682 (primcall cons (const 1)
683 (primcall cons (const 2)
686 ;; These two tests doesn't work any more because we changed the way we
687 ;; deal with constants -- now the algorithm will see a construction as
688 ;; being bound to the lexical, so it won't propagate it. It can't
689 ;; even propagate it in the case that it is only referenced once,
692 ;; (let ((x (cons 1 2))) (lambda () x))
694 ;; is not the same as
696 ;; (lambda () (cons 1 2))
698 ;; Perhaps if we determined that not only was it only referenced once,
699 ;; it was not closed over by a lambda, then we could propagate it, and
700 ;; re-enable these two tests.
704 ;; First order, mutability preserved.
705 (let loop ((i 3) (r '()))
708 (loop (1- i) (cons (cons i i) r))))
710 (primcall cons (const 1) (const 1))
711 (primcall cons (const 2) (const 2))
712 (primcall cons (const 3) (const 3))))
717 ;; First order, evaluated.
722 (loop (1- i) (cons i r))))
725 ;; Instead here are tests for what happens for the above cases: they
726 ;; unroll but they don't fold.
728 (let loop ((i 3) (r '()))
731 (loop (1- i) (cons (cons i i) r))))
734 (primcall cons (const 3) (const 3))))
737 (primcall cons (const 2) (const 2))
740 (primcall cons (const 1) (const 1))
749 (loop (1- i) (cons i r))))
751 ((primcall list (const 4)))
769 (let loop ((l '(1 2 3 4)) (sum 0))
772 (loop (cdr l) (+ sum (car l)))))
775 (pass-if-peval resolve-primitives
787 (string->chars "yo"))
788 (apply (primitive list) (const #\y) (const #\o)))
791 ;; Primitives in module-refs are resolved (the expansion of `pmatch'
792 ;; below leads to calls to (@@ (system base pmatch) car) and
793 ;; similar, which is what we want to be inlined.)
795 (use-modules (system base pmatch))
803 ;; Mutability preserved.
804 ((lambda (x y z) (list x y z)) 1 2 3)
805 (primcall list (const 1) (const 2) (const 3)))
808 ;; Don't propagate effect-free expressions that operate on mutable
814 (let (x) (_) ((primcall list (const 1)))
815 (let (y) (_) ((primcall car (lexical x _)))
817 (call (toplevel set-car!) (lexical x _) (const 0))
821 ;; Don't propagate effect-free expressions that operate on objects we
826 (let (y) (_) ((primcall car (toplevel x)))
828 (call (toplevel set-car!) (toplevel x) (const 0))
832 ;; Infinite recursion
833 ((lambda (x) (x x)) (lambda (x) (x x)))
838 (call (lexical x _) (lexical x _))))))
839 (call (lexical x _) (lexical x _))))
842 ;; First order, aliased primitive.
843 (let* ((x *) (y (x 1 2))) y)
847 ;; First order, shadowed primitive.
849 (define (+ x y) (pk x y))
855 (((x y) #f #f #f () (_ _))
856 (call (toplevel pk) (lexical x _) (lexical y _))))))
857 (call (toplevel +) (const 1) (const 2))))
860 ;; First-order, effects preserved.
865 (call (toplevel do-something!))
869 ;; First order, residual bindings removed.
872 (primcall * (const 5) (toplevel z)))
875 ;; First order, with lambda.
877 (define (bar z) (* z z))
882 (((x) #f #f #f () (_))
883 (primcall + (lexical x _) (const 9)))))))
886 ;; First order, with lambda inlined & specialized twice.
887 (let ((f (lambda (x y)
896 (primcall + ; (f 2 3)
901 (let (x) (_) ((toplevel something)) ; (f something 2)
902 ;; `something' is not const, so preserve order of
903 ;; effects with a lexical binding.
911 ;; First order, with lambda inlined & specialized 3 times.
912 (let ((f (lambda (x y) (if (> x 0) y x))))
919 (const -1) ; (f -1 0)
921 (seq (toplevel y) (const -1)) ; (f -1 y)
922 (toplevel y) ; (f 2 y)
923 (let (x y) (_ _) ((toplevel z) (toplevel y)) ; (f z y)
924 (if (primcall > (lexical x _) (const 0))
929 ;; First order, conditional.
937 (((x) #f #f #f () (_))
938 (call (toplevel display) (lexical x _))))))
941 ;; First order, recursive procedure.
942 (letrec ((fibo (lambda (n)
951 ;; Don't propagate toplevel references, as intervening expressions
952 ;; could alter their bindings.
956 (let (x) (_) ((toplevel top))
958 (call (toplevel foo))
964 (f (* (car x) (cadr x))))
971 ;; Higher order with optional argument (default value).
972 ((lambda* (f x #:optional (y 0))
973 (+ y (f (* (car x) (cadr x)))))
980 ;; Higher order with optional argument (caller-supplied value).
981 ((lambda* (f x #:optional (y 0))
982 (+ y (f (* (car x) (cadr x)))))
990 ;; Higher order with optional argument (side-effecting default
992 ((lambda* (f x #:optional (y (foo)))
993 (+ y (f (* (car x) (cadr x)))))
997 (let (y) (_) ((call (toplevel foo)))
998 (primcall + (lexical y _) (const 7))))
1001 ;; Higher order with optional argument (caller-supplied value).
1002 ((lambda* (f x #:optional (y (foo)))
1003 (+ y (f (* (car x) (cadr x)))))
1012 ((lambda (f) (f x)) (lambda (x) x))
1017 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
1018 (let ((fold (lambda (f g) (f (g top)))))
1019 (fold 1+ (lambda (x) x)))
1020 (primcall 1+ (toplevel top)))
1023 ;; Procedure not inlined when residual code contains recursive calls.
1024 ;; <http://debbugs.gnu.org/9542>
1025 (letrec ((fold (lambda (f x3 b null? car cdr)
1028 (f (car x3) (fold f (cdr x3) b null? car cdr))))))
1029 (fold * x 1 zero? (lambda (x1) x1) (lambda (x2) (- x2 1))))
1030 (letrec (fold) (_) (_)
1031 (call (lexical fold _)
1038 (((x1) #f #f #f () (_))
1042 (((x2) #f #f #f () (_))
1043 (primcall - (lexical x2 _) (const 1))))))))
1045 (pass-if "inlined lambdas are alpha-renamed"
1046 ;; In this example, `make-adder' is inlined more than once; thus,
1047 ;; they should use different gensyms for their arguments, because
1048 ;; the various optimization passes assume uniquely-named variables.
1051 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html> and
1052 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00029.html>.
1053 (pmatch (unparse-tree-il
1056 (lambda (x) (lambda (y) (+ x y)))))
1057 (cons (make-adder 1) (make-adder 2)))
1062 (((y) #f #f #f () (,gensym1))
1065 (lexical y ,ref1)))))
1068 (((y) #f #f #f () (,gensym2))
1071 (lexical y ,ref2))))))
1072 (and (eq? gensym1 ref1)
1074 (not (eq? gensym1 gensym2))))
1078 ;; Unused letrec bindings are pruned.
1079 (letrec ((a (lambda () (b)))
1086 ;; Unused letrec bindings are pruned.
1091 (seq (call (toplevel foo!))
1095 ;; Higher order, mutually recursive procedures.
1096 (letrec ((even? (lambda (x)
1101 (and (even? 4) (odd? 7)))
1105 ;; Memv with constants.
1110 ;; Memv with non-constant list. It could fold but doesn't
1112 (memv 1 (list 3 2 1))
1115 (primcall list (const 3) (const 2) (const 1))))
1118 ;; Memv with non-constant key, constant list, test context
1122 (if (let (t) (_) ((toplevel foo))
1123 (if (primcall eqv? (lexical t _) (const 3))
1125 (if (primcall eqv? (lexical t _) (const 2))
1127 (primcall eqv? (lexical t _) (const 1)))))
1132 ;; Memv with non-constant key, empty list, test context. Currently
1133 ;; doesn't fold entirely.
1137 (if (seq (toplevel foo) (const #f))
1142 ;; Below are cases where constant propagation should bail out.
1146 ;; Non-constant lexical is not propagated.
1147 (let ((v (make-vector 6 #f)))
1149 (vector-set! v n n)))
1151 ((call (toplevel make-vector) (const 6) (const #f)))
1154 (((n) #f #f #f () (_))
1155 (call (toplevel vector-set!)
1156 (lexical v _) (lexical n _) (lexical n _)))))))
1159 ;; Mutable lexical is not propagated.
1160 (let ((v (vector 1 2 3)))
1164 ((primcall vector (const 1) (const 2) (const 3)))
1167 ((() #f #f #f () ())
1171 ;; Lexical that is not provably pure is not inlined nor propagated.
1172 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
1175 (let (x) (_) ((if (primcall > (toplevel p) (toplevel q))
1176 (call (toplevel frob!))
1177 (call (toplevel display) (const chbouib))))
1178 (let (y) (_) ((primcall * (lexical x _) (const 2)))
1180 (lexical x _) (lexical x _) (lexical y _)))))
1183 ;; Non-constant arguments not propagated to lambdas.
1191 (let (x y z) (_ _ _)
1192 ((primcall vector (const 1) (const 2) (const 3))
1193 (call (toplevel make-list) (const 10))
1194 (primcall list (const 1) (const 2) (const 3)))
1196 (call (toplevel vector-set!)
1197 (lexical x _) (const 0) (const 0))
1198 (seq (call (toplevel set-car!)
1199 (lexical y _) (const 0))
1200 (call (toplevel set-cdr!)
1201 (lexical z _) (const ()))))))
1204 (let ((foo top-foo) (bar top-bar))
1205 (let* ((g (lambda (x y) (+ x y)))
1206 (f (lambda (g x) (g x x))))
1207 (+ (f g foo) (f g bar))))
1208 (let (foo bar) (_ _) ((toplevel top-foo) (toplevel top-bar))
1210 (primcall + (lexical foo _) (lexical foo _))
1211 (primcall + (lexical bar _) (lexical bar _)))))
1214 ;; Fresh objects are not turned into constants, nor are constants
1215 ;; turned into fresh objects.
1220 (let (x) (_) ((primcall cons (const 1) (const (2 3))))
1221 (primcall cons (const 0) (lexical x _))))
1224 ;; Bindings mutated.
1228 (let (x) (_) ((const 2))
1230 (set! (lexical x _) (const 3))
1234 ;; Bindings mutated.
1239 (frob f) ; may mutate `x'
1241 (letrec (x) (_) ((const 0))
1243 (call (toplevel frob) (lambda _ _))
1247 ;; Bindings mutated.
1248 (letrec ((f (lambda (x)
1249 (set! f (lambda (_) x))
1255 ;; Bindings possibly mutated.
1256 (let ((x (make-foo)))
1257 (frob! x) ; may mutate `x'
1259 (let (x) (_) ((call (toplevel make-foo)))
1261 (call (toplevel frob!) (lexical x _))
1265 ;; Inlining stops at recursive calls with dynamic arguments.
1267 (if (< x 0) x (loop (1- x))))
1268 (letrec (loop) (_) ((lambda (_)
1270 (((x) #f #f #f () (_))
1272 (call (lexical loop _)
1274 (lexical x _))))))))
1275 (call (lexical loop _) (toplevel x))))
1278 ;; Recursion on the 2nd argument is fully evaluated.
1280 (let loop ((x x) (y 10))
1284 (let (x) (_) ((call (toplevel top)))
1285 (call (toplevel foo) (lexical x _) (const 0))))
1288 ;; Inlining aborted when residual code contains recursive calls.
1290 ;; <http://debbugs.gnu.org/9542>
1291 (let loop ((x x) (y 0))
1293 (loop (1- x) (1- y))
1296 (loop (1+ x) (1+ y)))))
1297 (letrec (loop) (_) ((lambda (_)
1299 (((x y) #f #f #f () (_ _))
1301 (lexical y _) (const 0))
1303 (call (lexical loop _) (toplevel x) (const 0))))
1306 ;; Infinite recursion: `peval' gives up and leaves it as is.
1307 (letrec ((f (lambda (x) (g (1- x))))
1308 (g (lambda (x) (h (1+ x))))
1309 (h (lambda (x) (f x))))
1314 ;; Infinite recursion: all the arguments to `loop' are static, but
1315 ;; unrolling it would lead `peval' to enter an infinite loop.
1319 (letrec (loop) (_) ((lambda . _))
1320 (call (lexical loop _) (const 0))))
1323 ;; This test checks that the `start' binding is indeed residualized.
1324 ;; See the `referenced?' procedure in peval's `prune-bindings'.
1326 (set! pos 1) ;; Cause references to `pos' to residualize.
1327 (let ((here (let ((start pos)) (lambda () start))))
1329 (let (pos) (_) ((const 0))
1331 (set! (lexical pos _) (const 1))
1333 (call (lexical here _))))))
1336 ;; FIXME: should this one residualize the binding?
1342 ;; This is a fun one for peval to handle.
1345 (letrec (a) (_) ((lexical a _))
1349 ;; Another interesting recursive case.
1350 (letrec ((a b) (b a))
1352 (letrec (a) (_) ((lexical a _))
1356 ;; Another pruning case, that `a' is residualized.
1357 (letrec ((a (lambda () (a)))
1363 ;; "b c a" is the current order that we get with unordered letrec,
1364 ;; but it's not important to this test, so if it changes, just adapt
1366 (letrec (b c a) (_ _ _)
1369 ((() #f #f #f () ())
1370 (call (lexical a _)))))
1373 (((x) #f #f #f () (_))
1377 ((() #f #f #f () ())
1378 (call (lexical a _))))))
1381 ((call (toplevel foo) (lexical b _)))
1382 (call (lexical c _) (lexical d _)))))
1385 ;; In this case, we can prune the bindings. `a' ends up being copied
1386 ;; because it is only referenced once in the source program. Oh
1388 (letrec* ((a (lambda (x) (top x)))
1391 (call (toplevel foo)
1394 (((x) #f #f #f () (_))
1395 (call (toplevel top) (lexical x _)))))
1398 (((x) #f #f #f () (_))
1399 (call (toplevel top) (lexical x _)))))))
1402 ;; Constant folding: cons
1403 (begin (cons 1 2) #f)
1407 ;; Constant folding: cons
1408 (begin (cons (foo) 2) #f)
1409 (seq (call (toplevel foo)) (const #f)))
1412 ;; Constant folding: cons
1417 ;; Constant folding: car+cons
1422 ;; Constant folding: cdr+cons
1427 ;; Constant folding: car+cons, impure
1428 (car (cons 1 (bar)))
1429 (seq (call (toplevel bar)) (const 1)))
1432 ;; Constant folding: cdr+cons, impure
1433 (cdr (cons (bar) 0))
1434 (seq (call (toplevel bar)) (const 0)))
1437 ;; Constant folding: car+list
1442 ;; Constant folding: cdr+list
1444 (primcall list (const 0)))
1447 ;; Constant folding: car+list, impure
1448 (car (list 1 (bar)))
1449 (seq (call (toplevel bar)) (const 1)))
1452 ;; Constant folding: cdr+list, impure
1453 (cdr (list (bar) 0))
1454 (seq (call (toplevel bar)) (primcall list (const 0))))
1458 ;; Prompt is removed if tag is unreferenced
1459 (let ((tag (make-prompt-tag)))
1460 (call-with-prompt tag
1462 (lambda args args)))
1467 ;; Prompt is removed if tag is unreferenced, with explicit stem
1468 (let ((tag (make-prompt-tag "foo")))
1469 (call-with-prompt tag
1471 (lambda args args)))
1476 ;; `while' without `break' or `continue' has no prompts and gets its
1477 ;; condition folded. Unfortunately the outer `lp' does not yet get
1483 ((() #f #f #f () ())
1487 ((() #f #f #f () ())
1488 (call (lexical loop _))))))
1489 (call (lexical loop _)))))))
1490 (call (lexical lp _)))))
1494 (with-test-prefix "tree-il-fold"
1496 (pass-if "empty tree"
1497 (let ((leaf? #f) (up? #f) (down? #f) (mark (list 'mark)))
1499 (tree-il-fold (lambda (x y) (set! leaf? #t) y)
1500 (lambda (x y) (set! down? #t) y)
1501 (lambda (x y) (set! up? #t) y)
1508 (pass-if "lambda and application"
1509 (let* ((leaves '()) (ups '()) (downs '())
1510 (result (tree-il-fold (lambda (x y)
1511 (set! leaves (cons x leaves))
1514 (set! downs (cons x downs))
1517 (set! ups (cons x ups))
1523 (((x y) #f #f #f () (x1 y1))
1528 (and (equal? (map strip-source leaves)
1529 (list (make-lexical-ref #f 'y 'y1)
1530 (make-lexical-ref #f 'x 'x1)
1531 (make-toplevel-ref #f '+)))
1532 (= (length downs) 3)
1533 (equal? (reverse (map strip-source ups))
1534 (map strip-source downs))))))
1541 ;; Make sure we get English messages.
1542 (setlocale LC_ALL "C")
1544 (define (call-with-warnings thunk)
1545 (let ((port (open-output-string)))
1546 (with-fluids ((*current-warning-port* port)
1547 (*current-warning-prefix* ""))
1549 (let ((warnings (get-output-string port)))
1550 (string-tokenize warnings
1551 (char-set-complement (char-set #\newline))))))
1553 (define %opts-w-unused
1554 '(#:warnings (unused-variable)))
1556 (define %opts-w-unused-toplevel
1557 '(#:warnings (unused-toplevel)))
1559 (define %opts-w-unbound
1560 '(#:warnings (unbound-variable)))
1562 (define %opts-w-arity
1563 '(#:warnings (arity-mismatch)))
1565 (define %opts-w-format
1566 '(#:warnings (format)))
1569 (with-test-prefix "warnings"
1571 (pass-if "unknown warning type"
1572 (let ((w (call-with-warnings
1574 (compile #t #:opts '(#:warnings (does-not-exist)))))))
1575 (and (= (length w) 1)
1576 (number? (string-contains (car w) "unknown warning")))))
1578 (with-test-prefix "unused-variable"
1581 (null? (call-with-warnings
1583 (compile '(lambda (x y) (+ x y))
1584 #:opts %opts-w-unused)))))
1586 (pass-if "let/unused"
1587 (let ((w (call-with-warnings
1589 (compile '(lambda (x)
1592 #:opts %opts-w-unused)))))
1593 (and (= (length w) 1)
1594 (number? (string-contains (car w) "unused variable `y'")))))
1596 (pass-if "shadowed variable"
1597 (let ((w (call-with-warnings
1599 (compile '(lambda (x)
1603 #:opts %opts-w-unused)))))
1604 (and (= (length w) 1)
1605 (number? (string-contains (car w) "unused variable `y'")))))
1608 (null? (call-with-warnings
1610 (compile '(lambda ()
1611 (letrec ((x (lambda () (y)))
1612 (y (lambda () (x))))
1614 #:opts %opts-w-unused)))))
1616 (pass-if "unused argument"
1617 ;; Unused arguments should not be reported.
1618 (null? (call-with-warnings
1620 (compile '(lambda (x y z) #t)
1621 #:opts %opts-w-unused)))))
1623 (pass-if "special variable names"
1624 (null? (call-with-warnings
1626 (compile '(lambda ()
1627 (let ((_ 'underscore)
1628 (#{gensym name}# 'ignore-me))
1631 #:opts %opts-w-unused))))))
1633 (with-test-prefix "unused-toplevel"
1635 (pass-if "used after definition"
1636 (null? (call-with-warnings
1638 (let ((in (open-input-string
1639 "(define foo 2) foo")))
1640 (read-and-compile in
1642 #:opts %opts-w-unused-toplevel))))))
1644 (pass-if "used before definition"
1645 (null? (call-with-warnings
1647 (let ((in (open-input-string
1648 "(define (bar) foo) (define foo 2) (bar)")))
1649 (read-and-compile in
1651 #:opts %opts-w-unused-toplevel))))))
1653 (pass-if "unused but public"
1654 (let ((in (open-input-string
1655 "(define-module (test-suite tree-il x) #:export (bar))
1656 (define (bar) #t)")))
1657 (null? (call-with-warnings
1659 (read-and-compile in
1661 #:opts %opts-w-unused-toplevel))))))
1663 (pass-if "unused but public (more)"
1664 (let ((in (open-input-string
1665 "(define-module (test-suite tree-il x) #:export (bar))
1666 (define (bar) (baz))
1667 (define (baz) (foo))
1668 (define (foo) #t)")))
1669 (null? (call-with-warnings
1671 (read-and-compile in
1673 #:opts %opts-w-unused-toplevel))))))
1675 (pass-if "unused but define-public"
1676 (null? (call-with-warnings
1678 (compile '(define-public foo 2)
1680 #:opts %opts-w-unused-toplevel)))))
1682 (pass-if "used by macro"
1683 ;; FIXME: See comment about macros at `unused-toplevel-analysis'.
1686 (null? (call-with-warnings
1688 (let ((in (open-input-string
1689 "(define (bar) 'foo)
1691 (syntax-rules () ((_) (bar))))")))
1692 (read-and-compile in
1694 #:opts %opts-w-unused-toplevel))))))
1697 (let ((w (call-with-warnings
1699 (compile '(define foo 2)
1701 #:opts %opts-w-unused-toplevel)))))
1702 (and (= (length w) 1)
1703 (number? (string-contains (car w)
1704 (format #f "top-level variable `~A'"
1707 (pass-if "unused recursive"
1708 (let ((w (call-with-warnings
1710 (compile '(define (foo) (foo))
1712 #:opts %opts-w-unused-toplevel)))))
1713 (and (= (length w) 1)
1714 (number? (string-contains (car w)
1715 (format #f "top-level variable `~A'"
1718 (pass-if "unused mutually recursive"
1719 (let* ((in (open-input-string
1720 "(define (foo) (bar)) (define (bar) (foo))"))
1721 (w (call-with-warnings
1723 (read-and-compile in
1725 #:opts %opts-w-unused-toplevel)))))
1726 (and (= (length w) 2)
1727 (number? (string-contains (car w)
1728 (format #f "top-level variable `~A'"
1730 (number? (string-contains (cadr w)
1731 (format #f "top-level variable `~A'"
1734 (pass-if "special variable names"
1735 (null? (call-with-warnings
1737 (compile '(define #{gensym name}# 'ignore-me)
1739 #:opts %opts-w-unused-toplevel))))))
1741 (with-test-prefix "unbound variable"
1744 (null? (call-with-warnings
1746 (compile '+ #:opts %opts-w-unbound)))))
1750 (w (call-with-warnings
1754 #:opts %opts-w-unbound)))))
1755 (and (= (length w) 1)
1756 (number? (string-contains (car w)
1757 (format #f "unbound variable `~A'"
1762 (w (call-with-warnings
1764 (compile `(set! ,v 7)
1766 #:opts %opts-w-unbound)))))
1767 (and (= (length w) 1)
1768 (number? (string-contains (car w)
1769 (format #f "unbound variable `~A'"
1772 (pass-if "module-local top-level is visible"
1773 (let ((m (make-module))
1775 (beautify-user-module! m)
1776 (compile `(define ,v 123)
1777 #:env m #:opts %opts-w-unbound)
1778 (null? (call-with-warnings
1783 #:opts %opts-w-unbound))))))
1785 (pass-if "module-local top-level is visible after"
1786 (let ((m (make-module))
1788 (beautify-user-module! m)
1789 (null? (call-with-warnings
1791 (let ((in (open-input-string
1794 (define chbouib 5)")))
1795 (read-and-compile in
1797 #:opts %opts-w-unbound)))))))
1799 (pass-if "optional arguments are visible"
1800 (null? (call-with-warnings
1802 (compile '(lambda* (x #:optional y z) (list x y z))
1803 #:opts %opts-w-unbound
1806 (pass-if "keyword arguments are visible"
1807 (null? (call-with-warnings
1809 (compile '(lambda* (x #:key y z) (list x y z))
1810 #:opts %opts-w-unbound
1813 (pass-if "GOOPS definitions are visible"
1814 (let ((m (make-module))
1816 (beautify-user-module! m)
1817 (module-use! m (resolve-interface '(oop goops)))
1818 (null? (call-with-warnings
1820 (let ((in (open-input-string
1821 "(define-class <foo> ()
1822 (bar #:getter foo-bar))
1823 (define z (foo-bar (make <foo>)))")))
1824 (read-and-compile in
1826 #:opts %opts-w-unbound))))))))
1828 (with-test-prefix "arity mismatch"
1831 (null? (call-with-warnings
1833 (compile '(cons 'a 'b) #:opts %opts-w-arity)))))
1835 (pass-if "direct application"
1836 (let ((w (call-with-warnings
1838 (compile '((lambda (x y) (or x y)) 1 2 3 4 5)
1839 #:opts %opts-w-arity
1841 (and (= (length w) 1)
1842 (number? (string-contains (car w)
1843 "wrong number of arguments to")))))
1845 (let ((w (call-with-warnings
1847 (compile '(let ((f (lambda (x y) (+ x y))))
1849 #:opts %opts-w-arity
1851 (and (= (length w) 1)
1852 (number? (string-contains (car w)
1853 "wrong number of arguments to")))))
1856 (let ((w (call-with-warnings
1858 (compile '(cons 1 2 3 4)
1859 #:opts %opts-w-arity
1861 (and (= (length w) 1)
1862 (number? (string-contains (car w)
1863 "wrong number of arguments to")))))
1865 (pass-if "alias to global"
1866 (let ((w (call-with-warnings
1868 (compile '(let ((f cons)) (f 1 2 3 4))
1869 #:opts %opts-w-arity
1871 (and (= (length w) 1)
1872 (number? (string-contains (car w)
1873 "wrong number of arguments to")))))
1875 (pass-if "alias to lexical to global"
1876 (let ((w (call-with-warnings
1878 (compile '(let ((f number?))
1881 #:opts %opts-w-arity
1883 (and (= (length w) 1)
1884 (number? (string-contains (car w)
1885 "wrong number of arguments to")))))
1887 (pass-if "alias to lexical"
1888 (let ((w (call-with-warnings
1890 (compile '(let ((f (lambda (x y z) (+ x y z))))
1893 #:opts %opts-w-arity
1895 (and (= (length w) 1)
1896 (number? (string-contains (car w)
1897 "wrong number of arguments to")))))
1900 (let ((w (call-with-warnings
1902 (compile '(letrec ((odd? (lambda (x) (even? (1- x))))
1907 #:opts %opts-w-arity
1909 (and (= (length w) 1)
1910 (number? (string-contains (car w)
1911 "wrong number of arguments to")))))
1913 (pass-if "case-lambda"
1914 (null? (call-with-warnings
1916 (compile '(let ((f (case-lambda
1923 #:opts %opts-w-arity
1926 (pass-if "case-lambda with wrong number of arguments"
1927 (let ((w (call-with-warnings
1929 (compile '(let ((f (case-lambda
1933 #:opts %opts-w-arity
1935 (and (= (length w) 1)
1936 (number? (string-contains (car w)
1937 "wrong number of arguments to")))))
1939 (pass-if "case-lambda*"
1940 (null? (call-with-warnings
1942 (compile '(let ((f (case-lambda*
1943 ((x #:optional y) 1)
1945 ((x y #:key z) 3))))
1950 #:opts %opts-w-arity
1953 (pass-if "case-lambda* with wrong arguments"
1954 (let ((w (call-with-warnings
1956 (compile '(let ((f (case-lambda*
1957 ((x #:optional y) 1)
1959 ((x y #:key z) 3))))
1962 #:opts %opts-w-arity
1964 (and (= (length w) 2)
1965 (null? (filter (lambda (w)
1969 w "wrong number of arguments to"))))
1972 (pass-if "local toplevel-defines"
1973 (let ((w (call-with-warnings
1975 (let ((in (open-input-string "
1976 (define (g x) (f x))
1978 (read-and-compile in
1979 #:opts %opts-w-arity
1980 #:to 'assembly))))))
1981 (and (= (length w) 1)
1982 (number? (string-contains (car w)
1983 "wrong number of arguments to")))))
1985 (pass-if "global toplevel alias"
1986 (let ((w (call-with-warnings
1988 (let ((in (open-input-string "
1990 (define (g) (f))")))
1991 (read-and-compile in
1992 #:opts %opts-w-arity
1993 #:to 'assembly))))))
1994 (and (= (length w) 1)
1995 (number? (string-contains (car w)
1996 "wrong number of arguments to")))))
1998 (pass-if "local toplevel overrides global"
1999 (null? (call-with-warnings
2001 (let ((in (open-input-string "
2003 (define (foo x) (cons))")))
2004 (read-and-compile in
2005 #:opts %opts-w-arity
2006 #:to 'assembly))))))
2008 (pass-if "keyword not passed and quiet"
2009 (null? (call-with-warnings
2011 (compile '(let ((f (lambda* (x #:key y) y)))
2013 #:opts %opts-w-arity
2016 (pass-if "keyword passed and quiet"
2017 (null? (call-with-warnings
2019 (compile '(let ((f (lambda* (x #:key y) y)))
2021 #:opts %opts-w-arity
2024 (pass-if "keyword passed to global and quiet"
2025 (null? (call-with-warnings
2027 (let ((in (open-input-string "
2028 (use-modules (system base compile))
2029 (compile '(+ 2 3) #:env (current-module))")))
2030 (read-and-compile in
2031 #:opts %opts-w-arity
2032 #:to 'assembly))))))
2034 (pass-if "extra keyword"
2035 (let ((w (call-with-warnings
2037 (compile '(let ((f (lambda* (x #:key y) y)))
2039 #:opts %opts-w-arity
2041 (and (= (length w) 1)
2042 (number? (string-contains (car w)
2043 "wrong number of arguments to")))))
2045 (pass-if "extra keywords allowed"
2046 (null? (call-with-warnings
2048 (compile '(let ((f (lambda* (x #:key y #:allow-other-keys)
2051 #:opts %opts-w-arity
2052 #:to 'assembly))))))
2054 (with-test-prefix "format"
2056 (pass-if "quiet (no args)"
2057 (null? (call-with-warnings
2059 (compile '(format #t "hey!")
2060 #:opts %opts-w-format
2063 (pass-if "quiet (1 arg)"
2064 (null? (call-with-warnings
2066 (compile '(format #t "hey ~A!" "you")
2067 #:opts %opts-w-format
2070 (pass-if "quiet (2 args)"
2071 (null? (call-with-warnings
2073 (compile '(format #t "~A ~A!" "hello" "world")
2074 #:opts %opts-w-format
2077 (pass-if "wrong port arg"
2078 (let ((w (call-with-warnings
2080 (compile '(format 10 "foo")
2081 #:opts %opts-w-format
2083 (and (= (length w) 1)
2084 (number? (string-contains (car w)
2085 "wrong port argument")))))
2087 (pass-if "non-literal format string"
2088 (let ((w (call-with-warnings
2090 (compile '(format #f fmt)
2091 #:opts %opts-w-format
2093 (and (= (length w) 1)
2094 (number? (string-contains (car w)
2095 "non-literal format string")))))
2097 (pass-if "non-literal format string using gettext"
2098 (null? (call-with-warnings
2100 (compile '(format #t (_ "~A ~A!") "hello" "world")
2101 #:opts %opts-w-format
2104 (pass-if "wrong format string"
2105 (let ((w (call-with-warnings
2107 (compile '(format #f 'not-a-string)
2108 #:opts %opts-w-format
2110 (and (= (length w) 1)
2111 (number? (string-contains (car w)
2112 "wrong format string")))))
2114 (pass-if "wrong number of args"
2115 (let ((w (call-with-warnings
2117 (compile '(format "shbweeb")
2118 #:opts %opts-w-format
2120 (and (= (length w) 1)
2121 (number? (string-contains (car w)
2122 "wrong number of arguments")))))
2124 (pass-if "~%, ~~, ~&, ~t, ~_, and ~\\n"
2125 (null? (call-with-warnings
2127 (compile '(format some-port "~&~3_~~ ~\n~12they~%")
2128 #:opts %opts-w-format
2131 (pass-if "one missing argument"
2132 (let ((w (call-with-warnings
2134 (compile '(format some-port "foo ~A~%")
2135 #:opts %opts-w-format
2137 (and (= (length w) 1)
2138 (number? (string-contains (car w)
2139 "expected 1, got 0")))))
2141 (pass-if "one missing argument, gettext"
2142 (let ((w (call-with-warnings
2144 (compile '(format some-port (_ "foo ~A~%"))
2145 #:opts %opts-w-format
2147 (and (= (length w) 1)
2148 (number? (string-contains (car w)
2149 "expected 1, got 0")))))
2151 (pass-if "two missing arguments"
2152 (let ((w (call-with-warnings
2154 (compile '(format #f "foo ~10,2f and bar ~S~%")
2155 #:opts %opts-w-format
2157 (and (= (length w) 1)
2158 (number? (string-contains (car w)
2159 "expected 2, got 0")))))
2161 (pass-if "one given, one missing argument"
2162 (let ((w (call-with-warnings
2164 (compile '(format #t "foo ~A and ~S~%" hey)
2165 #:opts %opts-w-format
2167 (and (= (length w) 1)
2168 (number? (string-contains (car w)
2169 "expected 2, got 1")))))
2171 (pass-if "too many arguments"
2172 (let ((w (call-with-warnings
2174 (compile '(format #t "foo ~A~%" 1 2)
2175 #:opts %opts-w-format
2177 (and (= (length w) 1)
2178 (number? (string-contains (car w)
2179 "expected 1, got 2")))))
2181 (with-test-prefix "conditionals"
2183 (null? (call-with-warnings
2185 (compile '(format #f "~A ~[foo~;bar~;baz~;~] ~10,2f"
2187 #:opts %opts-w-format
2190 (pass-if "literals with selector"
2191 (let ((w (call-with-warnings
2193 (compile '(format #f "~2[foo~;bar~;baz~;~] ~A"
2195 #:opts %opts-w-format
2197 (and (= (length w) 1)
2198 (number? (string-contains (car w)
2199 "expected 1, got 2")))))
2201 (pass-if "escapes (exact count)"
2202 (let ((w (call-with-warnings
2204 (compile '(format #f "~[~a~;~a~]")
2205 #:opts %opts-w-format
2207 (and (= (length w) 1)
2208 (number? (string-contains (car w)
2209 "expected 2, got 0")))))
2211 (pass-if "escapes with selector"
2212 (let ((w (call-with-warnings
2214 (compile '(format #f "~1[chbouib~;~a~]")
2215 #:opts %opts-w-format
2217 (and (= (length w) 1)
2218 (number? (string-contains (car w)
2219 "expected 1, got 0")))))
2221 (pass-if "escapes, range"
2222 (let ((w (call-with-warnings
2224 (compile '(format #f "~[chbouib~;~a~;~2*~a~]")
2225 #:opts %opts-w-format
2227 (and (= (length w) 1)
2228 (number? (string-contains (car w)
2229 "expected 1 to 4, got 0")))))
2232 (let ((w (call-with-warnings
2234 (compile '(format #f "~@[temperature=~d~]")
2235 #:opts %opts-w-format
2237 (and (= (length w) 1)
2238 (number? (string-contains (car w)
2239 "expected 1, got 0")))))
2242 (let ((w (call-with-warnings
2244 (compile '(format #f "~:[~[hey~;~a~;~va~]~;~3*~]")
2245 #:opts %opts-w-format
2247 (and (= (length w) 1)
2248 (number? (string-contains (car w)
2249 "expected 2 to 4, got 0")))))
2251 (pass-if "unterminated"
2252 (let ((w (call-with-warnings
2254 (compile '(format #f "~[unterminated")
2255 #:opts %opts-w-format
2257 (and (= (length w) 1)
2258 (number? (string-contains (car w)
2259 "unterminated conditional")))))
2261 (pass-if "unexpected ~;"
2262 (let ((w (call-with-warnings
2264 (compile '(format #f "foo~;bar")
2265 #:opts %opts-w-format
2267 (and (= (length w) 1)
2268 (number? (string-contains (car w)
2271 (pass-if "unexpected ~]"
2272 (let ((w (call-with-warnings
2274 (compile '(format #f "foo~]")
2275 #:opts %opts-w-format
2277 (and (= (length w) 1)
2278 (number? (string-contains (car w)
2282 (null? (call-with-warnings
2284 (compile '(format #f "~A ~{~S~} ~A"
2285 'hello '("ladies" "and")
2287 #:opts %opts-w-format
2290 (pass-if "~{...~}, too many args"
2291 (let ((w (call-with-warnings
2293 (compile '(format #f "~{~S~}" 1 2 3)
2294 #:opts %opts-w-format
2296 (and (= (length w) 1)
2297 (number? (string-contains (car w)
2298 "expected 1, got 3")))))
2301 (null? (call-with-warnings
2303 (compile '(format #f "~@{~S~}" 1 2 3)
2304 #:opts %opts-w-format
2307 (pass-if "~@{...~}, too few args"
2308 (let ((w (call-with-warnings
2310 (compile '(format #f "~A ~@{~S~}")
2311 #:opts %opts-w-format
2313 (and (= (length w) 1)
2314 (number? (string-contains (car w)
2315 "expected at least 1, got 0")))))
2317 (pass-if "unterminated ~{...~}"
2318 (let ((w (call-with-warnings
2320 (compile '(format #f "~{")
2321 #:opts %opts-w-format
2323 (and (= (length w) 1)
2324 (number? (string-contains (car w)
2328 (null? (call-with-warnings
2330 (compile '(format #f "~:@(~A ~A~)" 'foo 'bar)
2331 #:opts %opts-w-format
2335 (let ((w (call-with-warnings
2337 (compile '(format #f "~v_foo")
2338 #:opts %opts-w-format
2340 (and (= (length w) 1)
2341 (number? (string-contains (car w)
2342 "expected 1, got 0")))))
2344 (null? (call-with-warnings
2346 (compile '(format #f "~v:@y" 1 123)
2347 #:opts %opts-w-format
2352 (let ((w (call-with-warnings
2354 (compile '(format #f "~2*~a" 'a 'b)
2355 #:opts %opts-w-format
2357 (and (= (length w) 1)
2358 (number? (string-contains (car w)
2359 "expected 3, got 2")))))
2362 (null? (call-with-warnings
2364 (compile '(format #f "~?" "~d ~d" '(1 2))
2365 #:opts %opts-w-format
2368 (pass-if "complex 1"
2369 (let ((w (call-with-warnings
2371 (compile '(format #f
2372 "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
2374 #:opts %opts-w-format
2376 (and (= (length w) 1)
2377 (number? (string-contains (car w)
2378 "expected 4, got 6")))))
2380 (pass-if "complex 2"
2381 (let ((w (call-with-warnings
2383 (compile '(format #f
2384 "~:(~A~) Commands~:[~; [abbrev]~]:~2%"
2386 #:opts %opts-w-format
2388 (and (= (length w) 1)
2389 (number? (string-contains (car w)
2390 "expected 2, got 4")))))
2392 (pass-if "complex 3"
2393 (let ((w (call-with-warnings
2395 (compile '(format #f "~9@a~:[~*~3_~;~3d~] ~v:@y~%")
2396 #:opts %opts-w-format
2398 (and (= (length w) 1)
2399 (number? (string-contains (car w)
2400 "expected 5, got 0")))))
2402 (pass-if "ice-9 format"
2403 (let ((w (call-with-warnings
2405 (let ((in (open-input-string
2406 "(use-modules ((ice-9 format)
2407 #:renamer (symbol-prefix-proc 'i9-)))
2408 (i9-format #t \"yo! ~A\" 1 2)")))
2409 (read-and-compile in
2410 #:opts %opts-w-format
2411 #:to 'assembly))))))
2412 (and (= (length w) 1)
2413 (number? (string-contains (car w)
2414 "expected 1, got 2")))))
2416 (pass-if "not format"
2417 (null? (call-with-warnings
2419 (compile '(let ((format chbouib))
2420 (format #t "not ~A a format string"))
2421 #:opts %opts-w-format
2422 #:to 'assembly)))))))