would be to put the check between evaluation of arguments, but it
could be tricky to check result types of PROG1, IF etc.
-228: "function-lambda-expression problems"
- in sbcl-0.7.9.6x, from the REPL:
- * (progn (declaim (inline foo)) (defun foo (x) x))
- FOO
- * (function-lambda-expression #'foo)
- (SB-C:LAMBDA-WITH-LEXENV NIL NIL NIL (X) (BLOCK FOO X)), NIL, FOO
- but this first return value is not suitable for input to FUNCTION or
- COMPILE, as required by ANSI.
-
229:
(subtypep 'function '(function)) => nil, t.
* fixed bug 157: TYPEP, SUBTYPEP, UPGRADED-ARRAY-ELEMENT-TYPE and
UPGRADED-COMPLEX-PART-TYPE now take (ignored, in all situations)
optional environment arguments, as required by ANSI.
+ * fixed bug 228: primary return values from
+ FUNCTION-LAMBDA-EXPRESSION are either NIL or suitable for input to
+ COMPILE or FUNCTION.
* fixed bugs in other functions taking environment objects, allowing
calls with an explicit NIL environment argument to be compiled
without error.
(defmacro-mundanely lambda (&whole whole args &body body)
(declare (ignore args body))
`#',whole)
+
+(defmacro-mundanely named-lambda (&whole whole name args &body body)
+ (declare (ignore name args body))
+ `#',whole)
+
+(defmacro-mundanely lambda-with-lexenv (&whole whole
+ declarations macros symbol-macros
+ &body body)
+ (declare (ignore declarations macros symbol-macros body))
+ `#',whole)
(values (svref (sb!c::debug-source-name source) 0)
nil
name))
+ ;; FIXME: shouldn't these two clauses be the other way
+ ;; round? Using VALID-FUNCTION-NAME-P to see if we
+ ;; want to find an inline-expansion?
((stringp name)
(values nil t name))
(t
be a lambda expression."
(if (consp thing)
(case (car thing)
- ((lambda)
+ ((lambda named-lambda instance-lambda lambda-with-lexenv)
(reference-leaf start
cont
- (ir1-convert-lambda thing
- :debug-name (debug-namify
- "#'~S" thing)
- :allow-debug-catch-tag t)))
+ (ir1-convert-lambdalike
+ thing
+ :debug-name (debug-namify "#'~S" thing)
+ :allow-debug-catch-tag t)))
((setf)
(let ((var (find-lexically-apparent-fun
thing "as the argument to FUNCTION")))
(reference-leaf start cont var)))
- ((instance-lambda)
- (let ((res (ir1-convert-lambda `(lambda ,@(cdr thing))
- :debug-name (debug-namify "#'~S"
- thing)
- :allow-debug-catch-tag t)))
- (setf (getf (functional-plist res) :fin-function) t)
- (reference-leaf start cont res)))
(t
(compiler-error "~S is not a legal function name." thing)))
(let ((var (find-lexically-apparent-fun
thing "as the argument to FUNCTION")))
(reference-leaf start cont var))))
-
-;;; `(NAMED-LAMBDA ,NAME ,@REST) is like `(FUNCTION (LAMBDA ,@REST)),
-;;; except that the value of NAME is passed to the compiler for use in
-;;; creation of debug information for the resulting function.
-;;;
-;;; NAME can be a legal function name or some arbitrary other thing.
-;;;
-;;; If NAME is a legal function name, then the caller should be
-;;; planning to set (FDEFINITION NAME) to the created function.
-;;; (Otherwise the debug names will be inconsistent and thus
-;;; unnecessarily confusing.)
-;;;
-;;; Arbitrary other things are appropriate for naming things which are
-;;; not the FDEFINITION of NAME. E.g.
-;;; NAME = (:FLET FOO BAR)
-;;; for the FLET function in
-;;; (DEFUN BAR (X)
-;;; (FLET ((FOO (Y) (+ X Y)))
-;;; FOO))
-;;; or
-;;; NAME = (:METHOD PRINT-OBJECT :AROUND (STARSHIP T))
-;;; for the function used to implement
-;;; (DEFMETHOD PRINT-OBJECT :AROUND ((SS STARSHIP) STREAM) ...).
-(def-ir1-translator named-lambda ((name &rest rest) start cont)
- (let* ((fun (if (legal-fun-name-p name)
- (ir1-convert-lambda `(lambda ,@rest)
- :source-name name
- :allow-debug-catch-tag t)
- (ir1-convert-lambda `(lambda ,@rest)
- :debug-name name
- :allow-debug-catch-tag t)))
- (leaf (reference-leaf start cont fun)))
- (when (legal-fun-name-p name)
- (assert-global-function-definition-type name fun))
- leaf))
\f
;;;; FUNCALL
(setf (functional-inline-expansion res) form)
(setf (functional-arg-documentation res) (cadr form))
res)))))
+
+;;; helper for LAMBDA-like things, to massage them into a form
+;;; suitable for IR1-CONVERT-LAMBDA.
+;;;
+;;; KLUDGE: We cons up a &REST list here, maybe for no particularly
+;;; good reason. It's probably lost in the noise of all the other
+;;; consing, but it's still inelegant. And we force our called
+;;; functions to do full runtime keyword parsing, ugh. -- CSR,
+;;; 2003-01-25
+(defun ir1-convert-lambdalike (thing &rest args
+ &key (source-name '.anonymous.)
+ debug-name allow-debug-catch-tag)
+ (ecase (car thing)
+ ((lambda) (apply #'ir1-convert-lambda thing args))
+ ((instance-lambda)
+ (let ((res (apply #'ir1-convert-lambda
+ `(lambda ,@(cdr thing)) args)))
+ (setf (getf (functional-plist res) :fin-function) t)
+ res))
+ ((named-lambda)
+ (let ((name (cadr thing)))
+ (if (legal-fun-name-p name)
+ (let ((res (apply #'ir1-convert-lambda `(lambda ,@(cddr thing))
+ :source-name name
+ :debug-name nil
+ args)))
+ (assert-global-function-definition-type name res)
+ res)
+ (apply #'ir1-convert-lambda `(lambda ,@(cddr thing))
+ :debug-name name args))))
+ ((lambda-with-lexenv) (apply #'ir1-convert-inline-lambda thing args))))
\f
;;;; defining global functions
;;; reflect the state at the definition site.
(defun ir1-convert-inline-lambda (fun &key
(source-name '.anonymous.)
- debug-name)
+ debug-name
+ allow-debug-catch-tag)
(destructuring-bind (decls macros symbol-macros &rest body)
(if (eq (car fun) 'lambda-with-lexenv)
(cdr fun)
:policy (lexenv-policy *lexenv*))))
(ir1-convert-lambda `(lambda ,@body)
:source-name source-name
- :debug-name debug-name))))
+ :debug-name debug-name
+ :allow-debug-catch-tag nil))))
;;; Get a DEFINED-FUN object for a function we are about to define. If
;;; the function has been forward referenced, then substitute for the
(setf (component-name component)
(debug-namify "~S initial component" name))
(setf (component-kind component) :initial)
- (let* ((locall-fun (ir1-convert-lambda
+ (let* ((locall-fun (ir1-convert-lambdalike
definition
:debug-name (debug-namify "top level local call ~S"
name)
;; Unlike the SOURCE-NAME slot, this slot's value should never
;; affect ordinary code behavior, only debugging/diagnostic behavior.
;;
+ ;; Ha. Ah, the starry-eyed idealism of the writer of the above
+ ;; paragraph. FUNCTION-LAMBDA-EXPRESSION's behaviour, as of
+ ;; sbcl-0.7.11.x, differs if the name of the a function is a string
+ ;; or not, as if it is a valid function name then it can look for an
+ ;; inline expansion.
+ ;;
;; The value of this slot can be anything, except that it shouldn't
;; be a legal function name, since otherwise debugging gets
;; confusing. (If a legal function name is a good name for the
(declare (type (vector (unsigned-byte 8)) x))
(setq *y* (the (unsigned-byte 8) (aref x 4))))
\f
+;;; FUNCTION-LAMBDA-EXPRESSION should return something that's COMPILE
+;;; can understand. Here's a simple test for that on a function
+;;; that's likely to return a hairier list than just a lambda:
+(macrolet ((def (fn) `(progn
+ (declaim (inline ,fn))
+ (defun ,fn (x) (1+ x)))))
+ (def bug228))
+(let ((x (function-lambda-expression #'bug228)))
+ (when x
+ (assert (= (funcall (compile nil x) 1) 2))))
+
;;;; tests not in the problem domain, but of the consistency of the
;;;; compiler machinery itself
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.7.12.6"
+"0.7.12.7"