deftype/record: clojure.lang collection interfaces + protocol identity

Running clojure.core.match (a macro-heavy library that builds its compiler out
of deftypes implementing clojure.lang interfaces) shook out a cluster of general
gaps. Its own suite goes from not-loading to 111/115 assertions.

- deftype/defrecord implementing a clojure.lang collection interface now drives
  the core fns: Indexed -> nth, Counted -> count, Associative -> assoc, ILookup
  -> get/valAt (non-field keys only, so a method's own field bindings don't
  recurse), ISeq -> seq/first/rest, IPersistentCollection -> conj, IFn -> the
  value is callable. A jrec is still a map of fields by default; the interface
  method wins when declared.

- Multi-arity inline methods are grouped into one fn (a type with (nth [_ i]) and
  (nth [_ i x]) kept only the last before). Built as data, not a nested
  syntax-quote, so a `(= ~ocr ~l) method body keeps its unquotes.

- instance?/satisfies? recognize a protocol a type implements, including a MARKER
  protocol with no methods (core.match's IPseudoPattern) — deftype/defrecord now
  record protocol satisfaction even with zero methods. Added ILookup/Indexed/
  Counted to the instance? taxonomy for the built-in collections.

- Syntax-quote: a fully-qualified class name (clojure.lang.ILookup) stays bare
  instead of being namespace-qualified; (unquote x) is detected in a lazy seq
  (a macro that builds its template with map, e.g. deftype's rewrite-set).

- clojure.set union/intersection/difference are variadic (& sets) + union 0-arity.
- java map view methods: keySet/values/entrySet/size/isEmpty.
- deprecated java.util.Date getters (getYear/getMonth/...) + the multi-arg
  (Date. year-1900 month0 date hrs min) constructor.

Seed change (deftype/defrecord macros + clojure.set) -> re-minted; the rest are
runtime. 11 JVM-certified corpus rows; make test + shakesmoke green.
This commit is contained in:
Yogthos 2026-06-25 00:14:19 -04:00
parent 3cbfa8719c
commit f5455115a0
12 changed files with 1044 additions and 907 deletions

View file

@ -435,7 +435,18 @@
;; or (Date. another-date) -> a jinst (ms-of accepts a number / jinst / instant), so
;; .getTime / inst? / instance? Date|Timestamp work.
(define (date-ctor . args)
(make-jinst (if (null? args) (now-ms) (ms->exact (ms-of (car args))))))
(cond
((null? args) (make-jinst (now-ms)))
((null? (cdr args)) (make-jinst (ms->exact (ms-of (car args)))))
;; deprecated (Date. year-1900 month0 date [hrs min sec]) — civil fields in UTC.
(else
(let* ((y (+ 1900 (jnum->exact (list-ref args 0))))
(mo (+ 1 (jnum->exact (list-ref args 1))))
(d (jnum->exact (list-ref args 2)))
(hh (if (> (length args) 3) (jnum->exact (list-ref args 3)) 0))
(mm (if (> (length args) 4) (jnum->exact (list-ref args 4)) 0))
(ss (if (> (length args) 5) (jnum->exact (list-ref args 5)) 0)))
(make-jinst (* 1000 (+ (* (days-from-civil y mo d) 86400) (* hh 3600) (* mm 60) ss)))))))
(register-class-ctor! "Date" date-ctor)
(register-class-ctor! "java.util.Date" date-ctor)
(register-class-ctor! "Timestamp" date-ctor)
@ -532,6 +543,14 @@
(cond
((jinst? obj)
(cond ((string=? method-name "getTime") (jinst-ms obj))
;; deprecated java.util.Date accessors (UTC civil fields).
((string=? method-name "getYear") (- (list-ref (inst-fields (jinst-ms obj)) 0) 1900))
((string=? method-name "getMonth") (- (list-ref (inst-fields (jinst-ms obj)) 1) 1))
((string=? method-name "getDate") (list-ref (inst-fields (jinst-ms obj)) 2))
((string=? method-name "getHours") (list-ref (inst-fields (jinst-ms obj)) 3))
((string=? method-name "getMinutes") (list-ref (inst-fields (jinst-ms obj)) 4))
((string=? method-name "getSeconds") (list-ref (inst-fields (jinst-ms obj)) 5))
((string=? method-name "getDay") (list-ref (inst-fields (jinst-ms obj)) 7))
((string=? method-name "toInstant") (mk-instant (jinst-ms obj)))
((string=? method-name "toLocalDate") (mk-local-date (jinst-ms obj)))
((string=? method-name "toLocalDateTime") (mk-local (jinst-ms obj)))