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