From: Robert B. <br...@go...> - 2004-06-04 17:41:03
|
I'm curious to know what the difference is between the following two different ways of defining an identity function with a restricted domain and range: (defun foo (x) (the (unsigned-byte 29) x)) (declaim (ftype (function ((unsigned-byte 29)) (unsigned-byte 29)) bar)) (defun bar (x) x) SBCL complains as follows when compiling BAR: ; in: LAMBDA NIL ; (SB-INT:NAMED-LAMBDA BAR (X) (BLOCK BAR X)) ; ==> ; #'(SB-INT:NAMED-LAMBDA BAR (X) (BLOCK BAR X)) ; ; note: type assertion too complex to check: ; (VALUES (UNSIGNED-BYTE 29) &REST T). Initially, it was unclear to me from the message text whether the argument or the return type was the problem. After experimenting a bit, I believe SBCL is complaining about the type check of the value BAR returns. My understanding (probably flawed), is that the FTYPE declaration for BAR is a promise to the compiler that I will never define or redefine BAR with argument or return types that are in conflict with those specified in the FTYPE declaration. By "in conflict" I mean types that would cause the compiler's previous assumptions about BAR to be invalid. Anyway, SBCL compiles FOO without warnings, and does range check the return value, so it seems capable of verify an (unsigned-byte 29) type at run time. Why does it say the same type assertion is too complex when compiling BAR? How should I write the function? Should I avoid FTYPE declarations completely and write: (defun baz (x) (declare (type (unsigned-byte 29) x)) (the (unsigned-byte 29) x)) In general, of course, I'm not really concerned with the identity function, but with more general functions that take several integer arguments and return an integer result. I want to give the compiler the maximum amount of type information, so that it can generate efficient code. bob |
From: Alexey D. <ade...@co...> - 2004-06-04 18:23:29
|
Hello, Robert Brown <br...@go...> writes: > I'm curious to know what the difference is between the following two > different ways of defining an identity function with a restricted domain and > range: > > (defun foo (x) (the (unsigned-byte 29) x)) > > (declaim (ftype (function ((unsigned-byte 29)) (unsigned-byte 29)) bar)) > (defun bar (x) x) The compiler cannot use the _derived_ [from your definition :-)] type of FOO in a call of FOO, but can use the _declared_ type of BAR in its call. > SBCL complains as follows when compiling BAR: > > ; in: LAMBDA NIL > ; (SB-INT:NAMED-LAMBDA BAR (X) (BLOCK BAR X)) > ; ==> > ; #'(SB-INT:NAMED-LAMBDA BAR (X) (BLOCK BAR X)) > ; > ; note: type assertion too complex to check: > ; (VALUES (UNSIGNED-BYTE 29) &REST T). It depends on DEBUG optimization setting (to be more precise, on SB-C::INSERT-DEBUG-CATCH as reported by SB-EXT:DESCRIBE-COMPILER-POLICY). With high level, the function is equivalent to (defun bar (x) (catch (generate-debug-catch-tag) x)) and, with FTYPE declaration, to (defun bar (x) (the ub29 (catch (generate-debug-catch-tag) (the ub29 x)))) CATCH may return any number of values, and so may BAR. Current SBCL does not try to check types and preserve the number of returned values. You can declare the returned type to be (VALUES UB29 &OPTIONAL). It tells that exactly one value must be returned. The compiler will not check the number of values, but will check the type of the first one. -- Regards, Alexey Dejneka "Alas, the spheres of truth are less transparent than those of illusion." -- L.E.J. Brouwer |
From: Robert B. <br...@go...> - 2004-06-07 14:40:37
|
Thanks very much for the explanation. It appears that I was doing nothing wrong, other than specifying (debug 3) when loading code with FTYPE declarations. I think the compiler's behavior should be listed as a bug in the BUGS file. All I did was increase the debugging level, while loading code that is essentially correct. Now the compiler is generating tons of "type assertion too complex to check" messages, which obscure the messages for real bugs in my code. Basically, debug level 3 is not usable because of the spurious messages. However, maybe debug 3 is only intended for some specialized purpose, and I should be using debug 2 for "normal" testing and coding. bob ==================== Alexey Dejneka writes: > Robert Brown <br...@go...> writes: > > I'm curious to know what the difference is between the following two > > different ways of defining an identity function with a restricted > > domain and range: > > > > (defun foo (x) (the (unsigned-byte 29) x)) > > > > (declaim (ftype (function ((unsigned-byte 29)) (unsigned-byte 29)) bar)) > > (defun bar (x) x) > > The compiler cannot use the _derived_ [from your definition :-)] type > of FOO in a call of FOO, but can use the _declared_ type of BAR in its > call. > > > SBCL complains as follows when compiling BAR: > > > > ; in: LAMBDA NIL > > ; (SB-INT:NAMED-LAMBDA BAR (X) (BLOCK BAR X)) > > ; ==> > > ; #'(SB-INT:NAMED-LAMBDA BAR (X) (BLOCK BAR X)) > > ; > > ; note: type assertion too complex to check: > > ; (VALUES (UNSIGNED-BYTE 29) &REST T). > > It depends on DEBUG optimization setting (to be more precise, on > SB-C::INSERT-DEBUG-CATCH as reported by > SB-EXT:DESCRIBE-COMPILER-POLICY). With high level, the function is > equivalent to > > (defun bar (x) (catch (generate-debug-catch-tag) x)) > > and, with FTYPE declaration, to > > (defun bar (x) (the ub29 (catch (generate-debug-catch-tag) (the ub29 x)))) > > CATCH may return any number of values, and so may BAR. Current SBCL > does not try to check types and preserve the number of returned > values. You can declare the returned type to be (VALUES UB29 > &OPTIONAL). It tells that exactly one value must be returned. The > compiler will not check the number of values, but will check the type > of the first one. |