Class/forName honesty + class/isa? conformance for builtins

Class/forName claimed every java.*/clojure.* name found (and any "x.y.Class"
matched the registered Class via a short-name fallback), so a library's
(class-found? "optional.Dep") feature-probe always said yes — tools.logging then
tried to build the java.util.logging / log4j backends jolt lacks and crashed.
Resolve forName by exact registry lookup + an honest prefix that excludes the
unbacked optional packages (java.util.logging, javax.management), so the probe
sees them absent and skips the backend.

class of a persistent collection / namespace now reports its JVM class name
(clojure.lang.PersistentHashSet, …Namespace, …) instead of jolt's internal :set/
:object tag, and isa? consults JVM class assignability — Object as every class's
root plus a modeled clojure.lang/java.util hierarchy — so (isa? (class x) C) and a
class-keyed multimethod dispatch like the JVM (e.g. (isa? Keyword Object) was
false). Adds the bare class tokens (Fn/Namespace/Set/…) these dispatch on.

(type x) is unchanged — it keeps jolt's documented internal-keyword form. Six
JVM-certified corpus rows. make test green, 0 new divergences.
This commit is contained in:
Yogthos 2026-06-26 17:02:39 -04:00
parent 283a0f0eec
commit e5563ba375
6 changed files with 80 additions and 5 deletions

View file

@ -565,6 +565,12 @@
{:suite "interop / java.util Optional" :label "value equality" :expected "true" :actual "(= (java.util.Optional/of 5) (java.util.Optional/of 5))"}
{:suite "interop / java.util Optional" :label "empty orElse" :expected "7" :actual "(.orElse (java.util.Optional/empty) 7)"}
{:suite "interop / java.util Optional" :label "ofNullable nil is empty" :expected "true" :actual "(= (java.util.Optional/empty) (java.util.Optional/ofNullable nil))"}
{:suite "interop / class + isa?" :label "forName throws for unknown class" :expected ":cnfe" :actual "(try (do (Class/forName \"totally.Bogus.Class\") :found) (catch ClassNotFoundException e :cnfe))"}
{:suite "interop / class + isa?" :label "PersistentHashSet isa java.util.Set" :expected "true" :actual "(isa? clojure.lang.PersistentHashSet java.util.Set)"}
{:suite "interop / class + isa?" :label "String isa Object" :expected "true" :actual "(isa? java.lang.String java.lang.Object)"}
{:suite "interop / class + isa?" :label "IFn isa Object" :expected "true" :actual "(isa? clojure.lang.IFn java.lang.Object)"}
{:suite "interop / class + isa?" :label "class of vector" :expected "true" :actual "(= clojure.lang.PersistentVector (class [1]))"}
{:suite "interop / class + isa?" :label "isa? class keyword Object" :expected "true" :actual "(isa? (class :k) java.lang.Object)"}
{:suite "interop / java.time shims" :label "Instant/now is current" :expected "true" :actual "(> (.toEpochMilli (Instant/now)) 1500000000000)"}
{:suite "interop / java.time shims" :label "sql types are not" :expected "false" :actual "(instance? java.sql.Timestamp #inst \"2020-01-01T00:00:00Z\")"}
{:suite "interop / StringReader & StringBuilder" :label "StringReader read" :expected "[97 98 -1]" :actual "(let [r (java.io.StringReader. \"ab\")] [(.read r) (.read r) (.read r)])"}