Lower typed Kotlin return statements

ober

d8411d7cb83e3606bf11b4426042360829284ae0

diff --git a/lib/jerboa/typed/checker.ss b/lib/jerboa/typed/checker.ss
index 035f009..7c5318a 100644
--- a/lib/jerboa/typed/checker.ss
+++ b/lib/jerboa/typed/checker.ss
@@ -3199,6 +3199,10 @@
                           (append cond-errors body-errors))))]
              [(break continue)
               (values moved '())]
+             [(return)
+              (if (= (length args) 1)
+                (check-ownership-expression (car args) env moved)
+                (values moved '()))]
              [(try)
               (if (= (length args) 2)
                 (let ([catch-form (expr-value (cadr args))])
@@ -3389,6 +3393,31 @@
                       exception-ir))
                (append exception-errors result-type-errors)))))]))
 
+  (def (infer-return args env type-names expr)
+    (cond
+      [(null? args)
+       (values
+         (make-typed-ir-return
+           'Unit
+           (expr-source expr)
+           (make-typed-ir-lit 'Unit (expr-source expr) '()))
+         '())]
+      [(= (length args) 1)
+       (let-values ([(value-ir value-errors)
+                     (infer-expression (car args) env type-names)])
+         (values
+           (and value-ir
+                (make-typed-ir-return
+                  'Unit
+                  (expr-source expr)
+                  value-ir))
+           value-errors))]
+      [else
+       (values #f
+         (list (error-at expr 'bad-return
+                 "return expects zero or one expression"
+                 expr)))]))
+
   (def (infer-try args env type-names expr)
     (cond
       [(not (= (length args) 2))
@@ -3522,6 +3551,8 @@
                   (list (error-at expr 'bad-continue
                           "continue expects no operands"
                           expr))))]
+             [(return)
+              (infer-return args env type-names expr)]
              [(throw)
               (infer-throw args env type-names expr)]
              [(try)
diff --git a/lib/jerboa/typed/core.ss b/lib/jerboa/typed/core.ss
index ebfc4d2..16360f6 100644
--- a/lib/jerboa/typed/core.ss
+++ b/lib/jerboa/typed/core.ss
@@ -62,6 +62,10 @@
     make-typed-ir-continue
     typed-ir-continue-type typed-ir-continue-source
 
+    typed-ir-return?
+    make-typed-ir-return
+    typed-ir-return-type typed-ir-return-source typed-ir-return-expr
+
     typed-ir-throw?
     make-typed-ir-throw
     typed-ir-throw-type typed-ir-throw-source
@@ -147,6 +151,7 @@
   (defstruct typed-ir-while (type source test body))
   (defstruct typed-ir-break (type source))
   (defstruct typed-ir-continue (type source))
+  (defstruct typed-ir-return (type source expr))
   (defstruct typed-ir-throw (type source exception))
   (defstruct typed-ir-try (type source body catch-name catch-type catch-body))
   (defstruct typed-ir-lambda (type source params body))
@@ -277,6 +282,7 @@
         (typed-ir-while? x)
         (typed-ir-break? x)
         (typed-ir-continue? x)
+        (typed-ir-return? x)
         (typed-ir-throw? x)
         (typed-ir-try? x)
         (typed-ir-lambda? x)
@@ -298,6 +304,7 @@
       [(typed-ir-while? node) (typed-ir-while-type node)]
       [(typed-ir-break? node) (typed-ir-break-type node)]
       [(typed-ir-continue? node) (typed-ir-continue-type node)]
+      [(typed-ir-return? node) (typed-ir-return-type node)]
       [(typed-ir-throw? node) (typed-ir-throw-type node)]
       [(typed-ir-try? node) (typed-ir-try-type node)]
       [(typed-ir-lambda? node) (typed-ir-lambda-type node)]
@@ -320,6 +327,7 @@
       [(typed-ir-while? node) (typed-ir-while-source node)]
       [(typed-ir-break? node) (typed-ir-break-source node)]
       [(typed-ir-continue? node) (typed-ir-continue-source node)]
+      [(typed-ir-return? node) (typed-ir-return-source node)]
       [(typed-ir-throw? node) (typed-ir-throw-source node)]
       [(typed-ir-try? node) (typed-ir-try-source node)]
       [(typed-ir-lambda? node) (typed-ir-lambda-source node)]
diff --git a/lib/jerboa/typed/kotlin/lower.ss b/lib/jerboa/typed/kotlin/lower.ss
index 23e8d4b..ba3535e 100644
--- a/lib/jerboa/typed/kotlin/lower.ss
+++ b/lib/jerboa/typed/kotlin/lower.ss
@@ -854,6 +854,10 @@
        (make-kt-break)]
       [(typed-ir-continue? ir)
        (make-kt-continue)]
+      [(typed-ir-return? ir)
+       (make-kt-block
+         (list (make-kt-return (lower-expr (typed-ir-return-expr ir))))
+         (make-kt-lit 'Unit '()))]
       [(typed-ir-throw? ir)
        (make-kt-throw (lower-expr (typed-ir-throw-exception ir)))]
       [(typed-ir-try? ir)
@@ -918,6 +922,8 @@
          (make-kt-while
            (lower-expr (typed-ir-while-test ir))
            (lower-unit-statements (typed-ir-while-body ir))))]
+      [(typed-ir-return? ir)
+       (list (make-kt-return (lower-expr (typed-ir-return-expr ir))))]
       [(and (typed-ir-call? ir)
             (eq? (typed-ir-call-kind ir) 'record-setter))
        (list (lower-record-setter-statement ir))]
diff --git a/tests/test-typed-checker.ss b/tests/test-typed-checker.ss
index b6bd209..ce72032 100644
--- a/tests/test-typed-checker.ss
+++ b/tests/test-typed-checker.ss
@@ -2016,6 +2016,28 @@
            (int32 1)))))
   '(while-body-type-mismatch))
 
+(test "return expression typechecks in sequence"
+  (error-kinds
+    '(typed-library (control return-ok)
+       (export f)
+       (type Int32)
+       (def (f (ready : Bool)) : Bool
+         (begin
+           (if ready
+             (return #t)
+             (begin))
+           #f))))
+  '())
+
+(test "return rejects too many operands"
+  (error-kinds
+    '(typed-library (control return-bad)
+       (export f)
+       (type Int32)
+       (def (f) : Unit
+         (return (int32 1) (int32 2)))))
+  '(bad-return))
+
 (printf "~%Typed checker: ~a passed, ~a failed~%" pass fail)
 (when (> fail 0)
   (exit 1))
diff --git a/tests/test-typed-kotlin.ss b/tests/test-typed-kotlin.ss
index 477d041..04675f6 100644
--- a/tests/test-typed-kotlin.ss
+++ b/tests/test-typed-kotlin.ss
@@ -1502,6 +1502,20 @@
        (def (ready) : Bool
          (densityReady density)))))
 
+(define return-form
+  '(typed-library (sample typed returns)
+     (export guarded)
+     (type Int32)
+     (def (guarded (ready : Bool)) : Bool
+       (begin
+         (if ready
+           (return #t)
+           (begin))
+         #f))))
+
+(define return-kotlin
+  (typed-library-form->kotlin-string return-form))
+
 (define class-declaration-kotlin
   (typed-library-form->kotlin-string class-declaration-form))
 
@@ -1520,6 +1534,9 @@
 (test-contains "typed class declaration lowers method modifiers"
   class-declaration-kotlin
   "override fun performClick(): Boolean {\n        return run {\n    bindSelf(this)\n    super.performClick()\n    true\n}")
+(test-contains "typed return lowers to Kotlin return statement"
+  return-kotlin
+  "return true")
 
 (printf "typed-kotlin tests: ~a passed, ~a failed~%" pass fail)
 (when (> fail 0) (exit 1))