import { VType } from "../vtype.ts";
import { Fn, Local, Mir, replaceBlockSrcs, RValue } from "./mir.ts";

export function makeMoveCopyExplicit(mir: Mir) {
    for (const fn of mir.fns) {
        for (const local of fn.locals) {
            new LocalExpliciter(fn, local).pass();
        }
    }
}

class LocalExpliciter {
    private copyable: boolean;

    public constructor(private fn: Fn, private local: Local) {
        this.copyable = copyableIsType(this.local.vtype);
    }

    public pass() {
        for (const block of this.fn.blocks) {
            replaceBlockSrcs(block, (src) => this.explicitSrc(src));
        }
    }

    private explicitSrc(src: RValue): RValue {
        if (src.type !== "local" || src.id !== this.local.id) {
            return src;
        }
        return this.copyable
            ? { type: "copy", id: src.id }
            : { type: "move", id: src.id };
    }
}

function copyableIsType(vtype: VType): boolean {
    switch (vtype.type) {
        case "error":
        case "unknown":
            throw new Error();
        case "null":
        case "int":
        case "bool":
        case "string":
            return true;
        case "ref":
        case "ref_mut":
            return false;
        case "ptr":
        case "ptr_mut":
            return true;
        case "array":
        case "struct":
        case "fn":
            return false;
        case "generic":
            return false;
        case "generic_spec":
            throw new Error();
    }
}