/**
 * Flow narrowing environment application helpers.
 *
 * Contains withAppliedNarrowings, withAssignedAccessPathType,
 * and supporting helpers for managing narrowing environments.
 */
import { getAccessPathKey } from "./access-paths.js";
export const withAppliedNarrowings = (ctx, narrowings) => {
    if (narrowings.length === 0)
        return ctx;
    let nextTypeEnv;
    let nextAccessEnv;
    for (const n of narrowings) {
        if (n.kind === "decl") {
            if (!nextTypeEnv)
                nextTypeEnv = new Map(ctx.typeEnv ?? []);
            nextTypeEnv.set(n.declId, n.targetType);
            continue;
        }
        if (!nextAccessEnv) {
            nextAccessEnv = new Map(ctx.accessEnv ?? []);
        }
        nextAccessEnv.set(n.key, n.targetType);
    }
    return {
        ...ctx,
        ...(nextTypeEnv ? { typeEnv: nextTypeEnv } : {}),
        ...(nextAccessEnv ? { accessEnv: nextAccessEnv } : {}),
    };
};
const isDescendantAccessPath = (target, candidateKey) => {
    const candidate = JSON.parse(candidateKey);
    if (candidate.kind !== target.kind) {
        return false;
    }
    if (target.kind === "decl" &&
        candidate.kind === "decl" &&
        candidate.declId !== target.declId.id) {
        return false;
    }
    if (candidate.segments.length < target.segments.length) {
        return false;
    }
    return target.segments.every((segment, index) => candidate.segments[index] === segment);
};
const withoutAssignedTargetFlow = (ctx, target) => {
    const nextTypeEnv = new Map(ctx.typeEnv ?? []);
    const nextAccessEnv = new Map(ctx.accessEnv ?? []);
    if (target.kind === "decl" && target.segments.length === 0) {
        nextTypeEnv.delete(target.declId.id);
    }
    for (const key of nextAccessEnv.keys()) {
        if (isDescendantAccessPath(target, key)) {
            nextAccessEnv.delete(key);
        }
    }
    return {
        ...ctx,
        typeEnv: nextTypeEnv,
        accessEnv: nextAccessEnv,
    };
};
export const withAssignedAccessPathType = (ctx, target, assignedType) => {
    const cleared = withoutAssignedTargetFlow(ctx, target);
    if (!assignedType) {
        return cleared;
    }
    if (target.kind === "decl" && target.segments.length === 0) {
        const nextTypeEnv = new Map(cleared.typeEnv ?? []);
        nextTypeEnv.set(target.declId.id, assignedType);
        return {
            ...cleared,
            typeEnv: nextTypeEnv,
        };
    }
    const nextAccessEnv = new Map(cleared.accessEnv ?? []);
    nextAccessEnv.set(getAccessPathKey(target), assignedType);
    return {
        ...cleared,
        accessEnv: nextAccessEnv,
    };
};
//# sourceMappingURL=narrowing-environment.js.map