Add typed Kotlin Int32 string conversion

ober

68cd15ee71d554cca08a5dc5e3f0e0bbc22744d1

diff --git a/docs/typed-kotlin.md b/docs/typed-kotlin.md
index 54613f7..cf0a221 100644
--- a/docs/typed-kotlin.md
+++ b/docs/typed-kotlin.md
@@ -29,6 +29,7 @@ JVM-sized numeric and array helpers are explicit typed forms:
 
 - `(float32 value)` narrows any numeric value to Kotlin `Float`.
 - `(int32 value)` narrows any numeric value to Kotlin `Int`.
+- `(int32->string value)` converts a Kotlin `Int` interop value to `String`.
 - `(float-array value ...)` produces a Kotlin `FloatArray`; each value must be
   `Float32`.
 - `(float-array-ref array index)` reads a `Float32` from a `FloatArray` at an
diff --git a/lib/jerboa/typed/checker.ss b/lib/jerboa/typed/checker.ss
index 3e84376..83d619d 100644
--- a/lib/jerboa/typed/checker.ss
+++ b/lib/jerboa/typed/checker.ss
@@ -397,6 +397,9 @@
       (cons 'float-array-ref
             (make-typed-call-sig (list 'FloatArray 'Int32) 'Float32 '()
               'jvm-float-array-ref '()))
+      (cons 'int32->string
+            (make-typed-call-sig (list 'Int32) 'String '()
+              'jvm-to-string '()))
       ;; crypto primitives — FFI to vetted RustCrypto crates, never reimplemented.
       ;; Each carries kind 'crypto-prim and an info `prim` the emitter dispatches
       ;; on; the Rust block they emit references the crate (sha2/hmac/hkdf) that
diff --git a/lib/jerboa/typed/kotlin/lower.ss b/lib/jerboa/typed/kotlin/lower.ss
index d7db9f4..a7897c3 100644
--- a/lib/jerboa/typed/kotlin/lower.ss
+++ b/lib/jerboa/typed/kotlin/lower.ss
@@ -220,6 +220,8 @@
                   (memq (kt-lit-type (car args)) '(Nat Int Int32)))
            (make-kt-lit 'Int32 (kt-lit-value (car args)))
            (make-kt-member-call (car args) 'toInt '()))]
+        [(jvm-to-string)
+         (make-kt-member-call (car args) 'toString '())]
         [(jvm-float-array)
          (make-kt-call (kt-name1 'floatArrayOf) args)]
         [(jvm-float-array-ref)
diff --git a/tests/test-typed-kotlin.ss b/tests/test-typed-kotlin.ss
index 9276ea7..2c45209 100644
--- a/tests/test-typed-kotlin.ss
+++ b/tests/test-typed-kotlin.ss
@@ -215,5 +215,23 @@
 (test-contains "FloatArray indexing lowers to brackets" geometry-kotlin
   "val left: Float = if ((a[0] > b[0])) a[0] else b[0]")
 
+(define key-form
+  '(typed-library (sample typed keys)
+     (export sourceKey)
+     (type Int32)
+     (def (sourceKey (sourceSha1 : String) (page : Int32) (dpi : Int32)) : String
+       (string-append
+         sourceSha1
+         (string-append
+           "-p"
+           (string-append
+             (int32->string page)
+             (string-append "-d" (int32->string dpi))))))))
+
+(define key-kotlin (typed-library-form->kotlin-string key-form))
+
+(test-contains "Int32 to string lowers to Kotlin toString" key-kotlin
+  "page.toString()")
+
 (printf "typed-kotlin tests: ~a passed, ~a failed~%" pass fail)
 (when (> fail 0) (exit 1))