diff --git a/base/src/main/java/org/aya/core/def/Def.java b/base/src/main/java/org/aya/core/def/Def.java index dd91c35edb..a7dd32a4e5 100644 --- a/base/src/main/java/org/aya/core/def/Def.java +++ b/base/src/main/java/org/aya/core/def/Def.java @@ -13,6 +13,7 @@ import org.aya.pretty.doc.Doc; import org.aya.ref.DefVar; import org.aya.util.prettier.PrettierOptions; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -35,8 +36,10 @@ public sealed interface Def extends AyaDocile, GenericDef permits SubLevelDef, T // guaranteed as this is already a core term else return defVar.concrete.checkedBody; } - static @NotNull Term defResult(@NotNull DefVar> defVar) { - if (defVar.core != null) return defVar.core.result(); + @SuppressWarnings("unchecked") @Contract(pure = true) + static @NotNull T + defResult(@NotNull DefVar> defVar) { + if (defVar.core != null) return (T) defVar.core.result(); // guaranteed as this is already a core term else return Objects.requireNonNull(defVar.concrete.signature()).result; } diff --git a/base/src/main/java/org/aya/core/pat/PatToTerm.java b/base/src/main/java/org/aya/core/pat/PatToTerm.java index 9115e8a14b..cd9acdaf9c 100644 --- a/base/src/main/java/org/aya/core/pat/PatToTerm.java +++ b/base/src/main/java/org/aya/core/pat/PatToTerm.java @@ -32,8 +32,6 @@ public Term visit(@NotNull Pat pat) { protected @NotNull Term visitCtor(Pat.@NotNull Ctor ctor) { var data = (DataCall) ctor.type(); var args = Arg.mapSeq(ctor.params(), this::visit); - return new ConCall(data.ref(), ctor.ref(), - data.args().map(Arg::implicitify), - data.ulift(), args); + return new ConCall(data.ref(), ctor.ref(), data.args(), data.ulift(), args); } } diff --git a/base/src/main/java/org/aya/core/pat/PatUnify.java b/base/src/main/java/org/aya/core/pat/PatUnify.java index 5db07b832c..878203b24e 100644 --- a/base/src/main/java/org/aya/core/pat/PatUnify.java +++ b/base/src/main/java/org/aya/core/pat/PatUnify.java @@ -1,13 +1,13 @@ -// Copyright (c) 2020-2022 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2023 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.core.pat; -import kala.collection.SeqLike; +import kala.collection.SeqView; import kala.collection.immutable.ImmutableSeq; import org.aya.core.term.RefTerm; import org.aya.core.visitor.Subst; -import org.aya.prettier.AyaPrettierOptions; import org.aya.generic.util.InternalException; +import org.aya.prettier.AyaPrettierOptions; import org.aya.pretty.doc.Doc; import org.aya.ref.LocalVar; import org.aya.tyck.env.LocalCtx; @@ -18,7 +18,7 @@ * The unification of patterns. This is not pattern unification. * * @author ice1000 - * @see PatUnify#unifyPat(SeqLike, SeqLike, Subst, Subst, LocalCtx) + * @see #unifyPat(SeqView, SeqView, Subst, Subst, LocalCtx) */ public record PatUnify(@NotNull Subst lhsSubst, @NotNull Subst rhsSubst, @NotNull LocalCtx ctx) { private void unify(@NotNull Pat lhs, @NotNull Pat rhs) { @@ -108,8 +108,8 @@ private static void unifyPat(Pat lhs, Pat rhs, Subst lhsSubst, Subst rhsSubst, L * @see PatUnify#visitAs(LocalVar, org.aya.core.pat.Pat) */ public static @NotNull LocalCtx unifyPat( - @NotNull SeqLike lpats, - @NotNull SeqLike rpats, + @NotNull SeqView lpats, + @NotNull SeqView rpats, @NotNull Subst lhsSubst, @NotNull Subst rhsSubst, @NotNull LocalCtx ctx diff --git a/base/src/main/java/org/aya/core/term/ConCall.java b/base/src/main/java/org/aya/core/term/ConCall.java index 85b047b6e4..96e9ff85eb 100644 --- a/base/src/main/java/org/aya/core/term/ConCall.java +++ b/base/src/main/java/org/aya/core/term/ConCall.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2023 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.core.term; @@ -43,11 +43,13 @@ public ConCall( } @Override public @NotNull ImmutableSeq> args() { - return head.dataArgs.view().concat(conArgs).toImmutableSeq(); + return head.dataArgs.view().map(Arg::implicitify).concat(conArgs).toImmutableSeq(); } /** * @param dataArgs the arguments to the data type, NOT the constructor patterns!! + * They need to be turned implicit when used as arguments. + * @see org.aya.tyck.pat.PatternTycker#mischa */ public record Head( @NotNull DefVar dataRef, diff --git a/base/src/main/java/org/aya/core/term/SigmaTerm.java b/base/src/main/java/org/aya/core/term/SigmaTerm.java index baf09410a0..573169d28d 100644 --- a/base/src/main/java/org/aya/core/term/SigmaTerm.java +++ b/base/src/main/java/org/aya/core/term/SigmaTerm.java @@ -1,11 +1,10 @@ -// Copyright (c) 2020-2022 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2023 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.core.term; import kala.collection.immutable.ImmutableSeq; import kala.collection.mutable.MutableArrayList; import kala.collection.mutable.MutableList; -import kala.collection.mutable.MutableMap; import org.aya.core.visitor.BetaExpander; import org.aya.core.visitor.Subst; import org.aya.generic.SortKind; @@ -84,7 +83,7 @@ record Item(@NotNull CoeTerm coe, @NotNull Arg arg) { public @Nullable TupTerm check(@NotNull ImmutableSeq it, @NotNull BiFunction inherit) { var items = MutableList.>create(); var againstTele = params.view(); - var subst = new Subst(MutableMap.create()); + var subst = new Subst(); for (var iter = it.iterator(); iter.hasNext(); ) { var item = iter.next(); var first = againstTele.first().subst(subst); diff --git a/base/src/main/java/org/aya/core/visitor/EndoTerm.java b/base/src/main/java/org/aya/core/visitor/EndoTerm.java index dcc5585635..873706492d 100644 --- a/base/src/main/java/org/aya/core/visitor/EndoTerm.java +++ b/base/src/main/java/org/aya/core/visitor/EndoTerm.java @@ -1,8 +1,7 @@ -// Copyright (c) 2020-2022 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2023 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.core.visitor; -import kala.collection.mutable.MutableMap; import org.aya.core.term.*; import org.aya.generic.util.InternalException; import org.aya.ref.AnyVar; @@ -37,7 +36,7 @@ public interface EndoTerm extends UnaryOperator { /** Not an IntelliJ Renamer. */ record Renamer(@NotNull Subst subst) implements EndoTerm { public Renamer() { - this(new Subst(MutableMap.create())); + this(new Subst()); } private @NotNull Term.Param handleBinder(@NotNull Term.Param param) { diff --git a/base/src/main/java/org/aya/core/visitor/Subst.java b/base/src/main/java/org/aya/core/visitor/Subst.java index 1f1ce7a1c8..9cedb76b47 100644 --- a/base/src/main/java/org/aya/core/visitor/Subst.java +++ b/base/src/main/java/org/aya/core/visitor/Subst.java @@ -1,21 +1,22 @@ -// Copyright (c) 2020-2022 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2023 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.core.visitor; import kala.collection.SeqLike; import kala.collection.immutable.ImmutableSeq; import kala.collection.mutable.MutableHashMap; +import kala.collection.mutable.MutableLinkedHashMap; import kala.collection.mutable.MutableMap; import kala.collection.mutable.MutableTreeMap; import org.aya.core.term.FormulaTerm; import org.aya.core.term.RefTerm; import org.aya.core.term.Term; -import org.aya.prettier.BasePrettier; import org.aya.generic.AyaDocile; import org.aya.generic.util.NormalizeMode; import org.aya.guest0x0.cubical.CofThy; import org.aya.guest0x0.cubical.Formula; import org.aya.guest0x0.cubical.Restr; +import org.aya.prettier.BasePrettier; import org.aya.pretty.doc.Doc; import org.aya.ref.AnyVar; import org.aya.ref.LocalVar; @@ -41,7 +42,7 @@ public record Subst( })); public Subst() { - this(MutableMap.create()); + this(MutableLinkedHashMap.of()); } public Subst(@NotNull AnyVar var, @NotNull Term term) { @@ -49,7 +50,7 @@ public Subst(@NotNull AnyVar var, @NotNull Term term) { } public Subst(@NotNull SeqLike from, @NotNull SeqLike to) { - this(MutableMap.from(from.zipView(to))); + this(MutableLinkedHashMap.from(from.zipView(to))); } public void subst(@NotNull Subst subst) { diff --git a/base/src/main/java/org/aya/tyck/StmtTycker.java b/base/src/main/java/org/aya/tyck/StmtTycker.java index 97e091bd5a..4010646a49 100644 --- a/base/src/main/java/org/aya/tyck/StmtTycker.java +++ b/base/src/main/java/org/aya/tyck/StmtTycker.java @@ -25,6 +25,7 @@ import org.aya.tyck.pat.ClauseTycker; import org.aya.tyck.pat.Conquer; import org.aya.tyck.pat.PatClassifier; +import org.aya.tyck.pat.YouTrack; import org.aya.tyck.trace.Trace; import org.aya.tyck.tycker.TracedTycker; import org.aya.util.Arg; @@ -89,7 +90,8 @@ public StmtTycker(@NotNull Reporter reporter, Trace.@Nullable Builder traceBuild def = factory.apply(result.result(), Either.right(result.matchings())); if (!result.hasLhsError()) { tracing(builder -> builder.shift(new Trace.LabelT(pos, "confluence check"))); - PatClassifier.confluence(result, tycker, pos, + var confluence = new YouTrack(signature.param(), tycker, pos); + confluence.check(result, PatClassifier.classify(result.clauses(), signature.param(), tycker, pos)); tracing(TreeBuilder::reduce); } diff --git a/base/src/main/java/org/aya/tyck/pat/Conquer.java b/base/src/main/java/org/aya/tyck/pat/Conquer.java index 705f234f5d..0e8d6a0e5b 100644 --- a/base/src/main/java/org/aya/tyck/pat/Conquer.java +++ b/base/src/main/java/org/aya/tyck/pat/Conquer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 Tesla (Yinsen) Zhang. +// Copyright (c) 2020-2023 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; @@ -11,14 +11,15 @@ import org.aya.core.term.MetaTerm; import org.aya.core.term.Term; import org.aya.core.visitor.AyaRestrSimplifier; +import org.aya.core.visitor.DeltaExpander; import org.aya.core.visitor.Subst; import org.aya.generic.util.NormalizeMode; import org.aya.guest0x0.cubical.CofThy; import org.aya.guest0x0.cubical.Partial; import org.aya.guest0x0.cubical.Restr; -import org.aya.tyck.ExprTycker; import org.aya.tyck.env.MapLocalCtx; import org.aya.tyck.error.UnifyInfo; +import org.aya.tyck.tycker.UnifiedTycker; import org.aya.util.Arg; import org.aya.util.error.SourcePos; import org.jetbrains.annotations.NotNull; @@ -33,11 +34,11 @@ public record Conquer( @NotNull ImmutableSeq matchings, @NotNull SourcePos sourcePos, boolean orderIndependent, - @NotNull ExprTycker tycker + @NotNull UnifiedTycker tycker ) { public static void against( @NotNull FnDef def, boolean orderIndependent, - @NotNull ExprTycker tycker, @NotNull SourcePos pos + @NotNull UnifiedTycker tycker, @NotNull SourcePos pos ) { var matchings = def.body.getRightValue(); var conquer = new Conquer(def, matchings, pos, orderIndependent, tycker); @@ -84,11 +85,13 @@ private void checkConditions(int nth, int i, Restr.Side condition, Subst m var matchResult = new FnCall(def.ref, 0, args).normalize(tycker.state, NormalizeMode.WHNF).subst(subst); currentClause.patterns().forEach(p -> p.term().storeBindings(ctx, subst)); if (newBody instanceof ErrorTerm error && error.description() instanceof MetaTerm hole) { - hole.ref().conditions.append(Tuple.of(matchy, matchResult)); + hole.ref().conditions.append(Tuple.of(subst, matchResult)); } else if (matchResult instanceof ErrorTerm error && error.description() instanceof MetaTerm hole) { - hole.ref().conditions.append(Tuple.of(matchy, newBody)); + hole.ref().conditions.append(Tuple.of(subst, newBody)); } - return tycker.unifyReported(newBody, matchResult, def.result.subst(matchy), + var retSubst = DeltaExpander.buildSubst(def.telescope, args); + retSubst.add(subst); + return tycker.unifyReported(newBody, matchResult, def.result.subst(retSubst), sourcePos, ctx, comparison -> new ClausesProblem.Conditions( sourcePos, currentClause.sourcePos(), nth + 1, i, args, new UnifyInfo(tycker.state), comparison)); }); diff --git a/base/src/main/java/org/aya/tyck/pat/PatClassifier.java b/base/src/main/java/org/aya/tyck/pat/PatClassifier.java index 6c0af32ff9..f33c76e8c6 100644 --- a/base/src/main/java/org/aya/tyck/pat/PatClassifier.java +++ b/base/src/main/java/org/aya/tyck/pat/PatClassifier.java @@ -6,22 +6,14 @@ import kala.collection.SeqView; import kala.collection.immutable.ImmutableSeq; import kala.collection.mutable.MutableList; -import kala.collection.mutable.MutableMap; -import kala.tuple.Tuple; -import kala.tuple.primitive.IntObjTuple2; import kala.value.MutableValue; import org.aya.concrete.Pattern; import org.aya.core.def.Def; import org.aya.core.pat.Pat; -import org.aya.core.pat.PatUnify; import org.aya.core.term.*; -import org.aya.core.visitor.Subst; import org.aya.generic.util.NormalizeMode; import org.aya.ref.AnyVar; -import org.aya.tyck.ExprTycker; -import org.aya.tyck.env.LocalCtx; import org.aya.tyck.error.TyckOrderError; -import org.aya.tyck.error.UnifyInfo; import org.aya.tyck.tycker.StatedTycker; import org.aya.tyck.tycker.TyckState; import org.aya.util.Arg; @@ -90,50 +82,6 @@ public static int[] firstMatchDomination( return numbers; } - public static void confluence( - @NotNull ClauseTycker.PatResult clauses, - @NotNull ExprTycker tycker, @NotNull SourcePos pos, - @NotNull MCT mct - ) { - var result = clauses.result(); - mct.forEach(results -> { - var contents = results.contents() - .flatMap(i -> Pat.Preclause.lift(clauses.clauses().get(i)) - .map(matching -> IntObjTuple2.of(i, matching))); - for (int i = 1, size = contents.size(); i < size; i++) { - var lhsInfo = contents.get(i - 1); - var rhsInfo = contents.get(i); - var lhsSubst = new Subst(MutableMap.create()); - var rhsSubst = new Subst(MutableMap.create()); - var ctx = PatUnify.unifyPat(lhsInfo.component2().patterns().map(Arg::term), rhsInfo.component2().patterns().map(Arg::term), - lhsSubst, rhsSubst, tycker.ctx.deriveMap()); - domination(ctx, rhsSubst, tycker.reporter, lhsInfo.component1(), rhsInfo.component1(), rhsInfo.component2()); - domination(ctx, lhsSubst, tycker.reporter, rhsInfo.component1(), lhsInfo.component1(), lhsInfo.component2()); - var lhsTerm = lhsInfo.component2().body().subst(lhsSubst); - var rhsTerm = rhsInfo.component2().body().subst(rhsSubst); - // TODO: Currently all holes at this point are in an ErrorTerm - if (lhsTerm instanceof ErrorTerm error && error.description() instanceof MetaTerm hole) { - hole.ref().conditions.append(Tuple.of(lhsSubst, rhsTerm)); - } else if (rhsTerm instanceof ErrorTerm error && error.description() instanceof MetaTerm hole) { - hole.ref().conditions.append(Tuple.of(rhsSubst, lhsTerm)); - } - tycker.unifyReported(lhsTerm, rhsTerm, result, pos, ctx, comparison -> - new ClausesProblem.Confluence(pos, rhsInfo.component1() + 1, lhsInfo.component1() + 1, - comparison, new UnifyInfo(tycker.state), rhsInfo.component2().sourcePos(), lhsInfo.component2().sourcePos())); - } - }); - } - - private static void domination( - LocalCtx ctx, Subst rhsSubst, Reporter reporter, - int lhsIx, int rhsIx, Term.Matching matching - ) { - if (rhsSubst.map().valuesView().allMatch(dom -> - dom instanceof RefTerm(var ref) && ctx.contains(ref)) - ) reporter.report(new ClausesProblem.Domination( - lhsIx + 1, rhsIx + 1, matching.sourcePos())); - } - private @NotNull MCT classifySub( @NotNull SeqView telescope, @NotNull ImmutableSeq> clauses, diff --git a/base/src/main/java/org/aya/tyck/pat/PatternTycker.java b/base/src/main/java/org/aya/tyck/pat/PatternTycker.java index 453e322aa3..0fd779a00a 100644 --- a/base/src/main/java/org/aya/tyck/pat/PatternTycker.java +++ b/base/src/main/java/org/aya/tyck/pat/PatternTycker.java @@ -388,7 +388,7 @@ public static Result mischa(DataCall dataCall, CtorDef ctor, @No if (ctor.pats.isNotEmpty()) { return PatMatcher.tryBuildSubst(true, ctor.pats, dataCall.args(), new Expander.WHNFer(state)); } else { - return kala.control.Result.ok(DeltaExpander.buildSubst(Def.defTele(dataCall.ref()), dataCall.args())); + return Result.ok(DeltaExpander.buildSubst(Def.defTele(dataCall.ref()), dataCall.args())); } } diff --git a/base/src/main/java/org/aya/tyck/pat/YouTrack.java b/base/src/main/java/org/aya/tyck/pat/YouTrack.java new file mode 100644 index 0000000000..c790470cb0 --- /dev/null +++ b/base/src/main/java/org/aya/tyck/pat/YouTrack.java @@ -0,0 +1,74 @@ +// Copyright (c) 2020-2023 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.immutable.ImmutableSeq; +import kala.tuple.Tuple; +import kala.tuple.primitive.IntObjTuple2; +import org.aya.core.pat.Pat; +import org.aya.core.pat.PatUnify; +import org.aya.core.term.ErrorTerm; +import org.aya.core.term.MetaTerm; +import org.aya.core.term.RefTerm; +import org.aya.core.term.Term; +import org.aya.core.visitor.DeltaExpander; +import org.aya.core.visitor.Subst; +import org.aya.tyck.ExprTycker; +import org.aya.tyck.env.LocalCtx; +import org.aya.tyck.error.UnifyInfo; +import org.aya.util.Arg; +import org.aya.util.error.SourcePos; +import org.aya.util.tyck.MCT; +import org.jetbrains.annotations.NotNull; + +/** + * YouTrack checks confluence. + * + * @author ice1000 + * @see PatClassifier#classify + */ +public record YouTrack( + @NotNull ImmutableSeq telescope, + @NotNull ExprTycker tycker, @NotNull SourcePos pos +) { + private void unifyClauses(Term result, IntObjTuple2 lhsInfo, IntObjTuple2 rhsInfo) { + var lhsSubst = new Subst(); + var rhsSubst = new Subst(); + var ctx = PatUnify.unifyPat( + lhsInfo.component2().patterns().view().map(Arg::term), + rhsInfo.component2().patterns().view().map(Arg::term), + lhsSubst, rhsSubst, tycker.ctx.deriveMap()); + domination(ctx, rhsSubst, lhsInfo.component1(), rhsInfo.component1(), rhsInfo.component2()); + domination(ctx, lhsSubst, rhsInfo.component1(), lhsInfo.component1(), lhsInfo.component2()); + var lhsTerm = lhsInfo.component2().body().subst(lhsSubst); + var rhsTerm = rhsInfo.component2().body().subst(rhsSubst); + // TODO: Currently all holes at this point are in an ErrorTerm + if (lhsTerm instanceof ErrorTerm error && error.description() instanceof MetaTerm hole) { + hole.ref().conditions.append(Tuple.of(lhsSubst, rhsTerm)); + } else if (rhsTerm instanceof ErrorTerm error && error.description() instanceof MetaTerm hole) { + hole.ref().conditions.append(Tuple.of(rhsSubst, lhsTerm)); + } + var resultSubst = DeltaExpander.buildSubst(telescope, Arg.mapSeq(lhsInfo.component2().patterns(), Pat::toTerm)); + resultSubst.add(lhsSubst); + tycker.unifyReported(lhsTerm, rhsTerm, result.subst(resultSubst), pos, ctx, comparison -> + new ClausesProblem.Confluence(pos, rhsInfo.component1() + 1, lhsInfo.component1() + 1, + comparison, new UnifyInfo(tycker.state), rhsInfo.component2().sourcePos(), lhsInfo.component2().sourcePos())); + } + + private void domination(LocalCtx ctx, Subst rhsSubst, int lhsIx, int rhsIx, Term.Matching matching) { + if (rhsSubst.map().valuesView().allMatch(dom -> + dom instanceof RefTerm(var ref) && ctx.contains(ref)) + ) tycker.reporter.report(new ClausesProblem.Domination( + lhsIx + 1, rhsIx + 1, matching.sourcePos())); + } + + public void check(@NotNull ClauseTycker.PatResult clauses, @NotNull MCT mct) { + mct.forEach(results -> { + var contents = results.contents() + .flatMap(i -> Pat.Preclause.lift(clauses.clauses().get(i)) + .map(matching -> IntObjTuple2.of(i, matching))); + for (int i = 1, size = contents.size(); i < size; i++) + unifyClauses(clauses.result(), contents.get(i - 1), contents.get(i)); + }); + } +} diff --git a/base/src/main/java/org/aya/tyck/tycker/StatedTycker.java b/base/src/main/java/org/aya/tyck/tycker/StatedTycker.java index 357d1629ec..9a519e0442 100644 --- a/base/src/main/java/org/aya/tyck/tycker/StatedTycker.java +++ b/base/src/main/java/org/aya/tyck/tycker/StatedTycker.java @@ -7,9 +7,12 @@ import org.aya.core.UntypedParam; import org.aya.core.def.*; import org.aya.core.term.*; +import org.aya.core.visitor.Subst; import org.aya.generic.Modifier; import org.aya.generic.util.InternalException; import org.aya.generic.util.NormalizeMode; +import org.aya.guest0x0.cubical.CofThy; +import org.aya.guest0x0.cubical.Restr; import org.aya.ref.DefVar; import org.aya.tyck.Result; import org.aya.tyck.env.LocalCtx; @@ -43,7 +46,8 @@ protected StatedTycker(@NotNull Reporter reporter, @Nullable Trace.Builder trace return term.normalize(state, NormalizeMode.WHNF); } - protected final @NotNull > Result defCall(DefVar defVar, Callable.Factory function) { + protected final > @NotNull Result + defCall(DefVar defVar, Callable.Factory function) { var tele = Def.defTele(defVar); var teleRenamed = tele.map(LamTerm::paramRenamed); // unbound these abstracted variables @@ -86,4 +90,13 @@ protected StatedTycker(@NotNull Reporter reporter, @Nullable Trace.Builder trace public @NotNull Unifier unifier(@NotNull SourcePos pos, @NotNull Ordering ord, @NotNull LocalCtx ctx) { return new Unifier(ord, reporter, false, true, traceBuilder, state, pos, ctx); } + + /** + * Sub lr, Sub rl are unused because they are solely for the purpose of unification. + * In this case, we don't expect unification. + */ + protected final boolean compareRestr(@NotNull Restr lhs, @NotNull Restr rhs) { + return CofThy.conv(lhs, new Subst(), s -> CofThy.satisfied(s.restr(state, rhs))) + && CofThy.conv(rhs, new Subst(), s -> CofThy.satisfied(s.restr(state, lhs))); + } } diff --git a/base/src/main/java/org/aya/tyck/unify/TermComparator.java b/base/src/main/java/org/aya/tyck/unify/TermComparator.java index 74de53d53d..0a19ef23ab 100644 --- a/base/src/main/java/org/aya/tyck/unify/TermComparator.java +++ b/base/src/main/java/org/aya/tyck/unify/TermComparator.java @@ -20,13 +20,13 @@ import org.aya.generic.util.InternalException; import org.aya.guest0x0.cubical.CofThy; import org.aya.guest0x0.cubical.Partial; -import org.aya.guest0x0.cubical.Restr; import org.aya.prettier.AyaPrettierOptions; import org.aya.ref.AnyVar; import org.aya.ref.DefVar; import org.aya.ref.LocalVar; import org.aya.tyck.env.LocalCtx; import org.aya.tyck.error.LevelError; +import org.aya.tyck.pat.PatternTycker; import org.aya.tyck.trace.Trace; import org.aya.tyck.tycker.MockTycker; import org.aya.tyck.tycker.TyckState; @@ -239,7 +239,8 @@ private boolean visitLists(SeqView l, SeqView r, Sub lr, Sub rl, @No @NotNull Callable lhs, @NotNull Callable rhs, Sub lr, Sub rl, @NotNull DefVar> lhsRef, int ulift ) { - var retType = getType(lhs, lhsRef); + var retType = synthesizer().press(lhs); + if (synthesizer().tryPress(retType) instanceof SortTerm sort && sort.isProp()) return retType; // Lossy comparison if (visitArgs(lhs.args(), rhs.args(), lr, rl, Term.Param.subst(Def.defTele(lhsRef), ulift))) return retType; @@ -250,15 +251,12 @@ private boolean visitLists(SeqView l, SeqView r, Sub lr, Sub rl, @No /** TODO: Revise when JDK 20 is released. */ private record Pair(Term lhs, Term rhs) {} - private @NotNull Term getType(@NotNull Callable lhs, @NotNull DefVar> lhsRef) { - var substMap = MutableMap.create(); - for (var pa : lhs.args().view().zip(Def.defTele(lhsRef))) { - substMap.set(pa.component2().ref(), pa.component1().term()); - } - return Def.defResult(lhsRef).subst(substMap); - } - private boolean doCompareTyped(@NotNull Term type, @NotNull Term lhs, @NotNull Term rhs, Sub lr, Sub rl) { + // Skip tracing, because too easy. + // Note that it looks tempting to apply some unification here, but it is not correct: + // If ?x =_A y where A : Prop, then it may not be the case that ?x is y! + // I think Arend has probably made such a mistake before, but they removed this feature anyway. + if (synthesizer().tryPress(type) instanceof SortTerm sort && sort.isProp()) return true; traceEntrance(new Trace.UnifyT(lhs.freezeHoles(state), rhs.freezeHoles(state), pos, type.freezeHoles(state))); var ret = switch (type) { @@ -391,15 +389,6 @@ private boolean compareCube(@NotNull PathTerm lhs, @NotNull PathTerm rhs, Sub lr })); } - /** - * Sub lr, Sub rl are unused because they are solely for the purpose of unification. - * In this case, we don't expect unification. - */ - private boolean compareRestr(@NotNull Restr lhs, @NotNull Restr rhs) { - return CofThy.conv(lhs, new Subst(), s -> CofThy.satisfied(s.restr(state, rhs))) - && CofThy.conv(rhs, new Subst(), s -> CofThy.satisfied(s.restr(state, lhs))); - } - /** * @implNote Do not need to compute result type precisely because unification won't need this info * (written by re-xyr) @@ -535,7 +524,7 @@ case OutTerm(var lPhi, var pal, var lU) -> { }; } - @NotNull private static InternalException noRules(@NotNull Term preLhs) { + private static @NotNull InternalException noRules(@NotNull Term preLhs) { return new InternalException(preLhs.getClass() + ": " + preLhs.toDoc(AyaPrettierOptions.debug()).debugRender()); } @@ -544,11 +533,15 @@ case OutTerm(var lPhi, var pal, var lU) -> { * If called from {@link #doCompareUntyped} then probably not so lossy. */ private @Nullable Term lossyUnifyCon(ConCall lhs, ConCall rhs, Sub lr, Sub rl, DefVar lef) { - if (!visitArgs(lhs.head().dataArgs(), rhs.head().dataArgs(), lr, rl, - Term.Param.subst(Def.defTele(lef.core.dataRef), lhs.ulift()))) return null; - var retType = getType(lhs, lef); + var retType = synthesizer().press(lhs); + var dataRef = lef.core.dataRef; + if (Def.defResult(dataRef).isProp()) return retType; + var dataAlgs = lhs.head().dataArgs(); + if (!visitArgs(dataAlgs, rhs.head().dataArgs(), lr, rl, + Term.Param.subst(Def.defTele(dataRef), lhs.ulift()))) return null; + var ownerSubst = PatternTycker.mischa(lhs.head().underlyingDataCall(), lef.core, state).get(); if (visitArgs(lhs.conArgs(), rhs.conArgs(), lr, rl, - Term.Param.subst(lef.core.selfTele, lhs.ulift()))) + Term.Param.subst(lef.core.selfTele, ownerSubst, lhs.ulift()))) return retType; return null; } diff --git a/base/src/test/resources/failure/holes/issue747.aya.txt b/base/src/test/resources/failure/holes/issue747.aya.txt index 1c62c2cba9..c189d603ab 100644 --- a/base/src/test/resources/failure/holes/issue747.aya.txt +++ b/base/src/test/resources/failure/holes/issue747.aya.txt @@ -11,7 +11,7 @@ Goal: Goal of type Context: {a : Nat} To ensure confluence: - Given (i ⇒ _), we should have: 0 + Given (i ⇒ _, _ ⇒ 0), we should have: 0 In file $FILE:11:13 -> diff --git a/base/src/test/resources/success/src/Prop.aya b/base/src/test/resources/success/src/Prop.aya index 3e9b66037e..380478f99e 100644 --- a/base/src/test/resources/success/src/Prop.aya +++ b/base/src/test/resources/success/src/Prop.aya @@ -1,3 +1,5 @@ +open import Paths + open struct Squash (A: Type): Prop | value: A @@ -9,3 +11,9 @@ def squashElim {A: Type} {P: Prop} (f: A -> P) (squash: Squash A): P => f squash def squash2Elim {A: Type} {P: Prop} (f: A -> P) (squash: Squash2 A): P | f, (squash a) => f a +open data Carry (A : Prop) : Type +| carry A + +open data Bool : Prop | true | false + +def check : carry true = carry false => idp diff --git a/note/glossary.md b/note/glossary.md index e8219ee5cd..648b3cacf1 100644 --- a/note/glossary.md +++ b/note/glossary.md @@ -57,7 +57,10 @@ data Vec (n : Nat) (A : Type) 对于非 simple indexed data types,它是 `dataTele` + `dataTele` -- 一个 data 的 telescope,对于 `Vec`,它是 `(n : Nat) (A : Type)` -> 关于类似的 xxxArgs,也使用这种解释方式。 +> 关于类似的 `xxxArgs`,也使用这种解释方式。 + ++ `ConCall::dataArgs` 完全对应 `dataTele`,因此和 `ownerTele` 是不配对的(在非 indexed constructor 下是配对的,但是 indexed 的情况下,`ownerTele` 对应的是 pattern 而不是 `dataTele`)。在获取对应的 subst 的时候应该使用 `PatternTycker::mischa`。 ++ `ConCall::conArgs` 完全对应 `selfTele`。 ## 类型检查时用到的状态