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
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 ;; FIXME: binding info for or-hacked locals might bork the disassembler,
552 ;; and could be tightened in any case
553 (with-test-prefix "the or hack"
554 (assert-tree-il->glil without-partial-evaluation
555 (let (x) (y) ((const 1))
558 (let (a) (b) ((const 2))
560 (program () (std-prelude 0 1 #f) (label _)
561 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
562 (lexical #t #f ref 0) (branch br-if-not ,l1)
563 (lexical #t #f ref 0) (call return 1)
565 (const 2) (bind (a #f 0)) (lexical #t #f set 0)
566 (lexical #t #f ref 0) (call return 1)
571 ;; second bound var is unreferenced
572 (assert-tree-il->glil without-partial-evaluation
573 (let (x) (y) ((const 1))
576 (let (a) (b) ((const 2))
578 (program () (std-prelude 0 1 #f) (label _)
579 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
580 (lexical #t #f ref 0) (branch br-if-not ,l1)
581 (lexical #t #f ref 0) (call return 1)
583 (lexical #t #f ref 0) (call return 1)
587 (with-test-prefix "apply"
588 (assert-tree-il->glil
589 (primcall @apply (toplevel foo) (toplevel bar))
590 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (toplevel ref bar) (call tail-apply 2)))
591 (assert-tree-il->glil
592 (begin (primcall @apply (toplevel foo) (toplevel bar)) (void))
593 (program () (std-prelude 0 0 #f) (label _)
594 (call new-frame 0) (toplevel ref apply) (toplevel ref foo) (toplevel ref bar) (mv-call 2 ,l1)
595 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
597 (void) (call return 1))
598 (and (eq? l1 l3) (eq? l2 l4)))
599 (assert-tree-il->glil
600 (call (toplevel foo) (call (toplevel @apply) (toplevel bar) (toplevel baz)))
601 (program () (std-prelude 0 0 #f) (label _)
603 (call new-frame 0) (toplevel ref bar) (toplevel ref baz) (call apply 2)
604 (call tail-call 1))))
606 (with-test-prefix "call/cc"
607 (assert-tree-il->glil
608 (primcall @call-with-current-continuation (toplevel foo))
609 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call tail-call/cc 1)))
610 (assert-tree-il->glil
611 (begin (primcall @call-with-current-continuation (toplevel foo)) (void))
612 (program () (std-prelude 0 0 #f) (label _)
613 (call new-frame 0) (toplevel ref call-with-current-continuation) (toplevel ref foo) (mv-call 1 ,l1)
614 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
616 (void) (call return 1))
617 (and (eq? l1 l3) (eq? l2 l4)))
618 (assert-tree-il->glil
620 (call (toplevel @call-with-current-continuation) (toplevel bar)))
621 (program () (std-prelude 0 0 #f) (label _)
623 (toplevel ref bar) (call call/cc 1)
624 (call tail-call 1))))
627 (with-test-prefix "labels allocation"
628 (pass-if "http://debbugs.gnu.org/9769"
629 ((compile '(lambda ()
630 (let ((fail (lambda () #f)))
631 (let ((test (lambda () (fail))))
634 ;; Prevent inlining. We're testing analyze.scm's
635 ;; labels allocator here, and inlining it will
636 ;; reduce the entire thing to #t.
637 #:opts '(#:partial-eval? #f)))))
640 (with-test-prefix "partial evaluation"
643 ;; First order, primitive.
644 (let ((x 1) (y 2)) (+ x y))
648 ;; First order, thunk.
650 (let ((f (lambda () (+ x y))))
655 ;; First order, let-values (requires primitive expansion for
656 ;; `call-with-values'.)
659 (lambda () (if (zero? x) (values 1 2) (values 3 4)))
665 ;; First order, multiple values.
668 (primcall values (const 1) (const 2)))
671 ;; First order, multiple values truncated.
672 (let ((x (values 1 'a)) (y 2))
674 (primcall values (const 1) (const 2)))
677 ;; First order, multiple values truncated.
682 ;; First order, coalesced, mutability preserved.
683 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
685 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
688 ;; First order, coalesced, mutability preserved.
689 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
690 ;; This must not be a constant.
692 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
695 ;; First order, coalesced, immutability preserved.
696 (cons 0 (cons 1 (cons 2 '(3 4 5))))
697 (primcall cons (const 0)
698 (primcall cons (const 1)
699 (primcall cons (const 2)
702 ;; These two tests doesn't work any more because we changed the way we
703 ;; deal with constants -- now the algorithm will see a construction as
704 ;; being bound to the lexical, so it won't propagate it. It can't
705 ;; even propagate it in the case that it is only referenced once,
708 ;; (let ((x (cons 1 2))) (lambda () x))
710 ;; is not the same as
712 ;; (lambda () (cons 1 2))
714 ;; Perhaps if we determined that not only was it only referenced once,
715 ;; it was not closed over by a lambda, then we could propagate it, and
716 ;; re-enable these two tests.
720 ;; First order, mutability preserved.
721 (let loop ((i 3) (r '()))
724 (loop (1- i) (cons (cons i i) r))))
726 (primcall cons (const 1) (const 1))
727 (primcall cons (const 2) (const 2))
728 (primcall cons (const 3) (const 3))))
733 ;; First order, evaluated.
738 (loop (1- i) (cons i r))))
741 ;; Instead here are tests for what happens for the above cases: they
742 ;; unroll but they don't fold.
744 (let loop ((i 3) (r '()))
747 (loop (1- i) (cons (cons i i) r))))
750 (primcall cons (const 3) (const 3))))
753 (primcall cons (const 2) (const 2))
756 (primcall cons (const 1) (const 1))
765 (loop (1- i) (cons i r))))
767 ((primcall list (const 4)))
785 (let loop ((l '(1 2 3 4)) (sum 0))
788 (loop (cdr l) (+ sum (car l)))))
803 (string->chars "yo"))
804 (primcall list (const #\y) (const #\o)))
807 ;; Primitives in module-refs are resolved (the expansion of `pmatch'
808 ;; below leads to calls to (@@ (system base pmatch) car) and
809 ;; similar, which is what we want to be inlined.)
811 (use-modules (system base pmatch))
819 ;; Mutability preserved.
820 ((lambda (x y z) (list x y z)) 1 2 3)
821 (primcall list (const 1) (const 2) (const 3)))
824 ;; Don't propagate effect-free expressions that operate on mutable
830 (let (x) (_) ((primcall list (const 1)))
831 (let (y) (_) ((primcall car (lexical x _)))
833 (primcall set-car! (lexical x _) (const 0))
837 ;; Don't propagate effect-free expressions that operate on objects we
842 (let (y) (_) ((primcall car (toplevel x)))
844 (primcall set-car! (toplevel x) (const 0))
848 ;; Infinite recursion
849 ((lambda (x) (x x)) (lambda (x) (x x)))
854 (call (lexical x _) (lexical x _))))))
855 (call (lexical x _) (lexical x _))))
858 ;; First order, aliased primitive.
859 (let* ((x *) (y (x 1 2))) y)
863 ;; First order, shadowed primitive.
865 (define (+ x y) (pk x y))
871 (((x y) #f #f #f () (_ _))
872 (call (toplevel pk) (lexical x _) (lexical y _))))))
873 (call (toplevel +) (const 1) (const 2))))
876 ;; First-order, effects preserved.
881 (call (toplevel do-something!))
885 ;; First order, residual bindings removed.
888 (primcall * (const 5) (toplevel z)))
891 ;; First order, with lambda.
893 (define (bar z) (* z z))
898 (((x) #f #f #f () (_))
899 (primcall + (lexical x _) (const 9)))))))
902 ;; First order, with lambda inlined & specialized twice.
903 (let ((f (lambda (x y)
912 (primcall + ; (f 2 3)
917 (let (x) (_) ((toplevel something)) ; (f something 2)
918 ;; `something' is not const, so preserve order of
919 ;; effects with a lexical binding.
927 ;; First order, with lambda inlined & specialized 3 times.
928 (let ((f (lambda (x y) (if (> x 0) y x))))
936 (const -1) ; (f -1 0)
942 (seq (toplevel y) (const -1)) ; (f -1 y)
945 (toplevel y) ; (f 2 y)
946 (let (x y) (_ _) ((toplevel z) (toplevel y)) ; (f z y)
947 (if (primcall > (lexical x _) (const 0))
952 ;; First order, conditional.
960 (((x) #f #f #f () (_))
961 (call (toplevel display) (lexical x _))))))
964 ;; First order, recursive procedure.
965 (letrec ((fibo (lambda (n)
974 ;; Don't propagate toplevel references, as intervening expressions
975 ;; could alter their bindings.
979 (let (x) (_) ((toplevel top))
981 (call (toplevel foo))
987 (f (* (car x) (cadr x))))
994 ;; Higher order with optional argument (default value).
995 ((lambda* (f x #:optional (y 0))
996 (+ y (f (* (car x) (cadr x)))))
1003 ;; Higher order with optional argument (caller-supplied value).
1004 ((lambda* (f x #:optional (y 0))
1005 (+ y (f (* (car x) (cadr x)))))
1013 ;; Higher order with optional argument (side-effecting default
1015 ((lambda* (f x #:optional (y (foo)))
1016 (+ y (f (* (car x) (cadr x)))))
1020 (let (y) (_) ((call (toplevel foo)))
1021 (primcall + (lexical y _) (const 7))))
1024 ;; Higher order with optional argument (caller-supplied value).
1025 ((lambda* (f x #:optional (y (foo)))
1026 (+ y (f (* (car x) (cadr x)))))
1035 ((lambda (f) (f x)) (lambda (x) x))
1040 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
1041 (let ((fold (lambda (f g) (f (g top)))))
1042 (fold 1+ (lambda (x) x)))
1043 (primcall 1+ (toplevel top)))
1046 ;; Procedure not inlined when residual code contains recursive calls.
1047 ;; <http://debbugs.gnu.org/9542>
1048 (letrec ((fold (lambda (f x3 b null? car cdr)
1051 (f (car x3) (fold f (cdr x3) b null? car cdr))))))
1052 (fold * x 1 zero? (lambda (x1) x1) (lambda (x2) (- x2 1))))
1053 (letrec (fold) (_) (_)
1054 (call (lexical fold _)
1061 (((x1) #f #f #f () (_))
1065 (((x2) #f #f #f () (_))
1066 (primcall 1- (lexical x2 _))))))))
1068 (pass-if "inlined lambdas are alpha-renamed"
1069 ;; In this example, `make-adder' is inlined more than once; thus,
1070 ;; they should use different gensyms for their arguments, because
1071 ;; the various optimization passes assume uniquely-named variables.
1074 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html> and
1075 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00029.html>.
1076 (pmatch (unparse-tree-il
1077 (peval (expand-primitives!
1078 (resolve-primitives!
1081 (lambda (x) (lambda (y) (+ x y)))))
1082 (cons (make-adder 1) (make-adder 2)))
1084 (current-module)))))
1088 (((y) #f #f #f () (,gensym1))
1091 (lexical y ,ref1)))))
1094 (((y) #f #f #f () (,gensym2))
1097 (lexical y ,ref2))))))
1098 (and (eq? gensym1 ref1)
1100 (not (eq? gensym1 gensym2))))
1104 ;; Unused letrec bindings are pruned.
1105 (letrec ((a (lambda () (b)))
1112 ;; Unused letrec bindings are pruned.
1117 (seq (call (toplevel foo!))
1121 ;; Higher order, mutually recursive procedures.
1122 (letrec ((even? (lambda (x)
1127 (and (even? 4) (odd? 7)))
1131 ;; Memv with constants.
1136 ;; Memv with non-constant list. It could fold but doesn't
1138 (memv 1 (list 3 2 1))
1141 (primcall list (const 3) (const 2) (const 1))))
1144 ;; Memv with non-constant key, constant list, test context
1148 (if (let (t) (_) ((toplevel foo))
1149 (if (primcall eqv? (lexical t _) (const 3))
1151 (if (primcall eqv? (lexical t _) (const 2))
1153 (primcall eqv? (lexical t _) (const 1)))))
1158 ;; Memv with non-constant key, empty list, test context. Currently
1159 ;; doesn't fold entirely.
1163 (if (seq (toplevel foo) (const #f))
1168 ;; Below are cases where constant propagation should bail out.
1172 ;; Non-constant lexical is not propagated.
1173 (let ((v (make-vector 6 #f)))
1175 (vector-set! v n n)))
1177 ((call (toplevel make-vector) (const 6) (const #f)))
1180 (((n) #f #f #f () (_))
1181 (primcall vector-set!
1182 (lexical v _) (lexical n _) (lexical n _)))))))
1185 ;; Mutable lexical is not propagated.
1186 (let ((v (vector 1 2 3)))
1190 ((primcall vector (const 1) (const 2) (const 3)))
1193 ((() #f #f #f () ())
1197 ;; Lexical that is not provably pure is not inlined nor propagated.
1198 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
1201 (let (x) (_) ((if (primcall > (toplevel p) (toplevel q))
1202 (call (toplevel frob!))
1203 (call (toplevel display) (const chbouib))))
1204 (let (y) (_) ((primcall * (lexical x _) (const 2)))
1207 (primcall + (lexical x _) (lexical y _))))))
1210 ;; Non-constant arguments not propagated to lambdas.
1218 (let (x y z) (_ _ _)
1219 ((primcall vector (const 1) (const 2) (const 3))
1220 (call (toplevel make-list) (const 10))
1221 (primcall list (const 1) (const 2) (const 3)))
1223 (primcall vector-set!
1224 (lexical x _) (const 0) (const 0))
1225 (seq (primcall set-car!
1226 (lexical y _) (const 0))
1228 (lexical z _) (const ()))))))
1231 (let ((foo top-foo) (bar top-bar))
1232 (let* ((g (lambda (x y) (+ x y)))
1233 (f (lambda (g x) (g x x))))
1234 (+ (f g foo) (f g bar))))
1235 (let (foo bar) (_ _) ((toplevel top-foo) (toplevel top-bar))
1237 (primcall + (lexical foo _) (lexical foo _))
1238 (primcall + (lexical bar _) (lexical bar _)))))
1241 ;; Fresh objects are not turned into constants, nor are constants
1242 ;; turned into fresh objects.
1247 (let (x) (_) ((primcall cons (const 1) (const (2 3))))
1248 (primcall cons (const 0) (lexical x _))))
1251 ;; Bindings mutated.
1255 (let (x) (_) ((const 2))
1257 (set! (lexical x _) (const 3))
1261 ;; Bindings mutated.
1266 (frob f) ; may mutate `x'
1268 (letrec (x) (_) ((const 0))
1270 (call (toplevel frob) (lambda _ _))
1274 ;; Bindings mutated.
1275 (letrec ((f (lambda (x)
1276 (set! f (lambda (_) x))
1282 ;; Bindings possibly mutated.
1283 (let ((x (make-foo)))
1284 (frob! x) ; may mutate `x'
1286 (let (x) (_) ((call (toplevel make-foo)))
1288 (call (toplevel frob!) (lexical x _))
1292 ;; Inlining stops at recursive calls with dynamic arguments.
1294 (if (< x 0) x (loop (1- x))))
1295 (letrec (loop) (_) ((lambda (_)
1297 (((x) #f #f #f () (_))
1299 (call (lexical loop _)
1301 (lexical x _))))))))
1302 (call (lexical loop _) (toplevel x))))
1305 ;; Recursion on the 2nd argument is fully evaluated.
1307 (let loop ((x x) (y 10))
1311 (let (x) (_) ((call (toplevel top)))
1312 (call (toplevel foo) (lexical x _) (const 0))))
1315 ;; Inlining aborted when residual code contains recursive calls.
1317 ;; <http://debbugs.gnu.org/9542>
1318 (let loop ((x x) (y 0))
1320 (loop (1- x) (1- y))
1323 (loop (1+ x) (1+ y)))))
1324 (letrec (loop) (_) ((lambda (_)
1326 (((x y) #f #f #f () (_ _))
1328 (lexical y _) (const 0))
1330 (call (lexical loop _) (toplevel x) (const 0))))
1333 ;; Infinite recursion: `peval' gives up and leaves it as is.
1334 (letrec ((f (lambda (x) (g (1- x))))
1335 (g (lambda (x) (h (1+ x))))
1336 (h (lambda (x) (f x))))
1341 ;; Infinite recursion: all the arguments to `loop' are static, but
1342 ;; unrolling it would lead `peval' to enter an infinite loop.
1346 (letrec (loop) (_) ((lambda . _))
1347 (call (lexical loop _) (const 0))))
1350 ;; This test checks that the `start' binding is indeed residualized.
1351 ;; See the `referenced?' procedure in peval's `prune-bindings'.
1353 (set! pos 1) ;; Cause references to `pos' to residualize.
1354 (let ((here (let ((start pos)) (lambda () start))))
1356 (let (pos) (_) ((const 0))
1358 (set! (lexical pos _) (const 1))
1360 (call (lexical here _))))))
1363 ;; FIXME: should this one residualize the binding?
1369 ;; This is a fun one for peval to handle.
1372 (letrec (a) (_) ((lexical a _))
1376 ;; Another interesting recursive case.
1377 (letrec ((a b) (b a))
1379 (letrec (a) (_) ((lexical a _))
1383 ;; Another pruning case, that `a' is residualized.
1384 (letrec ((a (lambda () (a)))
1390 ;; "b c a" is the current order that we get with unordered letrec,
1391 ;; but it's not important to this test, so if it changes, just adapt
1393 (letrec (b c a) (_ _ _)
1396 ((() #f #f #f () ())
1397 (call (lexical a _)))))
1400 (((x) #f #f #f () (_))
1404 ((() #f #f #f () ())
1405 (call (lexical a _))))))
1408 ((call (toplevel foo) (lexical b _)))
1409 (call (lexical c _) (lexical d _)))))
1412 ;; In this case, we can prune the bindings. `a' ends up being copied
1413 ;; because it is only referenced once in the source program. Oh
1415 (letrec* ((a (lambda (x) (top x)))
1418 (call (toplevel foo)
1421 (((x) #f #f #f () (_))
1422 (call (toplevel top) (lexical x _)))))
1425 (((x) #f #f #f () (_))
1426 (call (toplevel top) (lexical x _)))))))
1429 ;; Constant folding: cons of #nil does not make list
1431 (primcall cons (const 1) (const '#nil)))
1434 ;; Constant folding: cons
1435 (begin (cons 1 2) #f)
1439 ;; Constant folding: cons
1440 (begin (cons (foo) 2) #f)
1441 (seq (call (toplevel foo)) (const #f)))
1444 ;; Constant folding: cons
1449 ;; Constant folding: car+cons
1454 ;; Constant folding: cdr+cons
1459 ;; Constant folding: car+cons, impure
1460 (car (cons 1 (bar)))
1461 (seq (call (toplevel bar)) (const 1)))
1464 ;; Constant folding: cdr+cons, impure
1465 (cdr (cons (bar) 0))
1466 (seq (call (toplevel bar)) (const 0)))
1469 ;; Constant folding: car+list
1474 ;; Constant folding: cdr+list
1476 (primcall list (const 0)))
1479 ;; Constant folding: car+list, impure
1480 (car (list 1 (bar)))
1481 (seq (call (toplevel bar)) (const 1)))
1484 ;; Constant folding: cdr+list, impure
1485 (cdr (list (bar) 0))
1486 (seq (call (toplevel bar)) (primcall list (const 0))))
1489 ;; Non-constant guards get lexical bindings.
1490 (dynamic-wind foo (lambda () bar) baz)
1491 (let (w u) (_ _) ((toplevel foo) (toplevel baz))
1492 (dynwind (lexical w _)
1493 (call (lexical w _))
1495 (call (lexical u _))
1499 ;; Constant guards don't need lexical bindings.
1500 (dynamic-wind (lambda () foo) (lambda () bar) (lambda () baz))
1504 ((() #f #f #f () ()) (toplevel foo))))
1510 ((() #f #f #f () ()) (toplevel baz))))))
1513 ;; Prompt is removed if tag is unreferenced
1514 (let ((tag (make-prompt-tag)))
1515 (call-with-prompt tag
1517 (lambda args args)))
1521 ;; Prompt is removed if tag is unreferenced, with explicit stem
1522 (let ((tag (make-prompt-tag "foo")))
1523 (call-with-prompt tag
1525 (lambda args args)))
1529 ;; `while' without `break' or `continue' has no prompts and gets its
1530 ;; condition folded. Unfortunately the outer `lp' does not yet get
1536 ((() #f #f #f () ())
1540 ((() #f #f #f () ())
1541 (call (lexical loop _))))))
1542 (call (lexical loop _)))))))
1543 (call (lexical lp _)))))
1547 (with-test-prefix "tree-il-fold"
1549 (pass-if "empty tree"
1550 (let ((leaf? #f) (up? #f) (down? #f) (mark (list 'mark)))
1552 (tree-il-fold (lambda (x y) (set! leaf? #t) y)
1553 (lambda (x y) (set! down? #t) y)
1554 (lambda (x y) (set! up? #t) y)
1561 (pass-if "lambda and application"
1562 (let* ((leaves '()) (ups '()) (downs '())
1563 (result (tree-il-fold (lambda (x y)
1564 (set! leaves (cons x leaves))
1567 (set! downs (cons x downs))
1570 (set! ups (cons x ups))
1576 (((x y) #f #f #f () (x1 y1))
1581 (and (equal? (map strip-source leaves)
1582 (list (make-lexical-ref #f 'y 'y1)
1583 (make-lexical-ref #f 'x 'x1)
1584 (make-toplevel-ref #f '+)))
1585 (= (length downs) 3)
1586 (equal? (reverse (map strip-source ups))
1587 (map strip-source downs))))))
1594 ;; Make sure we get English messages.
1595 (setlocale LC_ALL "C")
1597 (define (call-with-warnings thunk)
1598 (let ((port (open-output-string)))
1599 (with-fluids ((*current-warning-port* port)
1600 (*current-warning-prefix* ""))
1602 (let ((warnings (get-output-string port)))
1603 (string-tokenize warnings
1604 (char-set-complement (char-set #\newline))))))
1606 (define %opts-w-unused
1607 '(#:warnings (unused-variable)))
1609 (define %opts-w-unused-toplevel
1610 '(#:warnings (unused-toplevel)))
1612 (define %opts-w-unbound
1613 '(#:warnings (unbound-variable)))
1615 (define %opts-w-arity
1616 '(#:warnings (arity-mismatch)))
1618 (define %opts-w-format
1619 '(#:warnings (format)))
1622 (with-test-prefix "warnings"
1624 (pass-if "unknown warning type"
1625 (let ((w (call-with-warnings
1627 (compile #t #:opts '(#:warnings (does-not-exist)))))))
1628 (and (= (length w) 1)
1629 (number? (string-contains (car w) "unknown warning")))))
1631 (with-test-prefix "unused-variable"
1634 (null? (call-with-warnings
1636 (compile '(lambda (x y) (+ x y))
1637 #:opts %opts-w-unused)))))
1639 (pass-if "let/unused"
1640 (let ((w (call-with-warnings
1642 (compile '(lambda (x)
1645 #:opts %opts-w-unused)))))
1646 (and (= (length w) 1)
1647 (number? (string-contains (car w) "unused variable `y'")))))
1649 (pass-if "shadowed variable"
1650 (let ((w (call-with-warnings
1652 (compile '(lambda (x)
1656 #:opts %opts-w-unused)))))
1657 (and (= (length w) 1)
1658 (number? (string-contains (car w) "unused variable `y'")))))
1661 (null? (call-with-warnings
1663 (compile '(lambda ()
1664 (letrec ((x (lambda () (y)))
1665 (y (lambda () (x))))
1667 #:opts %opts-w-unused)))))
1669 (pass-if "unused argument"
1670 ;; Unused arguments should not be reported.
1671 (null? (call-with-warnings
1673 (compile '(lambda (x y z) #t)
1674 #:opts %opts-w-unused)))))
1676 (pass-if "special variable names"
1677 (null? (call-with-warnings
1679 (compile '(lambda ()
1680 (let ((_ 'underscore)
1681 (#{gensym name}# 'ignore-me))
1684 #:opts %opts-w-unused))))))
1686 (with-test-prefix "unused-toplevel"
1688 (pass-if "used after definition"
1689 (null? (call-with-warnings
1691 (let ((in (open-input-string
1692 "(define foo 2) foo")))
1693 (read-and-compile in
1695 #:opts %opts-w-unused-toplevel))))))
1697 (pass-if "used before definition"
1698 (null? (call-with-warnings
1700 (let ((in (open-input-string
1701 "(define (bar) foo) (define foo 2) (bar)")))
1702 (read-and-compile in
1704 #:opts %opts-w-unused-toplevel))))))
1706 (pass-if "unused but public"
1707 (let ((in (open-input-string
1708 "(define-module (test-suite tree-il x) #:export (bar))
1709 (define (bar) #t)")))
1710 (null? (call-with-warnings
1712 (read-and-compile in
1714 #:opts %opts-w-unused-toplevel))))))
1716 (pass-if "unused but public (more)"
1717 (let ((in (open-input-string
1718 "(define-module (test-suite tree-il x) #:export (bar))
1719 (define (bar) (baz))
1720 (define (baz) (foo))
1721 (define (foo) #t)")))
1722 (null? (call-with-warnings
1724 (read-and-compile in
1726 #:opts %opts-w-unused-toplevel))))))
1728 (pass-if "unused but define-public"
1729 (null? (call-with-warnings
1731 (compile '(define-public foo 2)
1733 #:opts %opts-w-unused-toplevel)))))
1735 (pass-if "used by macro"
1736 ;; FIXME: See comment about macros at `unused-toplevel-analysis'.
1739 (null? (call-with-warnings
1741 (let ((in (open-input-string
1742 "(define (bar) 'foo)
1744 (syntax-rules () ((_) (bar))))")))
1745 (read-and-compile in
1747 #:opts %opts-w-unused-toplevel))))))
1750 (let ((w (call-with-warnings
1752 (compile '(define foo 2)
1754 #:opts %opts-w-unused-toplevel)))))
1755 (and (= (length w) 1)
1756 (number? (string-contains (car w)
1757 (format #f "top-level variable `~A'"
1760 (pass-if "unused recursive"
1761 (let ((w (call-with-warnings
1763 (compile '(define (foo) (foo))
1765 #:opts %opts-w-unused-toplevel)))))
1766 (and (= (length w) 1)
1767 (number? (string-contains (car w)
1768 (format #f "top-level variable `~A'"
1771 (pass-if "unused mutually recursive"
1772 (let* ((in (open-input-string
1773 "(define (foo) (bar)) (define (bar) (foo))"))
1774 (w (call-with-warnings
1776 (read-and-compile in
1778 #:opts %opts-w-unused-toplevel)))))
1779 (and (= (length w) 2)
1780 (number? (string-contains (car w)
1781 (format #f "top-level variable `~A'"
1783 (number? (string-contains (cadr w)
1784 (format #f "top-level variable `~A'"
1787 (pass-if "special variable names"
1788 (null? (call-with-warnings
1790 (compile '(define #{gensym name}# 'ignore-me)
1792 #:opts %opts-w-unused-toplevel))))))
1794 (with-test-prefix "unbound variable"
1797 (null? (call-with-warnings
1799 (compile '+ #:opts %opts-w-unbound)))))
1803 (w (call-with-warnings
1807 #:opts %opts-w-unbound)))))
1808 (and (= (length w) 1)
1809 (number? (string-contains (car w)
1810 (format #f "unbound variable `~A'"
1815 (w (call-with-warnings
1817 (compile `(set! ,v 7)
1819 #:opts %opts-w-unbound)))))
1820 (and (= (length w) 1)
1821 (number? (string-contains (car w)
1822 (format #f "unbound variable `~A'"
1825 (pass-if "module-local top-level is visible"
1826 (let ((m (make-module))
1828 (beautify-user-module! m)
1829 (compile `(define ,v 123)
1830 #:env m #:opts %opts-w-unbound)
1831 (null? (call-with-warnings
1836 #:opts %opts-w-unbound))))))
1838 (pass-if "module-local top-level is visible after"
1839 (let ((m (make-module))
1841 (beautify-user-module! m)
1842 (null? (call-with-warnings
1844 (let ((in (open-input-string
1847 (define chbouib 5)")))
1848 (read-and-compile in
1850 #:opts %opts-w-unbound)))))))
1852 (pass-if "optional arguments are visible"
1853 (null? (call-with-warnings
1855 (compile '(lambda* (x #:optional y z) (list x y z))
1856 #:opts %opts-w-unbound
1859 (pass-if "keyword arguments are visible"
1860 (null? (call-with-warnings
1862 (compile '(lambda* (x #:key y z) (list x y z))
1863 #:opts %opts-w-unbound
1866 (pass-if "GOOPS definitions are visible"
1867 (let ((m (make-module))
1869 (beautify-user-module! m)
1870 (module-use! m (resolve-interface '(oop goops)))
1871 (null? (call-with-warnings
1873 (let ((in (open-input-string
1874 "(define-class <foo> ()
1875 (bar #:getter foo-bar))
1876 (define z (foo-bar (make <foo>)))")))
1877 (read-and-compile in
1879 #:opts %opts-w-unbound))))))))
1881 (with-test-prefix "arity mismatch"
1884 (null? (call-with-warnings
1886 (compile '(cons 'a 'b) #:opts %opts-w-arity)))))
1888 (pass-if "direct application"
1889 (let ((w (call-with-warnings
1891 (compile '((lambda (x y) (or x y)) 1 2 3 4 5)
1892 #:opts %opts-w-arity
1894 (and (= (length w) 1)
1895 (number? (string-contains (car w)
1896 "wrong number of arguments to")))))
1898 (let ((w (call-with-warnings
1900 (compile '(let ((f (lambda (x y) (+ x y))))
1902 #:opts %opts-w-arity
1904 (and (= (length w) 1)
1905 (number? (string-contains (car w)
1906 "wrong number of arguments to")))))
1909 (let ((w (call-with-warnings
1911 (compile '(cons 1 2 3 4)
1912 #:opts %opts-w-arity
1914 (and (= (length w) 1)
1915 (number? (string-contains (car w)
1916 "wrong number of arguments to")))))
1918 (pass-if "alias to global"
1919 (let ((w (call-with-warnings
1921 (compile '(let ((f cons)) (f 1 2 3 4))
1922 #:opts %opts-w-arity
1924 (and (= (length w) 1)
1925 (number? (string-contains (car w)
1926 "wrong number of arguments to")))))
1928 (pass-if "alias to lexical to global"
1929 (let ((w (call-with-warnings
1931 (compile '(let ((f number?))
1934 #:opts %opts-w-arity
1936 (and (= (length w) 1)
1937 (number? (string-contains (car w)
1938 "wrong number of arguments to")))))
1940 (pass-if "alias to lexical"
1941 (let ((w (call-with-warnings
1943 (compile '(let ((f (lambda (x y z) (+ x y z))))
1946 #:opts %opts-w-arity
1948 (and (= (length w) 1)
1949 (number? (string-contains (car w)
1950 "wrong number of arguments to")))))
1953 (let ((w (call-with-warnings
1955 (compile '(letrec ((odd? (lambda (x) (even? (1- x))))
1960 #:opts %opts-w-arity
1962 (and (= (length w) 1)
1963 (number? (string-contains (car w)
1964 "wrong number of arguments to")))))
1966 (pass-if "case-lambda"
1967 (null? (call-with-warnings
1969 (compile '(let ((f (case-lambda
1976 #:opts %opts-w-arity
1979 (pass-if "case-lambda with wrong number of arguments"
1980 (let ((w (call-with-warnings
1982 (compile '(let ((f (case-lambda
1986 #:opts %opts-w-arity
1988 (and (= (length w) 1)
1989 (number? (string-contains (car w)
1990 "wrong number of arguments to")))))
1992 (pass-if "case-lambda*"
1993 (null? (call-with-warnings
1995 (compile '(let ((f (case-lambda*
1996 ((x #:optional y) 1)
1998 ((x y #:key z) 3))))
2003 #:opts %opts-w-arity
2006 (pass-if "case-lambda* with wrong arguments"
2007 (let ((w (call-with-warnings
2009 (compile '(let ((f (case-lambda*
2010 ((x #:optional y) 1)
2012 ((x y #:key z) 3))))
2015 #:opts %opts-w-arity
2017 (and (= (length w) 2)
2018 (null? (filter (lambda (w)
2022 w "wrong number of arguments to"))))
2025 (pass-if "local toplevel-defines"
2026 (let ((w (call-with-warnings
2028 (let ((in (open-input-string "
2029 (define (g x) (f x))
2031 (read-and-compile in
2032 #:opts %opts-w-arity
2033 #:to 'assembly))))))
2034 (and (= (length w) 1)
2035 (number? (string-contains (car w)
2036 "wrong number of arguments to")))))
2038 (pass-if "global toplevel alias"
2039 (let ((w (call-with-warnings
2041 (let ((in (open-input-string "
2043 (define (g) (f))")))
2044 (read-and-compile in
2045 #:opts %opts-w-arity
2046 #:to 'assembly))))))
2047 (and (= (length w) 1)
2048 (number? (string-contains (car w)
2049 "wrong number of arguments to")))))
2051 (pass-if "local toplevel overrides global"
2052 (null? (call-with-warnings
2054 (let ((in (open-input-string "
2056 (define (foo x) (cons))")))
2057 (read-and-compile in
2058 #:opts %opts-w-arity
2059 #:to 'assembly))))))
2061 (pass-if "keyword not passed and quiet"
2062 (null? (call-with-warnings
2064 (compile '(let ((f (lambda* (x #:key y) y)))
2066 #:opts %opts-w-arity
2069 (pass-if "keyword passed and quiet"
2070 (null? (call-with-warnings
2072 (compile '(let ((f (lambda* (x #:key y) y)))
2074 #:opts %opts-w-arity
2077 (pass-if "keyword passed to global and quiet"
2078 (null? (call-with-warnings
2080 (let ((in (open-input-string "
2081 (use-modules (system base compile))
2082 (compile '(+ 2 3) #:env (current-module))")))
2083 (read-and-compile in
2084 #:opts %opts-w-arity
2085 #:to 'assembly))))))
2087 (pass-if "extra keyword"
2088 (let ((w (call-with-warnings
2090 (compile '(let ((f (lambda* (x #:key y) y)))
2092 #:opts %opts-w-arity
2094 (and (= (length w) 1)
2095 (number? (string-contains (car w)
2096 "wrong number of arguments to")))))
2098 (pass-if "extra keywords allowed"
2099 (null? (call-with-warnings
2101 (compile '(let ((f (lambda* (x #:key y #:allow-other-keys)
2104 #:opts %opts-w-arity
2105 #:to 'assembly))))))
2107 (with-test-prefix "format"
2109 (pass-if "quiet (no args)"
2110 (null? (call-with-warnings
2112 (compile '(format #t "hey!")
2113 #:opts %opts-w-format
2116 (pass-if "quiet (1 arg)"
2117 (null? (call-with-warnings
2119 (compile '(format #t "hey ~A!" "you")
2120 #:opts %opts-w-format
2123 (pass-if "quiet (2 args)"
2124 (null? (call-with-warnings
2126 (compile '(format #t "~A ~A!" "hello" "world")
2127 #:opts %opts-w-format
2130 (pass-if "wrong port arg"
2131 (let ((w (call-with-warnings
2133 (compile '(format 10 "foo")
2134 #:opts %opts-w-format
2136 (and (= (length w) 1)
2137 (number? (string-contains (car w)
2138 "wrong port argument")))))
2140 (pass-if "non-literal format string"
2141 (let ((w (call-with-warnings
2143 (compile '(format #f fmt)
2144 #:opts %opts-w-format
2146 (and (= (length w) 1)
2147 (number? (string-contains (car w)
2148 "non-literal format string")))))
2150 (pass-if "non-literal format string using gettext"
2151 (null? (call-with-warnings
2153 (compile '(format #t (_ "~A ~A!") "hello" "world")
2154 #:opts %opts-w-format
2157 (pass-if "wrong format string"
2158 (let ((w (call-with-warnings
2160 (compile '(format #f 'not-a-string)
2161 #:opts %opts-w-format
2163 (and (= (length w) 1)
2164 (number? (string-contains (car w)
2165 "wrong format string")))))
2167 (pass-if "wrong number of args"
2168 (let ((w (call-with-warnings
2170 (compile '(format "shbweeb")
2171 #:opts %opts-w-format
2173 (and (= (length w) 1)
2174 (number? (string-contains (car w)
2175 "wrong number of arguments")))))
2177 (pass-if "~%, ~~, ~&, ~t, ~_, and ~\\n"
2178 (null? (call-with-warnings
2180 (compile '(format some-port "~&~3_~~ ~\n~12they~%")
2181 #:opts %opts-w-format
2184 (pass-if "one missing argument"
2185 (let ((w (call-with-warnings
2187 (compile '(format some-port "foo ~A~%")
2188 #:opts %opts-w-format
2190 (and (= (length w) 1)
2191 (number? (string-contains (car w)
2192 "expected 1, got 0")))))
2194 (pass-if "one missing argument, gettext"
2195 (let ((w (call-with-warnings
2197 (compile '(format some-port (_ "foo ~A~%"))
2198 #:opts %opts-w-format
2200 (and (= (length w) 1)
2201 (number? (string-contains (car w)
2202 "expected 1, got 0")))))
2204 (pass-if "two missing arguments"
2205 (let ((w (call-with-warnings
2207 (compile '(format #f "foo ~10,2f and bar ~S~%")
2208 #:opts %opts-w-format
2210 (and (= (length w) 1)
2211 (number? (string-contains (car w)
2212 "expected 2, got 0")))))
2214 (pass-if "one given, one missing argument"
2215 (let ((w (call-with-warnings
2217 (compile '(format #t "foo ~A and ~S~%" hey)
2218 #:opts %opts-w-format
2220 (and (= (length w) 1)
2221 (number? (string-contains (car w)
2222 "expected 2, got 1")))))
2224 (pass-if "too many arguments"
2225 (let ((w (call-with-warnings
2227 (compile '(format #t "foo ~A~%" 1 2)
2228 #:opts %opts-w-format
2230 (and (= (length w) 1)
2231 (number? (string-contains (car w)
2232 "expected 1, got 2")))))
2234 (with-test-prefix "conditionals"
2236 (null? (call-with-warnings
2238 (compile '(format #f "~A ~[foo~;bar~;baz~;~] ~10,2f"
2240 #:opts %opts-w-format
2243 (pass-if "literals with selector"
2244 (let ((w (call-with-warnings
2246 (compile '(format #f "~2[foo~;bar~;baz~;~] ~A"
2248 #:opts %opts-w-format
2250 (and (= (length w) 1)
2251 (number? (string-contains (car w)
2252 "expected 1, got 2")))))
2254 (pass-if "escapes (exact count)"
2255 (let ((w (call-with-warnings
2257 (compile '(format #f "~[~a~;~a~]")
2258 #:opts %opts-w-format
2260 (and (= (length w) 1)
2261 (number? (string-contains (car w)
2262 "expected 2, got 0")))))
2264 (pass-if "escapes with selector"
2265 (let ((w (call-with-warnings
2267 (compile '(format #f "~1[chbouib~;~a~]")
2268 #:opts %opts-w-format
2270 (and (= (length w) 1)
2271 (number? (string-contains (car w)
2272 "expected 1, got 0")))))
2274 (pass-if "escapes, range"
2275 (let ((w (call-with-warnings
2277 (compile '(format #f "~[chbouib~;~a~;~2*~a~]")
2278 #:opts %opts-w-format
2280 (and (= (length w) 1)
2281 (number? (string-contains (car w)
2282 "expected 1 to 4, got 0")))))
2285 (let ((w (call-with-warnings
2287 (compile '(format #f "~@[temperature=~d~]")
2288 #:opts %opts-w-format
2290 (and (= (length w) 1)
2291 (number? (string-contains (car w)
2292 "expected 1, got 0")))))
2295 (let ((w (call-with-warnings
2297 (compile '(format #f "~:[~[hey~;~a~;~va~]~;~3*~]")
2298 #:opts %opts-w-format
2300 (and (= (length w) 1)
2301 (number? (string-contains (car w)
2302 "expected 2 to 4, got 0")))))
2304 (pass-if "unterminated"
2305 (let ((w (call-with-warnings
2307 (compile '(format #f "~[unterminated")
2308 #:opts %opts-w-format
2310 (and (= (length w) 1)
2311 (number? (string-contains (car w)
2312 "unterminated conditional")))))
2314 (pass-if "unexpected ~;"
2315 (let ((w (call-with-warnings
2317 (compile '(format #f "foo~;bar")
2318 #:opts %opts-w-format
2320 (and (= (length w) 1)
2321 (number? (string-contains (car w)
2324 (pass-if "unexpected ~]"
2325 (let ((w (call-with-warnings
2327 (compile '(format #f "foo~]")
2328 #:opts %opts-w-format
2330 (and (= (length w) 1)
2331 (number? (string-contains (car w)
2335 (null? (call-with-warnings
2337 (compile '(format #f "~A ~{~S~} ~A"
2338 'hello '("ladies" "and")
2340 #:opts %opts-w-format
2343 (pass-if "~{...~}, too many args"
2344 (let ((w (call-with-warnings
2346 (compile '(format #f "~{~S~}" 1 2 3)
2347 #:opts %opts-w-format
2349 (and (= (length w) 1)
2350 (number? (string-contains (car w)
2351 "expected 1, got 3")))))
2354 (null? (call-with-warnings
2356 (compile '(format #f "~@{~S~}" 1 2 3)
2357 #:opts %opts-w-format
2360 (pass-if "~@{...~}, too few args"
2361 (let ((w (call-with-warnings
2363 (compile '(format #f "~A ~@{~S~}")
2364 #:opts %opts-w-format
2366 (and (= (length w) 1)
2367 (number? (string-contains (car w)
2368 "expected at least 1, got 0")))))
2370 (pass-if "unterminated ~{...~}"
2371 (let ((w (call-with-warnings
2373 (compile '(format #f "~{")
2374 #:opts %opts-w-format
2376 (and (= (length w) 1)
2377 (number? (string-contains (car w)
2381 (null? (call-with-warnings
2383 (compile '(format #f "~:@(~A ~A~)" 'foo 'bar)
2384 #:opts %opts-w-format
2388 (let ((w (call-with-warnings
2390 (compile '(format #f "~v_foo")
2391 #:opts %opts-w-format
2393 (and (= (length w) 1)
2394 (number? (string-contains (car w)
2395 "expected 1, got 0")))))
2397 (null? (call-with-warnings
2399 (compile '(format #f "~v:@y" 1 123)
2400 #:opts %opts-w-format
2405 (let ((w (call-with-warnings
2407 (compile '(format #f "~2*~a" 'a 'b)
2408 #:opts %opts-w-format
2410 (and (= (length w) 1)
2411 (number? (string-contains (car w)
2412 "expected 3, got 2")))))
2415 (null? (call-with-warnings
2417 (compile '(format #f "~?" "~d ~d" '(1 2))
2418 #:opts %opts-w-format
2421 (pass-if "complex 1"
2422 (let ((w (call-with-warnings
2424 (compile '(format #f
2425 "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
2427 #:opts %opts-w-format
2429 (and (= (length w) 1)
2430 (number? (string-contains (car w)
2431 "expected 4, got 6")))))
2433 (pass-if "complex 2"
2434 (let ((w (call-with-warnings
2436 (compile '(format #f
2437 "~:(~A~) Commands~:[~; [abbrev]~]:~2%"
2439 #:opts %opts-w-format
2441 (and (= (length w) 1)
2442 (number? (string-contains (car w)
2443 "expected 2, got 4")))))
2445 (pass-if "complex 3"
2446 (let ((w (call-with-warnings
2448 (compile '(format #f "~9@a~:[~*~3_~;~3d~] ~v:@y~%")
2449 #:opts %opts-w-format
2451 (and (= (length w) 1)
2452 (number? (string-contains (car w)
2453 "expected 5, got 0")))))
2455 (pass-if "ice-9 format"
2456 (let ((w (call-with-warnings
2458 (let ((in (open-input-string
2459 "(use-modules ((ice-9 format)
2460 #:renamer (symbol-prefix-proc 'i9-)))
2461 (i9-format #t \"yo! ~A\" 1 2)")))
2462 (read-and-compile in
2463 #:opts %opts-w-format
2464 #:to 'assembly))))))
2465 (and (= (length w) 1)
2466 (number? (string-contains (car w)
2467 "expected 1, got 2")))))
2469 (pass-if "not format"
2470 (null? (call-with-warnings
2472 (compile '(let ((format chbouib))
2473 (format #t "not ~A a format string"))
2474 #:opts %opts-w-format
2475 #:to 'assembly)))))))