WARNINGs due to inability to derive rank of array union types
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
Fix Released
|
Medium
|
Paul Khuong |
Bug Description
The DEFTRANSFORM for ARRAY-RANK gives up for many union types, so code like
;; simplified from opticl
(lambda (a)
(typecase a
((or (array * (* * 3)) (array * (* * 4)))
(case (array-rank a)
(2 (aref a 1 2))))))
WARNs with
; caught WARNING:
; Derived type of A is
; (VALUES (OR (ARRAY * (* * 3)) (ARRAY * (* * 4))) &OPTIONAL),
; conflicting with its asserted type
; (ARRAY * (* *)).
(ARRAY-RANK A) could have been simplified to 3, in which case the AREF is dead code so wouldn't warn.
More generally, code like
(lambda (a)
(typecase a
((or (array * ()) (array * (1)) (array * (1 2)))
(case (array-rank a)
(3 (aref a 1 2 3))))))
has the same problem but can't compile the ARRAY-RANK to a specific value. In that case, constraining the type of the returned value might be enough to avoid the warning.
Tested on 1.1.17.86, x8664 linux
1.1.16.83 compiles both forms, with a "deleting unreachable code" note for the first and no message for the second.
Changed in sbcl: | |
status: | New → Triaged |
importance: | Undecided → Medium |
Changed in sbcl: | |
assignee: | nobody → Paul Khuong (pvk) |
status: | Triaged → In Progress |
Changed in sbcl: | |
status: | Fix Committed → Fix Released |
An attempt at fixing the problem, not sure if it handles all types correctly, or if expanding to (THE (MEMBER ...) ...) is the right way to specify the result type if it isn't a constant:
(defun array-type- rank-or- give-up (type) array-type- ranks (type)
( typecase type
(array- type
(list
(if (listp (array- type-dimensions type))
(length (array- type-dimensions type))
'*)))
(union- type
(remove- duplicates
(remove nil (mapcan #'maybe- array-type- ranks
(union- type-types type)))))
(intersection- type
(let ((d (array- type-dimensions -or-give- up type)))
(list (if (consp d) (length d) d))))))) array-type- ranks type)
(give- up-ir1- transform
(type- specifier type)))))
(labels ((maybe-
(or (maybe-
(print "~@<don't know how to extract array dimensions from type ~S~:@>")
(deftransform array-rank ((array) (array) * :node node) type-rank- or-give- up array-type)))
(every #'numberp dims))
(car dims)
`(the (member ,@dims)
(%array- rank array))))
(array- type-complexp array-type)))
' (%array- rank array))
( delay-ir1- transform node :constraint)
(%array- rank array)
1)) ))))
(let ((array-type (lvar-type array)))
(let ((dims (array-
(cond ((and (consp dims)
(if (every (lambda (a) (= a (car dims))) (cdr dims))
((eq t (and (array-type-p array-type)
(t
`(if (array-header-p array)