typecheck

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package typecheck is the Luau-style gradual type checker for luascript.

The pass runs between parser and bytecode generator. It consumes the AST (compiler/ast), builds an internal Type representation, walks the program building a scoped type environment, and emits a list of typed errors. The bytecode generator never sees Type values — types are erased before codegen, so the runtime is unchanged.

Design intent: Luau-aligned. Untyped code is implicitly `any` (gradual escape hatch). `--!strict` tightens; `--!nocheck` skips this package entirely (the compiler glue handles that gate).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Same

func Same(a, b *Type) bool

Same reports whether two types are structurally identical. Used by dedup, by invariant comparisons (e.g. table-field width subtyping at shared keys), and by alias-of-itself checks.

Types

type FunctionShape

type FunctionShape struct {
	Params     []*Type
	Returns    []*Type
	IsVararg   bool
	VarargType *Type

	// TypeParams names the function's generic parameters (`f<T, U>`). Non-
	// empty for a generic function; call-site inference resolves them.
	TypeParams []string

	// Struct, when non-nil, marks this function as a struct constructor.
	// The checker then also accepts the single-table "named" call form
	// (`Point{ x = 1, y = 2 }`) in addition to the positional Params form.
	// Field is the ordered struct field list used to validate the named
	// form. FieldNames parallels Params for named-arg checking.
	Struct *StructCtor
}

FunctionShape is the parameter/return signature of a function type. IsVararg + VarargType model `(T, ...: U) -> R`. VarargType nil with IsVararg true means an untyped vararg (treated as any).

type Indexer

type Indexer struct {
	Key   *Type
	Value *Type
}

Indexer covers the `{[K]: V}` form. nil if the table only has named fields.

type Kind

type Kind int

Kind tags the variant of Type. Only one of {Fn, Table, Union} is populated, gated by Kind.

const (
	KindNumber Kind = iota
	KindString
	KindBoolean
	KindNil
	// KindAny is the gradual escape hatch: bidirectionally compatible with
	// every other type. Code that doesn't carry annotations is `any` by
	// default, which is why the checker is lenient on un-typed Lua code.
	KindAny
	// KindUnknown is the safe top: any value flows in, but `unknown` only
	// flows back out via narrowing or explicit assertion. Refinements
	// aren't in v1, so most uses of `unknown` will require `:: T` to be
	// useful.
	KindUnknown
	// KindNever is the bottom: assigns to anything, nothing assigns to it.
	// Used as a placeholder for unresolvable aliases and for the result
	// type of `error("...")`.
	KindNever
	KindFunction
	KindTable
	KindUnion
	// KindTypeParam is a generic type variable (`T` inside `function f<T>`).
	// Within a generic body it behaves gradually — assignable to and from
	// anything, so opaque type-variable code never produces spurious errors.
	// Precision comes from *instantiation*: call-site inference substitutes a
	// concrete type for the variable and re-checks the result. The variable's
	// name is carried in AliasName for display and identity.
	KindTypeParam
)

type Options

type Options struct {
	// Strict: report unannotated function parameters and missing alias
	// resolutions as errors (instead of falling back to `any`).
	Strict bool
}

Options controls checker behavior. Default zero value = nonstrict (Luau-style gradual). Set Strict to enforce annotations on params.

type StructCtor

type StructCtor struct {
	Name  string
	Shape *TableShape
}

StructCtor carries the extra shape a struct constructor needs to validate the brace/named call form. Shape is the structural table each instance conforms to (also what `Name` resolves to as a type alias).

type TableField

type TableField struct {
	Key  string
	Type *Type
}

TableField is one named entry in a TableShape.

type TableShape

type TableShape struct {
	Fields  []TableField
	Indexer *Indexer
}

TableShape is a structural table type. Fields are ordered for stable diagnostics. Indexer covers `{[K]: V}` and the array-shorthand `{T}`.

type Type

type Type struct {
	Kind Kind

	// Populated by Kind:
	Fn    *FunctionShape // KindFunction
	Table *TableShape    // KindTable
	Union []*Type        // KindUnion (always ≥ 2 members; flattened, deduped)

	// AliasName preserves the user-written alias for diagnostics. Set when
	// resolving a TypeName; the structural Kind/Fn/Table fields are still
	// the source of truth for assignability.
	AliasName string
}

Type is the internal type representation. Constructed by the checker from AST type nodes; never reaches the bytecode generator.

func AnyT

func AnyT() *Type

AnyT, NilT, NumberT, StringT, BooleanT, UnknownT, NeverT expose the singleton primitives. Used by package-external callers (stdlib_types.go, the REPL banner).

func BooleanT

func BooleanT() *Type

func NeverT

func NeverT() *Type

func NewFunction

func NewFunction(params []*Type, returns []*Type, isVararg bool, varargType *Type) *Type

NewFunction is a small convenience for stdlib_types.go.

func NewTable

func NewTable(fields []TableField, indexer *Indexer) *Type

NewTable builds a TableShape Type. Either fields or indexer (or both) may be supplied; fields nil/empty + indexer nil makes an empty table.

func NewUnion

func NewUnion(members ...*Type) *Type

NewUnion builds a union of `members`, flattening nested unions, deduping equal types, and short-circuiting to a singleton when the simplification leaves only one member. If `any` appears in the simplified set the result is `any` (the gradual sink absorbs everything).

func NilT

func NilT() *Type

func NumberT

func NumberT() *Type

func Optional

func Optional(t *Type) *Type

Optional builds `T | nil` via NewUnion.

func PrimitiveByName

func PrimitiveByName(name string) *Type

PrimitiveByName returns the singleton primitive Type for `name`, or nil if `name` is not one of the closed-set primitives.

func StringT

func StringT() *Type

func UnknownT

func UnknownT() *Type

func (*Type) String

func (t *Type) String() string

String renders a type in Luau-syntax-faithful form. AliasName takes priority so users see the name they wrote, not the structural expansion.

type TypeError

type TypeError struct {
	Line    int
	Code    string // short stable identifier for tooling, e.g. "incompat-assign"
	Message string // human-readable, single-line
	Got     *Type  // optional — populated for assignability errors
	Want    *Type  // optional — populated for assignability errors
}

TypeError is one entry in the checker's error list. The checker accumulates errors instead of bailing on the first one, so users see the full picture per compile.

func Check

func Check(prog *ast.Program, opts Options) []TypeError

Check runs the type checker over `prog` and returns the accumulated errors. The error list is sorted by source line. An empty slice means the program type-checks under the supplied options.

func (*TypeError) Format

func (e *TypeError) Format() string

Format renders the error in Luau-style:

"Type 'string' could not be converted into 'number' at line 5"

or, when only Message is set, just the bare message + line.

type TypeErrors

type TypeErrors struct {
	Errors []TypeError
}

TypeErrors is the aggregate error type returned by Check. It satisfies `error` so the compiler glue can return it through the standard error channel.

func (*TypeErrors) Error

func (te *TypeErrors) Error() string

Jump to

Keyboard shortcuts

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