When identifiers provided by typed modules were used in
certain submodules of the form (module* n #f ...) or were
used by modules implemented in a language defined by TR,
the wrong redirection was used in the expansion.
The reason was because TR's identifier redirection decided
whether it was in a typed or untyped context at module visit
time, but that's too early in the cases above.
(because TR's #%module-begin may not have begun expanding yet)
The fix uses a rename-transformer that delays the decision
to use the typed or untyped identifier until expansion time.
Closes GH issue #163 and #181
Closes PR 15118
Moves `get-alternate` since its only user is the require-contract
module. In addition, it appears that one of the cases in the
conditional in its body is unnecessary. This likely means that
the extra machinery for typed-renamers are not needed at all.
Also adds a test for `require/typed` of a typed module
Only parse and use the type annotations if they are present on
all fold variables. This matches the default for other forms in TR.
Also, this will usually result in a "insufficient type information"
message which is more helpful than if TR chose some default type.
Closes PR 15138
Closes PR 14893
I had forgotten to adjust the define-struct macro to work
like the struct macro for the #:prefab keyword, which made
TR think prefabs were ordinary structs.
Closes GH issue #188
Instead of local-expanding the entire top-level forms at
once, wrap expressions in a top-level begin in trampolining
macro forms. This allows the typechecker to trampoline back
to the evaluator, which is necessary to declare/register
declarations made in a top-level begin.
The point of this change is to eliminate top-level hacks
and faciliate various macros that need to communicate using
multiple top-level forms.
Previous version replaced calls to, e.g., `cadr` with calls to `cdr`
then `car`, called the typechecker to populate the type table, then
optimized the exploded operations. The call to the typechecker failed
on open terms, limiting the applicability of the optimization, and was
just generally brittle.
The new version instead explodes operations, then optimizes them inside
out for as long as the argument's type guarantees it's safe. This works
on open terms, and should be more robust.
In the case that a let rhs doesn't return and therefore the
bodies of the let are unreachable, the bodies need to be marked
as ignored for the optimizer.
In addition, don't attempt unboxed let optimization at all
if the return type is Nothing since it probably means some
body expressions have no type.
Closes GH issue #165
The old check was broken for cases with type constructors
with more than one type argument and was also too conservative
in some cases (e.g., when one cycle refers to another cycle of
aliases in a non-recursive manner).
The new check is still conservative, but it allows more types
than before.
Closes GH issue #157
This is the correct change for how attempting to bind AnyValues results
caused internal type-checking errors. The root cause was get-type/infer
violating its own contract by using the default return value from
tc-error/expr
This (partially) reverts 5e0e8ed713.
Because -let-internal wasn't rename-out'd, users would see its name in
syntax error messages. Adding #:context forces the error messages to be
phrased in terms of the given form.
Since these promises re-evaluate their bodies every time they
are forced, allowing them makes `force` not idempotent and not
safe to treat as a path.
This change is slightly backwards-incompatible, since programs
that previously passed `delay/name` promises across the typed
boundary will now fail at runtime. The alternative is also
incompatible: stop treating `force` as a path. Since `delay/name`
is quite obscure, this approach seems like the safer choice.
The `identifier-binding` function is now senstive to the "macro
introduction" scope that's on an indentifier provided to a currently
expanding macro. Unit tests for TR need to use
`syntax-local-intorduce` to remove it, in the same way that `tc-setup`
already does.
Also, recognize a class expansion when it's wrapped with
`#%expression`, since `class` now expands that way sometimes.
The `quote-syntax` form now suports a `#:local` option, which is
used for type annotations to preserve binding context.
Since `letrec-syntaxes+values` is now removed by `local-expand`,
some patterns must be adjusted, including the pattern used
for type annotations.
Using the enclosing module's context for the `#f` part of the
`(module* _ #f ....)` would generally enable a compact encoding of
bindings for the purposes of `module->namespace`. Disabling
`module->namespace` for the generated submodules seems more reliable,
and it seems unlikely that anyone will miss the extra debugging
capability (which is all that is lost for these submodules whose
content is, I think, unspecified).
This enables contract generation in the negative
direction (untyped->typed) for row polymorphic types
(basically mixin types).
Depends on `class-seal` and `class-unseal` in
the racket/class library.
This patch addresses two issues with `typed/racket/class`:
1. For multiple private fields declared with `define-values`, type
information does not propagate from the values produced by the
initialization expression to the declared fields. This breaks soundness
of private fields: A field can be annotated with a type that does not
contain the field's initial value.
This was resolved by keeping a table of temporary bindings introduced in
the expansion of the initializer along with their types. The field
setter's type is then checked against that of the corresponding
temporary.
2. The class body typechecker assumes that the `expr` of
a `define-values` clause will expand to a bare `(values vs ...)`.
This was resolved by generalizing the template for matching an expanded
`define-values` initializer and extracting the type information from the
`expr` instead of each element in `(vs ...)`.
In conjunction with a small change to syntax/parse, this means
that `typed/racket/base` no longer depends on `racket/set`,
`racket/contract/base`, or `racket/generic`.
Timings on my machine go from ~200ms for `#lang typed/racket/base`
as the whole file, to ~100ms. For comparison, `racket/base` is 30ms
and `#lang racket` is 150ms. `#lang typed/racket` is ~200ms with
this change.
Changes include:
- not using `in-syntax`
- switching to `syntax/parse/pre`
- avoiding `template` from `syntax/parse`
Previously the restriction didn't account for traversing
the object type with the given path. This also relies on
the previous commit that adds subtyping on filters.
(because this change seems to introduce filters which
only differ by an unrolling of a recursive type, but
the old subtyping only worked for identical types)
This makes a type like
(-> Any Boolean : #:+ Integer)
a subtype of a type like
(-> Any Boolean : #:+ Number)
For not filters, the direction is reversed.
There are several new files: one for structure prims, one for
annotation-related prims, one for contract related ones. The prims-contract
file uses trickery with submodules to avoid a direct dependency
on `racket/contract`.
Additionally, the rewritten versions of `for/set` et al now use
a submodule to avoid a direct dependency on `racket/set`.
Allow more cases that are allowed for ordinary function
contracts and explicitly error instead of internal errors
for other cases.
Closes Github Issue #50
This helped for debugging, especially since some of
the comments were inaccurate. Removed contract comments
that aren't more specific than the code contracts.
When exporting row polymorphic functions from TR, just
use absent clauses to ensure that TR won't accidentally
try to add pre-existing fields/methods. No sealing is
needed because the typechecker enforces parameteric use
of the class.
With the current macro expander, either should work, but
`free-id=?` is arguably the right choice for determining
that two identifiers refer to the same binding.
Instead of registering aliases before we find out if they are
recursive or not, register them after that information is found.
That avoids spurious aliases that end up in the type name
environment without the need for a `remove-type-name` operation.
For unions of multiple type aliases the new placeholder
would cause union collapsing incorrectly. Put an uninterned
symbol in the placeholder types to avoid this.
This allows the main TR module not to explicitly
depend on the contract library. Each exported name
can be redirected to either the original name (for a
typed client) or to another macro (for an untyped
client) which expands to a `local-require` for the
relevant submodule (named `#%contract-defs`).
Thanks to Matthew for the initial idea and an
implementation in plai-typed that this is based on.
Previously, TR only recognized a subset of the syntax that
the class macro accepts for method definitions (and errored
unhelpfully on other cases). Though that subset was sufficient
for most methods, macros will sometimes produce unusual forms.
Recent changes to contract generation have made this
`local-require` unnecessary. Using `require` is preferable
since `local-require` can interact poorly with submodules.
let-aliasing initially forgot to check if a variable that might act as
an alias was ever mutated. fixed by disallowing a mutated variable to
act as an alias.
This compensates for a change in commit bb3f446186
that made the possible-domains function more permissive
(possibly returning results that are inconsistent with the
expected type).
Closes PR 14889