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
82 (compile 'in #:from 'scheme #:to 'tree-il)
86 (let ((evaled (unparse-tree-il (peval code))))
89 (_ (pk 'peval-mismatch)
90 ((@ (ice-9 pretty-print) pretty-print)
93 ((@ (ice-9 pretty-print) pretty-print)
96 ((@ (ice-9 pretty-print) pretty-print)
102 (with-test-prefix "tree-il->scheme"
103 (pass-if-tree-il->scheme
104 (case-lambda ((a) a) ((b c) (list b c)))
105 (case-lambda ((,a) ,a1) ((,b ,c) (list ,b1 ,c1)))
106 (and (eq? a a1) (eq? b b1) (eq? c c1))))
108 (with-test-prefix "void"
109 (assert-tree-il->glil
111 (program () (std-prelude 0 0 #f) (label _) (void) (call return 1)))
112 (assert-tree-il->glil
113 (begin (void) (const 1))
114 (program () (std-prelude 0 0 #f) (label _) (const 1) (call return 1)))
115 (assert-tree-il->glil
116 (primcall + (void) (const 1))
117 (program () (std-prelude 0 0 #f) (label _) (void) (call add1 1) (call return 1))))
119 (with-test-prefix "application"
120 (assert-tree-il->glil
121 (call (toplevel foo) (const 1))
122 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (const 1) (call tail-call 1)))
123 (assert-tree-il->glil
124 (begin (call (toplevel foo) (const 1)) (void))
125 (program () (std-prelude 0 0 #f) (label _) (call new-frame 0) (toplevel ref foo) (const 1) (mv-call 1 ,l1)
126 (call drop 1) (branch br ,l2)
127 (label ,l3) (mv-bind 0 #f)
129 (void) (call return 1))
130 (and (eq? l1 l3) (eq? l2 l4)))
131 (assert-tree-il->glil
132 (call (toplevel foo) (call (toplevel bar)))
133 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call new-frame 0) (toplevel ref bar) (call call 0)
134 (call tail-call 1))))
136 (with-test-prefix "conditional"
137 (assert-tree-il->glil
138 (if (toplevel foo) (const 1) (const 2))
139 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1)
140 (const 1) (call return 1)
141 (label ,l2) (const 2) (call return 1))
144 (assert-tree-il->glil without-partial-evaluation
145 (begin (if (toplevel foo) (const 1) (const 2)) (const #f))
146 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1) (branch br ,l2)
147 (label ,l3) (label ,l4) (const #f) (call return 1))
148 (eq? l1 l3) (eq? l2 l4))
150 (assert-tree-il->glil
151 (primcall null? (if (toplevel foo) (const 1) (const 2)))
152 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1)
153 (const 1) (branch br ,l2)
154 (label ,l3) (const 2) (label ,l4)
155 (call null? 1) (call return 1))
156 (eq? l1 l3) (eq? l2 l4)))
158 (with-test-prefix "primitive-ref"
159 (assert-tree-il->glil
161 (program () (std-prelude 0 0 #f) (label _) (toplevel ref +) (call return 1)))
163 (assert-tree-il->glil
164 (begin (primitive +) (const #f))
165 (program () (std-prelude 0 0 #f) (label _) (const #f) (call return 1)))
167 (assert-tree-il->glil
168 (primcall null? (primitive +))
169 (program () (std-prelude 0 0 #f) (label _) (toplevel ref +) (call null? 1)
172 (with-test-prefix "lexical refs"
173 (assert-tree-il->glil without-partial-evaluation
174 (let (x) (y) ((const 1)) (lexical x y))
175 (program () (std-prelude 0 1 #f) (label _)
176 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
177 (lexical #t #f ref 0) (call return 1)
180 (assert-tree-il->glil without-partial-evaluation
181 (let (x) (y) ((const 1)) (begin (lexical x y) (const #f)))
182 (program () (std-prelude 0 1 #f) (label _)
183 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
184 (const #f) (call return 1)
187 (assert-tree-il->glil without-partial-evaluation
188 (let (x) (y) ((const 1)) (primcall null? (lexical x y)))
189 (program () (std-prelude 0 1 #f) (label _)
190 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
191 (lexical #t #f ref 0) (call null? 1) (call return 1)
194 (with-test-prefix "lexical sets"
195 (assert-tree-il->glil
196 ;; unreferenced sets may be optimized away -- make sure they are ref'd
197 (let (x) (y) ((const 1))
198 (set! (lexical x y) (primcall 1+ (lexical x y))))
199 (program () (std-prelude 0 1 #f) (label _)
200 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
201 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0)
202 (void) (call return 1)
205 (assert-tree-il->glil
206 (let (x) (y) ((const 1))
207 (begin (set! (lexical x y) (primcall 1+ (lexical x y)))
209 (program () (std-prelude 0 1 #f) (label _)
210 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
211 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0)
212 (lexical #t #t ref 0) (call return 1)
215 (assert-tree-il->glil
216 (let (x) (y) ((const 1))
218 (set! (lexical x y) (primcall 1+ (lexical x y)))))
219 (program () (std-prelude 0 1 #f) (label _)
220 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
221 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0) (void)
222 (call null? 1) (call return 1)
225 (with-test-prefix "module refs"
226 (assert-tree-il->glil
228 (program () (std-prelude 0 0 #f) (label _)
229 (module public ref (foo) bar)
232 (assert-tree-il->glil
233 (begin (@ (foo) bar) (const #f))
234 (program () (std-prelude 0 0 #f) (label _)
235 (module public ref (foo) bar) (call drop 1)
236 (const #f) (call return 1)))
238 (assert-tree-il->glil
239 (primcall null? (@ (foo) bar))
240 (program () (std-prelude 0 0 #f) (label _)
241 (module public ref (foo) bar)
242 (call null? 1) (call return 1)))
244 (assert-tree-il->glil
246 (program () (std-prelude 0 0 #f) (label _)
247 (module private ref (foo) bar)
250 (assert-tree-il->glil
251 (begin (@@ (foo) bar) (const #f))
252 (program () (std-prelude 0 0 #f) (label _)
253 (module private ref (foo) bar) (call drop 1)
254 (const #f) (call return 1)))
256 (assert-tree-il->glil
257 (primcall null? (@@ (foo) bar))
258 (program () (std-prelude 0 0 #f) (label _)
259 (module private ref (foo) bar)
260 (call null? 1) (call return 1))))
262 (with-test-prefix "module sets"
263 (assert-tree-il->glil
264 (set! (@ (foo) bar) (const 2))
265 (program () (std-prelude 0 0 #f) (label _)
266 (const 2) (module public set (foo) bar)
267 (void) (call return 1)))
269 (assert-tree-il->glil
270 (begin (set! (@ (foo) bar) (const 2)) (const #f))
271 (program () (std-prelude 0 0 #f) (label _)
272 (const 2) (module public set (foo) bar)
273 (const #f) (call return 1)))
275 (assert-tree-il->glil
276 (primcall null? (set! (@ (foo) bar) (const 2)))
277 (program () (std-prelude 0 0 #f) (label _)
278 (const 2) (module public set (foo) bar)
279 (void) (call null? 1) (call return 1)))
281 (assert-tree-il->glil
282 (set! (@@ (foo) bar) (const 2))
283 (program () (std-prelude 0 0 #f) (label _)
284 (const 2) (module private set (foo) bar)
285 (void) (call return 1)))
287 (assert-tree-il->glil
288 (begin (set! (@@ (foo) bar) (const 2)) (const #f))
289 (program () (std-prelude 0 0 #f) (label _)
290 (const 2) (module private set (foo) bar)
291 (const #f) (call return 1)))
293 (assert-tree-il->glil
294 (primcall null? (set! (@@ (foo) bar) (const 2)))
295 (program () (std-prelude 0 0 #f) (label _)
296 (const 2) (module private set (foo) bar)
297 (void) (call null? 1) (call return 1))))
299 (with-test-prefix "toplevel refs"
300 (assert-tree-il->glil
302 (program () (std-prelude 0 0 #f) (label _)
306 (assert-tree-il->glil without-partial-evaluation
307 (begin (toplevel bar) (const #f))
308 (program () (std-prelude 0 0 #f) (label _)
309 (toplevel ref bar) (call drop 1)
310 (const #f) (call return 1)))
312 (assert-tree-il->glil
313 (primcall null? (toplevel bar))
314 (program () (std-prelude 0 0 #f) (label _)
316 (call null? 1) (call return 1))))
318 (with-test-prefix "toplevel sets"
319 (assert-tree-il->glil
320 (set! (toplevel bar) (const 2))
321 (program () (std-prelude 0 0 #f) (label _)
322 (const 2) (toplevel set bar)
323 (void) (call return 1)))
325 (assert-tree-il->glil
326 (begin (set! (toplevel bar) (const 2)) (const #f))
327 (program () (std-prelude 0 0 #f) (label _)
328 (const 2) (toplevel set bar)
329 (const #f) (call return 1)))
331 (assert-tree-il->glil
332 (primcall null? (set! (toplevel bar) (const 2)))
333 (program () (std-prelude 0 0 #f) (label _)
334 (const 2) (toplevel set bar)
335 (void) (call null? 1) (call return 1))))
337 (with-test-prefix "toplevel defines"
338 (assert-tree-il->glil
339 (define bar (const 2))
340 (program () (std-prelude 0 0 #f) (label _)
341 (const 2) (toplevel define bar)
342 (void) (call return 1)))
344 (assert-tree-il->glil
345 (begin (define bar (const 2)) (const #f))
346 (program () (std-prelude 0 0 #f) (label _)
347 (const 2) (toplevel define bar)
348 (const #f) (call return 1)))
350 (assert-tree-il->glil
351 (primcall null? (define bar (const 2)))
352 (program () (std-prelude 0 0 #f) (label _)
353 (const 2) (toplevel define bar)
354 (void) (call null? 1) (call return 1))))
356 (with-test-prefix "constants"
357 (assert-tree-il->glil
359 (program () (std-prelude 0 0 #f) (label _)
360 (const 2) (call return 1)))
362 (assert-tree-il->glil
363 (begin (const 2) (const #f))
364 (program () (std-prelude 0 0 #f) (label _)
365 (const #f) (call return 1)))
367 (assert-tree-il->glil
368 ;; This gets simplified by `peval'.
369 (primcall null? (const 2))
370 (program () (std-prelude 0 0 #f) (label _)
371 (const #f) (call return 1))))
373 (with-test-prefix "letrec"
374 ;; simple bindings -> let
375 (assert-tree-il->glil without-partial-evaluation
376 (letrec (x y) (x1 y1) ((const 10) (const 20))
377 (call (toplevel foo) (lexical x x1) (lexical y y1)))
378 (program () (std-prelude 0 2 #f) (label _)
379 (const 10) (const 20)
380 (bind (x #f 0) (y #f 1))
381 (lexical #t #f set 1) (lexical #t #f set 0)
383 (lexical #t #f ref 0) (lexical #t #f ref 1)
387 ;; complex bindings -> box and set! within let
388 (assert-tree-il->glil without-partial-evaluation
389 (letrec (x y) (x1 y1) ((call (toplevel foo)) (call (toplevel bar)))
390 (primcall + (lexical x x1) (lexical y y1)))
391 (program () (std-prelude 0 4 #f) (label _)
392 (void) (void) ;; what are these?
393 (bind (x #t 0) (y #t 1))
394 (lexical #t #t box 1) (lexical #t #t box 0)
395 (call new-frame 0) (toplevel ref foo) (call call 0)
396 (call new-frame 0) (toplevel ref bar) (call call 0)
397 (bind (x #f 2) (y #f 3)) (lexical #t #f set 3) (lexical #t #f set 2)
398 (lexical #t #f ref 2) (lexical #t #t set 0)
399 (lexical #t #f ref 3) (lexical #t #t set 1)
400 (void) (lexical #t #f set 2) (void) (lexical #t #f set 3) ;; clear bindings
402 (lexical #t #t ref 0) (lexical #t #t ref 1)
403 (call add 2) (call return 1) (unbind)))
405 ;; complex bindings in letrec* -> box and set! in order
406 (assert-tree-il->glil without-partial-evaluation
407 (letrec* (x y) (x1 y1) ((call (toplevel foo)) (call (toplevel bar)))
408 (primcall + (lexical x x1) (lexical y y1)))
409 (program () (std-prelude 0 2 #f) (label _)
410 (void) (void) ;; what are these?
411 (bind (x #t 0) (y #t 1))
412 (lexical #t #t box 1) (lexical #t #t box 0)
413 (call new-frame 0) (toplevel ref foo) (call call 0)
414 (lexical #t #t set 0)
415 (call new-frame 0) (toplevel ref bar) (call call 0)
416 (lexical #t #t set 1)
417 (lexical #t #t ref 0)
418 (lexical #t #t ref 1)
419 (call add 2) (call return 1) (unbind)))
421 ;; simple bindings in letrec* -> equivalent to letrec
422 (assert-tree-il->glil without-partial-evaluation
423 (letrec* (x y) (xx yy) ((const 1) (const 2))
425 (program () (std-prelude 0 1 #f) (label _)
427 (bind (y #f 0)) ;; X is removed, and Y is unboxed
428 (lexical #t #f set 0)
429 (lexical #t #f ref 0)
430 (call return 1) (unbind))))
432 (with-test-prefix "lambda"
433 (assert-tree-il->glil
435 (lambda-case (((x) #f #f #f () (y)) (const 2)) #f))
436 (program () (std-prelude 0 0 #f) (label _)
437 (program () (std-prelude 1 1 #f)
438 (bind (x #f 0)) (label _)
439 (const 2) (call return 1) (unbind))
442 (assert-tree-il->glil
444 (lambda-case (((x y) #f #f #f () (x1 y1))
447 (program () (std-prelude 0 0 #f) (label _)
448 (program () (std-prelude 2 2 #f)
449 (bind (x #f 0) (y #f 1)) (label _)
450 (const 2) (call return 1)
454 (assert-tree-il->glil
456 (lambda-case ((() #f x #f () (y)) (const 2))
458 (program () (std-prelude 0 0 #f) (label _)
459 (program () (opt-prelude 0 0 0 1 #f)
460 (bind (x #f 0)) (label _)
461 (const 2) (call return 1)
465 (assert-tree-il->glil
467 (lambda-case (((x) #f x1 #f () (y y1)) (const 2))
469 (program () (std-prelude 0 0 #f) (label _)
470 (program () (opt-prelude 1 0 1 2 #f)
471 (bind (x #f 0) (x1 #f 1)) (label _)
472 (const 2) (call return 1)
476 (assert-tree-il->glil
478 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x y))
480 (program () (std-prelude 0 0 #f) (label _)
481 (program () (opt-prelude 1 0 1 2 #f)
482 (bind (x #f 0) (x1 #f 1)) (label _)
483 (lexical #t #f ref 0) (call return 1)
487 (assert-tree-il->glil
489 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x1 y1))
491 (program () (std-prelude 0 0 #f) (label _)
492 (program () (opt-prelude 1 0 1 2 #f)
493 (bind (x #f 0) (x1 #f 1)) (label _)
494 (lexical #t #f ref 1) (call return 1)
498 (assert-tree-il->glil
500 (lambda-case (((x) #f #f #f () (x1))
502 (lambda-case (((y) #f #f #f () (y1))
506 (program () (std-prelude 0 0 #f) (label _)
507 (program () (std-prelude 1 1 #f)
508 (bind (x #f 0)) (label _)
509 (program () (std-prelude 1 1 #f)
510 (bind (y #f 0)) (label _)
511 (lexical #f #f ref 0) (call return 1)
513 (lexical #t #f ref 0)
514 (call make-closure 1)
519 (with-test-prefix "sequence"
520 (assert-tree-il->glil
521 (begin (begin (const 2) (const #f)) (const #t))
522 (program () (std-prelude 0 0 #f) (label _)
523 (const #t) (call return 1)))
525 (assert-tree-il->glil
526 ;; This gets simplified by `peval'.
527 (primcall null? (begin (const #f) (const 2)))
528 (program () (std-prelude 0 0 #f) (label _)
529 (const #f) (call return 1))))
531 (with-test-prefix "values"
532 (assert-tree-il->glil
534 (primcall values (const 1) (const 2)))
535 (program () (std-prelude 0 0 #f) (label _)
536 (const 1) (call return 1)))
538 (assert-tree-il->glil
540 (primcall values (const 1) (const 2))
542 (program () (std-prelude 0 0 #f) (label _)
543 (const 1) (const 3) (call return/values 2)))
545 (assert-tree-il->glil
547 (primcall values (const 1) (const 2)))
548 (program () (std-prelude 0 0 #f) (label _)
549 (const 1) (call return 1)))
551 ;; Testing `(values foo)' in push context with RA.
552 (assert-tree-il->glil without-partial-evaluation
554 (letrec (lp) (#{lp ~V9KrhVD4PFEL6oCTrLg3A}#)
555 ((lambda ((name . lp))
556 (lambda-case ((() #f #f #f () ())
557 (primcall values (const (one two)))))))
558 (call (lexical lp #{lp ~V9KrhVD4PFEL6oCTrLg3A}#))))
559 (program () (std-prelude 0 0 #f) (label _)
560 (branch br _) ;; entering the fix, jump to :2
561 ;; :1 body of lp, jump to :3
562 (label _) (bind) (const (one two)) (branch br _) (unbind)
563 ;; :2 initial call of lp, jump to :1
564 (label _) (bind) (branch br _) (label _) (unbind)
565 ;; :3 the push continuation
566 (call cdr 1) (call return 1))))
568 ;; FIXME: binding info for or-hacked locals might bork the disassembler,
569 ;; and could be tightened in any case
570 (with-test-prefix "the or hack"
571 (assert-tree-il->glil without-partial-evaluation
572 (let (x) (y) ((const 1))
575 (let (a) (b) ((const 2))
577 (program () (std-prelude 0 1 #f) (label _)
578 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
579 (lexical #t #f ref 0) (branch br-if-not ,l1)
580 (lexical #t #f ref 0) (call return 1)
582 (const 2) (bind (a #f 0)) (lexical #t #f set 0)
583 (lexical #t #f ref 0) (call return 1)
588 ;; second bound var is unreferenced
589 (assert-tree-il->glil without-partial-evaluation
590 (let (x) (y) ((const 1))
593 (let (a) (b) ((const 2))
595 (program () (std-prelude 0 1 #f) (label _)
596 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
597 (lexical #t #f ref 0) (branch br-if-not ,l1)
598 (lexical #t #f ref 0) (call return 1)
600 (lexical #t #f ref 0) (call return 1)
604 (with-test-prefix "apply"
605 (assert-tree-il->glil
606 (primcall @apply (toplevel foo) (toplevel bar))
607 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (toplevel ref bar) (call tail-apply 2)))
608 (assert-tree-il->glil
609 (begin (primcall @apply (toplevel foo) (toplevel bar)) (void))
610 (program () (std-prelude 0 0 #f) (label _)
611 (call new-frame 0) (toplevel ref apply) (toplevel ref foo) (toplevel ref bar) (mv-call 2 ,l1)
612 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
614 (void) (call return 1))
615 (and (eq? l1 l3) (eq? l2 l4)))
616 (assert-tree-il->glil
617 (call (toplevel foo) (call (toplevel @apply) (toplevel bar) (toplevel baz)))
618 (program () (std-prelude 0 0 #f) (label _)
620 (call new-frame 0) (toplevel ref bar) (toplevel ref baz) (call apply 2)
621 (call tail-call 1))))
623 (with-test-prefix "call/cc"
624 (assert-tree-il->glil
625 (primcall @call-with-current-continuation (toplevel foo))
626 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call tail-call/cc 1)))
627 (assert-tree-il->glil
628 (begin (primcall @call-with-current-continuation (toplevel foo)) (void))
629 (program () (std-prelude 0 0 #f) (label _)
630 (call new-frame 0) (toplevel ref call-with-current-continuation) (toplevel ref foo) (mv-call 1 ,l1)
631 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
633 (void) (call return 1))
634 (and (eq? l1 l3) (eq? l2 l4)))
635 (assert-tree-il->glil
637 (call (toplevel @call-with-current-continuation) (toplevel bar)))
638 (program () (std-prelude 0 0 #f) (label _)
640 (toplevel ref bar) (call call/cc 1)
641 (call tail-call 1))))
644 (with-test-prefix "labels allocation"
645 (pass-if "http://debbugs.gnu.org/9769"
646 ((compile '(lambda ()
647 (let ((fail (lambda () #f)))
648 (let ((test (lambda () (fail))))
651 ;; Prevent inlining. We're testing analyze.scm's
652 ;; labels allocator here, and inlining it will
653 ;; reduce the entire thing to #t.
654 #:opts '(#:partial-eval? #f)))))
657 (with-test-prefix "partial evaluation"
660 ;; First order, primitive.
661 (let ((x 1) (y 2)) (+ x y))
665 ;; First order, thunk.
667 (let ((f (lambda () (+ x y))))
672 ;; First order, let-values (requires primitive expansion for
673 ;; `call-with-values'.)
676 (lambda () (if (zero? x) (values 1 2) (values 3 4)))
682 ;; First order, multiple values.
685 (primcall values (const 1) (const 2)))
688 ;; First order, multiple values truncated.
689 (let ((x (values 1 'a)) (y 2))
691 (primcall values (const 1) (const 2)))
694 ;; First order, multiple values truncated.
699 ;; First order, coalesced, mutability preserved.
700 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
702 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
705 ;; First order, coalesced, mutability preserved.
706 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
707 ;; This must not be a constant.
709 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
712 ;; First order, coalesced, immutability preserved.
713 (cons 0 (cons 1 (cons 2 '(3 4 5))))
714 (primcall cons (const 0)
715 (primcall cons (const 1)
716 (primcall cons (const 2)
719 ;; These two tests doesn't work any more because we changed the way we
720 ;; deal with constants -- now the algorithm will see a construction as
721 ;; being bound to the lexical, so it won't propagate it. It can't
722 ;; even propagate it in the case that it is only referenced once,
725 ;; (let ((x (cons 1 2))) (lambda () x))
727 ;; is not the same as
729 ;; (lambda () (cons 1 2))
731 ;; Perhaps if we determined that not only was it only referenced once,
732 ;; it was not closed over by a lambda, then we could propagate it, and
733 ;; re-enable these two tests.
737 ;; First order, mutability preserved.
738 (let loop ((i 3) (r '()))
741 (loop (1- i) (cons (cons i i) r))))
743 (primcall cons (const 1) (const 1))
744 (primcall cons (const 2) (const 2))
745 (primcall cons (const 3) (const 3))))
750 ;; First order, evaluated.
755 (loop (1- i) (cons i r))))
758 ;; Instead here are tests for what happens for the above cases: they
759 ;; unroll but they don't fold.
761 (let loop ((i 3) (r '()))
764 (loop (1- i) (cons (cons i i) r))))
767 (primcall cons (const 3) (const 3))))
770 (primcall cons (const 2) (const 2))
773 (primcall cons (const 1) (const 1))
782 (loop (1- i) (cons i r))))
784 ((primcall list (const 4)))
802 (let loop ((l '(1 2 3 4)) (sum 0))
805 (loop (cdr l) (+ sum (car l)))))
820 (string->chars "yo"))
821 (primcall list (const #\y) (const #\o)))
824 ;; Primitives in module-refs are resolved (the expansion of `pmatch'
825 ;; below leads to calls to (@@ (system base pmatch) car) and
826 ;; similar, which is what we want to be inlined.)
828 (use-modules (system base pmatch))
836 ;; Mutability preserved.
837 ((lambda (x y z) (list x y z)) 1 2 3)
838 (primcall list (const 1) (const 2) (const 3)))
841 ;; Don't propagate effect-free expressions that operate on mutable
847 (let (x) (_) ((primcall list (const 1)))
848 (let (y) (_) ((primcall car (lexical x _)))
850 (primcall set-car! (lexical x _) (const 0))
854 ;; Don't propagate effect-free expressions that operate on objects we
859 (let (y) (_) ((primcall car (toplevel x)))
861 (primcall set-car! (toplevel x) (const 0))
865 ;; Infinite recursion
866 ((lambda (x) (x x)) (lambda (x) (x x)))
871 (call (lexical x _) (lexical x _))))))
872 (call (lexical x _) (lexical x _))))
875 ;; First order, aliased primitive.
876 (let* ((x *) (y (x 1 2))) y)
880 ;; First order, shadowed primitive.
882 (define (+ x y) (pk x y))
888 (((x y) #f #f #f () (_ _))
889 (call (toplevel pk) (lexical x _) (lexical y _))))))
890 (call (toplevel +) (const 1) (const 2))))
893 ;; First-order, effects preserved.
898 (call (toplevel do-something!))
902 ;; First order, residual bindings removed.
905 (primcall * (const 5) (toplevel z)))
908 ;; First order, with lambda.
910 (define (bar z) (* z z))
915 (((x) #f #f #f () (_))
916 (primcall + (lexical x _) (const 9)))))))
919 ;; First order, with lambda inlined & specialized twice.
920 (let ((f (lambda (x y)
929 (primcall + ; (f 2 3)
934 (let (x) (_) ((toplevel something)) ; (f something 2)
935 ;; `something' is not const, so preserve order of
936 ;; effects with a lexical binding.
944 ;; First order, with lambda inlined & specialized 3 times.
945 (let ((f (lambda (x y) (if (> x 0) y x))))
953 (const -1) ; (f -1 0)
959 (seq (toplevel y) (const -1)) ; (f -1 y)
962 (toplevel y) ; (f 2 y)
963 (let (x y) (_ _) ((toplevel z) (toplevel y)) ; (f z y)
964 (if (primcall > (lexical x _) (const 0))
969 ;; First order, conditional.
977 (((x) #f #f #f () (_))
978 (call (toplevel display) (lexical x _))))))
981 ;; First order, recursive procedure.
982 (letrec ((fibo (lambda (n)
991 ;; Don't propagate toplevel references, as intervening expressions
992 ;; could alter their bindings.
996 (let (x) (_) ((toplevel top))
998 (call (toplevel foo))
1004 (f (* (car x) (cadr x))))
1011 ;; Higher order with optional argument (default value).
1012 ((lambda* (f x #:optional (y 0))
1013 (+ y (f (* (car x) (cadr x)))))
1020 ;; Higher order with optional argument (caller-supplied value).
1021 ((lambda* (f x #:optional (y 0))
1022 (+ y (f (* (car x) (cadr x)))))
1030 ;; Higher order with optional argument (side-effecting default
1032 ((lambda* (f x #:optional (y (foo)))
1033 (+ y (f (* (car x) (cadr x)))))
1037 (let (y) (_) ((call (toplevel foo)))
1038 (primcall + (lexical y _) (const 7))))
1041 ;; Higher order with optional argument (caller-supplied value).
1042 ((lambda* (f x #:optional (y (foo)))
1043 (+ y (f (* (car x) (cadr x)))))
1052 ((lambda (f) (f x)) (lambda (x) x))
1057 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
1058 (let ((fold (lambda (f g) (f (g top)))))
1059 (fold 1+ (lambda (x) x)))
1060 (primcall 1+ (toplevel top)))
1063 ;; Procedure not inlined when residual code contains recursive calls.
1064 ;; <http://debbugs.gnu.org/9542>
1065 (letrec ((fold (lambda (f x3 b null? car cdr)
1068 (f (car x3) (fold f (cdr x3) b null? car cdr))))))
1069 (fold * x 1 zero? (lambda (x1) x1) (lambda (x2) (- x2 1))))
1070 (letrec (fold) (_) (_)
1071 (call (lexical fold _)
1078 (((x1) #f #f #f () (_))
1082 (((x2) #f #f #f () (_))
1083 (primcall 1- (lexical x2 _))))))))
1085 (pass-if "inlined lambdas are alpha-renamed"
1086 ;; In this example, `make-adder' is inlined more than once; thus,
1087 ;; they should use different gensyms for their arguments, because
1088 ;; the various optimization passes assume uniquely-named variables.
1091 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html> and
1092 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00029.html>.
1093 (pmatch (unparse-tree-il
1094 (peval (expand-primitives!
1095 (resolve-primitives!
1098 (lambda (x) (lambda (y) (+ x y)))))
1099 (cons (make-adder 1) (make-adder 2)))
1101 (current-module)))))
1105 (((y) #f #f #f () (,gensym1))
1108 (lexical y ,ref1)))))
1111 (((y) #f #f #f () (,gensym2))
1114 (lexical y ,ref2))))))
1115 (and (eq? gensym1 ref1)
1117 (not (eq? gensym1 gensym2))))
1121 ;; Unused letrec bindings are pruned.
1122 (letrec ((a (lambda () (b)))
1129 ;; Unused letrec bindings are pruned.
1134 (seq (call (toplevel foo!))
1138 ;; Higher order, mutually recursive procedures.
1139 (letrec ((even? (lambda (x)
1144 (and (even? 4) (odd? 7)))
1148 ;; Memv with constants.
1153 ;; Memv with non-constant list. It could fold but doesn't
1155 (memv 1 (list 3 2 1))
1158 (primcall list (const 3) (const 2) (const 1))))
1161 ;; Memv with non-constant key, constant list, test context
1165 (let (key) (_) ((toplevel foo))
1166 (if (if (primcall eqv? (lexical key _) (const 3))
1168 (if (primcall eqv? (lexical key _) (const 2))
1170 (primcall eqv? (lexical key _) (const 1))))
1175 ;; Memv with non-constant key, empty list, test context.
1179 (seq (toplevel foo) (const 'b)))
1182 ;; Below are cases where constant propagation should bail out.
1186 ;; Non-constant lexical is not propagated.
1187 (let ((v (make-vector 6 #f)))
1189 (vector-set! v n n)))
1191 ((call (toplevel make-vector) (const 6) (const #f)))
1194 (((n) #f #f #f () (_))
1195 (primcall vector-set!
1196 (lexical v _) (lexical n _) (lexical n _)))))))
1199 ;; Mutable lexical is not propagated.
1200 (let ((v (vector 1 2 3)))
1204 ((primcall vector (const 1) (const 2) (const 3)))
1207 ((() #f #f #f () ())
1211 ;; Lexical that is not provably pure is not inlined nor propagated.
1212 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
1215 (let (x) (_) ((if (primcall > (toplevel p) (toplevel q))
1216 (call (toplevel frob!))
1217 (call (toplevel display) (const chbouib))))
1218 (let (y) (_) ((primcall * (lexical x _) (const 2)))
1221 (primcall + (lexical x _) (lexical y _))))))
1224 ;; Non-constant arguments not propagated to lambdas.
1232 (let (x y z) (_ _ _)
1233 ((primcall vector (const 1) (const 2) (const 3))
1234 (call (toplevel make-list) (const 10))
1235 (primcall list (const 1) (const 2) (const 3)))
1237 (primcall vector-set!
1238 (lexical x _) (const 0) (const 0))
1239 (seq (primcall set-car!
1240 (lexical y _) (const 0))
1242 (lexical z _) (const ()))))))
1245 (let ((foo top-foo) (bar top-bar))
1246 (let* ((g (lambda (x y) (+ x y)))
1247 (f (lambda (g x) (g x x))))
1248 (+ (f g foo) (f g bar))))
1249 (let (foo bar) (_ _) ((toplevel top-foo) (toplevel top-bar))
1251 (primcall + (lexical foo _) (lexical foo _))
1252 (primcall + (lexical bar _) (lexical bar _)))))
1255 ;; Fresh objects are not turned into constants, nor are constants
1256 ;; turned into fresh objects.
1261 (let (x) (_) ((primcall cons (const 1) (const (2 3))))
1262 (primcall cons (const 0) (lexical x _))))
1265 ;; Bindings mutated.
1269 (let (x) (_) ((const 2))
1271 (set! (lexical x _) (const 3))
1275 ;; Bindings mutated.
1280 (frob f) ; may mutate `x'
1282 (letrec (x) (_) ((const 0))
1284 (call (toplevel frob) (lambda _ _))
1288 ;; Bindings mutated.
1289 (letrec ((f (lambda (x)
1290 (set! f (lambda (_) x))
1296 ;; Bindings possibly mutated.
1297 (let ((x (make-foo)))
1298 (frob! x) ; may mutate `x'
1300 (let (x) (_) ((call (toplevel make-foo)))
1302 (call (toplevel frob!) (lexical x _))
1306 ;; Inlining stops at recursive calls with dynamic arguments.
1308 (if (< x 0) x (loop (1- x))))
1309 (letrec (loop) (_) ((lambda (_)
1311 (((x) #f #f #f () (_))
1313 (call (lexical loop _)
1315 (lexical x _))))))))
1316 (call (lexical loop _) (toplevel x))))
1319 ;; Recursion on the 2nd argument is fully evaluated.
1321 (let loop ((x x) (y 10))
1325 (let (x) (_) ((call (toplevel top)))
1326 (call (toplevel foo) (lexical x _) (const 0))))
1329 ;; Inlining aborted when residual code contains recursive calls.
1331 ;; <http://debbugs.gnu.org/9542>
1332 (let loop ((x x) (y 0))
1334 (loop (1- x) (1- y))
1337 (loop (1+ x) (1+ y)))))
1338 (letrec (loop) (_) ((lambda (_)
1340 (((x y) #f #f #f () (_ _))
1342 (lexical y _) (const 0))
1344 (call (lexical loop _) (toplevel x) (const 0))))
1347 ;; Infinite recursion: `peval' gives up and leaves it as is.
1348 (letrec ((f (lambda (x) (g (1- x))))
1349 (g (lambda (x) (h (1+ x))))
1350 (h (lambda (x) (f x))))
1355 ;; Infinite recursion: all the arguments to `loop' are static, but
1356 ;; unrolling it would lead `peval' to enter an infinite loop.
1360 (letrec (loop) (_) ((lambda . _))
1361 (call (lexical loop _) (const 0))))
1364 ;; This test checks that the `start' binding is indeed residualized.
1365 ;; See the `referenced?' procedure in peval's `prune-bindings'.
1367 (set! pos 1) ;; Cause references to `pos' to residualize.
1368 (let ((here (let ((start pos)) (lambda () start))))
1370 (let (pos) (_) ((const 0))
1372 (set! (lexical pos _) (const 1))
1374 (call (lexical here _))))))
1377 ;; FIXME: should this one residualize the binding?
1383 ;; This is a fun one for peval to handle.
1386 (letrec (a) (_) ((lexical a _))
1390 ;; Another interesting recursive case.
1391 (letrec ((a b) (b a))
1393 (letrec (a) (_) ((lexical a _))
1397 ;; Another pruning case, that `a' is residualized.
1398 (letrec ((a (lambda () (a)))
1404 ;; "b c a" is the current order that we get with unordered letrec,
1405 ;; but it's not important to this test, so if it changes, just adapt
1407 (letrec (b c a) (_ _ _)
1410 ((() #f #f #f () ())
1411 (call (lexical a _)))))
1414 (((x) #f #f #f () (_))
1418 ((() #f #f #f () ())
1419 (call (lexical a _))))))
1422 ((call (toplevel foo) (lexical b _)))
1423 (call (lexical c _) (lexical d _)))))
1426 ;; In this case, we can prune the bindings. `a' ends up being copied
1427 ;; because it is only referenced once in the source program. Oh
1429 (letrec* ((a (lambda (x) (top x)))
1432 (call (toplevel foo)
1435 (((x) #f #f #f () (_))
1436 (call (toplevel top) (lexical x _)))))
1439 (((x) #f #f #f () (_))
1440 (call (toplevel top) (lexical x _)))))))
1443 ;; Constant folding: cons of #nil does not make list
1445 (primcall cons (const 1) (const '#nil)))
1448 ;; Constant folding: cons
1449 (begin (cons 1 2) #f)
1453 ;; Constant folding: cons
1454 (begin (cons (foo) 2) #f)
1455 (seq (call (toplevel foo)) (const #f)))
1458 ;; Constant folding: cons
1463 ;; Constant folding: car+cons
1468 ;; Constant folding: cdr+cons
1473 ;; Constant folding: car+cons, impure
1474 (car (cons 1 (bar)))
1475 (seq (call (toplevel bar)) (const 1)))
1478 ;; Constant folding: cdr+cons, impure
1479 (cdr (cons (bar) 0))
1480 (seq (call (toplevel bar)) (const 0)))
1483 ;; Constant folding: car+list
1488 ;; Constant folding: cdr+list
1490 (primcall list (const 0)))
1493 ;; Constant folding: car+list, impure
1494 (car (list 1 (bar)))
1495 (seq (call (toplevel bar)) (const 1)))
1498 ;; Constant folding: cdr+list, impure
1499 (cdr (list (bar) 0))
1500 (seq (call (toplevel bar)) (primcall list (const 0))))
1503 ;; Non-constant guards get lexical bindings.
1504 (dynamic-wind foo (lambda () bar) baz)
1505 (let (w u) (_ _) ((toplevel foo) (toplevel baz))
1506 (dynwind (lexical w _)
1507 (call (lexical w _))
1509 (call (lexical u _))
1513 ;; Constant guards don't need lexical bindings.
1514 (dynamic-wind (lambda () foo) (lambda () bar) (lambda () baz))
1518 ((() #f #f #f () ()) (toplevel foo))))
1524 ((() #f #f #f () ()) (toplevel baz))))))
1527 ;; Prompt is removed if tag is unreferenced
1528 (let ((tag (make-prompt-tag)))
1529 (call-with-prompt tag
1531 (lambda args args)))
1535 ;; Prompt is removed if tag is unreferenced, with explicit stem
1536 (let ((tag (make-prompt-tag "foo")))
1537 (call-with-prompt tag
1539 (lambda args args)))
1543 ;; `while' without `break' or `continue' has no prompts and gets its
1544 ;; condition folded. Unfortunately the outer `lp' does not yet get
1550 ((() #f #f #f () ())
1554 ((() #f #f #f () ())
1555 (call (lexical loop _))))))
1556 (call (lexical loop _)))))))
1557 (call (lexical lp _)))))
1561 (with-test-prefix "tree-il-fold"
1563 (pass-if "empty tree"
1564 (let ((leaf? #f) (up? #f) (down? #f) (mark (list 'mark)))
1566 (tree-il-fold (lambda (x y) (set! leaf? #t) y)
1567 (lambda (x y) (set! down? #t) y)
1568 (lambda (x y) (set! up? #t) y)
1575 (pass-if "lambda and application"
1576 (let* ((leaves '()) (ups '()) (downs '())
1577 (result (tree-il-fold (lambda (x y)
1578 (set! leaves (cons x leaves))
1581 (set! downs (cons x downs))
1584 (set! ups (cons x ups))
1590 (((x y) #f #f #f () (x1 y1))
1595 (and (equal? (map strip-source leaves)
1596 (list (make-lexical-ref #f 'y 'y1)
1597 (make-lexical-ref #f 'x 'x1)
1598 (make-toplevel-ref #f '+)))
1599 (= (length downs) 3)
1600 (equal? (reverse (map strip-source ups))
1601 (map strip-source downs))))))
1608 ;; Make sure we get English messages.
1609 (setlocale LC_ALL "C")
1611 (define (call-with-warnings thunk)
1612 (let ((port (open-output-string)))
1613 (with-fluids ((*current-warning-port* port)
1614 (*current-warning-prefix* ""))
1616 (let ((warnings (get-output-string port)))
1617 (string-tokenize warnings
1618 (char-set-complement (char-set #\newline))))))
1620 (define %opts-w-unused
1621 '(#:warnings (unused-variable)))
1623 (define %opts-w-unused-toplevel
1624 '(#:warnings (unused-toplevel)))
1626 (define %opts-w-unbound
1627 '(#:warnings (unbound-variable)))
1629 (define %opts-w-arity
1630 '(#:warnings (arity-mismatch)))
1632 (define %opts-w-format
1633 '(#:warnings (format)))
1636 (with-test-prefix "warnings"
1638 (pass-if "unknown warning type"
1639 (let ((w (call-with-warnings
1641 (compile #t #:opts '(#:warnings (does-not-exist)))))))
1642 (and (= (length w) 1)
1643 (number? (string-contains (car w) "unknown warning")))))
1645 (with-test-prefix "unused-variable"
1648 (null? (call-with-warnings
1650 (compile '(lambda (x y) (+ x y))
1651 #:opts %opts-w-unused)))))
1653 (pass-if "let/unused"
1654 (let ((w (call-with-warnings
1656 (compile '(lambda (x)
1659 #:opts %opts-w-unused)))))
1660 (and (= (length w) 1)
1661 (number? (string-contains (car w) "unused variable `y'")))))
1663 (pass-if "shadowed variable"
1664 (let ((w (call-with-warnings
1666 (compile '(lambda (x)
1670 #:opts %opts-w-unused)))))
1671 (and (= (length w) 1)
1672 (number? (string-contains (car w) "unused variable `y'")))))
1675 (null? (call-with-warnings
1677 (compile '(lambda ()
1678 (letrec ((x (lambda () (y)))
1679 (y (lambda () (x))))
1681 #:opts %opts-w-unused)))))
1683 (pass-if "unused argument"
1684 ;; Unused arguments should not be reported.
1685 (null? (call-with-warnings
1687 (compile '(lambda (x y z) #t)
1688 #:opts %opts-w-unused)))))
1690 (pass-if "special variable names"
1691 (null? (call-with-warnings
1693 (compile '(lambda ()
1694 (let ((_ 'underscore)
1695 (#{gensym name}# 'ignore-me))
1698 #:opts %opts-w-unused))))))
1700 (with-test-prefix "unused-toplevel"
1702 (pass-if "used after definition"
1703 (null? (call-with-warnings
1705 (let ((in (open-input-string
1706 "(define foo 2) foo")))
1707 (read-and-compile in
1709 #:opts %opts-w-unused-toplevel))))))
1711 (pass-if "used before definition"
1712 (null? (call-with-warnings
1714 (let ((in (open-input-string
1715 "(define (bar) foo) (define foo 2) (bar)")))
1716 (read-and-compile in
1718 #:opts %opts-w-unused-toplevel))))))
1720 (pass-if "unused but public"
1721 (let ((in (open-input-string
1722 "(define-module (test-suite tree-il x) #:export (bar))
1723 (define (bar) #t)")))
1724 (null? (call-with-warnings
1726 (read-and-compile in
1728 #:opts %opts-w-unused-toplevel))))))
1730 (pass-if "unused but public (more)"
1731 (let ((in (open-input-string
1732 "(define-module (test-suite tree-il x) #:export (bar))
1733 (define (bar) (baz))
1734 (define (baz) (foo))
1735 (define (foo) #t)")))
1736 (null? (call-with-warnings
1738 (read-and-compile in
1740 #:opts %opts-w-unused-toplevel))))))
1742 (pass-if "unused but define-public"
1743 (null? (call-with-warnings
1745 (compile '(define-public foo 2)
1747 #:opts %opts-w-unused-toplevel)))))
1749 (pass-if "used by macro"
1750 ;; FIXME: See comment about macros at `unused-toplevel-analysis'.
1753 (null? (call-with-warnings
1755 (let ((in (open-input-string
1756 "(define (bar) 'foo)
1758 (syntax-rules () ((_) (bar))))")))
1759 (read-and-compile in
1761 #:opts %opts-w-unused-toplevel))))))
1764 (let ((w (call-with-warnings
1766 (compile '(define foo 2)
1768 #:opts %opts-w-unused-toplevel)))))
1769 (and (= (length w) 1)
1770 (number? (string-contains (car w)
1771 (format #f "top-level variable `~A'"
1774 (pass-if "unused recursive"
1775 (let ((w (call-with-warnings
1777 (compile '(define (foo) (foo))
1779 #:opts %opts-w-unused-toplevel)))))
1780 (and (= (length w) 1)
1781 (number? (string-contains (car w)
1782 (format #f "top-level variable `~A'"
1785 (pass-if "unused mutually recursive"
1786 (let* ((in (open-input-string
1787 "(define (foo) (bar)) (define (bar) (foo))"))
1788 (w (call-with-warnings
1790 (read-and-compile in
1792 #:opts %opts-w-unused-toplevel)))))
1793 (and (= (length w) 2)
1794 (number? (string-contains (car w)
1795 (format #f "top-level variable `~A'"
1797 (number? (string-contains (cadr w)
1798 (format #f "top-level variable `~A'"
1801 (pass-if "special variable names"
1802 (null? (call-with-warnings
1804 (compile '(define #{gensym name}# 'ignore-me)
1806 #:opts %opts-w-unused-toplevel))))))
1808 (with-test-prefix "unbound variable"
1811 (null? (call-with-warnings
1813 (compile '+ #:opts %opts-w-unbound)))))
1817 (w (call-with-warnings
1821 #:opts %opts-w-unbound)))))
1822 (and (= (length w) 1)
1823 (number? (string-contains (car w)
1824 (format #f "unbound variable `~A'"
1829 (w (call-with-warnings
1831 (compile `(set! ,v 7)
1833 #:opts %opts-w-unbound)))))
1834 (and (= (length w) 1)
1835 (number? (string-contains (car w)
1836 (format #f "unbound variable `~A'"
1839 (pass-if "module-local top-level is visible"
1840 (let ((m (make-module))
1842 (beautify-user-module! m)
1843 (compile `(define ,v 123)
1844 #:env m #:opts %opts-w-unbound)
1845 (null? (call-with-warnings
1850 #:opts %opts-w-unbound))))))
1852 (pass-if "module-local top-level is visible after"
1853 (let ((m (make-module))
1855 (beautify-user-module! m)
1856 (null? (call-with-warnings
1858 (let ((in (open-input-string
1861 (define chbouib 5)")))
1862 (read-and-compile in
1864 #:opts %opts-w-unbound)))))))
1866 (pass-if "optional arguments are visible"
1867 (null? (call-with-warnings
1869 (compile '(lambda* (x #:optional y z) (list x y z))
1870 #:opts %opts-w-unbound
1873 (pass-if "keyword arguments are visible"
1874 (null? (call-with-warnings
1876 (compile '(lambda* (x #:key y z) (list x y z))
1877 #:opts %opts-w-unbound
1880 (pass-if "GOOPS definitions are visible"
1881 (let ((m (make-module))
1883 (beautify-user-module! m)
1884 (module-use! m (resolve-interface '(oop goops)))
1885 (null? (call-with-warnings
1887 (let ((in (open-input-string
1888 "(define-class <foo> ()
1889 (bar #:getter foo-bar))
1890 (define z (foo-bar (make <foo>)))")))
1891 (read-and-compile in
1893 #:opts %opts-w-unbound))))))))
1895 (with-test-prefix "arity mismatch"
1898 (null? (call-with-warnings
1900 (compile '(cons 'a 'b) #:opts %opts-w-arity)))))
1902 (pass-if "direct application"
1903 (let ((w (call-with-warnings
1905 (compile '((lambda (x y) (or x y)) 1 2 3 4 5)
1906 #:opts %opts-w-arity
1908 (and (= (length w) 1)
1909 (number? (string-contains (car w)
1910 "wrong number of arguments to")))))
1912 (let ((w (call-with-warnings
1914 (compile '(let ((f (lambda (x y) (+ x y))))
1916 #:opts %opts-w-arity
1918 (and (= (length w) 1)
1919 (number? (string-contains (car w)
1920 "wrong number of arguments to")))))
1923 (let ((w (call-with-warnings
1925 (compile '(cons 1 2 3 4)
1926 #:opts %opts-w-arity
1928 (and (= (length w) 1)
1929 (number? (string-contains (car w)
1930 "wrong number of arguments to")))))
1932 (pass-if "alias to global"
1933 (let ((w (call-with-warnings
1935 (compile '(let ((f cons)) (f 1 2 3 4))
1936 #:opts %opts-w-arity
1938 (and (= (length w) 1)
1939 (number? (string-contains (car w)
1940 "wrong number of arguments to")))))
1942 (pass-if "alias to lexical to global"
1943 (let ((w (call-with-warnings
1945 (compile '(let ((f number?))
1948 #:opts %opts-w-arity
1950 (and (= (length w) 1)
1951 (number? (string-contains (car w)
1952 "wrong number of arguments to")))))
1954 (pass-if "alias to lexical"
1955 (let ((w (call-with-warnings
1957 (compile '(let ((f (lambda (x y z) (+ x y z))))
1960 #:opts %opts-w-arity
1962 (and (= (length w) 1)
1963 (number? (string-contains (car w)
1964 "wrong number of arguments to")))))
1967 (let ((w (call-with-warnings
1969 (compile '(letrec ((odd? (lambda (x) (even? (1- x))))
1974 #:opts %opts-w-arity
1976 (and (= (length w) 1)
1977 (number? (string-contains (car w)
1978 "wrong number of arguments to")))))
1980 (pass-if "case-lambda"
1981 (null? (call-with-warnings
1983 (compile '(let ((f (case-lambda
1990 #:opts %opts-w-arity
1993 (pass-if "case-lambda with wrong number of arguments"
1994 (let ((w (call-with-warnings
1996 (compile '(let ((f (case-lambda
2000 #:opts %opts-w-arity
2002 (and (= (length w) 1)
2003 (number? (string-contains (car w)
2004 "wrong number of arguments to")))))
2006 (pass-if "case-lambda*"
2007 (null? (call-with-warnings
2009 (compile '(let ((f (case-lambda*
2010 ((x #:optional y) 1)
2012 ((x y #:key z) 3))))
2017 #:opts %opts-w-arity
2020 (pass-if "case-lambda* with wrong arguments"
2021 (let ((w (call-with-warnings
2023 (compile '(let ((f (case-lambda*
2024 ((x #:optional y) 1)
2026 ((x y #:key z) 3))))
2029 #:opts %opts-w-arity
2031 (and (= (length w) 2)
2032 (null? (filter (lambda (w)
2036 w "wrong number of arguments to"))))
2039 (pass-if "local toplevel-defines"
2040 (let ((w (call-with-warnings
2042 (let ((in (open-input-string "
2043 (define (g x) (f x))
2045 (read-and-compile in
2046 #:opts %opts-w-arity
2047 #:to 'assembly))))))
2048 (and (= (length w) 1)
2049 (number? (string-contains (car w)
2050 "wrong number of arguments to")))))
2052 (pass-if "global toplevel alias"
2053 (let ((w (call-with-warnings
2055 (let ((in (open-input-string "
2057 (define (g) (f))")))
2058 (read-and-compile in
2059 #:opts %opts-w-arity
2060 #:to 'assembly))))))
2061 (and (= (length w) 1)
2062 (number? (string-contains (car w)
2063 "wrong number of arguments to")))))
2065 (pass-if "local toplevel overrides global"
2066 (null? (call-with-warnings
2068 (let ((in (open-input-string "
2070 (define (foo x) (cons))")))
2071 (read-and-compile in
2072 #:opts %opts-w-arity
2073 #:to 'assembly))))))
2075 (pass-if "keyword not passed and quiet"
2076 (null? (call-with-warnings
2078 (compile '(let ((f (lambda* (x #:key y) y)))
2080 #:opts %opts-w-arity
2083 (pass-if "keyword passed and quiet"
2084 (null? (call-with-warnings
2086 (compile '(let ((f (lambda* (x #:key y) y)))
2088 #:opts %opts-w-arity
2091 (pass-if "keyword passed to global and quiet"
2092 (null? (call-with-warnings
2094 (let ((in (open-input-string "
2095 (use-modules (system base compile))
2096 (compile '(+ 2 3) #:env (current-module))")))
2097 (read-and-compile in
2098 #:opts %opts-w-arity
2099 #:to 'assembly))))))
2101 (pass-if "extra keyword"
2102 (let ((w (call-with-warnings
2104 (compile '(let ((f (lambda* (x #:key y) y)))
2106 #:opts %opts-w-arity
2108 (and (= (length w) 1)
2109 (number? (string-contains (car w)
2110 "wrong number of arguments to")))))
2112 (pass-if "extra keywords allowed"
2113 (null? (call-with-warnings
2115 (compile '(let ((f (lambda* (x #:key y #:allow-other-keys)
2118 #:opts %opts-w-arity
2119 #:to 'assembly))))))
2121 (with-test-prefix "format"
2123 (pass-if "quiet (no args)"
2124 (null? (call-with-warnings
2126 (compile '(format #t "hey!")
2127 #:opts %opts-w-format
2130 (pass-if "quiet (1 arg)"
2131 (null? (call-with-warnings
2133 (compile '(format #t "hey ~A!" "you")
2134 #:opts %opts-w-format
2137 (pass-if "quiet (2 args)"
2138 (null? (call-with-warnings
2140 (compile '(format #t "~A ~A!" "hello" "world")
2141 #:opts %opts-w-format
2144 (pass-if "wrong port arg"
2145 (let ((w (call-with-warnings
2147 (compile '(format 10 "foo")
2148 #:opts %opts-w-format
2150 (and (= (length w) 1)
2151 (number? (string-contains (car w)
2152 "wrong port argument")))))
2154 (pass-if "non-literal format string"
2155 (let ((w (call-with-warnings
2157 (compile '(format #f fmt)
2158 #:opts %opts-w-format
2160 (and (= (length w) 1)
2161 (number? (string-contains (car w)
2162 "non-literal format string")))))
2164 (pass-if "non-literal format string using gettext"
2165 (null? (call-with-warnings
2167 (compile '(format #t (_ "~A ~A!") "hello" "world")
2168 #:opts %opts-w-format
2171 (pass-if "wrong format string"
2172 (let ((w (call-with-warnings
2174 (compile '(format #f 'not-a-string)
2175 #:opts %opts-w-format
2177 (and (= (length w) 1)
2178 (number? (string-contains (car w)
2179 "wrong format string")))))
2181 (pass-if "wrong number of args"
2182 (let ((w (call-with-warnings
2184 (compile '(format "shbweeb")
2185 #:opts %opts-w-format
2187 (and (= (length w) 1)
2188 (number? (string-contains (car w)
2189 "wrong number of arguments")))))
2191 (pass-if "~%, ~~, ~&, ~t, ~_, and ~\\n"
2192 (null? (call-with-warnings
2194 (compile '((@ (ice-9 format) format) some-port
2195 "~&~3_~~ ~\n~12they~%")
2196 #:opts %opts-w-format
2199 (pass-if "one missing argument"
2200 (let ((w (call-with-warnings
2202 (compile '(format some-port "foo ~A~%")
2203 #:opts %opts-w-format
2205 (and (= (length w) 1)
2206 (number? (string-contains (car w)
2207 "expected 1, got 0")))))
2209 (pass-if "one missing argument, gettext"
2210 (let ((w (call-with-warnings
2212 (compile '(format some-port (_ "foo ~A~%"))
2213 #:opts %opts-w-format
2215 (and (= (length w) 1)
2216 (number? (string-contains (car w)
2217 "expected 1, got 0")))))
2219 (pass-if "two missing arguments"
2220 (let ((w (call-with-warnings
2222 (compile '((@ (ice-9 format) format) #f
2223 "foo ~10,2f and bar ~S~%")
2224 #:opts %opts-w-format
2226 (and (= (length w) 1)
2227 (number? (string-contains (car w)
2228 "expected 2, got 0")))))
2230 (pass-if "one given, one missing argument"
2231 (let ((w (call-with-warnings
2233 (compile '(format #t "foo ~A and ~S~%" hey)
2234 #:opts %opts-w-format
2236 (and (= (length w) 1)
2237 (number? (string-contains (car w)
2238 "expected 2, got 1")))))
2240 (pass-if "too many arguments"
2241 (let ((w (call-with-warnings
2243 (compile '(format #t "foo ~A~%" 1 2)
2244 #:opts %opts-w-format
2246 (and (= (length w) 1)
2247 (number? (string-contains (car w)
2248 "expected 1, got 2")))))
2251 (null? (call-with-warnings
2253 (compile '((@ (ice-9 format) format) #t
2254 "foo ~h ~a~%" 123.4 'bar)
2255 #:opts %opts-w-format
2258 (pass-if "~:h with locale object"
2259 (null? (call-with-warnings
2261 (compile '((@ (ice-9 format) format) #t
2262 "foo ~:h~%" 123.4 %global-locale)
2263 #:opts %opts-w-format
2266 (pass-if "~:h without locale object"
2267 (let ((w (call-with-warnings
2269 (compile '((@ (ice-9 format) format) #t "foo ~,2:h" 123.4)
2270 #:opts %opts-w-format
2272 (and (= (length w) 1)
2273 (number? (string-contains (car w)
2274 "expected 2, got 1")))))
2276 (with-test-prefix "conditionals"
2278 (null? (call-with-warnings
2280 (compile '((@ (ice-9 format) format) #f "~A ~[foo~;bar~;baz~;~] ~10,2f"
2282 #:opts %opts-w-format
2285 (pass-if "literals with selector"
2286 (let ((w (call-with-warnings
2288 (compile '((@ (ice-9 format) format) #f "~2[foo~;bar~;baz~;~] ~A"
2290 #:opts %opts-w-format
2292 (and (= (length w) 1)
2293 (number? (string-contains (car w)
2294 "expected 1, got 2")))))
2296 (pass-if "escapes (exact count)"
2297 (let ((w (call-with-warnings
2299 (compile '((@ (ice-9 format) format) #f "~[~a~;~a~]")
2300 #:opts %opts-w-format
2302 (and (= (length w) 1)
2303 (number? (string-contains (car w)
2304 "expected 2, got 0")))))
2306 (pass-if "escapes with selector"
2307 (let ((w (call-with-warnings
2309 (compile '((@ (ice-9 format) format) #f "~1[chbouib~;~a~]")
2310 #:opts %opts-w-format
2312 (and (= (length w) 1)
2313 (number? (string-contains (car w)
2314 "expected 1, got 0")))))
2316 (pass-if "escapes, range"
2317 (let ((w (call-with-warnings
2319 (compile '((@ (ice-9 format) format) #f "~[chbouib~;~a~;~2*~a~]")
2320 #:opts %opts-w-format
2322 (and (= (length w) 1)
2323 (number? (string-contains (car w)
2324 "expected 1 to 4, got 0")))))
2327 (let ((w (call-with-warnings
2329 (compile '((@ (ice-9 format) format) #f "~@[temperature=~d~]")
2330 #:opts %opts-w-format
2332 (and (= (length w) 1)
2333 (number? (string-contains (car w)
2334 "expected 1, got 0")))))
2337 (let ((w (call-with-warnings
2339 (compile '((@ (ice-9 format) format) #f "~:[~[hey~;~a~;~va~]~;~3*~]")
2340 #:opts %opts-w-format
2342 (and (= (length w) 1)
2343 (number? (string-contains (car w)
2344 "expected 2 to 4, got 0")))))
2346 (pass-if "unterminated"
2347 (let ((w (call-with-warnings
2349 (compile '((@ (ice-9 format) format) #f "~[unterminated")
2350 #:opts %opts-w-format
2352 (and (= (length w) 1)
2353 (number? (string-contains (car w)
2354 "unterminated conditional")))))
2356 (pass-if "unexpected ~;"
2357 (let ((w (call-with-warnings
2359 (compile '((@ (ice-9 format) format) #f "foo~;bar")
2360 #:opts %opts-w-format
2362 (and (= (length w) 1)
2363 (number? (string-contains (car w)
2366 (pass-if "unexpected ~]"
2367 (let ((w (call-with-warnings
2369 (compile '((@ (ice-9 format) format) #f "foo~]")
2370 #:opts %opts-w-format
2372 (and (= (length w) 1)
2373 (number? (string-contains (car w)
2377 (null? (call-with-warnings
2379 (compile '((@ (ice-9 format) format) #f "~A ~{~S~} ~A"
2380 'hello '("ladies" "and")
2382 #:opts %opts-w-format
2385 (pass-if "~{...~}, too many args"
2386 (let ((w (call-with-warnings
2388 (compile '((@ (ice-9 format) format) #f "~{~S~}" 1 2 3)
2389 #:opts %opts-w-format
2391 (and (= (length w) 1)
2392 (number? (string-contains (car w)
2393 "expected 1, got 3")))))
2396 (null? (call-with-warnings
2398 (compile '((@ (ice-9 format) format) #f "~@{~S~}" 1 2 3)
2399 #:opts %opts-w-format
2402 (pass-if "~@{...~}, too few args"
2403 (let ((w (call-with-warnings
2405 (compile '((@ (ice-9 format) format) #f "~A ~@{~S~}")
2406 #:opts %opts-w-format
2408 (and (= (length w) 1)
2409 (number? (string-contains (car w)
2410 "expected at least 1, got 0")))))
2412 (pass-if "unterminated ~{...~}"
2413 (let ((w (call-with-warnings
2415 (compile '((@ (ice-9 format) format) #f "~{")
2416 #:opts %opts-w-format
2418 (and (= (length w) 1)
2419 (number? (string-contains (car w)
2423 (null? (call-with-warnings
2425 (compile '((@ (ice-9 format) format) #f "~:@(~A ~A~)" 'foo 'bar)
2426 #:opts %opts-w-format
2430 (let ((w (call-with-warnings
2432 (compile '((@ (ice-9 format) format) #f "~v_foo")
2433 #:opts %opts-w-format
2435 (and (= (length w) 1)
2436 (number? (string-contains (car w)
2437 "expected 1, got 0")))))
2439 (null? (call-with-warnings
2441 (compile '((@ (ice-9 format) format) #f "~v:@y" 1 123)
2442 #:opts %opts-w-format
2447 (let ((w (call-with-warnings
2449 (compile '((@ (ice-9 format) format) #f "~2*~a" 'a 'b)
2450 #:opts %opts-w-format
2452 (and (= (length w) 1)
2453 (number? (string-contains (car w)
2454 "expected 3, got 2")))))
2457 (null? (call-with-warnings
2459 (compile '((@ (ice-9 format) format) #f "~?" "~d ~d" '(1 2))
2460 #:opts %opts-w-format
2463 (pass-if "complex 1"
2464 (let ((w (call-with-warnings
2466 (compile '((@ (ice-9 format) format) #f
2467 "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
2469 #:opts %opts-w-format
2471 (and (= (length w) 1)
2472 (number? (string-contains (car w)
2473 "expected 4, got 6")))))
2475 (pass-if "complex 2"
2476 (let ((w (call-with-warnings
2478 (compile '((@ (ice-9 format) format) #f
2479 "~:(~A~) Commands~:[~; [abbrev]~]:~2%"
2481 #:opts %opts-w-format
2483 (and (= (length w) 1)
2484 (number? (string-contains (car w)
2485 "expected 2, got 4")))))
2487 (pass-if "complex 3"
2488 (let ((w (call-with-warnings
2490 (compile '((@ (ice-9 format) format) #f "~9@a~:[~*~3_~;~3d~] ~v:@y~%")
2491 #:opts %opts-w-format
2493 (and (= (length w) 1)
2494 (number? (string-contains (car w)
2495 "expected 5, got 0")))))
2497 (pass-if "ice-9 format"
2498 (let ((w (call-with-warnings
2500 (let ((in (open-input-string
2501 "(use-modules ((ice-9 format)
2502 #:renamer (symbol-prefix-proc 'i9-)))
2503 (i9-format #t \"yo! ~A\" 1 2)")))
2504 (read-and-compile in
2505 #:opts %opts-w-format
2506 #:to 'assembly))))))
2507 (and (= (length w) 1)
2508 (number? (string-contains (car w)
2509 "expected 1, got 2")))))
2511 (pass-if "not format"
2512 (null? (call-with-warnings
2514 (compile '(let ((format chbouib))
2515 (format #t "not ~A a format string"))
2516 #:opts %opts-w-format
2519 (with-test-prefix "simple-format"
2522 (null? (call-with-warnings
2524 (compile '(simple-format #t "foo ~a bar ~s ~%~~" 1 2)
2525 #:opts %opts-w-format
2528 (pass-if "wrong number of args"
2529 (let ((w (call-with-warnings
2531 (compile '(simple-format #t "foo ~a ~s~%" 'one-missing)
2532 #:opts %opts-w-format
2534 (and (= (length w) 1)
2535 (number? (string-contains (car w) "wrong number")))))
2537 (pass-if "unsupported"
2538 (let ((w (call-with-warnings
2540 (compile '(simple-format #t "foo ~x~%" 16)
2541 #:opts %opts-w-format
2543 (and (= (length w) 1)
2544 (number? (string-contains (car w) "unsupported format option"))))))))