Tsonic GitHub

Model (Data Structures)

The Model defines all data structures used throughout the pipeline. These are immutable records that flow from Load through Emit.

SymbolGraph

File: Model/SymbolGraph.cs

Central registry of all types. The SymbolGraph is the primary data structure passed between phases.

public sealed record SymbolGraph
{
    public ImmutableArray<NamespaceSymbol> Namespaces { get; }
    public IReadOnlyDictionary<string, TypeSymbol> TypeIndex { get; }

    public bool TryGetType(string clrFullName, out TypeSymbol? type);
    public SymbolGraph WithIndices();  // Rebuild lookup indices
}

Key invariants:

  • TypeIndex is keyed by CLR full name (e.g., System.Collections.Generic.List1`)
  • Each namespace appears once
  • Types are unique by StableId

NamespaceSymbol

File: Model/Symbols/NamespaceSymbol.cs

public sealed record NamespaceSymbol
{
    public string Name { get; }                              // "System.Collections.Generic"
    public bool IsRoot { get; }                              // true for empty namespace
    public ImmutableArray<TypeSymbol> Types { get; }
    public ImmutableArray<string> ContributingAssemblies { get; }  // Which DLLs contributed types
}

TypeSymbol

File: Model/Symbols/TypeSymbol.cs

Represents a CLR type (class, interface, struct, enum, delegate).

public sealed record TypeSymbol
{
    // Identity
    public TypeStableId StableId { get; }
    public string ClrFullName { get; }                       // "System.Collections.Generic.List`1"
    public string TsEmitName { get; }                        // "List_1"
    public string Namespace { get; }
    public int Arity { get; }                                // Generic parameter count

    // Classification
    public TypeKind Kind { get; }                            // Class, Interface, Struct, Enum, Delegate
    public Accessibility Accessibility { get; }
    public bool IsAbstract { get; }
    public bool IsSealed { get; }
    public bool IsStatic { get; }

    // Inheritance
    public TypeReference? BaseClass { get; }
    public ImmutableArray<TypeReference> Interfaces { get; }

    // Generics
    public ImmutableArray<GenericParameterSymbol> GenericParameters { get; }

    // Members
    public MemberCollection Members { get; }

    // Shape pass outputs
    public ImmutableArray<ExplicitView> ExplicitViews { get; }  // From ViewPlanner
}

TypeKind

Classification of CLR types:

public enum TypeKind
{
    Class,              // Reference type with implementation
    Interface,          // Contract only
    Struct,             // Value type
    Enum,               // Enumeration
    Delegate,           // Callable type
    StaticNamespace     // Static class (no instance members)
}

TypeScript mapping:

TypeKind TypeScript Pattern
Class interface + const
Interface interface
Struct interface + const
Enum const enum
Delegate type = (...) => R
StaticNamespace abstract class

MemberCollection

Container for all member types on a TypeSymbol:

public sealed record MemberCollection
{
    public ImmutableArray<MethodSymbol> Methods { get; }
    public ImmutableArray<PropertySymbol> Properties { get; }
    public ImmutableArray<FieldSymbol> Fields { get; }
    public ImmutableArray<EventSymbol> Events { get; }
    public ImmutableArray<ConstructorSymbol> Constructors { get; }
}

MethodSymbol

File: Model/Symbols/MemberSymbols/MethodSymbol.cs

public sealed record MethodSymbol
{
    public MemberStableId StableId { get; }
    public string ClrName { get; }
    public string TsEmitName { get; }

    public TypeReference ReturnType { get; }
    public ImmutableArray<ParameterSymbol> Parameters { get; }
    public ImmutableArray<GenericParameterSymbol> GenericParameters { get; }

    public bool IsStatic { get; }
    public bool IsVirtual { get; }
    public bool IsAbstract { get; }
    public bool IsOverride { get; }
    public bool IsExtensionMethod { get; }

    public EmitScope EmitScope { get; }
    public TypeReference? SourceInterface { get; }  // If from interface
}

EmitScope

Determines where a member appears in TypeScript output:

public enum EmitScope
{
    Unspecified,    // Not yet decided (invalid after Shape)
    ClassSurface,   // On the $instance interface
    StaticSurface,  // On the static const declaration
    ViewOnly,       // Only in __$views interface (explicit impl)
    Omitted         // Not emitted to .d.ts (tracked in metadata)
}

EmitScope Assignment

Shape passes assign EmitScope based on analysis:

Scenario EmitScope
Normal instance method ClassSurface
Static method StaticSurface
Explicit interface impl ViewOnly
Indexer (conflicts) Omitted
Generic static member Omitted

EmitScope in Output

// ClassSurface -> $instance interface
export interface List_1$instance<T> {
    add(item: T): void;        // EmitScope.ClassSurface
    readonly count: int;       // EmitScope.ClassSurface
}

// StaticSurface -> const declaration
export declare const List_1: {
    new <T>(): List_1<T>;     // Constructor
    empty<T>(): List_1<T>;    // EmitScope.StaticSurface
};

// ViewOnly -> __$views interface
export interface __List_1$views<T> {
    As_ICollection(): ICollection;  // EmitScope.ViewOnly
}

TypeReference Hierarchy

File: Model/Types/TypeReference.cs

Abstract base for all type references. Used in signatures, constraints, and inheritance.

public abstract record TypeReference;

NamedTypeReference

Reference to a named type (class, interface, struct, enum, delegate):

public sealed record NamedTypeReference(
    string AssemblyName,                         // "System.Private.CoreLib"
    string FullName,                             // "System.Collections.Generic.List`1"
    string Name,                                 // "List`1"
    ImmutableArray<TypeReference> TypeArguments  // Generic arguments
) : TypeReference;

Examples:

  • List<string> -> FullName: System.Collections.Generic.List1, TypeArguments: [string`]
  • Dictionary<int, string> -> FullName: ...Dictionary2, TypeArguments: [int, string`]

GenericParameterReference

Reference to a generic type parameter (T, TKey, etc.):

public sealed record GenericParameterReference(
    string Name,              // "T", "TKey", "TResult"
    int Position,             // 0-based position
    bool IsMethodParameter    // true if method-level, false if type-level
) : TypeReference;

ArrayTypeReference

Reference to an array type:

public sealed record ArrayTypeReference(
    TypeReference ElementType,
    int Rank                   // 1 for T[], 2 for T[,], etc.
) : TypeReference;

PointerTypeReference

Reference to a pointer type (unsafe):

public sealed record PointerTypeReference(
    TypeReference ElementType  // The pointed-to type
) : TypeReference;

Maps to ptr<T> in TypeScript (from @tsonic/core/types.js).

ByRefTypeReference

Reference to a by-reference type (ref/out/in parameters):

public sealed record ByRefTypeReference(
    TypeReference ElementType,
    RefKind Kind               // Ref, Out, In
) : TypeReference;

Tracked in metadata.json via parameterModifiers (ref/out/in). The emitted .d.ts uses the element type directly.

NullableTypeReference

Reference to a nullable type:

public sealed record NullableTypeReference(
    TypeReference UnderlyingType
) : TypeReference;

Maps to T | null in TypeScript.

StableId

Unique identifier for symbols that survives transformations. Used as dictionary keys and for tracking across phases.

TypeStableId

public sealed record TypeStableId
{
    public string AssemblyName { get; }   // "System.Private.CoreLib"
    public string ClrFullName { get; }    // "System.Collections.Generic.List`1"

    // Format: "AssemblyName:ClrFullName"
    public override string ToString() => $"{AssemblyName}:{ClrFullName}";
}

MemberStableId

public sealed record MemberStableId
{
    public string DeclaringClrType { get; }    // "System.Collections.Generic.List`1"
    public string CanonicalSignature { get; }  // "Add(T):void"
    public int MetadataToken { get; }          // CLR metadata token

    // Format: "DeclaringType::Signature (Token)"
}

Canonical Signature Format:

  • Methods: MethodName(ParamType1,ParamType2):ReturnType
  • Properties: PropertyName|PropertyType
  • Fields: FieldName|FieldType

ExplicitView

Output from ViewPlanner - represents an As_IInterface property:

public sealed record ExplicitView(
    TypeReference InterfaceReference,  // The interface being viewed
    string ViewPropertyName,           // "As_IEnumerable_1"
    ImmutableArray<MemberStableId> Members  // Members in this view
);

GenericParameterSymbol

Represents a generic type parameter with constraints:

public sealed record GenericParameterSymbol
{
    public string Name { get; }                              // "T", "TKey"
    public int Position { get; }                             // 0-based
    public GenericParameterConstraints Constraints { get; }
}

public sealed record GenericParameterConstraints
{
    public bool HasReferenceTypeConstraint { get; }    // where T : class
    public bool HasValueTypeConstraint { get; }        // where T : struct
    public bool HasDefaultConstructorConstraint { get } // where T : new()
    public ImmutableArray<TypeReference> TypeConstraints { get; }  // where T : IFoo
}