factor/basis/stack-checker/stack-checker-tests.factor

471 lines
14 KiB
Factor
Raw Normal View History

2008-07-20 05:24:37 -04:00
USING: accessors arrays generic stack-checker
stack-checker.backend stack-checker.errors kernel classes
kernel.private math math.parser math.private namespaces
namespaces.private parser sequences strings vectors words
quotations effects tools.test continuations generic.standard
sorting assocs definitions prettyprint io inspector
classes.tuple classes.union classes.predicate debugger
threads.private io.streams.string io.timeouts io.thread
2009-02-27 00:30:48 -05:00
sequences.private destructors combinators eval locals.backend
system compiler.units shuffle vocabs ;
2008-07-20 05:24:37 -04:00
IN: stack-checker.tests
[ 1234 infer ] must-fail
2008-07-20 05:24:37 -04:00
{ 0 2 } [ 2 "Hello" ] must-infer-as
{ 1 2 } [ dup ] must-infer-as
{ 1 2 } [ [ dup ] call ] must-infer-as
[ [ call ] infer ] [ T{ unknown-macro-input f call } = ] must-fail-with
[ [ curry call ] infer ] [ T{ unknown-macro-input f call } = ] must-fail-with
[ [ { } >quotation call ] infer ] [ T{ bad-macro-input f call } = ] must-fail-with
[ [ append curry call ] infer ] [ T{ bad-macro-input f call } = ] must-fail-with
2008-07-20 05:24:37 -04:00
{ 2 4 } [ 2dup ] must-infer-as
{ 1 0 } [ [ ] [ ] if ] must-infer-as
[ [ if ] infer ] [ T{ unknown-macro-input f if } = ] must-fail-with
[ [ { } >quotation { } >quotation if ] infer ] [ T{ bad-macro-input f if } = ] must-fail-with
[ [ [ ] if ] infer ] [ T{ unknown-macro-input f if } = ] must-fail-with
[ [ [ 2 ] [ ] if ] infer ] [ unbalanced-branches-error? ] must-fail-with
2008-07-20 05:24:37 -04:00
{ 4 3 } [ [ rot ] [ -rot ] if ] must-infer-as
{ 4 3 } [
[
[ swap 3 ] [ nip 5 5 ] if
] [
-rot
] if
] must-infer-as
{ 1 1 } [ dup [ ] when ] must-infer-as
{ 1 1 } [ dup [ dup fixnum* ] when ] must-infer-as
{ 2 1 } [ [ dup fixnum* ] when ] must-infer-as
{ 1 0 } [ [ drop ] when* ] must-infer-as
{ 1 1 } [ [ { { [ ] } } ] unless* ] must-infer-as
{ 0 1 }
[ [ 2 2 fixnum+ ] dup [ ] when call ] must-infer-as
[
[ [ [ 2 2 fixnum+ ] ] [ [ 2 2 fixnum* ] ] if call ] infer
] [ T{ bad-macro-input f call } = ] must-fail-with
2008-07-20 05:24:37 -04:00
! Test inference of termination of control flow
: termination-test-1 ( -- * ) "foo" throw ;
: termination-test-2 ( ? -- x ) [ termination-test-1 ] [ 3 ] if ;
{ 1 1 } [ termination-test-2 ] must-infer-as
: simple-recursion-1 ( obj -- obj )
dup [ simple-recursion-1 ] [ ] if ;
{ 1 1 } [ simple-recursion-1 ] must-infer-as
: simple-recursion-2 ( obj -- obj )
dup [ ] [ simple-recursion-2 ] if ;
{ 1 1 } [ simple-recursion-2 ] must-infer-as
: funny-recursion ( obj -- obj )
dup [ funny-recursion 1 ] [ 2 ] if drop ;
{ 1 1 } [ funny-recursion ] must-infer-as
! Simple combinators
{ 1 2 } [ [ first ] keep second ] must-infer-as
! Mutual recursion
DEFER: foe
: fie ( element obj -- ? )
dup array? [ foe ] [ eq? ] if ;
: foe ( element tree -- ? )
dup [
2dup first fie [
nip
] [
second dup array? [
foe
] [
fie
] if
] if
] [
2drop f
] if ;
{ 2 1 } [ fie ] must-infer-as
{ 2 1 } [ foe ] must-infer-as
: nested-when ( -- )
t [
t [
5 drop
] when
] when ;
{ 0 0 } [ nested-when ] must-infer-as
: nested-when* ( obj -- )
[
[
drop
] when*
] when* ;
{ 1 0 } [ nested-when* ] must-infer-as
SYMBOL: sym-test
{ 0 1 } [ sym-test ] must-infer-as
: terminator-branch ( a -- b )
dup [
length
] [
"foo" throw
] if ;
{ 1 1 } [ terminator-branch ] must-infer-as
: recursive-terminator ( obj -- )
dup [
recursive-terminator
] [
"Hi" throw
] if ;
{ 1 0 } [ recursive-terminator ] must-infer-as
GENERIC: potential-hang ( obj -- obj )
M: fixnum potential-hang dup [ potential-hang ] when ;
[ ] [ [ 5 potential-hang ] infer drop ] unit-test
TUPLE: funny-cons car cdr ;
GENERIC: iterate ( obj -- )
2008-09-02 02:53:55 -04:00
M: funny-cons iterate cdr>> iterate ;
2008-07-20 05:24:37 -04:00
M: f iterate drop ;
M: real iterate drop ;
{ 1 0 } [ iterate ] must-infer-as
! Regression
: cat ( obj -- * ) dup [ throw ] [ throw ] if ;
: dog ( a b c -- ) dup [ cat ] [ 3drop ] if ;
{ 3 0 } [ dog ] must-infer-as
! Regression
DEFER: monkey
: friend ( a b c -- ) dup [ friend ] [ monkey ] if ;
: monkey ( a b c -- ) dup [ 3drop ] [ friend ] if ;
{ 3 0 } [ friend ] must-infer-as
! Regression -- same as above but we infer the second word first
DEFER: blah2
: blah ( a b c -- ) dup [ blah ] [ blah2 ] if ;
: blah2 ( a b c -- ) dup [ blah ] [ 3drop ] if ;
{ 3 0 } [ blah2 ] must-infer-as
! Regression
DEFER: blah4
: blah3 ( a b c -- )
dup [ blah3 ] [ dup [ blah4 ] [ blah3 ] if ] if ;
: blah4 ( a b c -- )
dup [ blah4 ] [ dup [ 3drop ] [ blah3 ] if ] if ;
{ 3 0 } [ blah4 ] must-infer-as
! Regression
: bad-combinator ( obj quot: ( -- ) -- )
over [
2drop
] [
[ dip ] keep swap bad-combinator
2008-07-20 05:24:37 -04:00
] if ; inline recursive
[ [ [ 1 ] [ ] bad-combinator ] infer ] must-fail
! Regression
{ 2 2 } [
dup string? [ 2array throw ] unless
over string? [ 2array throw ] unless
] must-infer-as
! Regression
: too-deep ( a b -- c )
dup [ drop ] [ 2dup too-deep too-deep * ] if ; inline recursive
{ 2 1 } [ too-deep ] must-infer-as
! This used to hang
[ [ [ dup call ] dup call ] infer ]
[ recursive-quotation-error? ] must-fail-with
2008-07-20 05:24:37 -04:00
2009-03-07 16:58:14 -05:00
: m ( q -- ) dup call ; inline
2008-07-20 05:24:37 -04:00
[ [ [ m ] m ] infer ] [ recursive-quotation-error? ] must-fail-with
2008-07-20 05:24:37 -04:00
: m' ( quot -- ) dup curry call ; inline
2008-07-20 05:24:37 -04:00
[ [ [ m' ] m' ] infer ] [ recursive-quotation-error? ] must-fail-with
2008-07-20 05:24:37 -04:00
2009-03-07 16:58:14 -05:00
: m'' ( -- q ) [ dup curry ] ; inline
2008-07-20 05:24:37 -04:00
2009-03-07 16:58:14 -05:00
: m''' ( -- ) m'' call call ; inline
2008-07-20 05:24:37 -04:00
[ [ [ m''' ] m''' ] infer ] [ recursive-quotation-error? ] must-fail-with
2008-07-20 05:24:37 -04:00
: m-if ( a b c -- ) t over when ; inline
2008-07-20 05:24:37 -04:00
[ [ [ m-if ] m-if ] infer ] [ recursive-quotation-error? ] must-fail-with
2008-07-20 05:24:37 -04:00
! This doesn't hang but it's also an example of the
! undedicable case
[ [ [ [ drop 3 ] swap call ] dup call ] infer ]
[ recursive-quotation-error? ] must-fail-with
2008-07-20 05:24:37 -04:00
[ [ 1 drop-locals ] infer ] [ too-many-r>? ] must-fail-with
2008-07-20 05:24:37 -04:00
! Regression
[ [ cleave ] infer ] [ T{ unknown-macro-input f cleave } = ] must-fail-with
2008-07-20 05:24:37 -04:00
! Test some curry stuff
{ 1 1 } [ 3 [ ] curry 4 [ ] curry if ] must-infer-as
{ 3 1 } [ [ ] curry [ [ ] curry ] dip if ] must-infer-as
2008-07-20 05:24:37 -04:00
{ 2 1 } [ [ ] curry 4 [ ] curry if ] must-infer-as
[ [ 3 [ ] curry 1 2 [ ] 2curry if ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ ] curry [ [ ] 2curry ] dip if ] infer ] [ unbalanced-branches-error? ] must-fail-with
2008-07-20 05:24:37 -04:00
{ 1 3 } [ [ 2drop f ] assoc-find ] must-infer-as
! Test words with continuations
{ 0 0 } [ [ drop ] callcc0 ] must-infer-as
{ 0 1 } [ [ 4 swap continue-with ] callcc1 ] must-infer-as
{ 2 1 } [ [ + ] [ ] [ ] cleanup ] must-infer-as
{ 2 1 } [ [ + ] [ 3drop 0 ] recover ] must-infer-as
! A typo
{ 1 0 } [ { [ ] } dispatch ] must-infer-as
DEFER: inline-recursive-2
: inline-recursive-1 ( -- ) inline-recursive-2 ;
: inline-recursive-2 ( -- ) inline-recursive-1 ;
{ 0 0 } [ inline-recursive-1 ] must-infer-as
! Hooks
SYMBOL: my-var
HOOK: my-hook my-var ( -- x )
M: integer my-hook "an integer" ;
M: string my-hook "a string" ;
{ 0 1 } [ my-hook ] must-infer-as
DEFER: deferred-word
{ 1 1 } [ [ deferred-word ] [ 3 ] if ] must-infer-as
DEFER: an-inline-word
: normal-word-3 ( -- )
3 [ [ 2 + ] curry ] an-inline-word call drop ;
: normal-word-2 ( -- )
normal-word-3 ;
: normal-word ( x -- x )
dup [ normal-word-2 ] when ;
: an-inline-word ( obj quot -- )
2008-12-17 20:17:37 -05:00
[ normal-word ] dip call ; inline
2008-07-20 05:24:37 -04:00
{ 1 1 } [ [ 3 * ] an-inline-word ] must-infer-as
{ 0 1 } [ [ 2 ] [ 2 ] [ + ] compose compose call ] must-infer-as
ERROR: custom-error ;
2010-01-14 10:10:13 -05:00
[ T{ effect f { } { } t } ] [
2008-07-20 05:24:37 -04:00
[ custom-error ] infer
] unit-test
2009-03-07 16:58:14 -05:00
: funny-throw ( a -- * ) throw ; inline
2008-07-20 05:24:37 -04:00
2010-01-14 10:10:13 -05:00
[ T{ effect f { } { } t } ] [
2008-07-20 05:24:37 -04:00
[ 3 funny-throw ] infer
] unit-test
2010-01-14 10:10:13 -05:00
[ T{ effect f { } { } t } ] [
2008-07-20 05:24:37 -04:00
[ custom-error inference-error ] infer
] unit-test
2010-01-14 10:10:13 -05:00
[ T{ effect f { "x" } { "x" "x" } t } ] [
2008-12-17 20:17:37 -05:00
[ dup [ 3 throw ] dip ] infer
2008-07-20 05:24:37 -04:00
] unit-test
! Regression
[ [ 1 load-locals ] infer ] [ too-many->r? ] must-fail-with
2008-07-20 05:24:37 -04:00
! Corner case
[ [ [ f dup ] [ dup ] produce ] infer ] must-fail
2008-07-20 05:24:37 -04:00
[ [ [ f dup ] [ ] while ] infer ] must-fail
2008-07-20 05:24:37 -04:00
2009-03-07 16:58:14 -05:00
: erg's-inference-bug ( -- ) f dup [ erg's-inference-bug ] when ; inline recursive
2008-07-20 05:24:37 -04:00
[ [ erg's-inference-bug ] infer ] must-fail
FORGET: erg's-inference-bug
2008-07-20 05:24:37 -04:00
2009-03-07 16:58:14 -05:00
: bad-recursion-3 ( -- ) dup [ [ bad-recursion-3 ] dip ] when ; inline recursive
2008-07-20 05:24:37 -04:00
[ [ bad-recursion-3 ] infer ] must-fail
FORGET: bad-recursion-3
2008-07-20 05:24:37 -04:00
2009-11-06 03:35:43 -05:00
: bad-recursion-4 ( -- ) 4 [ dup call [ rot ] dip swap ] times ; inline recursive
2008-07-20 05:24:37 -04:00
[ [ [ ] [ 1 2 3 ] over dup bad-recursion-4 ] infer ] must-fail
: bad-recursion-5 ( obj quot: ( -- ) -- ) dup call swap bad-recursion-5 ; inline recursive
[ [ f [ ] bad-recursion-5 ] infer ] must-fail
: bad-recursion-6 ( quot: ( -- ) -- )
dup bad-recursion-6 call ; inline recursive
[ [ [ drop f ] bad-recursion-6 ] infer ] must-fail
2008-07-28 18:56:15 -04:00
[ ] [ [ \ bad-recursion-6 forget ] with-compilation-unit ] unit-test
2008-07-28 18:56:15 -04:00
{ 3 0 } [ [ 2drop "A" throw ] [ ] if 2drop ] must-infer-as
{ 2 0 } [ drop f f [ 2drop "A" throw ] [ ] if 2drop ] must-infer-as
2008-08-15 00:35:19 -04:00
: unbalanced-retain-usage ( a b -- )
dup 10 < [ 2drop 5 1 + unbalanced-retain-usage ] [ 2drop ] if ;
inline recursive
[ [ unbalanced-retain-usage ] infer ] [ inference-error? ] must-fail-with
FORGET: unbalanced-retain-usage
DEFER: eee'
: ddd' ( ? -- ) [ f eee' ] when ; inline recursive
2008-12-17 20:17:37 -05:00
: eee' ( ? -- ) [ swap [ ] ] dip ddd' call ; inline recursive
[ [ eee' ] infer ] [ inference-error? ] must-fail-with
2008-08-28 23:28:34 -04:00
[ ] [ [ \ ddd' forget ] with-compilation-unit ] unit-test
[ ] [ [ \ eee' forget ] with-compilation-unit ] unit-test
2008-08-28 23:28:34 -04:00
: bogus-error ( x -- )
dup "A" throw [ bogus-error ] [ drop ] if ; inline recursive
[ bogus-error ] must-infer
2008-11-17 12:16:32 -05:00
[ [ clear ] infer. ] [ inference-error? ] must-fail-with
: debugging-curry-folding ( quot -- )
[ debugging-curry-folding ] curry call ; inline recursive
2009-02-27 00:30:48 -05:00
[ [ ] debugging-curry-folding ] must-infer
[ [ exit ] [ 1 2 3 ] if ] must-infer
! Stack effects are required now but FORGET: clears them...
: forget-test ( -- ) ;
[ forget-test ] must-infer
[ ] [ [ \ forget-test forget ] with-compilation-unit ] unit-test
2009-04-17 13:46:04 -04:00
[ forget-test ] must-infer
[ [ cond ] infer ] [ T{ unknown-macro-input f cond } = ] must-fail-with
[ [ bi ] infer ] [ T{ unknown-macro-input f call } = ] must-fail-with
[ [ each ] infer ] [ T{ unknown-macro-input f each } = ] must-fail-with
[ [ if* ] infer ] [ T{ unknown-macro-input f if* } = ] must-fail-with
[ [ [ "derp" ] if* ] infer ] [ T{ unknown-macro-input f if* } = ] must-fail-with
[ [ [ "OOPS" throw ] dip ] [ drop ] if ] must-infer
! Found during code review
[ [ [ drop [ ] ] when call ] infer ] must-fail
[ swap [ [ drop [ ] ] when call ] infer ] must-fail
{ 3 1 } [ call( a b -- c ) ] must-infer-as
{ 3 1 } [ execute( a b -- c ) ] must-infer-as
[ [ call-effect ] infer ] [ T{ unknown-macro-input f call-effect } = ] must-fail-with
[ [ execute-effect ] infer ] [ T{ unknown-macro-input f execute-effect } = ] must-fail-with
[ \ set-datastack def>> infer ] [ T{ do-not-compile f do-primitive } = ] must-fail-with
2010-01-06 23:40:23 -05:00
[ ] [ [ \ set-datastack def>> infer ] try ] unit-test
! Make sure all primitives are covered
[ { } ] [
all-words [ primitive? ] filter
[ "default-output-classes" word-prop not ] filter
[ "special" word-prop not ] filter
[ "shuffle" word-prop not ] filter
] unit-test
{ 1 0 } [ [ drop ] each ] must-infer-as
{ 2 1 } [ [ append ] each ] must-infer-as
{ 1 1 } [ [ ] map ] must-infer-as
{ 1 1 } [ [ reverse ] map ] must-infer-as
{ 2 2 } [ [ append dup ] map ] must-infer-as
{ 2 2 } [ [ swap nth suffix dup ] map-index ] must-infer-as
{ 4 1 } [ [ 2drop ] [ 2nip ] if ] must-infer-as
{ 3 3 } [ [ dup ] [ over ] if ] must-infer-as
{ 1 1 } [ [ 1 ] [ 0 ] if ] must-infer-as
{ 2 2 } [ [ t ] [ 1 + f ] if ] must-infer-as
{ 1 0 } [ [ write ] [ "(f)" write ] if* ] must-infer-as
{ 1 1 } [ [ ] [ f ] if* ] must-infer-as
{ 2 1 } [ [ nip ] [ drop f ] if* ] must-infer-as
{ 2 1 } [ [ nip ] [ ] if* ] must-infer-as
{ 3 2 } [ [ 3append f ] [ ] if* ] must-infer-as
{ 1 0 } [ [ drop ] [ ] if* ] must-infer-as
{ 1 1 } [ [ 1 + ] [ "oops" throw ] if* ] must-infer-as
: strict-each ( seq quot: ( x -- ) -- )
each ; inline
: strict-map ( seq quot: ( x -- x' ) -- seq' )
map ; inline
: strict-2map ( xs ys quot: ( x y -- z ) -- zs )
2map ; inline
{ 1 0 } [ [ drop ] strict-each ] must-infer-as
{ 1 1 } [ [ 1 + ] strict-map ] must-infer-as
{ 1 1 } [ [ ] strict-map ] must-infer-as
{ 2 1 } [ [ + ] strict-2map ] must-infer-as
{ 2 1 } [ [ drop ] strict-2map ] must-infer-as
[ [ [ append ] strict-each ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ 1 + ] strict-2map ] infer ] [ unbalanced-branches-error? ] must-fail-with
! ensure that polymorphic checking works on recursive combinators
FROM: splitting.private => split, ;
{ 2 0 } [ [ member? ] curry split, ] must-infer-as
[ [ [ write write ] each ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ ] each ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ dup ] map ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ drop ] map ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ 1 + ] map-index ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ dup ] [ ] if ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ 2dup ] [ over ] if ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ drop ] [ ] if ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ ] [ ] if* ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ dup ] [ ] if* ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ drop ] [ drop ] if* ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ ] [ drop ] if* ] infer ] [ unbalanced-branches-error? ] must-fail-with
[ [ [ ] [ 2dup ] if* ] infer ] [ unbalanced-branches-error? ] must-fail-with
! M\ declared-effect infer-call* didn't properly unify branches
{ 1 0 } [ [ 1 [ drop ] [ drop ] if ] each ] must-infer-as