diff --git a/test/chez/corpus.edn b/test/chez/corpus.edn index 0e74fd2..e178fe0 100644 --- a/test/chez/corpus.edn +++ b/test/chez/corpus.edn @@ -2751,6 +2751,21 @@ {:suite "chunking-model / unchunked realization granularity" :label "nth 0 over a vector realizes one" :expected "1" :actual "(let [a (atom 0)] (nth (map (fn [x] (swap! a inc) x) (vec (range 100))) 0) @a)"} {:suite "chunking-model / unchunked realization granularity" :label "mapcat is fully lazy at construction" :expected "0" :actual "(let [a (atom 0)] (mapcat (fn [x] (swap! a inc) [x]) (range 5)) @a)"} {:suite "chunking-model / unchunked realization granularity" :label "dedupe is fully lazy at construction" :expected "0" :actual "(let [a (atom 0)] (dedupe (map (fn [x] (swap! a inc) x) (range 5))) @a)"} + ;; --- integer-box-model: narrow int values behave as integers (certified) --- + ;; jolt unifies every integer as one exact-integer type, so (byte/short/int n) + ;; produce value-correct integers — only the reified class differs (below). + {:suite "integer-box-model / narrow ints behave as integers" :label "byte = plain integer by value" :expected "true" :actual "(= (byte 5) 5)"} + {:suite "integer-box-model / narrow ints behave as integers" :label "byte arithmetic promotes" :expected "6" :actual "(+ (byte 5) 1)"} + {:suite "integer-box-model / narrow ints behave as integers" :label "byte is a Number" :expected "true" :actual "(instance? Number (byte 5))"} + ;; --- integer-box-model divergences (allowlisted): no narrow box types. A Chez + ;; fixnum is an immediate identical to the plain integer (cannot be tagged), so + ;; (byte/short/int n) report Long, not Byte/Short/Integer. Value is correct. + ;; jolt-k9sw (accepted divergence). + {:suite "integer-box-model / narrow int class collapses to Long" :label "byte class" :expected "java.lang.Long" :actual "(class (byte 5))"} + {:suite "integer-box-model / narrow int class collapses to Long" :label "short class" :expected "java.lang.Long" :actual "(class (short 5))"} + {:suite "integer-box-model / narrow int class collapses to Long" :label "int class" :expected "java.lang.Long" :actual "(class (int 5))"} + {:suite "integer-box-model / narrow int class collapses to Long" :label "instance? Byte is false" :expected "false" :actual "(instance? Byte (byte 5))"} + {:suite "integer-box-model / narrow int class collapses to Long" :label "instance? Long is true" :expected "true" :actual "(instance? Long (byte 5))"} {:suite "untested / JVM-shape stubs (documented jolt behavior)" :label "class number" :expected "java.lang.Long" :actual "(class 1)"} {:suite "untested / JVM-shape stubs (documented jolt behavior)" :label "class string" :expected "java.lang.String" :actual "(class \"s\")"} {:suite "untested / JVM-shape stubs (documented jolt behavior)" :label "class keyword" :expected "clojure.lang.Keyword" :actual "(class :k)"} diff --git a/test/conformance/SPEC.md b/test/conformance/SPEC.md index d8c58a4..bf9cef1 100644 --- a/test/conformance/SPEC.md +++ b/test/conformance/SPEC.md @@ -119,6 +119,19 @@ allowlisted in `known-divergences.edn`: chunk. Strictly finer-grained laziness, decided after the chunk fast path (jolt-j9dz) was made O(n). +## Narrow integer types + +jolt unifies every integer as one exact-integer type (`:integer-box-model`, +jolt-k9sw). `(byte n)`/`(short n)`/`(int n)` produce value-correct integers — +arithmetic, `=`, and `hash` behave exactly as the JVM — but report `Long`, not +`Byte`/`Short`/`Integer`, so `(class (byte 5))` and `(instance? Byte (byte 5))` +diverge. This is substrate-inherent: a Chez fixnum is an immediate `identical?` +to the plain integer (nothing to tag, and numbers carry no metadata), so the only +faithful representation is a boxed type — which would crash raw compiled `(+ …)` +(arithmetic emits a bare Chez `+`) or force every `+`/`-`/`*` through an +unwrapping dispatcher, de-optimizing all arithmetic. Same shape as the accepted +BigInt-vs-Long unification. + ## Hosting jolt on a new runtime 1. Implement the reader + analyzer + a backend for your runtime (see the Chez port diff --git a/test/conformance/known-divergences.edn b/test/conformance/known-divergences.edn index 2940b78..a49ea24 100644 --- a/test/conformance/known-divergences.edn +++ b/test/conformance/known-divergences.edn @@ -16,7 +16,9 @@ :seq-type-model "jolt models every seq as PersistentList (eager) or LazySeq (deferred); JVM reifies a specialized class per producer (Cons/Iterate/LongRange/Repeat/Cycle/ChunkedSeq/StringSeq/KeySeq/RSeq/ArraySeq/SubVector). Values and laziness are correct, only (class …) differs. jolt-aei7", :chunking-model - "jolt seqs are unchunked: forcing one element realizes one (JVM realizes a ~32-element chunk), and mapcat/dedupe realize 0 at construction where JVM forces the first chunk — jolt is a finer-grained lazy superset. jolt-mm6v"}, + "jolt seqs are unchunked: forcing one element realizes one (JVM realizes a ~32-element chunk), and mapcat/dedupe realize 0 at construction where JVM forces the first chunk — jolt is a finer-grained lazy superset. jolt-mm6v", + :integer-box-model + "jolt unifies every integer as one exact-integer type. A Chez fixnum is an immediate identical to the plain integer (no distinct identity to tag, no metadata on numbers), so (byte/short/int n) report Long, not Byte/Short/Integer. Value/arithmetic/equality are correct; a faithful narrow box would crash raw compiled (+ …) or de-optimize all arithmetic. jolt-k9sw"}, :entries [{:suite "forms / fn", :label "no param vector", @@ -54,4 +56,9 @@ {:suite "chunking-model / unchunked realization granularity", :label "first over a vector realizes one, not a chunk", :category :chunking-model} {:suite "chunking-model / unchunked realization granularity", :label "nth 0 over a vector realizes one", :category :chunking-model} {:suite "chunking-model / unchunked realization granularity", :label "mapcat is fully lazy at construction", :category :chunking-model} - {:suite "chunking-model / unchunked realization granularity", :label "dedupe is fully lazy at construction", :category :chunking-model}]} + {:suite "chunking-model / unchunked realization granularity", :label "dedupe is fully lazy at construction", :category :chunking-model} + {:suite "integer-box-model / narrow int class collapses to Long", :label "byte class", :category :integer-box-model} + {:suite "integer-box-model / narrow int class collapses to Long", :label "short class", :category :integer-box-model} + {:suite "integer-box-model / narrow int class collapses to Long", :label "int class", :category :integer-box-model} + {:suite "integer-box-model / narrow int class collapses to Long", :label "instance? Byte is false", :category :integer-box-model} + {:suite "integer-box-model / narrow int class collapses to Long", :label "instance? Long is true", :category :integer-box-model}]}