Simplify ALWAYS-BOUND usage.
[sbcl.git] / src / compiler / proclaim.lisp
bloba93204c2ec5d747a5d8efbdfd2a16d557004ebf1
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.
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.
15 (in-package "SB!C")
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*))
22 (declaim (ftype (function (list list) list)
23 process-handle-conditions-decl))
24 (defun process-handle-conditions-decl (spec list)
25 (let ((new (copy-alist list)))
26 (dolist (clause (cdr spec) new)
27 (destructuring-bind (typespec restart-name) clause
28 (let ((type (compiler-specifier-type typespec))
29 (ospec (rassoc restart-name new :test #'eq)))
30 (cond ((not type))
31 (ospec
32 (setf (car ospec) (type-union (car ospec) type)))
34 (push (cons type restart-name) new))))))))
36 (declaim (ftype (function (list list) list)
37 process-muffle-conditions-decl))
38 (defun process-muffle-conditions-decl (spec list)
39 (process-handle-conditions-decl
40 `(handle-conditions ((or ,@(cdr spec)) muffle-warning))
41 list))
43 (declaim (ftype (function (list list) list)
44 process-unhandle-conditions-decl))
45 (defun process-unhandle-conditions-decl (spec list)
46 (let ((new (copy-alist list)))
47 (dolist (clause (cdr spec) new)
48 (block nil
49 (destructuring-bind (typespec restart-name) clause
50 (let ((ospec (rassoc restart-name new :test #'eq)))
51 (when ospec
52 (let ((type (type-intersection
53 (car ospec)
54 (or (compiler-specifier-type `(not ,typespec))
55 (return)))))
56 (if (type= type *empty-type*)
57 (setq new (delete restart-name new :test #'eq :key #'cdr))
58 (setf (car ospec) type))))))))))
60 (declaim (ftype (function (list list) list)
61 process-unmuffle-conditions-decl))
62 (defun process-unmuffle-conditions-decl (spec list)
63 (process-unhandle-conditions-decl
64 `(unhandle-conditions ((or ,@(cdr spec)) muffle-warning))
65 list))
67 (declaim (ftype (function (list list) list)
68 process-package-lock-decl))
69 (defun process-package-lock-decl (spec old)
70 (destructuring-bind (decl &rest names) spec
71 (ecase decl
72 (disable-package-locks
73 ;; Why are we using EQUAL here if the only way to disable the
74 ;; lock on (SETF CAR) is to list the name CAR and not (SETF CAR)?
75 (union old names :test #'equal))
76 (enable-package-locks
77 (set-difference old names :test #'equal)))))
79 (!defvar *queued-proclaims* nil) ; should this be !*QUEUED-PROCLAIMS* ?
81 (defun process-variable-declaration (name kind info-value)
82 (unless (symbolp name)
83 (error "Cannot proclaim a non-symbol as ~A: ~S" kind name))
85 (when (and (eq kind 'always-bound) (eq info-value :always-bound)
86 (not (boundp name))
87 ;; Allow it to be unbound at compile-time.
88 (not *compile-time-eval*))
89 (error "Cannot proclaim an unbound symbol as ~A: ~S" kind name))
91 (multiple-value-bind (allowed test)
92 (ecase kind
93 (special (values '(:special :unknown) #'eq))
94 (global (values '(:global :unknown) #'eq))
95 (always-bound (values '(:constant) #'neq)))
96 (let ((old (info :variable :kind name)))
97 (unless (member old allowed :test test)
98 (error "Cannot proclaim a ~A variable ~A: ~S" old kind name))))
100 (with-single-package-locked-error
101 (:symbol name "globally declaring ~A ~A" kind)
102 (if (eq kind 'always-bound)
103 (setf (info :variable :always-bound name) info-value)
104 (setf (info :variable :kind name) info-value))))
106 (defun type-proclamation-mismatch-warn (name old new &optional description)
107 (warn 'type-proclamation-mismatch-warning
108 :name name :old old :new new :description description))
110 (defun proclaim-type (name type type-specifier where-from)
111 (unless (symbolp name)
112 (error "Cannot proclaim TYPE of a non-symbol: ~S" name))
114 (with-single-package-locked-error
115 (:symbol name "globally declaring the TYPE of ~A")
116 (when (eq (info :variable :where-from name) :declared)
117 (let ((old-type (info :variable :type name)))
118 (when (type/= type old-type)
119 (type-proclamation-mismatch-warn
120 name (type-specifier old-type) type-specifier))))
121 (setf (info :variable :type name) type
122 (info :variable :where-from name) where-from)))
124 (defun ftype-proclamation-mismatch-warn (name old new &optional description)
125 (warn 'ftype-proclamation-mismatch-warning
126 :name name :old old :new new :description description))
128 (defun proclaim-ftype (name type-oid type-specifier where-from)
129 (declare (type (or ctype defstruct-description) type-oid))
130 (unless (legal-fun-name-p name)
131 (error "Cannot declare FTYPE of illegal function name ~S" name))
132 (when (and (ctype-p type-oid)
133 (not (csubtypep type-oid (specifier-type 'function))))
134 (error "Not a function type: ~/sb!impl:print-type/" type-oid))
135 (with-single-package-locked-error
136 (:symbol name "globally declaring the FTYPE of ~A")
137 (when (eq (info :function :where-from name) :declared)
138 (let ((old-type (proclaimed-ftype name))
139 (type (if (ctype-p type-oid)
140 type-oid
141 (specifier-type type-specifier))))
142 (cond
143 ((not (type/= type old-type))) ; not changed
144 ((not (info :function :info name)) ; not a known function
145 (ftype-proclamation-mismatch-warn
146 name (type-specifier old-type) type-specifier))
147 ((csubtypep type old-type)) ; tighten known function type
149 (cerror "Continue"
150 'ftype-proclamation-mismatch-error
151 :name name
152 :old (type-specifier old-type)
153 :new type-specifier)))))
154 ;; Now references to this function shouldn't be warned about as
155 ;; undefined, since even if we haven't seen a definition yet, we
156 ;; know one is planned.
158 ;; Other consequences of we-know-you're-a-function-now are
159 ;; appropriate too, e.g. any MACRO-FUNCTION goes away.
160 (proclaim-as-fun-name name)
161 (note-name-defined name :function)
163 ;; The actual type declaration.
164 (setf (info :function :type name) type-oid
165 (info :function :where-from name) where-from)))
167 (defun seal-class (class)
168 (declare (type classoid class))
169 (setf (classoid-state class) :sealed)
170 (let ((subclasses (classoid-subclasses class)))
171 (when subclasses
172 (dohash ((subclass layout) subclasses :locked t)
173 (declare (ignore layout))
174 (setf (classoid-state subclass) :sealed)))))
176 (defun process-freeze-type-declaration (type-specifier)
177 (let ((class (specifier-type type-specifier)))
178 (when (typep class 'classoid)
179 (seal-class class))))
181 (defun process-inline-declaration (name kind)
182 ;; since implicitly it is a function, also scrubs *FREE-FUNS*
183 (proclaim-as-fun-name name)
184 ;; Check for problems before touching globaldb,
185 ;; so that the report function can see the old value.
186 (let ((newval
187 (ecase kind
188 (inline :inline)
189 (notinline :notinline)
190 (maybe-inline :maybe-inline))))
191 (warn-if-inline-failed/proclaim name newval)
192 (setf (info :function :inlinep name) newval)))
194 (defun check-deprecation-declaration (state since form)
195 (unless (typep state 'deprecation-state)
196 (error 'simple-type-error
197 :datum state
198 :expected-type 'deprecation-state
199 :format-control "~@<In declaration ~S, ~S state is not a ~
200 valid deprecation state. Expected one ~
201 of ~{~S~^, ~}.~@:>"
202 :format-arguments (list form state
203 (rest (typexpand 'deprecation-state)))))
204 (multiple-value-call #'values
205 state (sb!impl::normalize-deprecation-since since)))
207 (defun process-deprecation-declaration (thing state software version)
208 (destructuring-bind (namespace name &key replacement) thing
209 (let ((info (make-deprecation-info state software version replacement)))
210 (ecase namespace
211 (function
212 (when (eq state :final)
213 (sb!impl::setup-function-in-final-deprecation
214 software version name replacement))
215 (setf (info :function :deprecated name) info))
216 (variable
217 (check-variable-name
218 name :context "deprecated variable declaration" :signal-via #'error)
219 (when (eq state :final)
220 (sb!impl::setup-variable-in-final-deprecation
221 software version name replacement))
222 (setf (info :variable :deprecated name) info))
223 (type
224 (when (eq state :final)
225 (sb!impl::setup-type-in-final-deprecation
226 software version name replacement))
227 (setf (info :type :deprecated name) info))))))
229 (defun process-declaration-declaration (name form)
230 (unless (symbolp name)
231 (error "In~% ~S~%the declaration to be recognized is not a ~
232 symbol:~% ~S"
233 form name))
234 (with-single-package-locked-error
235 (:symbol name "globally declaring ~A as a declaration proclamation"))
236 (setf (info :declaration :recognized name) t))
238 ;;; ANSI defines the declaration (FOO X Y) to be equivalent to
239 ;;; (TYPE FOO X Y) when FOO is a type specifier. This function
240 ;;; implements that by converting (FOO X Y) to (TYPE FOO X Y).
241 (defun canonized-decl-spec (decl-spec)
242 (let ((id (first decl-spec)))
243 (if (cond ((symbolp id) (info :type :kind id))
244 ((listp id)
245 (let ((id (car id)))
246 (and (symbolp id)
247 (or (info :type :expander id)
248 (info :type :kind id)))))
250 ;; FIXME: should be (TYPEP id '(OR CLASS CLASSOID))
251 ;; but that references CLASS too soon.
252 ;; See related hack in DEF!TYPE TYPE-SPECIFIER.
253 (typep id 'instance)))
254 (cons 'type decl-spec)
255 decl-spec)))
257 ;; These return values are intended for EQ-comparison in
258 ;; STORE-LOCATION in %PROCLAIM.
259 (defun deprecation-location-key (namespace)
260 (case namespace
261 (function '(deprecated function))
262 (variable '(deprecated variable))
263 (type '(deprecated type))))
265 (defun %proclaim (raw-form location)
266 (destructuring-bind (&whole form &optional kind &rest args)
267 (canonized-decl-spec raw-form)
268 (labels ((store-location (name &key (key kind))
269 (if location
270 (setf (getf (info :source-location :declaration name) key)
271 location)
272 ;; Without this WHEN, globaldb would accumulate
273 ;; a bunch of explicitly stored empty lists because
274 ;; it does not know that there's no need to store NIL.
275 (when (info :source-location :declaration name)
276 (remf (info :source-location :declaration name) key))))
277 (map-names (names function &rest extra-args)
278 (mapc (lambda (name)
279 (store-location name)
280 (apply function name extra-args))
281 names))
282 (map-args (function &rest extra-args)
283 (apply #'map-names args function extra-args)))
284 (case kind
285 ((special global always-bound)
286 (map-args #'process-variable-declaration kind
287 (case kind
288 (special :special)
289 (global :global)
290 (always-bound :always-bound))))
291 ((type ftype)
292 (if *type-system-initialized*
293 (destructuring-bind (type &rest names) args
294 (check-deprecated-type type)
295 (let ((ctype (specifier-type type)))
296 (map-names names (ecase kind
297 (type #'proclaim-type)
298 (ftype #'proclaim-ftype))
299 ctype type :declared)))
300 (push raw-form *queued-proclaims*)))
301 (freeze-type
302 (map-args #'process-freeze-type-declaration))
303 (optimize
304 (multiple-value-bind (new-policy specified-qualities)
305 (process-optimize-decl form *policy*)
306 (setq *policy* new-policy)
307 (warn-repeated-optimize-qualities new-policy specified-qualities)))
308 (muffle-conditions
309 (setq *handled-conditions*
310 (process-muffle-conditions-decl form *handled-conditions*)))
311 (unmuffle-conditions
312 (setq *handled-conditions*
313 (process-unmuffle-conditions-decl form *handled-conditions*)))
314 ((disable-package-locks enable-package-locks)
315 (setq *disabled-package-locks*
316 (process-package-lock-decl form *disabled-package-locks*)))
317 ((inline notinline maybe-inline)
318 (map-args #'process-inline-declaration kind))
319 (deprecated
320 (destructuring-bind (state since &rest things) args
321 (multiple-value-bind (state software version)
322 (check-deprecation-declaration state since form)
323 (mapc (lambda (thing)
324 (process-deprecation-declaration thing state software version)
325 (destructuring-bind (namespace name &rest rest) thing
326 (declare (ignore rest))
327 (store-location
328 name :key (deprecation-location-key namespace))))
329 things))))
330 (declaration
331 (map-args #'process-declaration-declaration form))
333 (unless (info :declaration :recognized kind)
334 (compiler-warn "unrecognized declaration ~S" raw-form)))))))
336 (defun sb!xc:proclaim (raw-form)
337 #!+(and sb-show (host-feature sb-xc))
338 (progn (write-string "* ") (write `(declaim ,raw-form) :level nil) (terpri))
339 (%proclaim raw-form nil)
340 (values))
342 ;; Issue a style warning if there are any repeated OPTIMIZE declarations
343 ;; given the SPECIFIED-QUALITIES, unless there is no ambiguity.
344 (defun warn-repeated-optimize-qualities (new-policy specified-qualities)
345 (let (dups)
346 (dolist (quality-and-value specified-qualities)
347 (let* ((quality (car quality-and-value))
348 (current ; Read the raw quality value, not the adjusted value.
349 (%%policy-quality new-policy (policy-quality-name-p quality))))
350 (when (and (not (eql (cdr quality-and-value) current))
351 (not (assq quality dups)))
352 (push `(,quality ,current) dups))))
353 (when dups
354 ;; If a restriction is in force, this message can be misleading,
355 ;; as the "effective" value isn't always what the message claims.
356 (compiler-style-warn "Repeated OPTIMIZE qualit~@P. Using ~{~S~^ and ~}"
357 (length dups) dups))))