typecheck

package
v0.7.0-9a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: MIT Imports: 6 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func Assignable

func Assignable(dst, src Type) bool

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:

  • opaque accepts anything, and an opaque source flows only into an opaque slot: the value passes through unread, and a typed slot is a promise to read. 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

func FieldKindLabel(kind string) string

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

type EachBinding struct {
	Key   Type
	Value Type
}

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

type FuncSig struct {
	Params   []Type
	Variadic *Type
	Result   Type
}

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.

const (
	Unknown Kind = iota
	Opaque
	String
	Integer
	Number
	Boolean
	Null
	List
	Map
	Object
	Tuple
	Optional
	// Union appears only in builtin function signatures, constructed
	// by their registrations; inference never produces it and no
	// source syntax writes it.
	Union
)

type LookupLocalFn

type LookupLocalFn func(name string) (Type, bool)

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

type LookupNodeFn func(kind, alias, typ, name string) (Type, bool)

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

type ObjectField struct {
	Name      string
	Type      Type
	Optional  bool
	Defaulted bool
}

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.
	// Names are distinct across nesting; validation rejects an inner
	// comprehension that rebinds an enclosing name.
	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
	// Observe, when set, receives every inferred expression with its
	// type. The residual-Unknown harness reads the stream to find
	// positions the checker cannot type.
	Observe func(e lang.Expr, t Type)
}

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.

func NarrowedWhere added in v0.6.0

func NarrowedWhere(scope *Scope, cond lang.Expr) *Scope

NarrowedWhere returns scope with the narrowings a true condition puts in force, or the scope itself when the condition proves nothing. A constraint's require is checked this way under its when.

type Type

type Type struct {
	Kind   Kind
	Open   bool
	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.

Open applies to Object only: an open object may hold fields beyond the declared ones. Open changes what may be present, never what may be read - dotting into an undeclared field stays an error.

func Check

func Check(e lang.Expr, target Type, scope *Scope, errs *lang.ErrorList) Type

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

func FromLang(t lang.TypeExpr) Type

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

func Infer(e lang.Expr, target Type, scope *Scope, errs *lang.ErrorList) Type

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 TBoolean

func TBoolean() Type

func TInteger

func TInteger() Type

func TList

func TList(elem Type) Type

func TMap

func TMap(elem Type) Type

func TNull

func TNull() Type

func TNumber

func TNumber() Type

func TObject

func TObject(fields []ObjectField) Type

func TOpaque added in v0.6.0

func TOpaque() Type

func TOpenObject added in v0.6.0

func TOpenObject(fields []ObjectField) Type

func TOptional

func TOptional(elem Type) Type

func TString

func TString() Type

func TTuple

func TTuple(elems []Type) Type

func TUnion added in v0.6.0

func TUnion(members []Type) Type

func TUnknown

func TUnknown() Type

func (Type) ContainsUnknown added in v0.6.0

func (t Type) ContainsUnknown() bool

ContainsUnknown reports whether t or any type nested inside it is Unknown. IsKnown looks only through Optional; this walks every element, tuple member, and object field.

func (Type) Equal

func (t Type) Equal(other Type) bool

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

func (t Type) IsKnown() bool

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

func (t Type) String() 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.

func (Type) Unwrap

func (t Type) Unwrap() Type

Unwrap returns the inner type when t is Optional, else t itself. The checker peels optionality before comparing the underlying types.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL