Fix six JVM divergences surfaced by rewrite-clj
Running the rewrite-clj test suite under jolt exposed six bugs, each fixed here:
- `for`/`doseq` `:let` bindings never went through `destructure`, so a
destructuring pattern (`:let [{:keys [y]} x]`) hit `let*` raw and failed to
compile. Emit `let`, like Clojure.
- `with-open` couldn't close a deftype/defrecord that implements a `close` method
(java.io.Closeable / AutoCloseable, e.g. tools.reader's readers) — `__close`
only knew jhost readers and map `:close` fns. Dispatch a record's `close`.
- A deftype/defrecord method param named like a field didn't shadow the field
(the field's let-binding wrapped the params). Params now shadow, as in Clojure.
- A deftype whose simple name collided with a built-in host class clobbered it in
the global ctor table, so `(java.io.PushbackReader. …)` built tools.reader's
same-named deftype. Register deftypes/built-ins by FQN, don't let a deftype
overwrite a built-in's simple name, and qualify a bare `(Name. …)` to the
deftype's FQN only in the ns that defined it.
- `clojure.walk` was lazy over a non-list seq (missing `doall`), so a walk whose
fn has side effects read stale state. Make it eager, like Clojure.
- `Character/isWhitespace` used an ASCII-only check that missed U+2028 and other
Unicode whitespace. Use the JVM's Unicode set (minus the no-break spaces it
excludes).
Regressions: corpus rows (for-let destructure, method-param shadow, walk eager,
isWhitespace), a unit row (with-open closes a record), and smoke checks (the
class-name collision, run in a fresh -e process so the deftype doesn't leak).
One divergence remains unfixed: a submatch from a losing regex alternation branch
leaks when the winning branch has a quantified group (a bug in the vendored
irregex engine, not jolt) — tracked separately.
This commit is contained in:
parent
0bad467372
commit
77e80dab9c
14 changed files with 640 additions and 572 deletions
|
|
@ -587,11 +587,18 @@
|
|||
(number? a) (not (flonum? a)))
|
||||
(exact->inexact a) a))
|
||||
(loop (cdr as) (+ i 1)))))))))
|
||||
;; Register the ctor globally by simple class name (like StringBuilder) so
|
||||
;; (Name. …) interop resolves ns-agnostically: a deftype used across files works
|
||||
;; even when the runtime current ns is the caller's, not the defining ns
|
||||
;; (host-new checks class-ctors-tbl before the current-ns var fallback).
|
||||
(register-class-ctor! (symbol-t-name name-sym) ctor)
|
||||
;; Register the ctor under its fully-qualified tag ("ns.Name") — a bare
|
||||
;; (Name. …) in the DEFINING ns is qualified to this by the analyzer, so a
|
||||
;; deftype whose simple name collides with a built-in host class (tools.reader's
|
||||
;; PushbackReader vs java.io.PushbackReader) still resolves correctly there.
|
||||
(register-class-ctor! tag ctor)
|
||||
;; Also register the simple name so (Name. …) resolves ns-agnostically across
|
||||
;; files — BUT never clobber a built-in host class of the same simple name (an
|
||||
;; unrelated ns's bare (Name. …) must still reach the built-in). A prior deftype
|
||||
;; (tracked in chez-simple-name-tag) is fine to overwrite (last def wins / redef).
|
||||
(when (or (not (hashtable-ref class-ctors-tbl (symbol-t-name name-sym) #f))
|
||||
(hashtable-ref chez-simple-name-tag (symbol-t-name name-sym) #f))
|
||||
(register-class-ctor! (symbol-t-name name-sym) ctor))
|
||||
;; index the tag so a cross-ns extend-protocol resolves the bare type name.
|
||||
(hashtable-set! chez-deftype-tag-set tag #t)
|
||||
(hashtable-set! chez-simple-name-tag (symbol-t-name name-sym) tag)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue