Skip to content

Commit

Permalink
propagate intersection of static info from if and cond branches
Browse files Browse the repository at this point in the history
  • Loading branch information
mflatt committed Mar 20, 2024
1 parent 5d79d9b commit 910982d
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 22 deletions.
61 changes: 42 additions & 19 deletions rhombus/private/cond.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"expression.rkt"
"parse.rkt"
"else-clause.rkt"
"static-info.rkt"
"parens.rkt"
"realm.rkt")

Expand All @@ -21,12 +22,17 @@
(syntax-parse #'(alt ...)
[((tag-thn::block thn ...)
(tag-els::block els ...))
(define thn-e (enforest-expression-block #'(tag-thn thn ...)))
(define els-e (enforest-expression-block #'(tag-els els ...)))
(values
(relocate+reraw
(respan stx)
#'(if (rhombus-expression (group test ...))
(rhombus-body-at tag-thn thn ...)
(rhombus-body-at tag-els els ...)))
(wrap-static-info*
(relocate+reraw
(respan stx)
#`(if (rhombus-expression (group test ...))
#,(discard-static-infos thn-e)
#,(discard-static-infos els-e)))
(static-infos-intersect (extract-static-infos thn-e)
(extract-static-infos els-e)))
#'())]
[_
(raise-syntax-error #f
Expand All @@ -42,26 +48,43 @@
(_::block (group pred ... (tag::block rhs ...)))
...
e::else-clause))
(define rhs-es (map enforest-expression-block
(syntax->list #'((tag rhs ...) ...))))
(define els-e (syntax-parse #'e.parsed
#:literals (rhombus-body-at)
[(rhombus-body-at tag else-rhs ...)
(enforest-expression-block #'(tag else-rhs ...))]
[(rhombus-expression g)
(enforest-expression-block #'g)]
[_ #'e.parsed]))
(values
(relocate+reraw
(respan stx)
#'(cond
[(rhombus-expression (group pred ...))
(rhombus-body-at tag rhs ...)]
...
[else e.parsed]))
(with-syntax ([(rhs ...) (map discard-static-infos rhs-es)])
(wrap-static-info*
(relocate+reraw
(respan stx)
#`(cond
[(rhombus-expression (group pred ...)) rhs]
...
[else #,(discard-static-infos els-e)]))
(for/fold ([si (extract-static-infos els-e)]) ([rhs-e (in-list rhs-es)])
(static-infos-intersect si (extract-static-infos rhs-e)))))
#'())]
[(form-id (_::alts
(_::block (group pred ... (tag::block rhs ...)))
...))
(define rhs-es (map enforest-expression-block
(syntax->list #'((tag rhs ...) ...))))
(values
(relocate+reraw
(respan stx)
#'(cond
[(rhombus-expression (group pred ...))
(rhombus-body-at tag rhs ...)]
...
[else (cond-fallthrough 'form-id)]))
(with-syntax ([(rhs ...) (map discard-static-infos rhs-es)])
(wrap-static-info*
(relocate+reraw
(respan stx)
#'(cond
[(rhombus-expression (group pred ...)) rhs]
...
[else (cond-fallthrough 'form-id)]))
(for/fold ([si (extract-static-infos (car rhs-es))]) ([rhs-e (in-list (cdr rhs-es))])
(static-infos-intersect si (extract-static-infos rhs-e)))))
#'())]
[(form-id (_::block))
(values
Expand Down
13 changes: 13 additions & 0 deletions rhombus/scribblings/ref-cond.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
@rhombus(#false)), returns the result of the @rhombus(then_body) clause,
otherwise returns the result of the @rhombus(else_body) clause.

Static information is gathered from @rhombus(then_body) and
@rhombus(else_body) under the same conditions as the right-hand side of
@rhombus(def) (see @secref("static-info-rules")), and the information is
intersected to determine the static information of the @rhombus(if)
form.

@examples(
if #true
| "yes"
Expand Down Expand Up @@ -69,6 +75,13 @@
If no @rhombus(clause_test_expr) produces a true value and there is no
@rhombus(~else) clause, a run-time exception is thrown.

Static information is gathered from @rhombus(clause_result_body)s or
@rhombus(clause_result_expr) under the same conditions as the right-hand
side of @rhombus(def) (see @secref("static-info-rules")), and the
information is intersected to determine the static information of the
@rhombus(cond) form.


}

@doc(
Expand Down
9 changes: 6 additions & 3 deletions rhombus/scribblings/ref-def.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@
A @rhombus(bind) can be just an identifier or @rhombus(id_name), or it
can be constructed with a binding operator, such as a pattern form or
@rhombus(::) for annotations. The number of result values must match
the number of @rhombus(bind)s.
the number of @rhombus(bind)s. Static information is gathered from
@rhombus(rhs_expr) or @rhombus(body) and propagated to
@rhombus(lhs_bind) as described in @secref("static-info-rules")).

An identifier is bound in the @rhombus(expr, ~space) @tech{space}, and most
binding operators also create bindings in the @rhombus(expr, ~space) space.
An identifier is bound in the @rhombus(expr, ~space) @tech{space}, and
most binding operators also create bindings in the
@rhombus(expr, ~space) space.

When @rhombus(def) is used with @rhombus(=), then @rhombus(rhs_expr) must
not contain any immediate @rhombus(=) terms (although @rhombus(=) can
Expand Down
49 changes: 49 additions & 0 deletions rhombus/tests/cond.rhm
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,52 @@ check:
| #false: 17
| ~else: 18
~is 18

check:
use_static
(if #true | [1] | ["one"])[0]
~is 1

check:
~eval
use_static
(if #true | [1] | "one")[0]
~throws "specialization not known"

check:
use_static
(cond | 1 == 2: [1] | 2 == 2: ["one"])[0]
~is "one"

check:
use_static
(cond | 1 == 2: [1] | ~else: ["one"])[0]
~is "one"

check:
use_static
(cond | 1 == 2: [1] | ~else ["one"])[0]
~is "one"

check:
~eval
use_static
(if #true | [1] | "one")[0]
~throws "specialization not known"

check:
~eval
use_static
(cond | #true: [1] | ~else: "one")[0]
~throws "specialization not known"


check:
~eval
use_static
class Posn(x, y)
def p = (if #true
| Posn(1, 2)
| #void)
p.x
~throws "no such field or method"

0 comments on commit 910982d

Please sign in to comment.