declare module '@glimmer/interfaces/lib/template' {
    import type { PresentArray } from "@glimmer/interfaces/lib/array.js";
    import type { EncoderError } from "@glimmer/interfaces/lib/compile/encoder.js";
    import type { Operand, SerializedInlineBlock, SerializedTemplateBlock } from "@glimmer/interfaces/lib/compile/index.js";
    import type { Nullable, Optional } from "@glimmer/interfaces/lib/core.js";
    import type { InternalComponentCapabilities } from "@glimmer/interfaces/lib/managers/internal/component.js";
    import type { ConstantPool, EvaluationContext, SerializedHeap } from "@glimmer/interfaces/lib/program.js";
    import type { Owner } from "@glimmer/interfaces/lib/runtime.js";
    import type { BlockSymbolTable, ProgramSymbolTable, SymbolTable } from "@glimmer/interfaces/lib/tier1/symbol-table.js";

    export interface CompilableProgram extends CompilableTemplate<ProgramSymbolTable> {
      moduleName: string;
    }

    export type CompilableBlock = CompilableTemplate<BlockSymbolTable>;

    export interface LayoutWithContext {
      readonly id: string;
      readonly block: SerializedTemplateBlock;
      readonly moduleName: string;
      readonly owner: Owner | null;
      readonly scope: (() => unknown[]) | undefined | null;
      readonly isStrictMode: boolean;
    }

    export interface BlockWithContext {
      readonly block: SerializedInlineBlock;
      readonly containingLayout: LayoutWithContext;
    }

    /**
     * Environment specific template.
     */
    export interface TemplateOk {
      result: "ok";

      /**
       * Module name associated with the template, used for debugging purposes
       */
      moduleName: string;

      // internal casts, these are lazily created and cached
      asLayout(): CompilableProgram;
      asWrappedLayout(): CompilableProgram;
    }

    export interface TemplateError {
      result: "error";

      problem: string;
      span: {
        start: number;
        end: number;
      };
    }

    export type Template = TemplateOk | TemplateError;

    export type TemplateFactory = (owner?: Owner) => Template;

    export interface STDLib {
      main: number;
      "cautious-append": number;
      "trusting-append": number;
      "cautious-non-dynamic-append": number;
      "trusting-non-dynamic-append": number;
    }

    export type SerializedStdlib = [number, number, number];

    export type STDLibName = keyof STDLib;

    export type CompilerBuffer = Array<Operand>;

    export interface ResolvedLayout {
      handle: number;
      capabilities: InternalComponentCapabilities;
      compilable: Nullable<CompilableProgram>;
    }

    export type OkHandle = number;
    export interface ErrHandle {
      handle: number;
      errors: PresentArray<EncoderError>;
    }

    export type HandleResult = OkHandle | ErrHandle;

    export interface NamedBlocks {
      get(name: string): Nullable<SerializedInlineBlock>;
      has(name: string): boolean;
      with(name: string, block: Nullable<SerializedInlineBlock>): NamedBlocks;
      hasAny: boolean;
      names: string[];
    }

    export interface CompilerArtifacts {
      heap: SerializedHeap;
      constants: ConstantPool;
    }

    export interface CompilableTemplate<S extends SymbolTable = SymbolTable> {
      symbolTable: S;
      meta: BlockMetadata;
      compile(context: EvaluationContext): HandleResult;
    }

    export interface BlockSymbolNames {
      locals: Nullable<string[]>;
      lexical?: Optional<string[]>;
      upvars: Nullable<string[]>;
    }

    export interface DebuggerInfo {
      locals: Record<string, number>;
      lexical: Record<string, number>;
      upvars: Record<string, number>;
    }

    export interface BlockMetadata {
      symbols: BlockSymbolNames;
      scopeValues: unknown[] | null;
      isStrictMode: boolean;
      moduleName: string | undefined;
      owner: Owner | null;
      size: number;
    }
}