All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aya.tyck.pat.PatUnify Maven / Gradle / Ivy

There is a newer version: 0.36.0
Show newest version
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.tyck.pat;

import kala.collection.Seq;
import kala.collection.SeqView;
import kala.collection.immutable.ImmutableSeq;
import kala.collection.mutable.MutableList;
import org.aya.syntax.core.pat.Pat;
import org.aya.syntax.core.pat.PatToTerm;
import org.aya.syntax.core.term.FreeTerm;
import org.aya.syntax.core.term.Term;
import org.aya.syntax.core.term.TupTerm;
import org.aya.syntax.core.term.call.ConCall;
import org.aya.syntax.ref.LocalCtx;
import org.aya.syntax.ref.LocalVar;
import org.aya.util.error.Panic;
import org.jetbrains.annotations.NotNull;

/**
 * The unification of patterns. This is not pattern unification.
 * Used for confluence checking.
 *
 * @author ice1000
 * @see #unifyPat
 * @see YouTrack
 */
public record PatUnify(
  @NotNull MutableList lhsSubst, @NotNull MutableList rhsSubst,
  @NotNull LocalCtx ctx
) {
  public record Result(PatUnify unify, @NotNull Seq args) { }

  private @NotNull Term unify(@NotNull Pat lhs, @NotNull Pat rhs) {
    return switch (lhs) {
      case Pat.Bind bind -> visitAs(bind.bind(), rhs);
      case Pat.Tuple(var lX, var lY) -> rhs instanceof Pat.Tuple(var rX, var rY)
        ? new TupTerm(unify(lX, rX), unify(lY, rY))
        : Panic.unreachable();
      case Pat.Con con -> switch (rhs) {
        case Pat.Con con1 -> {
          // Assumption
          assert con.ref().equals(con1.ref());
          yield new ConCall(con.head(), visitList(con.args(), con1.args()));
        }
        case Pat.ShapedInt lit -> unify(con, lit.constructorForm());
        default -> Panic.unreachable();
      };
      case Pat.ShapedInt lhsInt -> switch (rhs) {
        case Pat.ShapedInt _ -> lhsInt.toTerm();
        case Pat.Con con -> unify(lhsInt.constructorForm(), con);
        // Try one more time in case we add more rhs case when lhs is a constructor.
        // see: PatMatcher#match(Pat, Term)
        default -> unify(lhsInt.constructorForm(), rhs);
      };
      default -> Panic.unreachable();
    };
  }

  private @NotNull ImmutableSeq visitList(ImmutableSeq lpats, ImmutableSeq rpats) {
    assert rpats.sizeEquals(lpats.size());
    return lpats.zip(rpats, (lp, rp) -> unifyPat(lp, rp, ctx, lhsSubst, rhsSubst));
  }

  private @NotNull Term visitAs(@NotNull LocalVar as, Pat rhs) {
    if (rhs instanceof Pat.Bind(var bind, var ty)) {
      var fresh = new FreeTerm(new LocalVar(as.name() + bind.name()));
      ctx.put(fresh.name(), ty.instantiateTele(rhsSubst.view()));
      lhsSubst.append(fresh);
      rhsSubst.append(fresh);
      return fresh;
    } else {
      var e = PatToTerm.visit(rhs).instantiateTele(rhsSubst.view());
      lhsSubst.append(e);
      rhs.consumeBindings((v, ty) -> {
        ctx.put(v, ty.instantiateTele(rhsSubst.view()));
        rhsSubst.append(new FreeTerm(v));
      });
      return e;
    }
  }

  private static @NotNull Term unifyPat(
    Pat lhs, Pat rhs, LocalCtx ctx,
    MutableList lhsSubst, MutableList rhsSubst
  ) {
    if (rhs instanceof Pat.Bind) {
      var unify = new PatUnify(rhsSubst, lhsSubst, ctx);
      return unify.unify(rhs, lhs);
    } else {
      var unify = new PatUnify(lhsSubst, rhsSubst, ctx);
      return unify.unify(lhs, rhs);
    }
  }

  /**
   * The unification of patterns. Assumes well-typedness, homogeneous-ness and positive success.
   *
   * @param lhsSubst the substitutions that would turn the lhs pattern to the rhs one.
   * @param rhsSubst the substitutions that would turn the rhs pattern to the lhs one.
   * @return a ctx that contains all variables that are not unified.
   * @throws Panic if failed
   * @see PatUnify#visitAs(LocalVar, Pat)
   */
  public static @NotNull Result unifyPat(
    @NotNull SeqView lpats, @NotNull SeqView rpats, @NotNull LocalCtx ctx,
    @NotNull MutableList lhsSubst, @NotNull MutableList rhsSubst
  ) {
    assert rpats.sizeEquals(lpats);
    var args = lpats.zip(rpats, (lp, rp) -> unifyPat(lp, rp, ctx, lhsSubst, rhsSubst));
    return new Result(new PatUnify(lhsSubst, rhsSubst, ctx), args.toImmutableSeq());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy