This makes the racket compiler check for new versions of modules it
already compiled. Should avoid some confusing errors when developing the
racket libs.
If a user arbitrarily permutes the links associated with code, it's
possible to end up with a load request that appears to have mutually
recursive definitions without common hashes. So, this has been made into
a catchable exception instead of throwing a Haskell error.
The initial hashing in the runtime just calls error when this happens,
since it means some internal code generation generated bad SCCs, not
that some kind of user error happened.
Solves one observed problem and potentially some others.
The observed problem was the process of unhashing and rehashing does not
replace any term links in the original terms. This is because term link
literals can't be turned into variables and subsequently replaced with
new hashes. So, instead we use our available variable mappings to
replace the literals manually.
A superior methodology might be to replicate the SCC behavior already in
hashTermComponents, and incrementally remap individual components.
However, that is a considerable amount of additional work, and the
post-floating references are just used as a translation layer between
the codebase and verifiable hashes, so making them completely consistent
doesn't seem necessary.
I've also added some codebase->verifiable replacements from the context
in some places. It's possible not doing this would have caused problems
during UCM sessions where some terms are loaded incrementally due to
multiple calls into the runtime. I didn't observe any failing tests due
to this, though.
When the interpreter is called for things in a scratch file, the code
path is slightly different, because all the definitions are pre-combined
into a letrec. If the definitions are subsequently added to the
codebase, we will have already loaded and compiled their code. However,
previously the remapping from base to floated references would not
exist, because that was only being generated for loaded dependencies in
the other path.
So, this code adds a similar remapping for a top-level letrec in this
code path. This fixes a problem with compiling a definition that had
just been added from a scratch file. The remap was expected to be there,
but it wasn't, so the compiler could find the code to emit.