0.8.0.3:
[sbcl.git] / src / compiler / info-functions.lisp
index 66a8347..a5abe11 100644 (file)
 
 (in-package "SB!C")
 \f
 
 (in-package "SB!C")
 \f
-;;; Check the legality of a function name that is being introduced.
-;;; -- If it names a macro, then give a warning and blast the macro
-;;;    information.
-;;; -- If it is a structure slot accessor, give a warning and blast 
-;;;    the structure.
-;;; -- Check for conflicting setf macros.
-(declaim (ftype (function ((or symbol cons)) t) proclaim-as-function-name))
-(defun proclaim-as-function-name (name)
-  (check-function-name name)
-  (ecase (info :function :kind name)
-    (:function
-     (let ((accessor-for (info :function :accessor-for name)))
-       (when accessor-for
-        (compiler-warning
-         "Undefining structure type:~%  ~S~@
-          so that this slot accessor can be redefined:~%  ~S"
-         (sb!xc:class-name accessor-for) name)
-        ;; FIXME: This is such weird, unfriendly behavior.. (What if
-        ;; the user didn't want his structure blasted?) It probably
-        ;; violates ANSI, too. (Check this.) Perhaps instead of
-        ;; undefining the structure, we should attach the lost
-        ;; accessor function to SB-EXT:LOST-STRUCTURE-ACCESSORS on
-        ;; the property list of the symbol which names the structure?
-        (undefine-structure accessor-for)
-        (setf (info :function :kind name) :function))))
-    (:macro
-     (compiler-style-warning "~S previously defined as a macro." name)
-     (setf (info :function :kind name) :function)
-     (setf (info :function :where-from name) :assumed)
-     (clear-info :function :macro-function name))
-    ((nil)
-     (setf (info :function :kind name) :function)))
-  (note-if-setf-function-and-macro name)
-  name)
-
-;;; Make NAME no longer be a function name: clear everything back to the
-;;; default.
-(defun undefine-function-name (name)
+;;;; internal utilities defined in terms of INFO
+
+;;; Check that NAME is a valid function name, returning the name if
+;;; OK, and signalling an error if not. In addition to checking for
+;;; basic well-formedness, we also check that symbol names are not NIL
+;;; or the name of a special form.
+(defun check-fun-name (name)
+  (typecase name
+    (list
+     (unless (legal-fun-name-p name)
+       (compiler-error "illegal function name: ~S" name)))
+    (symbol
+     (when (eq (info :function :kind name) :special-form)
+       (compiler-error "Special form is an illegal function name: ~S" name)))
+    (t
+     (compiler-error "illegal function name: ~S" name)))
+  (values))
+
+;;; Record a new function definition, and check its legality.
+(defun proclaim-as-fun-name (name)
+
+  ;; legal name?
+  (check-fun-name name)
+
+  ;; scrubbing old data I: possible collision with old definition
+  (when (fboundp name)
+    (ecase (info :function :kind name)
+      (:function) ; happy case
+      ((nil)) ; another happy case
+      (:macro ; maybe-not-so-good case
+       (compiler-style-warn "~S was previously defined as a macro." name)
+       (setf (info :function :where-from name) :assumed)
+       (clear-info :function :macro-function name))))
+
+  ;; scrubbing old data II: dangling forward references
+  ;;
+  ;; (This could happen if someone executes PROCLAIM FTYPE at
+  ;; macroexpansion time, which is bad style, or at compile time, e.g.
+  ;; in EVAL-WHEN (:COMPILE) inside something like DEFSTRUCT, in which
+  ;; case it's reasonable style. Either way, NAME is no longer a free
+  ;; function.)
+  (when (boundp '*free-funs*) ; when compiling
+    (remhash name *free-funs*))
+
+  ;; recording the ordinary case
+  (setf (info :function :kind name) :function)
+  (note-if-setf-fun-and-macro name)
+
+  (values))
+
+;;; This is called to do something about SETF functions that overlap
+;;; with SETF macros. Perhaps we should interact with the user to see
+;;; whether the macro should be blown away, but for now just give a
+;;; warning. Due to the weak semantics of the (SETF FUNCTION) name, we
+;;; can't assume that they aren't just naming a function (SETF FOO)
+;;; for the heck of it. NAME is already known to be well-formed.
+(defun note-if-setf-fun-and-macro (name)
+  (when (consp name)
+    (when (or (info :setf :inverse name)
+             (info :setf :expander name))
+      (compiler-style-warn
+       "defining as a SETF function a name that already has a SETF macro:~
+       ~%  ~S"
+       name)))
+  (values))
+
+;;; Make NAME no longer be a function name: clear everything back to
+;;; the default.
+(defun undefine-fun-name (name)
   (when name
     (macrolet ((frob (type &optional val)
                 `(unless (eq (info :function ,type name) ,val)
   (when name
     (macrolet ((frob (type &optional val)
                 `(unless (eq (info :function ,type name) ,val)
       (frob :where-from :assumed)
       (frob :inlinep)
       (frob :kind)
       (frob :where-from :assumed)
       (frob :inlinep)
       (frob :kind)
-      (frob :accessor-for)
-      (frob :inline-expansion)
+      (frob :inline-expansion-designator)
       (frob :source-transform)
       (frob :assumed-type)))
   (values))
 
       (frob :source-transform)
       (frob :assumed-type)))
   (values))
 
-;;; part of what happens with DEFUN, also with some PCL stuff:
-;;; Make NAME known to be a function definition.
-(defun become-defined-function-name (name)
-  (proclaim-as-function-name name)
+;;; part of what happens with DEFUN, also with some PCL stuff: Make
+;;; NAME known to be a function definition.
+(defun become-defined-fun-name (name)
+  (proclaim-as-fun-name name)
   (when (eq (info :function :where-from name) :assumed)
     (setf (info :function :where-from name) :defined)
     (if (info :function :assumed-type name)
        (setf (info :function :assumed-type name) nil))))
   (when (eq (info :function :where-from name) :assumed)
     (setf (info :function :where-from name) :defined)
     (if (info :function :assumed-type name)
        (setf (info :function :assumed-type name) nil))))
+
+;;; Decode any raw (INFO :FUNCTION :INLINE-EXPANSION-DESIGNATOR FUN-NAME)
+;;; value into a lambda expression, or return NIL if there is none.
+(declaim (ftype (function ((or symbol cons)) list) fun-name-inline-expansion))
+(defun fun-name-inline-expansion (fun-name)
+  (let ((info (info :function :inline-expansion-designator fun-name)))
+    (if (functionp info)
+       (funcall info)
+       info)))
 \f
 ;;;; ANSI Common Lisp functions which are defined in terms of the info
 ;;;; database
 \f
 ;;;; ANSI Common Lisp functions which are defined in terms of the info
 ;;;; database
   #!+sb-doc
   "True of any Lisp object that has a constant value: types that eval to
   themselves, keywords, constants, and list whose car is QUOTE."
   #!+sb-doc
   "True of any Lisp object that has a constant value: types that eval to
   themselves, keywords, constants, and list whose car is QUOTE."
-  ;; FIXME: Should STRUCTURE-OBJECT and/or STANDARD-OBJECT be here?
-  ;; They eval to themselves..
-  ;;
-  ;; KLUDGE: Someday it might be nice to make the code recognize foldable
+  ;; FIXME: Someday it would be nice to make the code recognize foldable
   ;; functions and call itself recursively on their arguments, so that
   ;; more of the examples in the ANSI CL definition are recognized.
   ;; (e.g. (+ 3 2), (SQRT PI), and (LENGTH '(A B C)))
   (declare (ignore environment))
   (typecase object
   ;; functions and call itself recursively on their arguments, so that
   ;; more of the examples in the ANSI CL definition are recognized.
   ;; (e.g. (+ 3 2), (SQRT PI), and (LENGTH '(A B C)))
   (declare (ignore environment))
   (typecase object
-    (number t)
-    (character t)
-    (array t)
     ;; (Note that the following test on INFO catches KEYWORDs as well as
     ;; explicitly DEFCONSTANT symbols.)
     (symbol (eq (info :variable :kind object) :constant))
     ;; (Note that the following test on INFO catches KEYWORDs as well as
     ;; explicitly DEFCONSTANT symbols.)
     (symbol (eq (info :variable :kind object) :constant))
-    (list (eq (car object) 'quote))))
+    (list (and (eq (car object) 'quote)
+               (consp (cdr object))))
+    (t t)))
+
+(defun constant-form-value (form)
+  (typecase form
+    (symbol (info :variable :constant-value form))
+    ((cons (eql quote) cons)
+     (second form))
+    (t form)))
 
 (declaim (ftype (function (symbol &optional (or null sb!c::lexenv))) sb!xc:macro-function))
 (defun sb!xc:macro-function (symbol &optional env)
 
 (declaim (ftype (function (symbol &optional (or null sb!c::lexenv))) sb!xc:macro-function))
 (defun sb!xc:macro-function (symbol &optional env)
    else returns NIL. If ENV is unspecified or NIL, use the global
    environment only."
   (declare (symbol symbol))
    else returns NIL. If ENV is unspecified or NIL, use the global
    environment only."
   (declare (symbol symbol))
-  (let* ((fenv (when env (sb!c::lexenv-functions env)))
+  (let* ((fenv (when env (sb!c::lexenv-funs env)))
         (local-def (cdr (assoc symbol fenv))))
     (cond (local-def
           (if (and (consp local-def) (eq (car local-def) 'MACRO))
         (local-def (cdr (assoc symbol fenv))))
     (cond (local-def
           (if (and (consp local-def) (eq (car local-def) 'MACRO))
 
 (defun sb!xc:compiler-macro-function (name &optional env)
   #!+sb-doc
 
 (defun sb!xc:compiler-macro-function (name &optional env)
   #!+sb-doc
-  "If NAME names a compiler-macro, returns the expansion function,
-   else returns NIL. Note: if the name is shadowed in ENV by a local
-   definition, or declared NOTINLINE, NIL is returned. Can be
-   set with SETF."
-  (let ((found (and env
-                   (cdr (assoc name (sb!c::lexenv-functions env)
-                               :test #'equal)))))
-    (unless (eq (cond ((sb!c::defined-function-p found)
-                      (sb!c::defined-function-inlinep found))
-                     (found :notinline)
-                     (t
-                      (info :function :inlinep name)))
-               :notinline)
-      (values (info :function :compiler-macro-function name)))))
-(defun (setf sb!xc:compiler-macro-function) (function name)
+  "If NAME names a compiler-macro in ENV, return the expansion function, else
+   return NIL. Can be set with SETF when ENV is NIL."
+  (declare (ignore env))
+  (legal-fun-name-or-type-error name)
+  ;; Note: CMU CL used to return NIL here when a NOTINLINE declaration
+  ;; was in force. That's fairly logical, given the specified effect
+  ;; of NOTINLINE declarations on compiler-macro expansion. However,
+  ;; (1) it doesn't seem to be consistent with the ANSI spec for
+  ;; COMPILER-MACRO-FUNCTION, and (2) it would give surprising
+  ;; behavior for (SETF (COMPILER-MACRO-FUNCTION FOO) ...) in the
+  ;; presence of a (PROCLAIM '(NOTINLINE FOO)). So we don't do it.
+  (values (info :function :compiler-macro-function name)))
+(defun (setf sb!xc:compiler-macro-function) (function name &optional env)
   (declare (type (or symbol list) name)
           (type (or function null) function))
   (declare (type (or symbol list) name)
           (type (or function null) function))
+  (when env
+    ;; ANSI says this operation is undefined.
+    (error "can't SETF COMPILER-MACRO-FUNCTION when ENV is non-NIL"))
   (when (eq (info :function :kind name) :special-form)
     (error "~S names a special form." name))
   (setf (info :function :compiler-macro-function name) function)
   (when (eq (info :function :kind name) :special-form)
     (error "~S names a special form." name))
   (setf (info :function :compiler-macro-function name) function)
         (symbol (values (info :variable :documentation x)))))
       (function
        (cond ((functionp x)
         (symbol (values (info :variable :documentation x)))))
       (function
        (cond ((functionp x)
-             (function-doc x))
-            ((legal-function-name-p x)
+             (%fun-doc x))
+            ((legal-fun-name-p x)
              ;; FIXME: Is it really right to make
              ;; (DOCUMENTATION '(SETF FOO) 'FUNCTION) equivalent to
              ;; (DOCUMENTATION 'FOO 'FUNCTION)? That's what CMU CL
              ;; did, so we do it, but I'm not sure it's what ANSI wants.
              (values (info :function :documentation
              ;; FIXME: Is it really right to make
              ;; (DOCUMENTATION '(SETF FOO) 'FUNCTION) equivalent to
              ;; (DOCUMENTATION 'FOO 'FUNCTION)? That's what CMU CL
              ;; did, so we do it, but I'm not sure it's what ANSI wants.
              (values (info :function :documentation
-                           (function-name-block-name x))))))
+                           (fun-name-block-name x))))))
       (structure
        (typecase x
         (symbol (when (eq (info :type :kind x) :instance)
       (structure
        (typecase x
         (symbol (when (eq (info :type :kind x) :instance)
       (setf (info :setf :documentation x))
       ((t)
        (typecase x
       (setf (info :setf :documentation x))
       ((t)
        (typecase x
-        (function (function-doc x))
+        (function (%fun-doc x))
         (package (package-doc-string x))
         (structure-class (values (info :type :documentation (class-name x))))
         (symbol (try-cmucl-random-doc x doc-type))))
         (package (package-doc-string x))
         (structure-class (values (info :type :documentation (class-name x))))
         (symbol (try-cmucl-random-doc x doc-type))))