The contract for `(U (I-Hash k1 v1) (M-Hash k2 v2) (W-Hash k3 v3))`
is now `(hash/c (or/c k1 k2 k3) (or/c v1 v2 v3))`
ONLY WHEN the key and value types are distinct.
The contract should no longer include duplicate key or value types.
The old 'HashTable' type is now the union of the other 3 hash types.
- all operations that used to work on 'HashTable's still work,
but some now have more specific outputs
- `#hash` literals have type `ImmutableHash`
- `immutable?` and `hash-weak?` are filters
- `Mutable-` and `Weak-` hashes have corresponding `Top` types, `HashTableTop` is now a union
- the contact for `(U (Immutable-Hash K1 V1) (Mutable-Hash K2 V2))` is ONE `hash/c`
Minor notes:
- renamed internal identifiers containing 'Hashtable' to all use 'HashTable'
- add Racket guide/reference 'secref' functions
check calls to resolve-once to see if they return #f
(i.e. if a type is not yet defined), and have overlap
only extend its seen list when it is resolving/unfolding
a potentially infinite type
this commit involves no functional changes, just tries
to clean up some of the helper functions in type-rep
related to instantiate/abstract for type vars
fix intersection bug
intersections with resolvable types would occasionally generate
spurious weird types (e.g. μx.x) when a type name
is not yet fully defined -- this patches that problem by
using resolve-once instead of resolve and checking the result
for #f before proceeding to compute the intersection
This PR adds more support for refinement reasoning, in particular
type inference is now aware of argument objects which allows for
more programs w/ refinements to typecheck. Additionally, working
with vector types and literals that are refined or need to have
properties about their length proven now works.
The optimizer should only run when the code being compiled could
directly access racket/unsafe/ops. This prevents unsoundness in Typed
Racket from giving untrusted code access to dangerous operations.
This PR adds about half of the needed primitives and logic for
reasoning about linear integer arithmetic in programs with interesting
dependent types. Things have been added in a way s.t. programs will
still continue to typecheck as they did, but if you want integer literals
and certain operations (e.g. *,+,<,<=,=,>=,>) to include linear inequality
information by default, you need to include the
'#:with-linear-integer-arithmetic' keyword at the top of your module.
The other features needed to get TR to be able to check things like
verified vector operations will be to ajust function types so
dependencies can exist between arguments and a minor tweak to get
type inference to consider the symbolic objects of functions arguments.
These features should be coming shortly in a future pull request.
Keyword functions are a little tricky. This PR addresses issues
checking the body of kw functions.
Basically, a function with keyword arguments such as inc:
(define (inc x #:n [n 1])
(+ x n))
actually expands into a more complex function with 3 arguments that
looks something resembling the following:
(define (inc-expanded n* n-given? x)
(let ([n (if n-given? n* 1)]) (+ x n)))
and calls to inc are converted to match this form:
(inc 42) => (inc-expanded #f #f 42)
(inc 42 #:n 2) => (inc-expanded 2 #t 42)
Note that each optional keyword argument has a boolean flag argument
that signals whether or not the caller provided that keyword argument.
This PR takes advantage of the observation that the value for the n*
argument in inc is only reachable in code when n-given? is #t, and so,
assuming the kw-expansion protocol always only accesses n* if n-given?
is #t, we can actually safely check the body of the function against
the following simple but correct type:
(-> Number Boolean Number Number)
An alternative previous approach expanded the function type into every
possible combination of optional argument and optional argument flag,
but this was prohibitively expensive.
An opaque object contract is stronger than another (opaque) object contract if:
- it has stronger field/method contracts on fields/methods common to both
- and it has no more field/method contracts than the other, if the other is opaque
`field` needs to be a literal; with the bug, the following syntax
```
(object/c-opaque (any-var (->m any/c)))
```
made a contract with 1 field (named `->m`, value `any/c`)
This PR primarily changes how we represent Base types and unions of
Base types. Basically, Base types now contain a bits field, which
contains an exact-nonnegative-integer? with exactly one bit set to
1. This allows us to represent unions of Base types by simply OR-ing
together the various base bits. We store these unions in a new type
called a BaseUnion (which contains a field for numeric Base type bits
and a field for non-numeric Base type bits). We can perform set
operations on BaseUnion types rather quickly (using simple bitwise
arithmetic operations).
To make Union and BaseUnion work together nicely, the Union type now
has a field for non-Base types, and a field which contains any and all
Base types placed directly in the Union ( either as a Base if there is
only one, or as a BaseUnion if there are more than one).
Other changes present in this PR:
Base types are now "closed" -- i.e. Base types are only declared in
base-types.rkt and numeric-base-types.rkt with a special macro that
assigns them their respective bits. The constructor make-Base is no
longer provided for miscellaneous usages.
Some singleton Value types were moved to Base so all of our common
unions of basic types can fit into the new BaseUnion type (namely
Null, Void, One, Zero, and the booleans).
A new Val-able match expander lets us match on singleton types that
used to all be Value types, but, as described above, now some are Base
types.
Unions contain deterministically ordered, duplicate free lists (in
addition to sets for equality and constant time membership checks), so
iterating over Unions can be done deterministically (yay!) -- this
gets rid of some otherwise problematic behavior in areas like type
inference, where the order Unions are iterated over can actually
affect the results (i.e. if two valid type inferences are possible,
nondeterministic ordering means we can sometimes get one and sometimes
get another, which makes for particularly difficult to debug issues
and in general has no immediate solution (both substitutions are
valid, after all!))
Previously expected propositions were erased frequently
(at lets and ifs) and checking for logical entailment
was unidirectional instead of bidirectional. In other words,
instead of checking if propositions held at the leaves
of the AST, we would typecheck the AST and blindly propagate
up ALL logical info we learned at each step. This meant that
we would get exponential blow up of propositions even when
we didn't care about their content.
With this commit, instead now we send down expected types
*and* propositions so we can verify expected types and
propisitions are satisfied at leaves, thereby relieving the
need to constantly report up huge amounts of logical info
while typechecking.