4c86f5f19cf5d661447b6e8743e503365697ed29
[sbcl.git] / src / compiler / proclaim.lisp
1 ;;;; This file contains load-time support for declaration processing.
2 ;;;; In CMU CL it was split off from the compiler so that the compiler
3 ;;;; doesn't have to be in the cold load, but in SBCL the compiler is
4 ;;;; in the cold load again, so this might not be valuable.
5
6 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; more information.
8 ;;;;
9 ;;;; This software is derived from the CMU CL system, which was
10 ;;;; written at Carnegie Mellon University and released into the
11 ;;;; public domain. The software is in the public domain and is
12 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
13 ;;;; files for more information.
14
15 (in-package "SB!C")
16
17 ;;; A list of UNDEFINED-WARNING structures representing references to unknown
18 ;;; stuff which came up in a compilation unit.
19 (defvar *undefined-warnings*)
20 (declaim (list *undefined-warnings*))
21
22 ;;; Look up some symbols in *FREE-VARIABLES*, returning the var
23 ;;; structures for any which exist. If any of the names aren't
24 ;;; symbols, we complain.
25 (declaim (ftype (function (list) list) get-old-vars))
26 (defun get-old-vars (names)
27   (collect ((vars))
28     (dolist (name names (vars))
29       (unless (symbolp name)
30         (compiler-error "The name ~S is not a symbol." name))
31       (let ((old (gethash name *free-variables*)))
32         (when old (vars old))))))
33
34 ;;; Return a new POLICY containing the policy information represented
35 ;;; by the optimize declaration SPEC. Any parameters not specified are
36 ;;; defaulted from the POLICY argument.
37 (declaim (ftype (function (list policy) policy) process-optimize-decl))
38 (defun process-optimize-decl (spec policy)
39   (let ((result nil))
40     ;; Add new entries from SPEC.
41     (dolist (q-and-v-or-just-q (cdr spec))
42       (multiple-value-bind (quality raw-value)
43           (if (atom q-and-v-or-just-q)
44               (values q-and-v-or-just-q 3)
45               (destructuring-bind (quality raw-value) q-and-v-or-just-q
46                 (values quality raw-value)))
47         (cond ((not (policy-quality-name-p quality))
48                (compiler-warning "ignoring unknown optimization quality ~
49                                  ~S in ~S"
50                                  quality spec))
51               ((not (and (typep raw-value 'real) (<= 0 raw-value 3)))
52                (compiler-warning "ignoring bad optimization value ~S in ~S"
53                                  raw-value spec))
54               (t
55                (push (cons quality (rational raw-value))
56                      result)))))
57     ;; Add any nonredundant entries from old POLICY.
58     (dolist (old-entry policy)
59       (unless (assq (car old-entry) result)
60         (push old-entry result)))
61     ;; Voila.
62     result))
63
64 ;;; ANSI defines the declaration (FOO X Y) to be equivalent to
65 ;;; (TYPE FOO X Y) when FOO is a type specifier. This function
66 ;;; implements that by converting (FOO X Y) to (TYPE FOO X Y).
67 (defun canonized-decl-spec (decl-spec)
68   (let ((id (first decl-spec)))
69     (unless (symbolp id)
70       (error "The declaration identifier is not a symbol: ~S" id))
71     (let ((id-is-type (info :type :kind id))
72           (id-is-declared-decl (info :declaration :recognized id)))
73       (cond ((and id-is-type id-is-declared-decl)
74              (compiler-error
75               "ambiguous declaration ~S:~%  ~
76               ~S was declared as a DECLARATION, but is also a type name."
77               decl-spec id))
78             (id-is-type
79              (cons 'type decl-spec))
80             (t
81              decl-spec)))))
82
83 (defun sb!xc:proclaim (raw-form)
84   (let* ((form (canonized-decl-spec raw-form))
85          (kind (first form))
86          (args (rest form)))
87     (case kind
88       (special
89        (dolist (name args)
90          (unless (symbolp name)
91            (error "can't declare a non-symbol as SPECIAL: ~S" name))
92          (when (constantp name)
93            (error "can't declare a constant as SPECIAL: ~S" name))
94          (clear-info :variable :constant-value name)
95          (setf (info :variable :kind name) :special)))
96       (type
97        (when *type-system-initialized*
98          (let ((type (specifier-type (first args))))
99            (dolist (name (rest args))
100              (unless (symbolp name)
101                (error "can't declare TYPE of a non-symbol: ~S" name))
102              (when (eq (info :variable :where-from name) :declared)
103                (let ((old-type (info :variable :type name)))
104                  (when (type/= type old-type)
105                    (style-warn "The new TYPE proclamation~%  ~S~@
106                                for ~S does not match the old TYPE~@
107                                proclamation ~S"
108                                type name old-type))))
109              (setf (info :variable :type name) type)
110              (setf (info :variable :where-from name) :declared)))))
111       (ftype
112        ;; FIXME: Since currently *TYPE-SYSTEM-INITIALIZED* is not set
113        ;; until many toplevel forms have run, this condition on
114        ;; PROCLAIM (FTYPE ..) (and on PROCLAIM (TYPE ..), above) means
115        ;; that valid PROCLAIMs in cold code could get lost. Probably
116        ;; the cleanest way to deal with this would be to initialize
117        ;; the type system completely in special cold init forms,
118        ;; before any ordinary toplevel forms run. Failing that, we
119        ;; could queue up PROCLAIMs to be done after the type system is
120        ;; initialized. Failing that, we could at least issue a warning
121        ;; when we have to ignore a PROCLAIM because the type system is
122        ;; uninitialized.
123        (when *type-system-initialized*
124          (let ((type (specifier-type (first args))))
125            (unless (csubtypep type (specifier-type 'function))
126              (error "not a function type: ~S" (first args)))
127            (dolist (name (rest args))
128              (cond ((info :function :accessor-for name)
129                     ;; FIXME: This used to be a WARNING, which was
130                     ;; clearly wrong, since it would cause warnings to
131                     ;; be issued for conforming code, which is really
132                     ;; annoying for people who use Lisp code to build
133                     ;; Lisp systems (and check the return values from
134                     ;; COMPILE and COMPILE-FILE). Changing it to a
135                     ;; compiler note is somewhat better, since it's
136                     ;; after all news about a limitation of the
137                     ;; compiler, not a problem in the code. But even
138                     ;; better would be to handle FTYPE proclamations
139                     ;; for slot accessors, and since in the long run
140                     ;; slot accessors should become more like other
141                     ;; functions, this should eventually become
142                     ;; straightforward.
143                     (maybe-compiler-note
144                      "~@<ignoring FTYPE proclamation for ~
145                       slot accessor (currently unsupported): ~2I~_~S~:>"
146                      name))
147                    (t
148
149                     ;; KLUDGE: Something like the commented-out TYPE/=
150                     ;; check here would be nice, but it has been
151                     ;; commented out because TYPE/= doesn't support
152                     ;; function types. It could probably be made to do
153                     ;; so, but it might take some time, since function
154                     ;; types involve values types, which aren't
155                     ;; supported, and since the SUBTYPEP operator for
156                     ;; FUNCTION types is rather broken, e.g.
157                     ;;   (SUBTYPEP '(FUNCTION (T BOOLEAN) NIL)
158                     ;;             '(FUNCTION (FIXNUM FIXNUM) NIL)) => T, T
159                     ;; -- WHN 20000229
160                     #+nil
161                     (when (eq (info :function :where-from name) :declared)
162                       (let ((old-type (info :function :type name)))
163                         (when (type/= type old-type)
164                           (style-warn
165                            "new FTYPE proclamation~@
166                             ~S~@
167                             for ~S does not match old FTYPE proclamation~@
168                             ~S"
169                            (list type name old-type)))))
170
171                     (proclaim-as-function-name name)
172                     (note-name-defined name :function)
173                     (setf (info :function :type name) type
174                           (info :function :where-from name) :declared)))))))
175       (freeze-type
176        (dolist (type args)
177          (let ((class (specifier-type type)))
178            (when (typep class 'sb!xc:class)
179              (setf (class-state class) :sealed)
180              (let ((subclasses (class-subclasses class)))
181                (when subclasses
182                  (dohash (subclass layout subclasses)
183                    (declare (ignore layout))
184                    (setf (class-state subclass) :sealed))))))))
185       (optimize
186        (setq *policy* (process-optimize-decl form *policy*)))
187       ((inline notinline maybe-inline)
188        (dolist (name args)
189          ;; (CMU CL did (PROCLAIM-AS-FUNCTION-NAME NAME) here, but that
190          ;; seems more likely to surprise the user than to help him, so
191          ;; we don't do it.)
192          (setf (info :function :inlinep name)
193                (ecase kind
194                  (inline :inline)
195                  (notinline :notinline)
196                  (maybe-inline :maybe-inline)))))
197       (declaration
198        (dolist (decl args)
199          (unless (symbolp decl)
200            (error "In~%  ~S~%the declaration to be recognized is not a ~
201                   symbol:~%  ~S"
202                   form decl))
203          (setf (info :declaration :recognized decl) t)))
204       (t
205        (unless (info :declaration :recognized kind)
206          (compiler-warning "unrecognized declaration ~S" raw-form)))))
207   (values))