Eliminate style-warning about undefined type GLOBAL-VAR
[sbcl.git] / src / compiler / proclaim.lisp
blobaf862b527319f29598740ae14dc521e5bfcd46fb
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 proclaim-type (name type type-specifier where-from)
113 (unless (symbolp name)
114 (error "Cannot proclaim TYPE of a non-symbol: ~S" name))
116 (with-single-package-locked-error
117 (:symbol name "globally declaring the TYPE of ~A")
118 (when (eq (info :variable :where-from name) :declared)
119 (let ((old-type (info :variable :type name)))
120 (when (type/= type old-type)
121 (type-proclamation-mismatch-warn
122 name (type-specifier old-type) type-specifier))))
123 (setf (info :variable :type name) type
124 (info :variable :where-from name) where-from)))
126 (defun proclaim-ftype (name type type-specifier where-from)
127 (unless (legal-fun-name-p name)
128 (error "Cannot declare FTYPE of illegal function name ~S" name))
129 (unless (csubtypep type (specifier-type 'function))
130 (error "Not a function type: ~S" (type-specifier type)))
132 (with-single-package-locked-error
133 (:symbol name "globally declaring the FTYPE of ~A")
134 (when (eq (info :function :where-from name) :declared)
135 (let ((old-type (info :function :type name)))
136 (cond
137 ((not (type/= type old-type))) ; not changed
138 ((not (info :function :info name)) ; not a known function
139 (ftype-proclamation-mismatch-warn
140 name (type-specifier old-type) type-specifier))
141 ((csubtypep type old-type)) ; tighten known function type
143 (cerror "Continue"
144 'ftype-proclamation-mismatch-error
145 :name name
146 :old (type-specifier old-type)
147 :new type-specifier)))))
148 ;; Now references to this function shouldn't be warned about as
149 ;; undefined, since even if we haven't seen a definition yet, we
150 ;; know one is planned.
152 ;; Other consequences of we-know-you're-a-function-now are
153 ;; appropriate too, e.g. any MACRO-FUNCTION goes away.
154 (proclaim-as-fun-name name)
155 (note-name-defined name :function)
157 ;; The actual type declaration.
158 (setf (info :function :type name) type
159 (info :function :where-from name) where-from)))
161 (defun seal-class (class)
162 (declare (type classoid class))
163 (setf (classoid-state class) :sealed)
164 (let ((subclasses (classoid-subclasses class)))
165 (when subclasses
166 (dohash ((subclass layout) subclasses :locked t)
167 (declare (ignore layout))
168 (setf (classoid-state subclass) :sealed)))))
170 (defun process-freeze-type-declaration (type-specifier)
171 (let ((class (specifier-type type-specifier)))
172 (when (typep class 'classoid)
173 (seal-class class))))
175 (defun process-inline-declaration (name kind)
176 ;; since implicitly it is a function, also scrubs *FREE-FUNS*
177 (proclaim-as-fun-name name)
178 ;; Check for problems before touching globaldb,
179 ;; so that the report function can see the old value.
180 (let ((newval
181 (ecase kind
182 (inline :inline)
183 (notinline :notinline)
184 (maybe-inline :maybe-inline))))
185 (warn-if-inline-failed/proclaim name newval)
186 (setf (info :function :inlinep name) newval)))
188 (defun check-deprecation-declaration (state since form)
189 (unless (typep state 'deprecation-state)
190 (error 'simple-type-error
191 :datum state
192 :expected-type 'deprecation-state
193 :format-control "~<In declaration ~S, ~S state is not a ~
194 valid deprecation state. Expected one ~
195 of ~{~A~^, ~}.~@:>"
196 :format-arguments (list form state
197 (rest (typexpand 'deprecation-state)))))
198 (multiple-value-call #'values
199 state (sb!impl::normalize-deprecation-since since)))
201 (defun process-deprecation-declaration (thing state software version)
202 (destructuring-bind (namespace name &key replacement) thing
203 (let ((info (make-deprecation-info state software version replacement)))
204 (ecase namespace
205 (function
206 (when (eq state :final)
207 (sb!impl::setup-function-in-final-deprecation
208 software version name replacement))
209 (setf (info :function :deprecated name) info))
210 (variable
211 ;; TODO (check-variable-name name "deprecated variable declaration")
212 (when (eq state :final)
213 (sb!impl::setup-variable-in-final-deprecation
214 software version name replacement))
215 (setf (info :variable :deprecated name) info))
216 (type
217 (when (eq state :final)
218 (sb!impl::setup-type-in-final-deprecation
219 software version name replacement))
220 (setf (info :type :deprecated name) info))))))
222 (defun process-declaration-declaration (name form)
223 (unless (symbolp name)
224 (error "In~% ~S~%the declaration to be recognized is not a ~
225 symbol:~% ~S"
226 form name))
227 (with-single-package-locked-error
228 (:symbol name "globally declaring ~A as a declaration proclamation"))
229 (setf (info :declaration :recognized name) t))
231 ;;; ANSI defines the declaration (FOO X Y) to be equivalent to
232 ;;; (TYPE FOO X Y) when FOO is a type specifier. This function
233 ;;; implements that by converting (FOO X Y) to (TYPE FOO X Y).
234 (defun canonized-decl-spec (decl-spec)
235 (let ((id (first decl-spec)))
236 (if (cond ((symbolp id) (info :type :kind id))
237 ((listp id)
238 (let ((id (car id)))
239 (and (symbolp id)
240 (or (info :type :translator id)
241 (info :type :kind id)))))
243 ;; FIXME: should be (TYPEP id '(OR CLASS CLASSOID))
244 ;; but that references CLASS too soon.
245 ;; See related hack in DEF!TYPE TYPE-SPECIFIER.
246 (typep id 'instance)))
247 (cons 'type decl-spec)
248 decl-spec)))
250 ;; These return values are intended for EQ-comparison in
251 ;; STORE-LOCATION in %PROCLAIM.
252 (defun deprecation-location-key (namespace)
253 (case namespace
254 (function '(deprecated function))
255 (variable '(deprecated variable))
256 (type '(deprecated type))))
258 (defun %proclaim (raw-form location)
259 (destructuring-bind (&whole form &optional kind &rest args)
260 (canonized-decl-spec raw-form)
261 (labels ((store-location (name &key (key kind))
262 (if location
263 (setf (getf (info :source-location :declaration name) key)
264 location)
265 (remf (info :source-location :declaration name) key)))
266 (map-names (names function &rest extra-args)
267 (mapc (lambda (name)
268 (store-location name)
269 (apply function name extra-args))
270 names))
271 (map-args (function &rest extra-args)
272 (apply #'map-names args function extra-args)))
273 (case kind
274 ((special global always-bound)
275 (map-args #'process-variable-declaration kind
276 (case kind
277 (special :special)
278 (global :global)
279 (always-bound :always-bound))))
280 ((type ftype)
281 (if *type-system-initialized*
282 (destructuring-bind (type &rest names) args
283 (check-deprecated-type type)
284 (let ((ctype (specifier-type type)))
285 (map-names names (ecase kind
286 (type #'proclaim-type)
287 (ftype #'proclaim-ftype))
288 ctype type :declared)))
289 (push raw-form *queued-proclaims*)))
290 (freeze-type
291 (map-args #'process-freeze-type-declaration))
292 (optimize
293 (multiple-value-bind (new-policy specified-qualities)
294 (process-optimize-decl form *policy*)
295 (setq *policy* new-policy)
296 (warn-repeated-optimize-qualities new-policy specified-qualities)))
297 (muffle-conditions
298 (setq *handled-conditions*
299 (process-muffle-conditions-decl form *handled-conditions*)))
300 (unmuffle-conditions
301 (setq *handled-conditions*
302 (process-unmuffle-conditions-decl form *handled-conditions*)))
303 ((disable-package-locks enable-package-locks)
304 (setq *disabled-package-locks*
305 (process-package-lock-decl form *disabled-package-locks*)))
306 ((inline notinline maybe-inline)
307 (map-args #'process-inline-declaration kind))
308 (deprecated
309 (destructuring-bind (state since &rest things) args
310 (multiple-value-bind (state software version)
311 (check-deprecation-declaration state since form)
312 (mapc (lambda (thing)
313 (destructuring-bind (namespace name &rest rest) thing
314 (declare (ignore rest))
315 (store-location
316 name :key (deprecation-location-key namespace)))
317 (process-deprecation-declaration thing state software version))
318 things))))
319 (declaration
320 (map-args #'process-declaration-declaration form))
322 (unless (info :declaration :recognized kind)
323 (compiler-warn "unrecognized declaration ~S" raw-form)))))))
325 (defun sb!xc:proclaim (raw-form)
326 #+sb-xc (/show0 "entering PROCLAIM, RAW-FORM=..")
327 #+sb-xc (/hexstr raw-form)
328 (%proclaim raw-form nil)
329 #+sb-xc (/show0 "returning from PROCLAIM")
330 (values))
332 ;; Issue a style warning if there are any repeated OPTIMIZE declarations
333 ;; given the SPECIFIED-QUALITIES, unless there is no ambiguity.
334 (defun warn-repeated-optimize-qualities (new-policy specified-qualities)
335 (let (dups)
336 (dolist (quality-and-value specified-qualities)
337 (let* ((quality (car quality-and-value))
338 (current ; Read the raw quality value, not the adjusted value.
339 (%%policy-quality new-policy (policy-quality-name-p quality))))
340 (when (and (not (eql (cdr quality-and-value) current))
341 (not (assq quality dups)))
342 (push `(,quality ,current) dups))))
343 (when dups
344 ;; If a restriction is in force, this message can be misleading,
345 ;; as the "effective" value isn't always what the message claims.
346 (compiler-style-warn "Repeated OPTIMIZE qualit~@P. Using ~{~S~^ and ~}"
347 (length dups) dups))))