racket / ChezScheme

Chez Scheme
Apache License 2.0
110 stars 8 forks source link

Cptypes: add support for call-with-values and use define-inline #17

Closed gus-massa closed 4 years ago

gus-massa commented 4 years ago

This is a big update. It's still work in progress but I'd like some feedback. (Definitively not ready for Racket 7.6, but hopefully ready for 7.7.)

It has a lot of small commits, my plan is to squash them in 4 of 5 before merging.

It has a lot of internal refactor. Main new features:

In some primitives, it is sure that the functions in the arguments will be called, and it's result is the result of the primitive.

(begin (call-with-values (lambda () (unbox b)) something) (box? b))
;==>
(begin (call-with-values (lambda () (unbox b)) something) #t)

This makes the code more modular. Instead of a single big cond, each primitive has it's own block. The arguments are not wrapped in a oprnd like in the other passes. I'm using some macro magic instead, perhaps too much.

There is a version of define-inline for normal cases like $sealed-record? and another version for special cases that have need more control like call-with-values. The current name is define-inline/weird but I'd like a better name. :)

I'm reusing the same bit in the flags for all cases, because 4 bits is too much. Perhaps the flag can be skipped completely using a macro that reads primdata.ss directly.

If a lambda is part of a list of an argument, it is analyzed after the other argument. So functions like map don't need an special case

(map (lambda (x) (box? b)) (unbox b))
;==>
(map (lambda (x) #t) (unbox b))

This simplifies some parts of the code. The problem is that the information that a expression raises an error now is returned twice, most of the time in both. I'm not sure I'm 100% consistent, but this can't cause a problem, only some missed reductions.


To do in a future version (in a few months, July?):

The idea is to call the first argument of (call f other-args ...) using a context that is app that is a record that has all the information about the arguments and types. In the current version, I'm using a special case that is call Expr/call to handle the reduction of the functions that will be called surely. Also, it would be good that the return type of these expressions is special record procedure/more-info instead of a plain 'procedure.

Perhaps the signature in primdata.ss can say that the primitive is a predicate. Now the code uses a giant case to detect them.

mflatt commented 4 years ago

This all sounds great. Mostly, I'm going by your high-level description, but I looked at a few commits just to make sure I understand the direction.

The name of define-inline doesn't seem right here, but I appreciate the analogy to define-inline in cp0 and cpnanopass, and I don't have a better suggestion at the moment.

I agree that "primdata.ss" seems like the right place to designate predicates, eventually.

gus-massa commented 4 years ago

I collapse the changes in three commits. (The second is too long, but it was difficult to reorder the parts in some blocks that make sense.)

I added support for dynamic-wind and a few more tests.

I think this is mergeable as is (but I still don't like define-inline/weird).

mflatt commented 4 years ago

How about define-specialize? (Or with a d at the end?)

gus-massa commented 4 years ago

define-specialize and define-specialize/weird

or

define-inline and define-specialize

?

mflatt commented 4 years ago

Am I misreading the commits, or did the introduction of define-inline get lost?

I had in mind define-specialize for define-inline. Although specialize is still fairly generic, it seems more fitting than inline in this context.

Instead of define-X/weird, maybe something like define-specialize-before? (My first thought was preorder in the tree-traversal sense, but that doesn't seem like an improvement, especially since "preorder" can mean other things.)

gus-massa commented 4 years ago

I rewrote the history more than usual. define-inline is in the second commit and define-inline/weird is in the third commit.

What about define-specialized and define-specialized/unresticted?

My idea is that for most of the functions define-specialized is enough and it's more simple to use because most of the work for the types are already done and it's only necessary to add one or two details.

In the more strange cases, it is necessary to use define-specialized/unresticted but it is necessary to be careful with all the intersection and unions of the types.

mflatt commented 4 years ago

Those names are fine with me. (And I see the diff portion of the second commit that I wasn't expanding in the GitHub view.)

gus-massa commented 4 years ago

I renamed the functions. (The name define-specialize/unrestricted with the mix is strange, but I prefer specialize to specialized.)

I fixed a few details. In the previous version the handler for dynamic-wind was defined as normal instead of weird. (It should work if not marked as weird, but it will re-expand the arguments and recalculate the types, and in a long chain of dynamic-wind may have quadratic behavior.)