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

Dynamic layout for inexhaustive case/indeterminately match case #1125

Draft
wants to merge 23 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1fe50f6
Merge branch 'dev' into haz3l-incon
cyrus- Sep 24, 2023
ed3bcc6
Added a case `NotExhaustive` to `DHExp.t`.
DavidFangWJ Sep 30, 2023
0745463
Init
pigumar1 Oct 22, 2023
190faa2
Revert, part I
pigumar1 Oct 22, 2023
9816251
Revert Exercise.re
pigumar1 Oct 22, 2023
d9d68a6
Update Exercise.re
pigumar1 Oct 22, 2023
42069c5
Revert, part II
pigumar1 Oct 22, 2023
cfc8e72
Merge branch 'haz3l-case-exhaustiveness' into haz3l-incon
pigumar1 Oct 22, 2023
6db5d24
Renamed NotExhaustive to InexhaustiveCase and corrected its behavior
pigumar1 Oct 22, 2023
f53c5c5
Reverted InvalidOperationError.re
pigumar1 Oct 22, 2023
e43a97d
Merge branch 'haz3l-case-advanced-ui' into haz3l-incon
pigumar1 Oct 22, 2023
57b8a76
Porting implementation of incon judgment into Hazel 3. (#1094)
pigumar1 Oct 22, 2023
2615f7c
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
pigumar1 Oct 22, 2023
5ddd220
Crossing out unmatched patterns, part I
pigumar1 Oct 23, 2023
a7d1693
Crossing out unmatched patterns, part II
pigumar1 Oct 23, 2023
4e5c586
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
pigumar1 Oct 23, 2023
e504885
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
pigumar1 Oct 23, 2023
9e8e0b7
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
pigumar1 Oct 26, 2023
9b852c5
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
pigumar1 Oct 26, 2023
cda0245
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
pigumar1 Oct 26, 2023
2e161ea
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
pigumar1 Oct 26, 2023
f34d540
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
cyrus- Nov 10, 2023
9c1ffab
Merge branch 'haz3l-case-redundancy' into haz3l-case-advanced-ui
pigumar1 Nov 18, 2023
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
15 changes: 13 additions & 2 deletions src/haz3lcore/dynamics/DH.re
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module rec DHExp: {
| Prj(t, int)
| Constructor(string)
| ConsistentCase(case)
| InexhaustiveCase(MetaVar.t, HoleInstanceId.t, case)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having three different case constructs in DHExp, let's merge them into one with an additional flag parameter for when there is an error.

| Cast(t, Typ.t, Typ.t)
| FailedCast(t, Typ.t, Typ.t)
| InvalidOperation(t, InvalidOperationError.t)
Expand Down Expand Up @@ -87,6 +88,7 @@ module rec DHExp: {
| Prj(t, int)
| Constructor(string)
| ConsistentCase(case)
| InexhaustiveCase(MetaVar.t, HoleInstanceId.t, case)
| Cast(t, Typ.t, Typ.t)
| FailedCast(t, Typ.t, Typ.t)
| InvalidOperation(t, InvalidOperationError.t)
Expand Down Expand Up @@ -126,6 +128,7 @@ module rec DHExp: {
| Prj(_) => "Prj"
| Constructor(_) => "Constructor"
| ConsistentCase(_) => "ConsistentCase"
| InexhaustiveCase(_, _, _) => "InexhaustiveCase"
| InconsistentBranches(_, _, _) => "InconsistentBranches"
| Cast(_, _, _) => "Cast"
| FailedCast(_, _, _) => "FailedCast"
Expand Down Expand Up @@ -174,6 +177,12 @@ module rec DHExp: {
ConsistentCase(
Case(strip_casts(a), List.map(strip_casts_rule, rs), b),
)
| InexhaustiveCase(u, i, Case(scrut, rules, n)) =>
InexhaustiveCase(
u,
i,
Case(strip_casts(scrut), List.map(strip_casts_rule, rules), n),
)
| InconsistentBranches(u, i, Case(scrut, rules, n)) =>
InconsistentBranches(
u,
Expand Down Expand Up @@ -284,15 +293,17 @@ module rec DHExp: {
| (
InconsistentBranches(u1, i1, case1),
InconsistentBranches(u2, i2, case2),
) =>
)
| (InexhaustiveCase(u1, i1, case1), InexhaustiveCase(u2, i2, case2)) =>
u1 == u2 && i1 == i2 && fast_equal_case(case1, case2)
| (EmptyHole(_), _)
| (NonEmptyHole(_), _)
| (ExpandingKeyword(_), _)
| (FreeVar(_), _)
| (InvalidText(_), _)
| (Closure(_), _)
| (InconsistentBranches(_), _) => false
| (InconsistentBranches(_), _)
| (InexhaustiveCase(_), _) => false
};
}
and fast_equal_case = (Case(d1, rules1, i1), Case(d2, rules2, i2)) => {
Expand Down
5 changes: 5 additions & 0 deletions src/haz3lcore/dynamics/Elaborator.re
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ let cast = (ctx: Ctx.t, mode: Mode.t, self_ty: Typ.t, d: DHExp.t) =>
}
/* Forms with special ana rules but no particular typing requirements */
| ConsistentCase(_)
| InexhaustiveCase(_)
| InconsistentBranches(_)
| Sequence(_)
| Let(_)
Expand Down Expand Up @@ -271,7 +272,11 @@ let rec dhexp_of_uexp =
| InHole(
InexhaustiveMatch(Some(Common(Inconsistent(Internal(_))))),
) =>
// TODO: review
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not problematic for now since currently DHExp.InexhaustiveCase behaves exactly the same as DHExp.InconsistentBranches

// If multiple errors are associated with a case expression,
// DHExp.InconsistentBranches is prioritized.
DHExp.InconsistentBranches(id, 0, d)
| InHole(InexhaustiveMatch(_)) => DHExp.InexhaustiveCase(id, 0, d)
| _ => ConsistentCase(d)
};
| TyAlias(_, _, e) => dhexp_of_uexp(m, e)
Expand Down
8 changes: 8 additions & 0 deletions src/haz3lcore/dynamics/Evaluator.re
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ and matches_cast_Sum =
| BinFloatOp(_)
| BinStringOp(_)
| InconsistentBranches(_)
| InexhaustiveCase(_)
| EmptyHole(_)
| NonEmptyHole(_)
| FailedCast(_, _, _)
Expand Down Expand Up @@ -409,6 +410,7 @@ and matches_cast_Tuple =
| Prj(_) => DoesNotMatch
| Constructor(_) => DoesNotMatch
| ConsistentCase(_)
| InexhaustiveCase(_)
| InconsistentBranches(_) => IndetMatch
| EmptyHole(_) => IndetMatch
| NonEmptyHole(_) => IndetMatch
Expand Down Expand Up @@ -544,6 +546,7 @@ and matches_cast_Cons =
| Prj(_) => DoesNotMatch
| Constructor(_) => DoesNotMatch
| ConsistentCase(_)
| InexhaustiveCase(_)
| InconsistentBranches(_) => IndetMatch
| EmptyHole(_) => IndetMatch
| NonEmptyHole(_) => IndetMatch
Expand Down Expand Up @@ -988,6 +991,11 @@ let rec evaluate: (ClosureEnvironment.t, DHExp.t) => m(EvaluatorResult.t) =
Indet(Closure(env, InconsistentBranches(u, i, Case(d1, rules, n))))
|> return

| InexhaustiveCase(u, i, Case(d1, rules, n)) =>
//TODO: revisit this, consider some kind of dynamic casting
Indet(Closure(env, InexhaustiveCase(u, i, Case(d1, rules, n))))
|> return

| EmptyHole(u, i) => Indet(Closure(env, EmptyHole(u, i))) |> return

| NonEmptyHole(reason, u, i, d1) =>
Expand Down
11 changes: 10 additions & 1 deletion src/haz3lcore/dynamics/EvaluatorPost.re
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ let rec pp_eval = (d: DHExp.t): m(DHExp.t) =>
| BoundVar(_)
| Let(_)
| ConsistentCase(_)
| InexhaustiveCase(_)
| Fun(_)
| EmptyHole(_)
| NonEmptyHole(_)
Expand Down Expand Up @@ -412,6 +413,13 @@ and pp_uneval = (env: ClosureEnvironment.t, d: DHExp.t): m(DHExp.t) =>
let* i = hii_add_instance(u, env);
Closure(env, InconsistentBranches(u, i, Case(scrut, rules, case_i)))
|> return;

| InexhaustiveCase(u, _, Case(scrut, rules, case_i)) =>
let* scrut = pp_uneval(env, scrut);
let* rules = pp_uneval_rules(env, rules);
let* i = hii_add_instance(u, env);
Closure(env, InexhaustiveCase(u, i, Case(scrut, rules, case_i)))
|> return;
}

and pp_uneval_rules =
Expand Down Expand Up @@ -501,7 +509,8 @@ let rec track_children_of_hole =
| NonEmptyHole(_, u, i, d) =>
let hii = track_children_of_hole(hii, parent, d);
hii |> HoleInstanceInfo.add_parent((u, i), parent);
| InconsistentBranches(u, i, Case(scrut, rules, _)) =>
| InconsistentBranches(u, i, Case(scrut, rules, _))
| InexhaustiveCase(u, i, Case(scrut, rules, _)) =>
let hii = track_children_of_hole(hii, parent, scrut);
let hii = track_children_of_hole_rules(hii, parent, rules);
hii |> HoleInstanceInfo.add_parent((u, i), parent);
Expand Down
4 changes: 4 additions & 0 deletions src/haz3lcore/dynamics/Substitution.re
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ let rec subst_var = (d1: DHExp.t, x: Var.t, d2: DHExp.t): DHExp.t =>
let d3 = subst_var(d1, x, d3);
let rules = subst_var_rules(d1, x, rules);
ConsistentCase(Case(d3, rules, n));
| InexhaustiveCase(u, i, Case(d3, rules, n)) =>
let d3 = subst_var(d1, x, d3);
let rules = subst_var_rules(d1, x, rules);
InexhaustiveCase(u, i, Case(d3, rules, n));
| InconsistentBranches(u, i, Case(d3, rules, n)) =>
let d3 = subst_var(d1, x, d3);
let rules = subst_var_rules(d1, x, rules);
Expand Down
5 changes: 5 additions & 0 deletions src/haz3lweb/view/dhcode/DHCode.re
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,16 @@ let view_of_layout = (~font_metrics: FontMetrics.t, l: DHLayout.t): Node.t => {
ds,
)
| VarHole(_) => ([with_cls("InVarHole", txt)], ds)
| MismatchedRuleDecoration => (
[with_cls("MismatchedRuleDecoration", txt)],
ds,
)
| Invalid((_, (-666))) =>
/* Evaluation and Elaboration exceptions */
([with_cls("exception", txt)], ds)
| NonEmptyHole(_)
| InconsistentBranches(_)
| InexhaustiveCase(_)
| Invalid(_) =>
let offset = start.col - indent;
let decoration =
Expand Down
4 changes: 3 additions & 1 deletion src/haz3lweb/view/dhcode/layout/DHAnnot.re
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ type t =
| NonEmptyHole(ErrStatus.HoleReason.t, HoleInstance.t)
| VarHole(VarErrStatus.HoleReason.t, HoleInstance.t)
| InconsistentBranches(HoleInstance.t)
| InexhaustiveCase(HoleInstance.t)
| Invalid(HoleInstance.t)
| FailedCastDelim
| FailedCastDecoration
| CastDecoration
| OperationError(InvalidOperationError.t);
| OperationError(InvalidOperationError.t)
| MismatchedRuleDecoration;
4 changes: 3 additions & 1 deletion src/haz3lweb/view/dhcode/layout/DHAnnot.rei
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ type t =
| NonEmptyHole(ErrStatus.HoleReason.t, HoleInstance.t)
| VarHole(VarErrStatus.HoleReason.t, HoleInstance.t)
| InconsistentBranches(HoleInstance.t)
| InexhaustiveCase(HoleInstance.t)
| Invalid(HoleInstance.t)
| FailedCastDelim
| FailedCastDecoration
| CastDecoration
| OperationError(InvalidOperationError.t);
| OperationError(InvalidOperationError.t)
| MismatchedRuleDecoration;
37 changes: 30 additions & 7 deletions src/haz3lweb/view/dhcode/layout/DHDoc_Exp.re
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ let rec precedence = (~show_casts: bool, d: DHExp.t) => {
| Let(_)
| FixF(_)
| ConsistentCase(_)
| InexhaustiveCase(_)
| InconsistentBranches(_) => DHDoc_common.precedence_max
| BinBoolOp(op, _, _) => precedence_bin_bool_op(op)
| BinIntOp(op, _, _) => precedence_bin_int_op(op)
Expand Down Expand Up @@ -93,6 +94,7 @@ let mk_bin_float_op = (op: TermBase.UExp.op_bin_float): DHDoc.t =>
let mk_bin_string_op = (op: TermBase.UExp.op_bin_string): DHDoc.t =>
Doc.text(TermBase.UExp.string_op_to_string(op));

// DHExp is annotated here
let rec mk =
(
~settings: Settings.Evaluation.t,
Expand Down Expand Up @@ -122,7 +124,7 @@ let rec mk =
: (DHDoc.t, option(Typ.t)) => {
open Doc;
let go' = go(~enforce_inline);
let go_case = (dscrut, drs) =>
let go_case = (dscrut, drs, current_rule_index) =>
if (enforce_inline) {
fail();
} else {
Expand All @@ -137,7 +139,15 @@ let rec mk =
vseps(
List.concat([
[hcat(DHDoc_common.Delim.open_Case, scrut_doc)],
drs |> List.map(mk_rule(~settings, ~selected_hole_instance)),
drs
|> List.mapi((i, rule) =>
mk_rule(
~settings,
~selected_hole_instance,
~crossed_out=i < current_rule_index,
rule,
)
),
[DHDoc_common.Delim.close_Case],
]),
);
Expand Down Expand Up @@ -173,7 +183,10 @@ let rec mk =
text(x) |> annot(DHAnnot.VarHole(Free, (u, i)))
| InvalidText(u, i, t) => DHDoc_common.mk_InvalidText(t, (u, i))
| InconsistentBranches(u, i, Case(dscrut, drs, _)) =>
go_case(dscrut, drs) |> annot(DHAnnot.InconsistentBranches((u, i)))
go_case(dscrut, drs, 0)
|> annot(DHAnnot.InconsistentBranches((u, i)))
| InexhaustiveCase(u, i, Case(dscrut, drs, _)) =>
go_case(dscrut, drs, 0) |> annot(DHAnnot.InexhaustiveCase((u, i)))
| BoundVar(x) => text(x)
| Constructor(name) => DHDoc_common.mk_ConstructorLit(name)
| BoolLit(b) => DHDoc_common.mk_BoolLit(b)
Expand Down Expand Up @@ -237,7 +250,8 @@ let rec mk =
| Tuple(ds) =>
DHDoc_common.mk_Tuple(ds |> List.map(d => mk_cast(go'(d))))
| Prj(d, n) => DHDoc_common.mk_Prj(mk_cast(go'(d)), n)
| ConsistentCase(Case(dscrut, drs, _)) => go_case(dscrut, drs)
| ConsistentCase(Case(dscrut, drs, current_rule_index)) =>
go_case(dscrut, drs, current_rule_index)
| Cast(d, _, _) =>
let (doc, _) = go'(d);
doc;
Expand Down Expand Up @@ -369,7 +383,12 @@ let rec mk =
mk_cast(go(~parenthesize, ~enforce_inline, d));
}
and mk_rule =
(~settings, ~selected_hole_instance, Rule(dp, dclause): DHExp.rule)
(
~settings,
~selected_hole_instance,
~crossed_out,
Rule(dp, dclause): DHExp.rule,
)
: DHDoc.t => {
open Doc;
let mk' = mk(~settings, ~selected_hole_instance);
Expand All @@ -384,7 +403,8 @@ and mk_rule =
]),
])
: hcat(space(), hidden_clause);
hcats([
// temporary name
let r = [
DHDoc_common.Delim.bar_Rule,
DHDoc_Pat.mk(dp)
|> DHDoc_common.pad_child(
Expand All @@ -393,5 +413,8 @@ and mk_rule =
),
DHDoc_common.Delim.arrow_Rule,
clause_doc,
]);
];
let r =
crossed_out ? List.map(annot(DHAnnot.MismatchedRuleDecoration), r) : r;
hcats(r);
};
5 changes: 5 additions & 0 deletions src/haz3lweb/www/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,11 @@ svg.expandable path {
color: var(--err-color)
}

.DHCode .MismatchedRuleDecoration {
text-decoration: line-through;
opacity: 0.5;
}

.DHCode .EmptyHole {
background-color: #ac9a6a;
border-radius: 0.2em;
Expand Down
Loading