class Myst::TypeCheck::MainVisitor
- Myst::TypeCheck::MainVisitor
- Myst::TypeCheck::SemanticVisitor
- Reference
- Object
Defined in:
typecheck/visitors/main_visitor.crInstance Method Summary
- #visit(node : Nop)
- #visit(node : Expressions)
- #visit(node : NilLiteral)
- #visit(node : BooleanLiteral)
- #visit(node : IntegerLiteral)
- #visit(node : FloatLiteral)
- #visit(node : StringLiteral)
- #visit(node : InterpolatedStringLiteral)
- #visit(node : SymbolLiteral)
- #visit(node : ListLiteral)
- #visit(node : MapLiteral)
- #visit(node : MagicConst)
- #visit(node : FunctionCapture)
-
#visit(node : StaticAssignable)
def visit(node : Const | Var | Underscore)
-
#visit(node : IVar)
Until instance variables can have type restrictions applied to them, we can't effectively/efficiently declare an exact type for them, because their mutations are not directly trackable from the AST.
- #visit(node : ValueInterpolation)
- #visit(node : Self)
- #visit(node : SimpleAssign)
- #visit(node : MatchAssign)
-
#visit(node : OpAssign)
Since OpAssigns are generally just a shorthand from
a op= b
to eithera = a op b
ora op a = b
, the typechecker can do a syntactic replacement to get the same result. -
#visit(node : When | Unless)
Merging of conditional scopes is complex.
-
#visit(node : While)
Looping expressions can potentially change the typings resolved in their bodies on each iteration.
- #visit(node : Until)
-
#visit(node : Or)
Boolean logic operations have some nuance to their typing.
- #visit(node : And)
-
#visit(node : Not)
Not is currently an overrideable boolean operator, though in practice it is not overridden, and even when it is it should return a boolean.
- #visit(node : Negation)
- #visit(node : Splat)
- #visit(node : Call)
- #visit(node : Block)
- #visit(node : Def)
- #visit(node : AnonymousFunction)
- #visit(node : Match)
- #visit(node : ModuleDef)
- #visit(node : TypeDef)
- #visit(node : TypeUnion)
- #visit(node : Instantiation)
- #visit(node : Require)
-
#visit(node : Return)
Return expressions have no immediate resulting type as they cause the flow of execution to break.
-
#visit(node : Next)
Next is currently a semantic equivalent of Return.
Instance methods inherited from class Myst::TypeCheck::SemanticVisitor
env : Environment
env,
env=(env : Environment)
env=,
visit(node : Node)
visit
Constructor methods inherited from class Myst::TypeCheck::SemanticVisitor
new(env : Environment)
new
Instance Method Detail
Until instance variables can have type restrictions applied to them,
we can't effectively/efficiently declare an exact type for them,
because their mutations are not directly trackable from the AST. So,
at least for now, they are always just typed as generic Object
s.
This is a bit of a cop-out, but is arguably nicer than trying to determine some exact typing that isn't helpfully-accurate at the time of use.
Since OpAssigns are generally just a shorthand from a op= b
to either
a = a op b
or a op a = b
, the typechecker can do a syntactic
replacement to get the same result.
Merging of conditional scopes is complex. For any given variable, if every clause in the conditional has an assignment to it, then the final type of that variable is simply the union of those types.
However, if any clause does not assign that variable, then the
resulting type must also be unionized with Nil. Also, if the variable
is newly created within the conditional, and is not guaranteed an
assignment (e.g., by an else
clause), then the final type is
inherently nilable and must be unioned.
Thankfully, all of these cases are handled by the combination of the
unionize
and nilify
options of Scope#merge!
.
Looping expressions can potentially change the typings resolved in their bodies on each iteration. To deal with this, the inferrer itself loops over the expression until the types generated by two consecutive iterations are equal. At this point, all possible type values must have been seen and the typing can be applied.
The resulting type of the loop expression is the type of the last expression in the body after the final iteration, unioned with Nil for the case that the loop is never visited.
Boolean logic operations have some nuance to their typing. For example,
in an Or
, if the first expression is nilable, but the second is not,
then the resulting type is guaranteed to not be Nil, so that can be
removed from the union.
Since the only possible falsey values are false
and nil
, if the
type of the left hand side does not include Boolean
or Nil
, the
type will be further restricted (to the left-hand-side only for Or
,
and to the right-hand side for And
).
Not is currently an overrideable boolean operator, though in practice it is not overridden, and even when it is it should return a boolean. This could be expanded to work like a normal Call, or maybe the language will change to disallow overriding the operator.
NOTE This is an intentional deviation from the current behavior of Myst
itself. Realistically, allowing the override of the Not operation
(!expr
) is not useful and causes unnecessary confusion and inconsistency
when done in multiple places.
Return expressions have no immediate resulting type as they cause the
flow of execution to break. Instead, the type gets added to the current
return_type
of the Environment to be considered as part of the
enclosing clause's return type.