sbcl-devel

Hi, all.
Here's another slightly dodgy type system patch that could probably do
with review.
I thought that I would attack the remaining major type system bug (bug
91, described in BUGS as
(subtypep '(or (integer -1 1)
unsigned-byte)
'(or (rational -1 7)
unsigned-byte
(integer -1 1))) => NIL, T
This I felt was especially bad, as we weren't just expressing
uncertainty, we were returning a wrong result.
Initial investigations revealed that this was slightly misleading, as
in sbcl-0.7.2
(sb-kernel::specifier-type '(or (integer -1 1) unsigned-byte))
is canonicalized to #<NUMERIC-TYPE (INTEGER -1)>. So it's not just
simple unions that were the problem.
Some of the discussion in the thread referred to in BUG 91 ("bug in type
handling") pointed me in the right direction; canonicalization of the
other type in the subtypep form above can happen in two ways, depending
on whether the union of (rational -1 7) (integer -1 1) or (integer -1 1)
unsigned-byte is taken first. This, coupled with the fact that the union
:complex-subtypep-arg2 method [ essentially
(any/type #'csubtypep type1 (union-type-types type2)) ]
was a sufficient but not necessary condition for subtypepness caused us
to give wrong results in the above case.
So, I've reimplemented union-complex-subtypep-arg2 in a more
mathematically correct way. I've commented the (attached) patch fairly
carefully, as "mathematically correct" unfortunately doesn't mean
"computable".
Somewhat unsurprisingly, this change exposed a number of assumptions and
infelicities in the rest of the type system :-/. Some notes:
The change in cross-type.lisp should probably be dealt with first. At
some point in make-host-2, during the compilation of (I think)
host-alieneval.lisp, the host tries to work out
(subtypep 'null '(or (and null (complex double-float))
(and null (complex single-float))))
Normal canonicalization of intersection types will make the latter type
equal to NIL, but as a consequence of another change the cross-compiler
couldn't work that out. Unfortunately I can't remember what change it
was...
The late-type patches, in order:
1. We canonicalize type-union2 earlier when the type system knows that
one type is a subset of the other.
2. The next is a FIXME note regarding type-intersection; eq appears not
to catch all type specifiers. I haven't investigated this in any more
detail.
3. Next, because of some more call-next-methodish invocations, the
internals of the type system now can ask complex-subtypep-arg1 whether
*wild-type* is subtypep. Therefore, I've removed the averrance, and
adjusted the logic in the type method.
4. In the HAIRY intersection method, I've adjusted it to check if the
types are equal. This isn't ideal (see 2) but I think it'll do for now.
This is necessary (I think) because src/compiler/node.lisp is compiling
with a forward reference to a type; see the INFO slot in the definition
of the COMPONENT structure.
5. In our brave new world of clever union subtype handling, we also need
to be clever about union type=. Again, we previously had a sufficient
but not necessary condition (that the union-type-types of the two union
types were the same, in some order). Also, we want to avoid returning
certainty when we shouldn't, so better return NIL NIL when a union
containing a hairy-type is tested for equality. Finally in this hunk we
get the meat of the patch (8 lines of code and 25 of comment...)
6. The UNION :intersection2 methods also need a bit of smartening up; in
the UNION :subtypep methods, we have used the fact that the complex
methods test a UNION type against a non-UNION, and now the averrances
catch that, so we ensure that we call only the applicable methods.
(Arguably, this might be cleaner if it were split into separate UNION
:simple-intersection2 and UNION :complex-intersection2 methods, with the
accumulator logic in a separate function. Discuss...)
That's all, folks, apart from a request for clarification in
src/code/typedefs.lisp and some extra bonus tests!
As you can gather from this, there were (again) some nasty surprises
along the path; effort and tinkering were required both to get it to
compile, and then to get it to be able to compile itself. It has now
done both, and I'm reasonably happy with it. Thoughts?
Cheers,
Christophe
PS: Is there any chance of having BUG defined on the host, too?
Otherwise failing AVERs during the compilation doesn't print out a
helpful message but only "ERROR: undefined function BUG" :-/

On Wed, Apr 10, 2002 at 02:17:45PM +0100, Christophe Rhodes wrote:
> Here's another slightly dodgy type system patch that could probably do
> with review.
If you want actual thought from me, it will have to wait until next
week. But skimming it very lightly, and not looking at the code at
all, it sounds plausible.
> PS: Is there any chance of having BUG defined on the host, too?
> Otherwise failing AVERs during the compilation doesn't print out a
> helpful message but only "ERROR: undefined function BUG" :-/
Yes, this is in itself a bug.:-/ Feel free to move the definition
to where it exists on the host too, or to create a host-only version; or
I'll probably do this myself the next time it annoys me.
--
William Harold Newman <william.newman@...>
"Just opened Christmas pressie from Sauron. Pretty, pretty, pretty,
pretty ring!" -- http://home.nyu.edu/~amw243/diaries/wraith.html
PGP key fingerprint 85 CE 1C BA 79 8D 51 8C B9 25 FB EE E0 C3 E5 7C

On Wed, Apr 10, 2002 at 02:17:45PM +0100, Christophe Rhodes wrote:
> Here's another slightly dodgy type system patch that could probably do
> with review.
>
> I thought that I would attack the remaining major type system bug (bug
> 91, described in BUGS as
As I said last week, I wouldn't have any detailed response to this
'til this week.
> (subtypep '(or (integer -1 1)
> unsigned-byte)
> '(or (rational -1 7)
> unsigned-byte
> (integer -1 1))) => NIL, T
>
> This I felt was especially bad, as we weren't just expressing
> uncertainty, we were returning a wrong result.
Yes.
> As you can gather from this, there were (again) some nasty surprises
> along the path; effort and tinkering were required both to get it to
> compile, and then to get it to be able to compile itself. It has now
> done both, and I'm reasonably happy with it. Thoughts?
I'm pretty happy with the patch. It's rather nice that the type system
no longer confidently gives a wrong answer. I'm not 100% sure that no
other problem will be exposed by the changes but the certainty of
fixing a wrong answer makes up for a fair amount of anxiety about
Messing With Things Better Left Alone.
> ===================================================================
> RCS file: /cvsroot/sbcl/sbcl/src/code/typedefs.lisp,v
> retrieving revision 1.15
> diff -u -r1.15 typedefs.lisp
> --- src/code/typedefs.lisp 8 Apr 2002 22:00:39 -0000 1.15
> +++ src/code/typedefs.lisp 10 Apr 2002 13:11:17 -0000
> @@ -107,6 +107,8 @@
> (multiple-value-bind (subtypep2 win2) (csubtypep type2 type1)
> (cond (subtypep1 type1)
> (subtypep2 type2)
> + ;; FIXME: I don't understand this clause. Can someone
> + ;; please explain? - CSR, 2002-04-09
> ((and win1 win2) *empty-type*)
> (t nil)))))
> (defun hierarchical-union2 (type1 type2)
It's old CMU CL code (though the CMU CL code called this
VANILLA-INTERSECTION instead of HIERARCHICAL-INTERSECTION). Isn't that
explanation enough?:-)
I thought about it for a while and maybe I understand it now. The
short version is:
For hierarchical types, which are the kinds of things which we should
be calling HIERARCHICAL-INTERSECTION2 on, then when TYPE1 is not
a subset of TYPE2 and TYPE2 is not a subset of TYPE1, then they don't
overlap at all.
So perhaps that code should look something like
(defun hierarchical-intersection2 (type1 type2)
(multiple-value-bind (subtypep1 win1) (csubtypep type1 type2)
(multiple-value-bind (subtypep2 win2) (csubtypep type2 type1)
(cond (subtypep1 type1)
(subtypep2 type2)
((and win1 win2)
;; For hierarchical types (which are of course the only
;; kinds of things which we should be calling
;; HIERARCHICAL-INTERSECTION2 on!) then when TYPE1 is not
;; a subset of TYPE2 and TYPE2 is not a subset of TYPE1,
;; there is no overlap between TYPE1 and TYPE2 at all.
*empty-type*)
(t nil)))))
The hierarchicalness of the types passed to HIERARCHICAL-INTERSECTION2
is implicit. As in the comment above DELEGATE-COMPLEX-INTERSECTION2,
;;; These functions are used as method for types which need a complex
;;; subtypep method to handle some superclasses, but cover a subtree
;;; of the type graph (i.e. there is no simple way for any other type
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;;; class to be a subtype.) There are always still complex ways,
^^^^^^^^^^^^^^^^^^^^^
Probably that comment should be rewritten as
;;; there is no simple way for any other type class to intersect
which is a stronger statement, and still true. Also it might be
reasonable to make hierarchicalness explicit in the representation of
types, with a CTYPE-HIERARCHICAL-P slot or some such thing.
(Incidentally, my CTYPE-MIGHT-CONTAIN-OTHER-TYPES? slot name should
probably be CTYPE-MIGHT-CONTAIN-OTHER-TYPES-P. (I've been doing too
much coding on another project with post-1977 naming conventions
recently.:-) I'll probably put this in the next patch I make.)
This hierarchicalness is a common (but not universal) property of
things in the Common Lisp type system. It is violated by e.g.
SIMPLE-ARRAY and (VECTOR T), which don't have a hierarchical
relationship with each other.
+---------------------------------------+
| |
| +------------------+ |
| ARRAY | | |
| | SIMPLE-ARRAY | |
| | | |
| +------------+---------------+ | |
| | | | | |
| | | SIMPLE-VECTOR | | |
| | (VECTOR T) | | | |
| | +---------------+--+ |
| | | |
| +----------------------------+ |
| |
+---------------------------------------+
And of course it's violated by the various interval types like
(INTEGER -10 10) and (INTEGER 0 20). But lots of Common Lisp types
are hierarchical: If HASH-TABLE isn't a subset of CONS, then it doesn't
overlap at all (and similarly NUMBER and ARRAY and STRUCTURE-OBJECT
and CLASS and CHARACTER, but not STREAM, since some STREAMs are
STRUCTURE-OBJECTs but Gray streams aren't).
--
William Harold Newman <william.newman@...>
Users like this are like a mongoose backed into a corner: with its back to
the wall and seeing certain death staring it in the face, it attacks
frantically, because doing something has to be better than doing nothing.
This is not well adapted to the type of problems computers produce.
-- <http://www.chiark.greenend.org.uk/~sgtatham/bugs.html&gt;
PGP key fingerprint 85 CE 1C BA 79 8D 51 8C B9 25 FB EE E0 C3 E5 7C

On Fri, Apr 19, 2002 at 08:20:06AM -0500, William Harold Newman wrote:
> On Wed, Apr 10, 2002 at 02:17:45PM +0100, Christophe Rhodes wrote:
> > Here's another slightly dodgy type system patch that could probably do
> > with review.
> >
> > I thought that I would attack the remaining major type system bug (bug
> > 91, described in BUGS as
>
> As I said last week, I wouldn't have any detailed response to this
> 'til this week.
That's fair enough :) I understand what it's like to have too many
things to do, and the logic is relatively involved... wading through
changes thinking "has he thought of that? is that covered?" doesn't feel
like fun :)
> > As you can gather from this, there were (again) some nasty surprises
> > along the path; effort and tinkering were required both to get it to
> > compile, and then to get it to be able to compile itself. It has now
> > done both, and I'm reasonably happy with it. Thoughts?
>
> I'm pretty happy with the patch. It's rather nice that the type system
> no longer confidently gives a wrong answer. I'm not 100% sure that no
> other problem will be exposed by the changes but the certainty of
> fixing a wrong answer makes up for a fair amount of anxiety about
> Messing With Things Better Left Alone.
Alright. I'll do some final tidying up and test that it builds (twice!),
and commit it later this afternoon (just in time for code freeze, whee!).
> (Incidentally, my CTYPE-MIGHT-CONTAIN-OTHER-TYPES? slot name should
> probably be CTYPE-MIGHT-CONTAIN-OTHER-TYPES-P. (I've been doing too
> much coding on another project with post-1977 naming conventions
> recently.:-) I'll probably put this in the next patch I make.)
Heh :)
> (INTEGER -10 10) and (INTEGER 0 20). But lots of Common Lisp types
> are hierarchical: If HASH-TABLE isn't a subset of CONS, then it doesn't
> overlap at all (and similarly NUMBER and ARRAY and STRUCTURE-OBJECT
> and CLASS and CHARACTER, but not STREAM, since some STREAMs are
> STRUCTURE-OBJECTs but Gray streams aren't).
OK, I think I get it now :-)
Thanks,
Christophe
--
Jesus College, Cambridge, CB5 8BL +44 1223 510 299
http://www-jcsu.jesus.cam.ac.uk/~csr21/ (defun pling-dollar
(str schar arg) (first (last +))) (make-dispatch-macro-character #\! t)
(set-dispatch-macro-character #\! #\$ #'pling-dollar)