57ad8243e0f76c25def4d4e4926a8065f8c8a0da
[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-VARS*, 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-vars*)))
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-warn "ignoring unknown optimization quality ~
49                                ~S in ~S"
50                                quality spec))
51               ((not (typep raw-value 'policy-quality))
52                (compiler-warn "ignoring bad optimization value ~S in ~S"
53                               raw-value spec))
54               (t
55                ;; we can't do this yet, because CLOS macros expand
56                ;; into code containing INHIBIT-WARNINGS.
57                #+nil
58                (when (eql quality 'sb!ext:inhibit-warnings)
59                  (compiler-style-warn "~S is deprecated: use ~S instead"
60                                       quality 'sb!ext:muffle-conditions))
61                (push (cons quality raw-value)
62                      result)))))
63     ;; Add any nonredundant entries from old POLICY.
64     (dolist (old-entry policy)
65       (unless (assq (car old-entry) result)
66         (push old-entry result)))
67     ;; Voila.
68     result))
69
70 (declaim (ftype (function (list list) list)
71                 process-handle-conditions-decl))
72 (defun process-handle-conditions-decl (spec list)
73   (let ((new (copy-alist list)))
74     (dolist (clause (cdr spec))
75       (destructuring-bind (typespec restart-name) clause
76         (let ((ospec (rassoc restart-name new :test #'eq)))
77           (if ospec
78               (setf (car ospec)
79                     (type-specifier
80                      (type-union (specifier-type (car ospec))
81                                  (specifier-type typespec))))
82               (push (cons (type-specifier (specifier-type typespec))
83                           restart-name)
84                     new)))))
85     new))
86 (declaim (ftype (function (list list) list)
87                 process-muffle-conditions-decl))
88 (defun process-muffle-conditions-decl (spec list)
89   (process-handle-conditions-decl
90    (cons 'handle-conditions
91          (mapcar (lambda (x) (list x 'muffle-warning)) (cdr spec)))
92    list))
93
94 (declaim (ftype (function (list list) list)
95                 process-unhandle-conditions-decl))
96 (defun process-unhandle-conditions-decl (spec list)
97   (let ((new (copy-alist list)))
98     (dolist (clause (cdr spec))
99       (destructuring-bind (typespec restart-name) clause
100         (let ((ospec (rassoc restart-name new :test #'eq)))
101           (if ospec
102               (let ((type-specifier
103                      (type-specifier
104                       (type-intersection
105                        (specifier-type (car ospec))
106                        (specifier-type `(not ,typespec))))))
107                 (if type-specifier
108                     (setf (car ospec) type-specifier)
109                     (setq new
110                           (delete restart-name new :test #'eq :key #'cdr))))
111               ;; do nothing?
112               nil))))
113     new))
114 (declaim (ftype (function (list list) list)
115                 process-unmuffle-conditions-decl))
116 (defun process-unmuffle-conditions-decl (spec list)
117   (process-unhandle-conditions-decl
118    (cons 'unhandle-conditions
119          (mapcar (lambda (x) (list x 'muffle-warning)) (cdr spec)))
120    list))
121
122 (declaim (ftype (function (list list) list)
123                 process-package-lock-decl))
124 (defun process-package-lock-decl (spec old)
125   (let ((decl (car spec))
126         (list (cdr spec)))
127     (ecase decl
128       (disable-package-locks
129        (union old list :test #'equal))
130       (enable-package-locks
131        (set-difference old list :test #'equal)))))
132
133 ;;; ANSI defines the declaration (FOO X Y) to be equivalent to
134 ;;; (TYPE FOO X Y) when FOO is a type specifier. This function
135 ;;; implements that by converting (FOO X Y) to (TYPE FOO X Y).
136 (defun canonized-decl-spec (decl-spec)
137   (let ((id (first decl-spec)))
138     (let ((id-is-type (if (symbolp id)
139                           (info :type :kind id)
140                           ;; A cons might not be a valid type specifier,
141                           ;; but it can't be a declaration either.
142                           (or (consp id)
143                               (typep id 'class))))
144           (id-is-declared-decl (info :declaration :recognized id)))
145       ;; FIXME: Checking ID-IS-DECLARED is probably useless these days,
146       ;; since we refuse to use the same symbol as both a type name and
147       ;; recognized declaration name.
148       (cond ((and id-is-type id-is-declared-decl)
149              (compiler-error
150               "ambiguous declaration ~S:~%  ~
151               ~S was declared as a DECLARATION, but is also a type name."
152               decl-spec id))
153             (id-is-type
154              (cons 'type decl-spec))
155             (t
156              decl-spec)))))
157
158 (defvar *queued-proclaims*) ; initialized in !COLD-INIT-FORMS
159
160 (!begin-collecting-cold-init-forms)
161 (!cold-init-forms (setf *queued-proclaims* nil))
162 (!defun-from-collected-cold-init-forms !early-proclaim-cold-init)
163
164 (defun sb!xc:proclaim (raw-form)
165   #+sb-xc (/show0 "entering PROCLAIM, RAW-FORM=..")
166   #+sb-xc (/hexstr raw-form)
167   (let* ((form (canonized-decl-spec raw-form))
168          (kind (first form))
169          (args (rest form)))
170     (case kind
171       (special
172        (dolist (name args)
173          (unless (symbolp name)
174            (error "can't declare a non-symbol as SPECIAL: ~S" name))
175          (when (sb!xc:constantp name)
176            (error "can't declare a constant as SPECIAL: ~S" name))
177          (with-single-package-locked-error
178              (:symbol name "globally declaring ~A special"))
179          (clear-info :variable :constant-value name)
180          (setf (info :variable :kind name) :special)))
181       (type
182        (if *type-system-initialized*
183            (let ((type (specifier-type (first args))))
184              (dolist (name (rest args))
185                (unless (symbolp name)
186                  (error "can't declare TYPE of a non-symbol: ~S" name))
187                (with-single-package-locked-error
188                    (:symbol name "globally declaring the type of ~A"))
189                (when (eq (info :variable :where-from name) :declared)
190                  (let ((old-type (info :variable :type name)))
191                    (when (type/= type old-type)
192                      (style-warn "The new TYPE proclamation~%  ~S~@
193                                   for ~S does not match the old TYPE~@
194                                   proclamation ~S"
195                                  type name old-type))))
196                (setf (info :variable :type name) type)
197                (setf (info :variable :where-from name) :declared)))
198            (push raw-form *queued-proclaims*)))
199       (ftype
200        (if *type-system-initialized*
201            (let ((ctype (specifier-type (first args))))
202              (unless (csubtypep ctype (specifier-type 'function))
203                (error "not a function type: ~S" (first args)))
204              (dolist (name (rest args))
205                (with-single-package-locked-error
206                    (:symbol name "globally declaring the ftype of ~A"))
207                (when (eq (info :function :where-from name) :declared)
208                  (let ((old-type (info :function :type name)))
209                    (when (type/= ctype old-type)
210                      (style-warn
211                       "new FTYPE proclamation~@
212                        ~S~@
213                        for ~S does not match old FTYPE proclamation~@
214                        ~S"
215                       ctype name old-type))))
216
217                ;; Now references to this function shouldn't be warned
218                ;; about as undefined, since even if we haven't seen a
219                ;; definition yet, we know one is planned.
220                ;;
221                ;; Other consequences of we-know-you're-a-function-now
222                ;; are appropriate too, e.g. any MACRO-FUNCTION goes away.
223                (proclaim-as-fun-name name)
224                (note-name-defined name :function)
225
226                ;; the actual type declaration
227                (setf (info :function :type name) ctype
228                      (info :function :where-from name) :declared)))
229            (push raw-form *queued-proclaims*)))
230       (freeze-type
231        (dolist (type args)
232          (let ((class (specifier-type type)))
233            (when (typep class 'classoid)
234              (setf (classoid-state class) :sealed)
235              (let ((subclasses (classoid-subclasses class)))
236                (when subclasses
237                  (dohash ((subclass layout) subclasses :locked t)
238                    (declare (ignore layout))
239                    (setf (classoid-state subclass) :sealed))))))))
240       (optimize
241        (setq *policy* (process-optimize-decl form *policy*)))
242       (muffle-conditions
243        (setq *handled-conditions*
244              (process-muffle-conditions-decl form *handled-conditions*)))
245       (unmuffle-conditions
246        (setq *handled-conditions*
247              (process-unmuffle-conditions-decl form *handled-conditions*)))
248       ((disable-package-locks enable-package-locks)
249          (setq *disabled-package-locks*
250                (process-package-lock-decl form *disabled-package-locks*)))
251       ((inline notinline maybe-inline)
252        (dolist (name args)
253          (proclaim-as-fun-name name) ; since implicitly it is a function
254          (setf (info :function :inlinep name)
255                (ecase kind
256                  (inline :inline)
257                  (notinline :notinline)
258                  (maybe-inline :maybe-inline)))))
259       (declaration
260        (dolist (decl args)
261          (unless (symbolp decl)
262            (error "In~%  ~S~%the declaration to be recognized is not a ~
263                   symbol:~%  ~S"
264                   form decl))
265          (with-single-package-locked-error
266              (:symbol decl "globally declaring ~A as a declaration proclamation"))
267          (setf (info :declaration :recognized decl) t)))
268       (t
269        (unless (info :declaration :recognized kind)
270          (compiler-warn "unrecognized declaration ~S" raw-form)))))
271   #+sb-xc (/show0 "returning from PROCLAIM")
272   (values))