5.2 Rules for Static Information
Exactly how static information is associated to expressions and bindings depends on the expression or binding form. So, it’s not possible to write down exhaustive rules for for Rhombus static information (in the same way that it’s not possible to write down a full grammar, since the grammar can be extended via macros). A binding or expression form’s documentation should define what static information it associates with a name or expression.
Here’s a summary of the static-information behavior of classes:
A class name bound by class acts as a namespace. It provides field-accessor functions, as in Posn.x.
As an annotation, a class name turns any binding or expression using the annotation into a dot provider. A class name followed by .of has the same effect; in addition, it associates any information implied by the argument annotations as static information for fields accessed from the binding or expression through a dot. For example, assuming a class Rect(top_left, side) declaration, r :: Rect.of(Posn, Int) causes r.top_left to have Posn information, with means that r.top_left.x works.
When a class field has an annotation, then that annotation’s static information is associated with a field accessed through the . operator. In the Line example, the p2 field of Line has a Posn annotation, so a l1 :: Line binding means that l1.p2 is a dot provider to access x and y.
When a class field has an annotation, then that annotation’s static information is associated as result information for a field accessor accessed through the . operator. For example, Line.p1 gets the Posn annotation’s static information as its call-result information, so Line.p1(e) has that information, which means that Line.p1(e) is a dot provider.
When a class field has an annotation, and when the class name is used as a pattern form in a binding, then the annotation’s static information is associated with the argument pattern. For example, Line(p1, p2) as a binding pattern associates Posn information to p1 and to p2, which means that they’re dot providers.
When a class name is used as a binding pattern, any “downward” static information that flows the binding is checked for static information keyed by the class’s accessors, and that information is propagated as “downward” information to the corresponding binding subpattern. For example, if Rect(tl, s) as a binding receives “downward” information that associates (the internal key for) Rect.top_left to Posn-annotation information, then the binding form tl receives Posn-annotation information.
More rules about static information in general:
A expression that is parentheses wrapped around an inner expression has the same static information as the inner expression.
When a function call’s function position has result static information, the function call as a whole is given that static information. For example, since Line.p1 has result information that describes a dot provider, Line.p1(e) is a dot provider.
When a fun definition form includes a result annotation, then the annotation’s information is associated to the defined function name as call-result information. For example, if a function definition starts fun flip(x) :: Posn, then Posn static information is associated to flip as result information, so flip(x) is a dot provider. The same applies to a def form that behaves like a fun definition form.
When the right-hand side of a def or let has a single group, and when that goes does not start with a definition-form name, then static information from that right-hand side expression is propagated to the binding side. For example, def p: Posn(1, 2) associated that static information of Posn(1, 2) with p, which among other things means that p.x will be allowed.
The List, Array, and Map expression and binding forms are analogous to class-name forms. For example, Array as a constructor in an expression form associates reference-result information to the overall Array expression, as does […] for constructing a list. In a list binding pattern, when ... is used after a binding subpattern, the “upward” static information of the subpattern for each identifier wrapped as reference-result information for the identifier outside the list pattern, since each; for example [p :: Posn, ...] as a binding pattern causes p to have static information that says its reference result as Posn-annotation information. The List.of, Array.of, and Map.of annotation forms in bindings propagate “downward” reference-result information to nested annotations. “Downward” static information is used by List or […] pattern constructions only in the case that there’s a single element binding pattern followed by ..., while Array and Map as pattern constructors cannot use “downward” information.
The :: binding form and the matching annotation form allow static information to flow both “downward” and “upward” through both annotations and binding patterns.