Documentation
¶
Overview ¶
Package typecheck holds unobin's semantic type model and the static type checker that runs after parsing. Type values carry no source position so the same value compares cleanly whether it came from a written declaration or was inferred from a literal.
The parser's lang.TypeExpr is the syntactic form of a written type declaration; convert it to a Type with FromLang before reasoning about it here.
Index ¶
- func Assignable(dst, src Type) bool
- func FieldKindLabel(kind string) string
- type EachBinding
- type FuncSig
- type Kind
- type LookupLocalFn
- type LookupNodeFn
- type ObjectField
- type Scope
- type Type
- func Check(e lang.Expr, target Type, scope *Scope, errs *lang.ErrorList) Type
- func FromLang(t lang.TypeExpr) Type
- func Infer(e lang.Expr, target Type, scope *Scope, errs *lang.ErrorList) Type
- func TAny() Type
- func TBoolean() Type
- func TInteger() Type
- func TList(elem Type) Type
- func TMap(elem Type) Type
- func TNull() Type
- func TNumber() Type
- func TObject(fields []ObjectField) Type
- func TOptional(elem Type) Type
- func TString() Type
- func TTuple(elems []Type) Type
- func TUnknown() Type
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Assignable ¶
Assignable reports whether a value of type src can flow into a slot declared with type dst. Either side being Unknown returns true so partial schema information fails open rather than producing spurious errors.
Rules in plain terms:
- any accepts anything; null is assignable only into a slot that includes null (an optional() wrapper or the null atom).
- integer widens into number but not the other way.
- optional(T) accepts T, null, or optional(T); a possibly-null source never flows into a slot that wants a value, so null handling is settled at compile and a null can only appear where the program wrote down what happens then.
- list/map/tuple compare element-wise.
- object types compare structurally: every required dst field must have a compatible src field; extra src fields are allowed (open against the source) and missing-optional dst fields are tolerated.
func FieldKindLabel ¶
FieldKindLabel returns the lowercase singular noun for a node kind ("resource", "data source", "action") used in error messages. Lives here so check_refs.go and the inferrer agree.
Types ¶
type EachBinding ¶
EachBinding is the type pair bound by an enclosing @for-each. Key is the index type (integer for lists, string for maps). Value is the iterated element type.
type FuncSig ¶ added in v0.6.0
FuncSig describes a library function to the inferrer: the fixed parameter types in order, the element type of a variadic tail (nil when the function is not variadic), and the result type. A function registered without declared types reads as all-Unknown, which checks nothing and infers nothing.
type Kind ¶
type Kind int
Kind discriminates the Type variants. The zero value Unknown stands in for a type the walker could not determine; the checker skips compatibility comparisons involving Unknown so source the inferrer cannot reason about fails open rather than producing noise.
type LookupLocalFn ¶
LookupLocalFn returns the inferred Type of a `locals:` entry by name. The boolean is false when no such local is declared; the inferrer then returns Unknown without an error (the reference checker reports an unknown local name).
type LookupNodeFn ¶
LookupNodeFn returns the output Type of a node by kind, alias, type, and name. The boolean is false when the node is not known; the inferrer then returns Unknown without an error (the existing reference checker has the responsibility to report unresolved node addresses).
type ObjectField ¶
ObjectField is one named field of an Object type. Optional is true when the field may be absent (e.g. it came from a *T Go field or an optional() declaration). Defaulted is true when an input declaration provides a default, so a missing or null value is replaced before anything reads it.
func InputsFromBlock ¶
func InputsFromBlock(decl *lang.ObjectLit) []ObjectField
InputsFromBlock walks an `inputs:` block object literal and returns each input's name to its semantic type. An input declared with `optional()` holds the inner type with Optional set; Defaulted is set too when the wrapper provides a default. A reader treats a defaulted input as its inner type (the default replaces a missing or null value), while a writer may still omit it or pass null.
type Scope ¶
type Scope struct {
Inputs []ObjectField
Each *EachBinding
LookupNode LookupNodeFn
LookupLocal LookupLocalFn
// LookupFunction resolves a library-qualified function to its
// signature so a call's arguments and result type-check. Nil, or a
// false return, leaves the call inferring Unknown; existence and
// argument count are the reference checker's to enforce.
LookupFunction func(library, name string) (FuncSig, bool)
// Bindings holds comprehension-bound names. They resolve as bare
// values and as dot-path roots ahead of var/resource/data/action,
// so an inner binding shadows an outer one.
Bindings map[string]Type
// Narrowed overrides reference types inside a region guarded by a
// null test, keyed by the canonical dot path ("var.x.y"). A lookup
// takes the longest matching prefix and resumes traversal from the
// narrowed type. Sound because values never change between the
// test and the read.
Narrowed map[string]Type
// MissingAsNull mirrors the evaluation mode of the same name:
// navigating into a possibly-null value reads as null instead of
// failing, so the result of such a path is optional. Constraint
// expressions check in this mode; everything else is strict.
MissingAsNull bool
}
Scope carries the lexical information the inferrer needs to type an expression: local input declarations, an optional @each binding, and a callback that returns the output Type for a node address (resource/data/action.<alias>.<type>.<name>). LookupNode may be nil when the caller has no node table; the walker returns Unknown for any node reference in that case.
type Type ¶
type Type struct {
Kind Kind
Elem *Type
Elems []Type
Fields []ObjectField
}
Type is a structural type description. The Kind field discrim- inates which of the value-bearing fields is populated:
- List/Set/Map/Optional read Elem.
- Tuple reads Elems.
- Object reads Fields.
Pass Type around by value; the recursive children live on the pointer fields so a deeply nested type still copies in constant time at the top level.
func Check ¶
Check infers the type of e and verifies it is assignable to the declared target. Returns the inferred type and appends a mismatch diagnostic to errs when the types are incompatible. An array or object literal matching a container target is enforced element by element inside Infer, so Check's own Assignable comparison skips exactly those pairings and the same mistake is not reported twice; everything else, references and calls included, is compared here.
func FromLang ¶
FromLang turns a parsed lang.TypeExpr into a semantic Type. Returns TUnknown when the input is nil or names a constructor the converter does not understand; the checker treats Unknown as a silent skip.
func Infer ¶
Infer walks e and returns its inferred type. The target steers how ambiguous literals decide between list/tuple and how object literals match against a declared type; pass TUnknown when no target is in effect. Errors found during inference are appended to errs; the return value is best-effort and may be Unknown when nothing useful can be determined.
func TObject ¶
func TObject(fields []ObjectField) Type
func (Type) Equal ¶
Equal reports whether two types describe the same thing. It is recursive and order-sensitive for tuples; object fields compare by name regardless of declaration order so two object types that declare the same fields in different orders match.
func (Type) Field ¶
func (t Type) Field(name string) (ObjectField, bool)
Field returns the named field of an Object type, ok=false when the field is absent or the type is not an Object.
func (Type) IsKnown ¶
IsKnown returns false when the Type is Unknown or wraps Unknown through an Optional. The checker uses this to bail out of comparisons it cannot reason about.
func (Type) String ¶
String renders the type in the unobin type vocabulary the operator would have written: `list(string)`, `optional(integer)`, `object({ a: string b: integer })`. Object field order follows the order the type was constructed in so error messages stay stable with respect to the source.