Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1243 #1248

Merged
merged 6 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions base/src/main/java/org/aya/tyck/StmtTycker.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,22 @@ public void suppress(@NotNull Decl decl) {
decl.suppresses.forEach(suppress -> {
switch (suppress) {
case MostGeneralSolution -> reporter.suppress(MetaVarError.DidSomethingBad.class);
case UnimportedCon -> reporter.suppress(PatternProblem.UnimportedConName.class);
case UnreachableClause -> {
reporter.suppress(ClausesProblem.FMDomination.class);
reporter.suppress(ClausesProblem.Domination.class);
}
}
});
}
public @Nullable TyckDef check(@NotNull Decl predecl) {
suppress(predecl);
ExprTycker tycker = null;
if (predecl instanceof TeleDecl decl) {
if (decl.ref().signature == null) tycker = checkHeader(decl);
}

return switch (predecl) {
suppress(predecl);
var core = switch (predecl) {
case FnDecl fnDecl -> {
var fnRef = fnDecl.ref;
assert fnRef.signature != null;
Expand Down Expand Up @@ -136,6 +141,8 @@ yield switch (fnDecl.body) {
yield new DataDef(data.ref, data.body.map(kon -> kon.ref.core));
}
};
reporter.clearSuppress();
return core;
}

public ExprTycker checkHeader(@NotNull TeleDecl decl) {
Expand Down Expand Up @@ -176,6 +183,7 @@ else fail(BadTypeError.doNotLike(tycker.state, result, signature.result(),
}
}
}
reporter.clearSuppress();
return tycker;
}
private void checkMember(@NotNull ClassMember member, @NotNull ExprTycker tycker) {
Expand Down
33 changes: 28 additions & 5 deletions base/src/main/java/org/aya/tyck/error/PatternProblem.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.tyck.error;

import kala.collection.mutable.MutableList;
import org.aya.prettier.BasePrettier;
import org.aya.pretty.doc.Doc;
import org.aya.syntax.concrete.Pattern;
import org.aya.syntax.core.term.Param;
import org.aya.syntax.core.term.Term;
import org.aya.syntax.core.term.call.ConCall;
import org.aya.syntax.core.term.call.DataCall;
import org.aya.tyck.tycker.Stateful;
import org.aya.util.error.SourcePos;
import org.aya.util.error.WithPos;
import org.aya.util.prettier.PrettierOptions;
Expand Down Expand Up @@ -80,15 +82,21 @@ record UnknownCon(@Override @NotNull WithPos<Pattern> pattern) implements Patter

record TupleNonSig(
@Override @NotNull WithPos<Pattern> pattern,
@NotNull Term type
@NotNull Stateful stateful, @NotNull Term type
) implements PatternProblem {
@Override public @NotNull Doc describe(@NotNull PrettierOptions options) {
return Doc.vcat(
var typeDoc = type.toDoc(options);
var lines = MutableList.of(
Doc.english("The tuple pattern"),
Doc.par(1, pattern.data().toDoc(options)),
Doc.english("splits only on sigma types, while the actual type"),
Doc.par(1, type.toDoc(options)),
Doc.english("does not look like one"));
Doc.english("splits only on sigma types, while the actual type is not:"),
Doc.par(1, typeDoc));
var normalizedDoc = stateful.fullNormalize(type).toDoc(options);
if (!typeDoc.equals(normalizedDoc)) {
lines.append(Doc.english("Normalized:"));
lines.append(Doc.par(1, normalizedDoc));
}
return Doc.vcat(lines);
}
}

Expand Down Expand Up @@ -126,6 +134,21 @@ record ImplicitDisallowed(@Override @NotNull WithPos<Pattern> pattern) implement
}
}

record UnimportedConName(
@Override @NotNull WithPos<Pattern.Bind> pattern
) implements PatternProblem {
@Override public @NotNull Severity level() { return Severity.WARN; }

@Override public @NotNull Doc describe(@NotNull PrettierOptions options) {
return Doc.vcat(
Doc.english("You wrote the following pattern:"),
Doc.par(1, Doc.plain(pattern.data().bind().name())),
Doc.english("It sounds like you are trying to match with a constructor that is not in scope, " +
"so it will be treated as a variable pattern.")
);
}
}

record TooManyImplicitPattern(
@Override @NotNull WithPos<Pattern> pattern,
@NotNull Param param
Expand Down
33 changes: 29 additions & 4 deletions base/src/main/java/org/aya/tyck/pat/PatternTycker.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
import org.aya.generic.term.DTKind;
import org.aya.normalize.Normalizer;
import org.aya.syntax.compile.JitCon;
import org.aya.syntax.compile.JitData;
import org.aya.syntax.concrete.Expr;
import org.aya.syntax.concrete.Pattern;
import org.aya.syntax.concrete.stmt.decl.DataDecl;
import org.aya.syntax.core.Jdg;
import org.aya.syntax.core.def.ConDef;
import org.aya.syntax.core.def.ConDefLike;
import org.aya.syntax.core.def.*;
import org.aya.syntax.core.pat.Pat;
import org.aya.syntax.core.pat.PatMatcher;
import org.aya.syntax.core.pat.PatToTerm;
Expand Down Expand Up @@ -127,7 +128,7 @@ public record TyckResult(
case Pattern.Tuple(var l, var r) -> {
if (!(exprTycker.whnf(type) instanceof DepTypeTerm(var kind, var lT, var rT) && kind == DTKind.Sigma)) {
var frozen = freezeHoles(type);
yield withError(new PatternProblem.TupleNonSig(pattern, frozen), frozen);
yield withError(new PatternProblem.TupleNonSig(pattern, this, frozen), frozen);
}
var lhs = doTyck(l, lT);
yield new Pat.Tuple(lhs, doTyck(r, rT.apply(PatToTerm.visit(lhs))));
Expand All @@ -147,9 +148,22 @@ public record TyckResult(
var typeRecog = state().shapeFactory.find(conCore.dataRef()).getOrNull();
yield new Pat.Con(conCore, patterns, realCon.conHead);
}
case Pattern.Bind(var bind, var tyRef) -> {
case Pattern.Bind bindPat -> {
var bind = bindPat.bind();
var tyRef = bindPat.type();

exprTycker.localCtx().put(bind, type);
tyRef.set(type);

// report after tyRef.set, the error message requires it
if (whnf(type) instanceof DataCall call) {
var unimportedCon = collectConNames(call.ref())
.anyMatch(it -> it.equalsIgnoreCase(bind.name()));
if (unimportedCon) {
fail(new PatternProblem.UnimportedConName(pattern.replace(bindPat)));
}
}

yield new Pat.Bind(bind, type);
}
case Pattern.CalmFace.INSTANCE ->
Expand Down Expand Up @@ -465,6 +479,17 @@ private record Selection(
};
}

private static @NotNull SeqView<String> collectConNames(@NotNull DataDefLike call) {
return switch (call) {
case JitData jitData -> jitData.body().view().map(AnyDef::name);
case DataDef.Delegate delegate -> {
// the core may be unchecked!
var concrete = (DataDecl) delegate.ref.concrete;
yield concrete.body.view().map(it -> it.ref.name());
}
};
}

/**
* Check whether {@param con} is available under {@param type}
*/
Expand Down
25 changes: 25 additions & 0 deletions cli-impl/src/test/java/org/aya/test/fixtures/PatTyckError.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ def test (a : Type) : Type
| unit y => a
""";

@Language("Aya") String testTupleOnNonSigma = """
def test (a' : Type) : Type
| (a, b) => a

def Alias => Type
def test2 (a' : Alias) : Type
| (a, b) => a
""";

@Language("Aya") String testBadLiteral = """
open inductive Test | t
def not-conf Test : Test
Expand Down Expand Up @@ -106,4 +115,20 @@ open inductive Wrap (A B : Type)
def foo (A : Type) A : A elim A
| _, {a} => a
""";

@Language("Aya") String testUnimportedCon = """
open import arith::bool using (Bool)

def not (b : Bool) : Bool
| true => Bool::false
| false => Bool::true

@suppress(UnimportedCon, UnreachableClause)
def don't-care (b : Bool) : Bool
| true => Bool::false
| false => Bool::true

inductive RealCase (b : Bool)
| true => real_true
""";
}
78 changes: 78 additions & 0 deletions cli-impl/src/test/resources/negative/PatTyckError.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,36 @@ Error: Cannot split on a non-inductive type
1 error(s), 0 warning(s).
Let's learn from that.

TupleOnNonSigma:
In file $FILE:2:3 ->

1 │ def test (a' : Type) : Type
2 │ | (a, b) => a
│ ╰────╯
3 │

Error: The tuple pattern
(a, b)
splits only on sigma types, while the actual type is not:
Type 0

In file $FILE:6:3 ->

4 │ def Alias => Type
5 │ def test2 (a' : Alias) : Type
6 │ | (a, b) => a
│ ╰────╯

Error: The tuple pattern
(a, b)
splits only on sigma types, while the actual type is not:
Alias
Normalized:
Type 0

2 error(s), 0 warning(s).
Let's learn from that.

BadLiteral:
In file $FILE:3:2 ->

Expand Down Expand Up @@ -270,3 +300,51 @@ Error: Pattern matching with elim is not compatible with implicit patterns.
1 error(s), 0 warning(s).
Let's learn from that.

UnimportedCon:
In file $FILE:4:2 ->

2 │
3 │ def not (b : Bool) : Bool
4 │ | true => Bool::false
│ ╰──╯

Warning: You wrote the following pattern:
true
It sounds like you are trying to match with a constructor that is not
in scope, so it will be treated as a variable pattern.

In file $FILE:5:2 ->

3 │ def not (b : Bool) : Bool
4 │ | true => Bool::false
5 │ | false => Bool::true
│ ╰───╯

Warning: You wrote the following pattern:
false
It sounds like you are trying to match with a constructor that is not
in scope, so it will be treated as a variable pattern.

In file $FILE:5:2 ->

3 │ def not (b : Bool) : Bool
4 │ | true => Bool::false
5 │ | false => Bool::true
│ ╰─────────────────╯

Warning: The 2nd clause is dominated by the other clauses, hence unreachable

In file $FILE:13:2 ->

11 │
12 │ inductive RealCase (b : Bool)
13 │ | true => real_true
│ ╰──╯

Warning: You wrote the following pattern:
true
It sounds like you are trying to match with a constructor that is not
in scope, so it will be treated as a variable pattern.

That looks right!

2 changes: 2 additions & 0 deletions syntax/src/main/java/org/aya/generic/Suppress.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@

public enum Suppress {
Shadowing,
UnimportedCon,
UnreachableClause,
MostGeneralSolution;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.util.reporter;

import kala.collection.mutable.MutableList;
import kala.collection.mutable.MutableSet;
import org.jetbrains.annotations.NotNull;

public record SuppressingReporter(
@NotNull Reporter reporter,
@NotNull MutableList<Class<? extends Problem>> suppressed
@NotNull MutableSet<Class<? extends Problem>> suppressed
) implements Reporter {
public SuppressingReporter(@NotNull Reporter reporter) {
this(reporter, MutableList.create());
this(reporter, MutableSet.create());
}

@Override public void report(@NotNull Problem problem) {
Expand All @@ -19,6 +19,8 @@ public SuppressingReporter(@NotNull Reporter reporter) {
}

public void suppress(@NotNull Class<? extends Problem> problem) {
suppressed.append(problem);
suppressed.add(problem);
}

public void clearSuppress() { suppressed.clear(); }
}
Loading