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, coalesced, mutability preserved.
666 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
668 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
671 ;; First order, coalesced, mutability preserved.
672 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
673 ;; This must not be a constant.
675 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5)))
678 ;; First order, coalesced, immutability preserved.
679 (cons 0 (cons 1 (cons 2 '(3 4 5))))
680 (primcall cons (const 0)
681 (primcall cons (const 1)
682 (primcall cons (const 2)
685 ;; These two tests doesn't work any more because we changed the way we
686 ;; deal with constants -- now the algorithm will see a construction as
687 ;; being bound to the lexical, so it won't propagate it. It can't
688 ;; even propagate it in the case that it is only referenced once,
691 ;; (let ((x (cons 1 2))) (lambda () x))
693 ;; is not the same as
695 ;; (lambda () (cons 1 2))
697 ;; Perhaps if we determined that not only was it only referenced once,
698 ;; it was not closed over by a lambda, then we could propagate it, and
699 ;; re-enable these two tests.
703 ;; First order, mutability preserved.
704 (let loop ((i 3) (r '()))
707 (loop (1- i) (cons (cons i i) r))))
709 (primcall cons (const 1) (const 1))
710 (primcall cons (const 2) (const 2))
711 (primcall cons (const 3) (const 3))))
716 ;; First order, evaluated.
721 (loop (1- i) (cons i r))))
724 ;; Instead here are tests for what happens for the above cases: they
725 ;; unroll but they don't fold.
727 (let loop ((i 3) (r '()))
730 (loop (1- i) (cons (cons i i) r))))
733 (primcall cons (const 3) (const 3))))
736 (primcall cons (const 2) (const 2))
739 (primcall cons (const 1) (const 1))
748 (loop (1- i) (cons i r))))
750 ((primcall list (const 4)))
768 (let loop ((l '(1 2 3 4)) (sum 0))
771 (loop (cdr l) (+ sum (car l)))))
786 (string->chars "yo"))
787 (primcall list (const #\y) (const #\o)))
790 ;; Primitives in module-refs are resolved (the expansion of `pmatch'
791 ;; below leads to calls to (@@ (system base pmatch) car) and
792 ;; similar, which is what we want to be inlined.)
794 (use-modules (system base pmatch))
802 ;; Mutability preserved.
803 ((lambda (x y z) (list x y z)) 1 2 3)
804 (primcall list (const 1) (const 2) (const 3)))
807 ;; Don't propagate effect-free expressions that operate on mutable
813 (let (x) (_) ((primcall list (const 1)))
814 (let (y) (_) ((primcall car (lexical x _)))
816 (primcall set-car! (lexical x _) (const 0))
820 ;; Don't propagate effect-free expressions that operate on objects we
825 (let (y) (_) ((primcall car (toplevel x)))
827 (primcall set-car! (toplevel x) (const 0))
831 ;; Infinite recursion
832 ((lambda (x) (x x)) (lambda (x) (x x)))
837 (call (lexical x _) (lexical x _))))))
838 (call (lexical x _) (lexical x _))))
841 ;; First order, aliased primitive.
842 (let* ((x *) (y (x 1 2))) y)
846 ;; First order, shadowed primitive.
848 (define (+ x y) (pk x y))
854 (((x y) #f #f #f () (_ _))
855 (call (toplevel pk) (lexical x _) (lexical y _))))))
856 (call (toplevel +) (const 1) (const 2))))
859 ;; First-order, effects preserved.
864 (call (toplevel do-something!))
868 ;; First order, residual bindings removed.
871 (primcall * (const 5) (toplevel z)))
874 ;; First order, with lambda.
876 (define (bar z) (* z z))
881 (((x) #f #f #f () (_))
882 (primcall + (lexical x _) (const 9)))))))
885 ;; First order, with lambda inlined & specialized twice.
886 (let ((f (lambda (x y)
895 (primcall + ; (f 2 3)
900 (let (x) (_) ((toplevel something)) ; (f something 2)
901 ;; `something' is not const, so preserve order of
902 ;; effects with a lexical binding.
910 ;; First order, with lambda inlined & specialized 3 times.
911 (let ((f (lambda (x y) (if (> x 0) y x))))
919 (const -1) ; (f -1 0)
925 (seq (toplevel y) (const -1)) ; (f -1 y)
928 (toplevel y) ; (f 2 y)
929 (let (x y) (_ _) ((toplevel z) (toplevel y)) ; (f z y)
930 (if (primcall > (lexical x _) (const 0))
935 ;; First order, conditional.
943 (((x) #f #f #f () (_))
944 (call (toplevel display) (lexical x _))))))
947 ;; First order, recursive procedure.
948 (letrec ((fibo (lambda (n)
957 ;; Don't propagate toplevel references, as intervening expressions
958 ;; could alter their bindings.
962 (let (x) (_) ((toplevel top))
964 (call (toplevel foo))
970 (f (* (car x) (cadr x))))
977 ;; Higher order with optional argument (default value).
978 ((lambda* (f x #:optional (y 0))
979 (+ y (f (* (car x) (cadr x)))))
986 ;; Higher order with optional argument (caller-supplied value).
987 ((lambda* (f x #:optional (y 0))
988 (+ y (f (* (car x) (cadr x)))))
996 ;; Higher order with optional argument (side-effecting default
998 ((lambda* (f x #:optional (y (foo)))
999 (+ y (f (* (car x) (cadr x)))))
1003 (let (y) (_) ((call (toplevel foo)))
1004 (primcall + (lexical y _) (const 7))))
1007 ;; Higher order with optional argument (caller-supplied value).
1008 ((lambda* (f x #:optional (y (foo)))
1009 (+ y (f (* (car x) (cadr x)))))
1018 ((lambda (f) (f x)) (lambda (x) x))
1023 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
1024 (let ((fold (lambda (f g) (f (g top)))))
1025 (fold 1+ (lambda (x) x)))
1026 (primcall 1+ (toplevel top)))
1029 ;; Procedure not inlined when residual code contains recursive calls.
1030 ;; <http://debbugs.gnu.org/9542>
1031 (letrec ((fold (lambda (f x3 b null? car cdr)
1034 (f (car x3) (fold f (cdr x3) b null? car cdr))))))
1035 (fold * x 1 zero? (lambda (x1) x1) (lambda (x2) (- x2 1))))
1036 (letrec (fold) (_) (_)
1037 (call (lexical fold _)
1044 (((x1) #f #f #f () (_))
1048 (((x2) #f #f #f () (_))
1049 (primcall 1- (lexical x2 _))))))))
1051 (pass-if "inlined lambdas are alpha-renamed"
1052 ;; In this example, `make-adder' is inlined more than once; thus,
1053 ;; they should use different gensyms for their arguments, because
1054 ;; the various optimization passes assume uniquely-named variables.
1057 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html> and
1058 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00029.html>.
1059 (pmatch (unparse-tree-il
1060 (peval (expand-primitives!
1061 (resolve-primitives!
1064 (lambda (x) (lambda (y) (+ x y)))))
1065 (cons (make-adder 1) (make-adder 2)))
1067 (current-module)))))
1071 (((y) #f #f #f () (,gensym1))
1074 (lexical y ,ref1)))))
1077 (((y) #f #f #f () (,gensym2))
1080 (lexical y ,ref2))))))
1081 (and (eq? gensym1 ref1)
1083 (not (eq? gensym1 gensym2))))
1087 ;; Unused letrec bindings are pruned.
1088 (letrec ((a (lambda () (b)))
1095 ;; Unused letrec bindings are pruned.
1100 (seq (call (toplevel foo!))
1104 ;; Higher order, mutually recursive procedures.
1105 (letrec ((even? (lambda (x)
1110 (and (even? 4) (odd? 7)))
1114 ;; Memv with constants.
1119 ;; Memv with non-constant list. It could fold but doesn't
1121 (memv 1 (list 3 2 1))
1124 (primcall list (const 3) (const 2) (const 1))))
1127 ;; Memv with non-constant key, constant list, test context
1131 (if (let (t) (_) ((toplevel foo))
1132 (if (primcall eqv? (lexical t _) (const 3))
1134 (if (primcall eqv? (lexical t _) (const 2))
1136 (primcall eqv? (lexical t _) (const 1)))))
1141 ;; Memv with non-constant key, empty list, test context. Currently
1142 ;; doesn't fold entirely.
1146 (if (seq (toplevel foo) (const #f))
1151 ;; Below are cases where constant propagation should bail out.
1155 ;; Non-constant lexical is not propagated.
1156 (let ((v (make-vector 6 #f)))
1158 (vector-set! v n n)))
1160 ((call (toplevel make-vector) (const 6) (const #f)))
1163 (((n) #f #f #f () (_))
1164 (primcall vector-set!
1165 (lexical v _) (lexical n _) (lexical n _)))))))
1168 ;; Mutable lexical is not propagated.
1169 (let ((v (vector 1 2 3)))
1173 ((primcall vector (const 1) (const 2) (const 3)))
1176 ((() #f #f #f () ())
1180 ;; Lexical that is not provably pure is not inlined nor propagated.
1181 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
1184 (let (x) (_) ((if (primcall > (toplevel p) (toplevel q))
1185 (call (toplevel frob!))
1186 (call (toplevel display) (const chbouib))))
1187 (let (y) (_) ((primcall * (lexical x _) (const 2)))
1190 (primcall + (lexical x _) (lexical y _))))))
1193 ;; Non-constant arguments not propagated to lambdas.
1201 (let (x y z) (_ _ _)
1202 ((primcall vector (const 1) (const 2) (const 3))
1203 (call (toplevel make-list) (const 10))
1204 (primcall list (const 1) (const 2) (const 3)))
1206 (primcall vector-set!
1207 (lexical x _) (const 0) (const 0))
1208 (seq (primcall set-car!
1209 (lexical y _) (const 0))
1211 (lexical z _) (const ()))))))
1214 (let ((foo top-foo) (bar top-bar))
1215 (let* ((g (lambda (x y) (+ x y)))
1216 (f (lambda (g x) (g x x))))
1217 (+ (f g foo) (f g bar))))
1218 (let (foo bar) (_ _) ((toplevel top-foo) (toplevel top-bar))
1220 (primcall + (lexical foo _) (lexical foo _))
1221 (primcall + (lexical bar _) (lexical bar _)))))
1224 ;; Fresh objects are not turned into constants, nor are constants
1225 ;; turned into fresh objects.
1230 (let (x) (_) ((primcall cons (const 1) (const (2 3))))
1231 (primcall cons (const 0) (lexical x _))))
1234 ;; Bindings mutated.
1238 (let (x) (_) ((const 2))
1240 (set! (lexical x _) (const 3))
1244 ;; Bindings mutated.
1249 (frob f) ; may mutate `x'
1251 (letrec (x) (_) ((const 0))
1253 (call (toplevel frob) (lambda _ _))
1257 ;; Bindings mutated.
1258 (letrec ((f (lambda (x)
1259 (set! f (lambda (_) x))
1265 ;; Bindings possibly mutated.
1266 (let ((x (make-foo)))
1267 (frob! x) ; may mutate `x'
1269 (let (x) (_) ((call (toplevel make-foo)))
1271 (call (toplevel frob!) (lexical x _))
1275 ;; Inlining stops at recursive calls with dynamic arguments.
1277 (if (< x 0) x (loop (1- x))))
1278 (letrec (loop) (_) ((lambda (_)
1280 (((x) #f #f #f () (_))
1282 (call (lexical loop _)
1284 (lexical x _))))))))
1285 (call (lexical loop _) (toplevel x))))
1288 ;; Recursion on the 2nd argument is fully evaluated.
1290 (let loop ((x x) (y 10))
1294 (let (x) (_) ((call (toplevel top)))
1295 (call (toplevel foo) (lexical x _) (const 0))))
1298 ;; Inlining aborted when residual code contains recursive calls.
1300 ;; <http://debbugs.gnu.org/9542>
1301 (let loop ((x x) (y 0))
1303 (loop (1- x) (1- y))
1306 (loop (1+ x) (1+ y)))))
1307 (letrec (loop) (_) ((lambda (_)
1309 (((x y) #f #f #f () (_ _))
1311 (lexical y _) (const 0))
1313 (call (lexical loop _) (toplevel x) (const 0))))
1316 ;; Infinite recursion: `peval' gives up and leaves it as is.
1317 (letrec ((f (lambda (x) (g (1- x))))
1318 (g (lambda (x) (h (1+ x))))
1319 (h (lambda (x) (f x))))
1324 ;; Infinite recursion: all the arguments to `loop' are static, but
1325 ;; unrolling it would lead `peval' to enter an infinite loop.
1329 (letrec (loop) (_) ((lambda . _))
1330 (call (lexical loop _) (const 0))))
1333 ;; This test checks that the `start' binding is indeed residualized.
1334 ;; See the `referenced?' procedure in peval's `prune-bindings'.
1336 (set! pos 1) ;; Cause references to `pos' to residualize.
1337 (let ((here (let ((start pos)) (lambda () start))))
1339 (let (pos) (_) ((const 0))
1341 (set! (lexical pos _) (const 1))
1343 (call (lexical here _))))))
1346 ;; FIXME: should this one residualize the binding?
1352 ;; This is a fun one for peval to handle.
1355 (letrec (a) (_) ((lexical a _))
1359 ;; Another interesting recursive case.
1360 (letrec ((a b) (b a))
1362 (letrec (a) (_) ((lexical a _))
1366 ;; Another pruning case, that `a' is residualized.
1367 (letrec ((a (lambda () (a)))
1373 ;; "b c a" is the current order that we get with unordered letrec,
1374 ;; but it's not important to this test, so if it changes, just adapt
1376 (letrec (b c a) (_ _ _)
1379 ((() #f #f #f () ())
1380 (call (lexical a _)))))
1383 (((x) #f #f #f () (_))
1387 ((() #f #f #f () ())
1388 (call (lexical a _))))))
1391 ((call (toplevel foo) (lexical b _)))
1392 (call (lexical c _) (lexical d _)))))
1395 ;; In this case, we can prune the bindings. `a' ends up being copied
1396 ;; because it is only referenced once in the source program. Oh
1398 (letrec* ((a (lambda (x) (top x)))
1401 (call (toplevel foo)
1404 (((x) #f #f #f () (_))
1405 (call (toplevel top) (lexical x _)))))
1408 (((x) #f #f #f () (_))
1409 (call (toplevel top) (lexical x _)))))))
1412 ;; Constant folding: cons
1413 (begin (cons 1 2) #f)
1417 ;; Constant folding: cons
1418 (begin (cons (foo) 2) #f)
1419 (seq (call (toplevel foo)) (const #f)))
1422 ;; Constant folding: cons
1427 ;; Constant folding: car+cons
1432 ;; Constant folding: cdr+cons
1437 ;; Constant folding: car+cons, impure
1438 (car (cons 1 (bar)))
1439 (seq (call (toplevel bar)) (const 1)))
1442 ;; Constant folding: cdr+cons, impure
1443 (cdr (cons (bar) 0))
1444 (seq (call (toplevel bar)) (const 0)))
1447 ;; Constant folding: car+list
1452 ;; Constant folding: cdr+list
1454 (primcall list (const 0)))
1457 ;; Constant folding: car+list, impure
1458 (car (list 1 (bar)))
1459 (seq (call (toplevel bar)) (const 1)))
1462 ;; Constant folding: cdr+list, impure
1463 (cdr (list (bar) 0))
1464 (seq (call (toplevel bar)) (primcall list (const 0))))
1467 ;; Non-constant guards get lexical bindings.
1468 (dynamic-wind foo (lambda () bar) baz)
1469 (let (w u) (_ _) ((toplevel foo) (toplevel baz))
1470 (dynwind (lexical w _)
1471 (call (lexical w _))
1473 (call (lexical u _))
1477 ;; Constant guards don't need lexical bindings.
1478 (dynamic-wind (lambda () foo) (lambda () bar) (lambda () baz))
1482 ((() #f #f #f () ()) (toplevel foo))))
1488 ((() #f #f #f () ()) (toplevel baz))))))
1491 ;; Prompt is removed if tag is unreferenced
1492 (let ((tag (make-prompt-tag)))
1493 (call-with-prompt tag
1495 (lambda args args)))
1499 ;; Prompt is removed if tag is unreferenced, with explicit stem
1500 (let ((tag (make-prompt-tag "foo")))
1501 (call-with-prompt tag
1503 (lambda args args)))
1507 ;; `while' without `break' or `continue' has no prompts and gets its
1508 ;; condition folded. Unfortunately the outer `lp' does not yet get
1514 ((() #f #f #f () ())
1518 ((() #f #f #f () ())
1519 (call (lexical loop _))))))
1520 (call (lexical loop _)))))))
1521 (call (lexical lp _)))))
1525 (with-test-prefix "tree-il-fold"
1527 (pass-if "empty tree"
1528 (let ((leaf? #f) (up? #f) (down? #f) (mark (list 'mark)))
1530 (tree-il-fold (lambda (x y) (set! leaf? #t) y)
1531 (lambda (x y) (set! down? #t) y)
1532 (lambda (x y) (set! up? #t) y)
1539 (pass-if "lambda and application"
1540 (let* ((leaves '()) (ups '()) (downs '())
1541 (result (tree-il-fold (lambda (x y)
1542 (set! leaves (cons x leaves))
1545 (set! downs (cons x downs))
1548 (set! ups (cons x ups))
1554 (((x y) #f #f #f () (x1 y1))
1559 (and (equal? (map strip-source leaves)
1560 (list (make-lexical-ref #f 'y 'y1)
1561 (make-lexical-ref #f 'x 'x1)
1562 (make-toplevel-ref #f '+)))
1563 (= (length downs) 3)
1564 (equal? (reverse (map strip-source ups))
1565 (map strip-source downs))))))
1572 ;; Make sure we get English messages.
1573 (setlocale LC_ALL "C")
1575 (define (call-with-warnings thunk)
1576 (let ((port (open-output-string)))
1577 (with-fluids ((*current-warning-port* port)
1578 (*current-warning-prefix* ""))
1580 (let ((warnings (get-output-string port)))
1581 (string-tokenize warnings
1582 (char-set-complement (char-set #\newline))))))
1584 (define %opts-w-unused
1585 '(#:warnings (unused-variable)))
1587 (define %opts-w-unused-toplevel
1588 '(#:warnings (unused-toplevel)))
1590 (define %opts-w-unbound
1591 '(#:warnings (unbound-variable)))
1593 (define %opts-w-arity
1594 '(#:warnings (arity-mismatch)))
1596 (define %opts-w-format
1597 '(#:warnings (format)))
1600 (with-test-prefix "warnings"
1602 (pass-if "unknown warning type"
1603 (let ((w (call-with-warnings
1605 (compile #t #:opts '(#:warnings (does-not-exist)))))))
1606 (and (= (length w) 1)
1607 (number? (string-contains (car w) "unknown warning")))))
1609 (with-test-prefix "unused-variable"
1612 (null? (call-with-warnings
1614 (compile '(lambda (x y) (+ x y))
1615 #:opts %opts-w-unused)))))
1617 (pass-if "let/unused"
1618 (let ((w (call-with-warnings
1620 (compile '(lambda (x)
1623 #:opts %opts-w-unused)))))
1624 (and (= (length w) 1)
1625 (number? (string-contains (car w) "unused variable `y'")))))
1627 (pass-if "shadowed variable"
1628 (let ((w (call-with-warnings
1630 (compile '(lambda (x)
1634 #:opts %opts-w-unused)))))
1635 (and (= (length w) 1)
1636 (number? (string-contains (car w) "unused variable `y'")))))
1639 (null? (call-with-warnings
1641 (compile '(lambda ()
1642 (letrec ((x (lambda () (y)))
1643 (y (lambda () (x))))
1645 #:opts %opts-w-unused)))))
1647 (pass-if "unused argument"
1648 ;; Unused arguments should not be reported.
1649 (null? (call-with-warnings
1651 (compile '(lambda (x y z) #t)
1652 #:opts %opts-w-unused)))))
1654 (pass-if "special variable names"
1655 (null? (call-with-warnings
1657 (compile '(lambda ()
1658 (let ((_ 'underscore)
1659 (#{gensym name}# 'ignore-me))
1662 #:opts %opts-w-unused))))))
1664 (with-test-prefix "unused-toplevel"
1666 (pass-if "used after definition"
1667 (null? (call-with-warnings
1669 (let ((in (open-input-string
1670 "(define foo 2) foo")))
1671 (read-and-compile in
1673 #:opts %opts-w-unused-toplevel))))))
1675 (pass-if "used before definition"
1676 (null? (call-with-warnings
1678 (let ((in (open-input-string
1679 "(define (bar) foo) (define foo 2) (bar)")))
1680 (read-and-compile in
1682 #:opts %opts-w-unused-toplevel))))))
1684 (pass-if "unused but public"
1685 (let ((in (open-input-string
1686 "(define-module (test-suite tree-il x) #:export (bar))
1687 (define (bar) #t)")))
1688 (null? (call-with-warnings
1690 (read-and-compile in
1692 #:opts %opts-w-unused-toplevel))))))
1694 (pass-if "unused but public (more)"
1695 (let ((in (open-input-string
1696 "(define-module (test-suite tree-il x) #:export (bar))
1697 (define (bar) (baz))
1698 (define (baz) (foo))
1699 (define (foo) #t)")))
1700 (null? (call-with-warnings
1702 (read-and-compile in
1704 #:opts %opts-w-unused-toplevel))))))
1706 (pass-if "unused but define-public"
1707 (null? (call-with-warnings
1709 (compile '(define-public foo 2)
1711 #:opts %opts-w-unused-toplevel)))))
1713 (pass-if "used by macro"
1714 ;; FIXME: See comment about macros at `unused-toplevel-analysis'.
1717 (null? (call-with-warnings
1719 (let ((in (open-input-string
1720 "(define (bar) 'foo)
1722 (syntax-rules () ((_) (bar))))")))
1723 (read-and-compile in
1725 #:opts %opts-w-unused-toplevel))))))
1728 (let ((w (call-with-warnings
1730 (compile '(define foo 2)
1732 #:opts %opts-w-unused-toplevel)))))
1733 (and (= (length w) 1)
1734 (number? (string-contains (car w)
1735 (format #f "top-level variable `~A'"
1738 (pass-if "unused recursive"
1739 (let ((w (call-with-warnings
1741 (compile '(define (foo) (foo))
1743 #:opts %opts-w-unused-toplevel)))))
1744 (and (= (length w) 1)
1745 (number? (string-contains (car w)
1746 (format #f "top-level variable `~A'"
1749 (pass-if "unused mutually recursive"
1750 (let* ((in (open-input-string
1751 "(define (foo) (bar)) (define (bar) (foo))"))
1752 (w (call-with-warnings
1754 (read-and-compile in
1756 #:opts %opts-w-unused-toplevel)))))
1757 (and (= (length w) 2)
1758 (number? (string-contains (car w)
1759 (format #f "top-level variable `~A'"
1761 (number? (string-contains (cadr w)
1762 (format #f "top-level variable `~A'"
1765 (pass-if "special variable names"
1766 (null? (call-with-warnings
1768 (compile '(define #{gensym name}# 'ignore-me)
1770 #:opts %opts-w-unused-toplevel))))))
1772 (with-test-prefix "unbound variable"
1775 (null? (call-with-warnings
1777 (compile '+ #:opts %opts-w-unbound)))))
1781 (w (call-with-warnings
1785 #:opts %opts-w-unbound)))))
1786 (and (= (length w) 1)
1787 (number? (string-contains (car w)
1788 (format #f "unbound variable `~A'"
1793 (w (call-with-warnings
1795 (compile `(set! ,v 7)
1797 #:opts %opts-w-unbound)))))
1798 (and (= (length w) 1)
1799 (number? (string-contains (car w)
1800 (format #f "unbound variable `~A'"
1803 (pass-if "module-local top-level is visible"
1804 (let ((m (make-module))
1806 (beautify-user-module! m)
1807 (compile `(define ,v 123)
1808 #:env m #:opts %opts-w-unbound)
1809 (null? (call-with-warnings
1814 #:opts %opts-w-unbound))))))
1816 (pass-if "module-local top-level is visible after"
1817 (let ((m (make-module))
1819 (beautify-user-module! m)
1820 (null? (call-with-warnings
1822 (let ((in (open-input-string
1825 (define chbouib 5)")))
1826 (read-and-compile in
1828 #:opts %opts-w-unbound)))))))
1830 (pass-if "optional arguments are visible"
1831 (null? (call-with-warnings
1833 (compile '(lambda* (x #:optional y z) (list x y z))
1834 #:opts %opts-w-unbound
1837 (pass-if "keyword arguments are visible"
1838 (null? (call-with-warnings
1840 (compile '(lambda* (x #:key y z) (list x y z))
1841 #:opts %opts-w-unbound
1844 (pass-if "GOOPS definitions are visible"
1845 (let ((m (make-module))
1847 (beautify-user-module! m)
1848 (module-use! m (resolve-interface '(oop goops)))
1849 (null? (call-with-warnings
1851 (let ((in (open-input-string
1852 "(define-class <foo> ()
1853 (bar #:getter foo-bar))
1854 (define z (foo-bar (make <foo>)))")))
1855 (read-and-compile in
1857 #:opts %opts-w-unbound))))))))
1859 (with-test-prefix "arity mismatch"
1862 (null? (call-with-warnings
1864 (compile '(cons 'a 'b) #:opts %opts-w-arity)))))
1866 (pass-if "direct application"
1867 (let ((w (call-with-warnings
1869 (compile '((lambda (x y) (or x y)) 1 2 3 4 5)
1870 #:opts %opts-w-arity
1872 (and (= (length w) 1)
1873 (number? (string-contains (car w)
1874 "wrong number of arguments to")))))
1876 (let ((w (call-with-warnings
1878 (compile '(let ((f (lambda (x y) (+ x y))))
1880 #:opts %opts-w-arity
1882 (and (= (length w) 1)
1883 (number? (string-contains (car w)
1884 "wrong number of arguments to")))))
1887 (let ((w (call-with-warnings
1889 (compile '(cons 1 2 3 4)
1890 #:opts %opts-w-arity
1892 (and (= (length w) 1)
1893 (number? (string-contains (car w)
1894 "wrong number of arguments to")))))
1896 (pass-if "alias to global"
1897 (let ((w (call-with-warnings
1899 (compile '(let ((f cons)) (f 1 2 3 4))
1900 #:opts %opts-w-arity
1902 (and (= (length w) 1)
1903 (number? (string-contains (car w)
1904 "wrong number of arguments to")))))
1906 (pass-if "alias to lexical to global"
1907 (let ((w (call-with-warnings
1909 (compile '(let ((f number?))
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 lexical"
1919 (let ((w (call-with-warnings
1921 (compile '(let ((f (lambda (x y z) (+ x y z))))
1924 #:opts %opts-w-arity
1926 (and (= (length w) 1)
1927 (number? (string-contains (car w)
1928 "wrong number of arguments to")))))
1931 (let ((w (call-with-warnings
1933 (compile '(letrec ((odd? (lambda (x) (even? (1- x))))
1938 #:opts %opts-w-arity
1940 (and (= (length w) 1)
1941 (number? (string-contains (car w)
1942 "wrong number of arguments to")))))
1944 (pass-if "case-lambda"
1945 (null? (call-with-warnings
1947 (compile '(let ((f (case-lambda
1954 #:opts %opts-w-arity
1957 (pass-if "case-lambda with wrong number of arguments"
1958 (let ((w (call-with-warnings
1960 (compile '(let ((f (case-lambda
1964 #:opts %opts-w-arity
1966 (and (= (length w) 1)
1967 (number? (string-contains (car w)
1968 "wrong number of arguments to")))))
1970 (pass-if "case-lambda*"
1971 (null? (call-with-warnings
1973 (compile '(let ((f (case-lambda*
1974 ((x #:optional y) 1)
1976 ((x y #:key z) 3))))
1981 #:opts %opts-w-arity
1984 (pass-if "case-lambda* with wrong arguments"
1985 (let ((w (call-with-warnings
1987 (compile '(let ((f (case-lambda*
1988 ((x #:optional y) 1)
1990 ((x y #:key z) 3))))
1993 #:opts %opts-w-arity
1995 (and (= (length w) 2)
1996 (null? (filter (lambda (w)
2000 w "wrong number of arguments to"))))
2003 (pass-if "local toplevel-defines"
2004 (let ((w (call-with-warnings
2006 (let ((in (open-input-string "
2007 (define (g x) (f x))
2009 (read-and-compile in
2010 #:opts %opts-w-arity
2011 #:to 'assembly))))))
2012 (and (= (length w) 1)
2013 (number? (string-contains (car w)
2014 "wrong number of arguments to")))))
2016 (pass-if "global toplevel alias"
2017 (let ((w (call-with-warnings
2019 (let ((in (open-input-string "
2021 (define (g) (f))")))
2022 (read-and-compile in
2023 #:opts %opts-w-arity
2024 #:to 'assembly))))))
2025 (and (= (length w) 1)
2026 (number? (string-contains (car w)
2027 "wrong number of arguments to")))))
2029 (pass-if "local toplevel overrides global"
2030 (null? (call-with-warnings
2032 (let ((in (open-input-string "
2034 (define (foo x) (cons))")))
2035 (read-and-compile in
2036 #:opts %opts-w-arity
2037 #:to 'assembly))))))
2039 (pass-if "keyword not passed and quiet"
2040 (null? (call-with-warnings
2042 (compile '(let ((f (lambda* (x #:key y) y)))
2044 #:opts %opts-w-arity
2047 (pass-if "keyword passed and quiet"
2048 (null? (call-with-warnings
2050 (compile '(let ((f (lambda* (x #:key y) y)))
2052 #:opts %opts-w-arity
2055 (pass-if "keyword passed to global and quiet"
2056 (null? (call-with-warnings
2058 (let ((in (open-input-string "
2059 (use-modules (system base compile))
2060 (compile '(+ 2 3) #:env (current-module))")))
2061 (read-and-compile in
2062 #:opts %opts-w-arity
2063 #:to 'assembly))))))
2065 (pass-if "extra keyword"
2066 (let ((w (call-with-warnings
2068 (compile '(let ((f (lambda* (x #:key y) y)))
2070 #:opts %opts-w-arity
2072 (and (= (length w) 1)
2073 (number? (string-contains (car w)
2074 "wrong number of arguments to")))))
2076 (pass-if "extra keywords allowed"
2077 (null? (call-with-warnings
2079 (compile '(let ((f (lambda* (x #:key y #:allow-other-keys)
2082 #:opts %opts-w-arity
2083 #:to 'assembly))))))
2085 (with-test-prefix "format"
2087 (pass-if "quiet (no args)"
2088 (null? (call-with-warnings
2090 (compile '(format #t "hey!")
2091 #:opts %opts-w-format
2094 (pass-if "quiet (1 arg)"
2095 (null? (call-with-warnings
2097 (compile '(format #t "hey ~A!" "you")
2098 #:opts %opts-w-format
2101 (pass-if "quiet (2 args)"
2102 (null? (call-with-warnings
2104 (compile '(format #t "~A ~A!" "hello" "world")
2105 #:opts %opts-w-format
2108 (pass-if "wrong port arg"
2109 (let ((w (call-with-warnings
2111 (compile '(format 10 "foo")
2112 #:opts %opts-w-format
2114 (and (= (length w) 1)
2115 (number? (string-contains (car w)
2116 "wrong port argument")))))
2118 (pass-if "non-literal format string"
2119 (let ((w (call-with-warnings
2121 (compile '(format #f fmt)
2122 #:opts %opts-w-format
2124 (and (= (length w) 1)
2125 (number? (string-contains (car w)
2126 "non-literal format string")))))
2128 (pass-if "non-literal format string using gettext"
2129 (null? (call-with-warnings
2131 (compile '(format #t (_ "~A ~A!") "hello" "world")
2132 #:opts %opts-w-format
2135 (pass-if "wrong format string"
2136 (let ((w (call-with-warnings
2138 (compile '(format #f 'not-a-string)
2139 #:opts %opts-w-format
2141 (and (= (length w) 1)
2142 (number? (string-contains (car w)
2143 "wrong format string")))))
2145 (pass-if "wrong number of args"
2146 (let ((w (call-with-warnings
2148 (compile '(format "shbweeb")
2149 #:opts %opts-w-format
2151 (and (= (length w) 1)
2152 (number? (string-contains (car w)
2153 "wrong number of arguments")))))
2155 (pass-if "~%, ~~, ~&, ~t, ~_, and ~\\n"
2156 (null? (call-with-warnings
2158 (compile '(format some-port "~&~3_~~ ~\n~12they~%")
2159 #:opts %opts-w-format
2162 (pass-if "one missing argument"
2163 (let ((w (call-with-warnings
2165 (compile '(format some-port "foo ~A~%")
2166 #:opts %opts-w-format
2168 (and (= (length w) 1)
2169 (number? (string-contains (car w)
2170 "expected 1, got 0")))))
2172 (pass-if "one missing argument, gettext"
2173 (let ((w (call-with-warnings
2175 (compile '(format some-port (_ "foo ~A~%"))
2176 #:opts %opts-w-format
2178 (and (= (length w) 1)
2179 (number? (string-contains (car w)
2180 "expected 1, got 0")))))
2182 (pass-if "two missing arguments"
2183 (let ((w (call-with-warnings
2185 (compile '(format #f "foo ~10,2f and bar ~S~%")
2186 #:opts %opts-w-format
2188 (and (= (length w) 1)
2189 (number? (string-contains (car w)
2190 "expected 2, got 0")))))
2192 (pass-if "one given, one missing argument"
2193 (let ((w (call-with-warnings
2195 (compile '(format #t "foo ~A and ~S~%" hey)
2196 #:opts %opts-w-format
2198 (and (= (length w) 1)
2199 (number? (string-contains (car w)
2200 "expected 2, got 1")))))
2202 (pass-if "too many arguments"
2203 (let ((w (call-with-warnings
2205 (compile '(format #t "foo ~A~%" 1 2)
2206 #:opts %opts-w-format
2208 (and (= (length w) 1)
2209 (number? (string-contains (car w)
2210 "expected 1, got 2")))))
2212 (with-test-prefix "conditionals"
2214 (null? (call-with-warnings
2216 (compile '(format #f "~A ~[foo~;bar~;baz~;~] ~10,2f"
2218 #:opts %opts-w-format
2221 (pass-if "literals with selector"
2222 (let ((w (call-with-warnings
2224 (compile '(format #f "~2[foo~;bar~;baz~;~] ~A"
2226 #:opts %opts-w-format
2228 (and (= (length w) 1)
2229 (number? (string-contains (car w)
2230 "expected 1, got 2")))))
2232 (pass-if "escapes (exact count)"
2233 (let ((w (call-with-warnings
2235 (compile '(format #f "~[~a~;~a~]")
2236 #:opts %opts-w-format
2238 (and (= (length w) 1)
2239 (number? (string-contains (car w)
2240 "expected 2, got 0")))))
2242 (pass-if "escapes with selector"
2243 (let ((w (call-with-warnings
2245 (compile '(format #f "~1[chbouib~;~a~]")
2246 #:opts %opts-w-format
2248 (and (= (length w) 1)
2249 (number? (string-contains (car w)
2250 "expected 1, got 0")))))
2252 (pass-if "escapes, range"
2253 (let ((w (call-with-warnings
2255 (compile '(format #f "~[chbouib~;~a~;~2*~a~]")
2256 #:opts %opts-w-format
2258 (and (= (length w) 1)
2259 (number? (string-contains (car w)
2260 "expected 1 to 4, got 0")))))
2263 (let ((w (call-with-warnings
2265 (compile '(format #f "~@[temperature=~d~]")
2266 #:opts %opts-w-format
2268 (and (= (length w) 1)
2269 (number? (string-contains (car w)
2270 "expected 1, got 0")))))
2273 (let ((w (call-with-warnings
2275 (compile '(format #f "~:[~[hey~;~a~;~va~]~;~3*~]")
2276 #:opts %opts-w-format
2278 (and (= (length w) 1)
2279 (number? (string-contains (car w)
2280 "expected 2 to 4, got 0")))))
2282 (pass-if "unterminated"
2283 (let ((w (call-with-warnings
2285 (compile '(format #f "~[unterminated")
2286 #:opts %opts-w-format
2288 (and (= (length w) 1)
2289 (number? (string-contains (car w)
2290 "unterminated conditional")))))
2292 (pass-if "unexpected ~;"
2293 (let ((w (call-with-warnings
2295 (compile '(format #f "foo~;bar")
2296 #:opts %opts-w-format
2298 (and (= (length w) 1)
2299 (number? (string-contains (car w)
2302 (pass-if "unexpected ~]"
2303 (let ((w (call-with-warnings
2305 (compile '(format #f "foo~]")
2306 #:opts %opts-w-format
2308 (and (= (length w) 1)
2309 (number? (string-contains (car w)
2313 (null? (call-with-warnings
2315 (compile '(format #f "~A ~{~S~} ~A"
2316 'hello '("ladies" "and")
2318 #:opts %opts-w-format
2321 (pass-if "~{...~}, too many args"
2322 (let ((w (call-with-warnings
2324 (compile '(format #f "~{~S~}" 1 2 3)
2325 #:opts %opts-w-format
2327 (and (= (length w) 1)
2328 (number? (string-contains (car w)
2329 "expected 1, got 3")))))
2332 (null? (call-with-warnings
2334 (compile '(format #f "~@{~S~}" 1 2 3)
2335 #:opts %opts-w-format
2338 (pass-if "~@{...~}, too few args"
2339 (let ((w (call-with-warnings
2341 (compile '(format #f "~A ~@{~S~}")
2342 #:opts %opts-w-format
2344 (and (= (length w) 1)
2345 (number? (string-contains (car w)
2346 "expected at least 1, got 0")))))
2348 (pass-if "unterminated ~{...~}"
2349 (let ((w (call-with-warnings
2351 (compile '(format #f "~{")
2352 #:opts %opts-w-format
2354 (and (= (length w) 1)
2355 (number? (string-contains (car w)
2359 (null? (call-with-warnings
2361 (compile '(format #f "~:@(~A ~A~)" 'foo 'bar)
2362 #:opts %opts-w-format
2366 (let ((w (call-with-warnings
2368 (compile '(format #f "~v_foo")
2369 #:opts %opts-w-format
2371 (and (= (length w) 1)
2372 (number? (string-contains (car w)
2373 "expected 1, got 0")))))
2375 (null? (call-with-warnings
2377 (compile '(format #f "~v:@y" 1 123)
2378 #:opts %opts-w-format
2383 (let ((w (call-with-warnings
2385 (compile '(format #f "~2*~a" 'a 'b)
2386 #:opts %opts-w-format
2388 (and (= (length w) 1)
2389 (number? (string-contains (car w)
2390 "expected 3, got 2")))))
2393 (null? (call-with-warnings
2395 (compile '(format #f "~?" "~d ~d" '(1 2))
2396 #:opts %opts-w-format
2399 (pass-if "complex 1"
2400 (let ((w (call-with-warnings
2402 (compile '(format #f
2403 "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
2405 #:opts %opts-w-format
2407 (and (= (length w) 1)
2408 (number? (string-contains (car w)
2409 "expected 4, got 6")))))
2411 (pass-if "complex 2"
2412 (let ((w (call-with-warnings
2414 (compile '(format #f
2415 "~:(~A~) Commands~:[~; [abbrev]~]:~2%"
2417 #:opts %opts-w-format
2419 (and (= (length w) 1)
2420 (number? (string-contains (car w)
2421 "expected 2, got 4")))))
2423 (pass-if "complex 3"
2424 (let ((w (call-with-warnings
2426 (compile '(format #f "~9@a~:[~*~3_~;~3d~] ~v:@y~%")
2427 #:opts %opts-w-format
2429 (and (= (length w) 1)
2430 (number? (string-contains (car w)
2431 "expected 5, got 0")))))
2433 (pass-if "ice-9 format"
2434 (let ((w (call-with-warnings
2436 (let ((in (open-input-string
2437 "(use-modules ((ice-9 format)
2438 #:renamer (symbol-prefix-proc 'i9-)))
2439 (i9-format #t \"yo! ~A\" 1 2)")))
2440 (read-and-compile in
2441 #:opts %opts-w-format
2442 #:to 'assembly))))))
2443 (and (= (length w) 1)
2444 (number? (string-contains (car w)
2445 "expected 1, got 2")))))
2447 (pass-if "not format"
2448 (null? (call-with-warnings
2450 (compile '(let ((format chbouib))
2451 (format #t "not ~A a format string"))
2452 #:opts %opts-w-format
2453 #:to 'assembly)))))))