Extend Kotlin JVM interop types

ober

41464c7b713d7382d2c66e9ed9ccb994a239c190

diff --git a/docs/typed-kotlin.md b/docs/typed-kotlin.md
index dcd3b2e..4cd0d7a 100644
--- a/docs/typed-kotlin.md
+++ b/docs/typed-kotlin.md
@@ -16,9 +16,12 @@ by the Rust and LLVM work:
   construction, and simple `for/fold`.
 
 For JVM/Android interop, a typed module may declare nominal external types with
-`(type ...)`. The Kotlin backend preserves those names, except for the
-conventional `(type Float32)`, which lowers to Kotlin `Float` for APIs such as
-Android graphics and ML Kit models.
+`(type ...)`. The Kotlin backend preserves those names, except for conventional
+JVM scalar interop aliases: `(type Int32)` lowers to Kotlin `Int`, and
+`(type Float32)` lowers to Kotlin `Float` for APIs such as Android graphics and
+ML Kit models. The Kotlin backend also accepts `(MutableList T)` for JVM APIs
+and Android model objects that require mutable Kotlin collections, and
+`(Nullable T)` for Kotlin nullable types such as `FloatArray?`.
 
 Public entry points:
 
diff --git a/lib/jerboa/typed/checker.ss b/lib/jerboa/typed/checker.ss
index 42ec470..1b598e4 100644
--- a/lib/jerboa/typed/checker.ss
+++ b/lib/jerboa/typed/checker.ss
@@ -49,6 +49,8 @@
   (def compound-type-arities
     '((List . 1)
       (Vector . 1)
+      (MutableList . 1)
+      (Nullable . 1)
       (Option . 1)
       (Result . 2)
       (Pair . 2)
diff --git a/lib/jerboa/typed/kotlin/lower.ss b/lib/jerboa/typed/kotlin/lower.ss
index fed61ac..e479cbb 100644
--- a/lib/jerboa/typed/kotlin/lower.ss
+++ b/lib/jerboa/typed/kotlin/lower.ss
@@ -82,6 +82,7 @@
          [(Bool) (make-kt-type 'Boolean #f '())]
          [(Char) (make-kt-type 'Char #f '())]
          [(Int Fixnum) (make-kt-type 'Long #f '())]
+         [(Int32) (make-kt-type 'Int #f '())]
          [(Nat) (make-kt-type 'ULong #f '())]
          [(Float) (make-kt-type 'Double #f '())]
          [(Float32) (make-kt-type 'Float #f '())]
@@ -93,6 +94,11 @@
        (make-kt-type 'List #f (list (typed-type->kotlin-type (cadr type))))]
       [(and (pair? type) (eq? (car type) 'Vector))
        (make-kt-type 'List #f (list (typed-type->kotlin-type (cadr type))))]
+      [(and (pair? type) (eq? (car type) 'MutableList))
+       (make-kt-type 'MutableList #f (list (typed-type->kotlin-type (cadr type))))]
+      [(and (pair? type) (eq? (car type) 'Nullable))
+       (let ([inner (typed-type->kotlin-type (cadr type))])
+         (make-kt-type (kt-type-name inner) #t (kt-type-args inner)))]
       [(and (pair? type) (eq? (car type) 'Pair))
        (make-kt-type 'Pair #f
          (list (typed-type->kotlin-type (cadr type))
diff --git a/tests/test-typed-kotlin.ss b/tests/test-typed-kotlin.ss
index 7240754..aa32ba9 100644
--- a/tests/test-typed-kotlin.ss
+++ b/tests/test-typed-kotlin.ss
@@ -128,18 +128,37 @@
 
 (define jvm-form
   '(typed-library (sample typed jvm)
-     (export make-OcrWord OcrWord? OcrWord-conf)
+     (export make-OcrWord OcrWord? OcrWord-conf
+             make-SsdGroup SsdGroup? SsdGroup-cellIds
+             make-SsdSession SsdSession? SsdSession-ssdArea
+             make-ViewportState ViewportState? ViewportState-rotation)
+     (type Int32)
      (type Float32)
      (type FloatArray)
      (record OcrWord
        ((text : String)
         (conf : Float32)
-        (bbox : FloatArray)))))
+        (bbox : FloatArray)))
+     (record SsdGroup
+       ((id : String)
+        (cellIds : (MutableList String))))
+     (record SsdSession
+       ((sessionId : String)
+        (ssdArea : (Nullable FloatArray))))
+     (record ViewportState
+       ((scale : Float32)
+        (rotation : Int32)))))
 
 (define jvm-kotlin (typed-library-form->kotlin-string jvm-form))
 
 (test-contains "declared Float32 lowers to JVM Float" jvm-kotlin
   "data class OcrWord(val text: String, val conf: Float, val bbox: FloatArray)")
+(test-contains "declared Int32 lowers to JVM Int" jvm-kotlin
+  "data class ViewportState(val scale: Float, val rotation: Int)")
+(test-contains "MutableList lowers to Kotlin mutable list" jvm-kotlin
+  "data class SsdGroup(val id: String, val cellIds: MutableList<String>)")
+(test-contains "Nullable lowers to Kotlin nullable type" jvm-kotlin
+  "data class SsdSession(val sessionId: String, val ssdArea: FloatArray?)")
 
 (printf "typed-kotlin tests: ~a passed, ~a failed~%" pass fail)
 (when (> fail 0) (exit 1))