1.0.47.8: No more INSTANCE-LAMBDA
[sbcl.git] / src / compiler / ir1tran-lambda.lisp
index b107a41..3374deb 100644 (file)
 ;;; If it is losing, we punt with a COMPILER-ERROR. NAMES-SO-FAR is a
 ;;; list of names which have previously been bound. If the NAME is in
 ;;; this list, then we error out.
-(declaim (ftype (sfunction (t list) lambda-var) varify-lambda-arg))
-(defun varify-lambda-arg (name names-so-far)
+(declaim (ftype (sfunction (t list &optional t) lambda-var) varify-lambda-arg))
+(defun varify-lambda-arg (name names-so-far &optional (context "lambda list"))
   (declare (inline member))
   (unless (symbolp name)
-    (compiler-error "The lambda variable ~S is not a symbol." name))
+    (compiler-error "~S is not a symbol, and cannot be used as a variable." name))
   (when (member name names-so-far :test #'eq)
-    (compiler-error "The variable ~S occurs more than once in the lambda list."
-                    name))
+    (compiler-error "The variable ~S occurs more than once in the ~A."
+                    name
+                    context))
   (let ((kind (info :variable :kind name)))
-    (when (or (keywordp name) (eq kind :constant))
-      (compiler-error "The name of the lambda variable ~S is already in use to name a constant."
-                      name))
-    (cond ((eq kind :special)
+    (cond ((keywordp name)
+           (compiler-error "~S is a keyword, and cannot be used as a local variable."
+                           name))
+          ((eq kind :constant)
+           (compiler-error "~@<~S names a defined constant, and cannot be used as a ~
+                            local variable.~:@>"
+                           name))
+          ((eq :global kind)
+           (compiler-error "~@<~S names a global lexical variable, and cannot be used ~
+                            as a local variable.~:@>"
+                           name))
+          ((eq kind :special)
            (let ((specvar (find-free-var name)))
              (make-lambda-var :%source-name name
                               :type (leaf-type specvar)
     (setf debug-name (name-lambdalike form)))
   (multiple-value-bind (vars keyp allow-other-keys aux-vars aux-vals)
       (make-lambda-vars (cadr form))
-    (multiple-value-bind (forms decls) (parse-body (cddr form))
+    (multiple-value-bind (forms decls doc) (parse-body (cddr form))
       (binding* (((*lexenv* result-type post-binding-lexenv)
                   (process-decls decls (append aux-vars vars) nil
                                  :binding-form-p t))
                                                       :system-lambda system-lambda)))))
         (setf (functional-inline-expansion res) form)
         (setf (functional-arg-documentation res) (cadr form))
+        (setf (functional-documentation res) doc)
         (when (boundp '*lambda-conversions*)
           ;; KLUDGE: Not counting TL-XEPs is a lie, of course, but
           ;; keeps things less confusing to users of TIME, where this
                          :maybe-add-debug-catch t
                          :source-name source-name
                          :debug-name debug-name))
-    ((instance-lambda)
-     (deprecation-warning 'instance-lambda 'lambda)
-     (ir1-convert-lambda `(lambda ,@(cdr thing))
-                         :source-name source-name
-                         :debug-name debug-name))
     ((named-lambda)
      (let ((name (cadr thing))
            (lambda-expression `(lambda ,@(cddr thing))))
        (if (and name (legal-fun-name-p name))
-           (let ((defined-fun-res (get-defined-fun name))
+           (let ((defined-fun-res (get-defined-fun name (second lambda-expression)))
                  (res (ir1-convert-lambda lambda-expression
                                           :maybe-add-debug-catch t
                                           :source-name name)))
       (setf (functional-inline-expanded clambda) t)
       clambda)))
 
+;;; Given a lambda-list, return a FUN-TYPE object representing the signature:
+;;; return type is *, and each individual arguments type is T -- but we get
+;;; the argument counts and keywords.
+(defun ftype-from-lambda-list (lambda-list)
+  (multiple-value-bind (req opt restp rest-name keyp key-list allowp morep)
+      (parse-lambda-list lambda-list)
+    (declare (ignore rest-name))
+    (flet ((t (list)
+             (mapcar (constantly t) list)))
+      (let ((reqs (t req))
+            (opts (when opt (cons '&optional (t opt))))
+            ;; When it comes to building a type, &REST means pretty much the
+            ;; same thing as &MORE.
+            (rest (when (or morep restp) (list '&rest t)))
+            (keys (when keyp
+                    (cons '&key (mapcar (lambda (spec)
+                                          (let ((key/var (if (consp spec)
+                                                             (car spec)
+                                                             spec)))
+                                            (list (if (consp key/var)
+                                                      (car key/var)
+                                                      (keywordicate key/var))
+                                                  t)))
+                                        key-list))))
+            (allow (when allowp (list '&allow-other-keys))))
+        (specifier-type `(function (,@reqs ,@opts ,@rest ,@keys ,@allow) *))))))
+
 ;;; Get a DEFINED-FUN object for a function we are about to define. If
 ;;; the function has been forward referenced, then substitute for the
 ;;; previous references.
-(defun get-defined-fun (name)
+(defun get-defined-fun (name &optional (lambda-list nil lp))
   (proclaim-as-fun-name name)
-  (let ((found (find-free-fun name "shouldn't happen! (defined-fun)")))
-    (note-name-defined name :function)
-    (cond ((not (defined-fun-p found))
-           (aver (not (info :function :inlinep name)))
-           (let* ((where-from (leaf-where-from found))
-                  (res (make-defined-fun
-                        :%source-name name
-                        :where-from (if (eq where-from :declared)
-                                        :declared :defined)
-                        :type (leaf-type found))))
-             (substitute-leaf res found)
-             (setf (gethash name *free-funs*) res)))
-          ;; If *FREE-FUNS* has a previously converted definition
-          ;; for this name, then blow it away and try again.
-          ((defined-fun-functionals found)
-           (remhash name *free-funs*)
-           (get-defined-fun name))
-          (t found))))
+  (when (boundp '*free-funs*)
+    (let ((found (find-free-fun name "shouldn't happen! (defined-fun)")))
+      (note-name-defined name :function)
+      (cond ((not (defined-fun-p found))
+             (aver (not (info :function :inlinep name)))
+             (let* ((where-from (leaf-where-from found))
+                    (res (make-defined-fun
+                          :%source-name name
+                          :where-from (if (eq where-from :declared)
+                                          :declared
+                                          :defined-here)
+                          :type (if (eq :declared where-from)
+                                    (leaf-type found)
+                                    (if lp
+                                        (ftype-from-lambda-list lambda-list)
+                                        (specifier-type 'function))))))
+               (substitute-leaf res found)
+               (setf (gethash name *free-funs*) res)))
+            ;; If *FREE-FUNS* has a previously converted definition
+            ;; for this name, then blow it away and try again.
+            ((defined-fun-functionals found)
+             (remhash name *free-funs*)
+             (get-defined-fun name lambda-list))
+            (t found)))))
 
 ;;; Check a new global function definition for consistency with
 ;;; previous declaration or definition, and assert argument/result
     (setf (functional-inlinep fun) inlinep)
     (assert-new-definition var fun)
     (setf (defined-fun-inline-expansion var) expansion)
+    ;; Associate VAR with the FUN -- and in case of an optional dispatch
+    ;; with the various entry-points. This allows XREF to know where the
+    ;; inline CLAMBDA comes from.
+    (flet ((note-inlining (f)
+             (typecase f
+               (functional
+                (setf (functional-inline-expanded f) var))
+               (cons
+                ;; Delayed entry-point.
+                (if (car f)
+                    (setf (functional-inline-expanded (cdr f)) var)
+                    (let ((old-thunk (cdr f)))
+                      (setf (cdr f) (lambda ()
+                                      (let ((g (funcall old-thunk)))
+                                        (setf (functional-inline-expanded g) var)
+                                        g)))))))))
+      (note-inlining fun)
+      (when (optional-dispatch-p fun)
+        (note-inlining (optional-dispatch-main-entry fun))
+        (note-inlining (optional-dispatch-more-entry fun))
+        (mapc #'note-inlining (optional-dispatch-entry-points fun))))
     ;; substitute for any old references
     (unless (or (not *block-compile*)
                 (and info
 (defun %compiler-defun (name lambda-with-lexenv compile-toplevel)
   (let ((defined-fun nil)) ; will be set below if we're in the compiler
     (when compile-toplevel
-      ;; better be in the compiler
-      (aver (boundp '*lexenv*))
-      (remhash name *free-funs*)
-      (setf defined-fun (get-defined-fun name))
-      (aver (fasl-output-p *compile-object*))
-      (if (member name *fun-names-in-this-file* :test #'equal)
-          (warn 'duplicate-definition :name name)
-          (push name *fun-names-in-this-file*)))
+      (setf defined-fun (if lambda-with-lexenv
+                            (get-defined-fun name (fifth lambda-with-lexenv))
+                            (get-defined-fun name)))
+      (when (boundp '*lexenv*)
+        (remhash name *free-funs*)
+        (aver (fasl-output-p *compile-object*))
+        (if (member name *fun-names-in-this-file* :test #'equal)
+            (warn 'duplicate-definition :name name)
+            (push name *fun-names-in-this-file*))))
 
     (become-defined-fun-name name)
 
     ;; old CMU CL comment:
     ;;   If there is a type from a previous definition, blast it,
     ;;   since it is obsolete.
-    (when (and defined-fun
-               (eq (leaf-where-from defined-fun) :defined))
+    (when (and defined-fun (neq :declared (leaf-where-from defined-fun)))
       (setf (leaf-type defined-fun)
             ;; FIXME: If this is a block compilation thing, shouldn't
             ;; we be setting the type to the full derived type for the