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

Record/tuple patterns and new pattern match compiler and coverage checker #430

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Kmeakin
Copy link
Contributor

@Kmeakin Kmeakin commented Dec 12, 2022

Future work

  • I have not done any optimization: there are a lot of allocations that could probably be eliminated.
  • The coverage checker simply reports that a match is in-exhaustive, but does not explain which patterns are missing. A more sophisticated algorithm for calculating missing patterns in described in the second half of "Warnings for pattern matching"
  • The implementation of shift is inefficient: we may want to add a new Weaken term kind instead
  • The match compiler produces ugly code: it inserts extra let bindings in the body of default branches, instead of binding the default branch to a variable:
match x {
    0 => 0,
    y => y + 1,
}

will become

match x {
    0 => 0,
    _ => let y = x; y + 1,
}

@Kmeakin Kmeakin force-pushed the pattern-matching branch 3 times, most recently from 1ef64a4 to d24c4f9 Compare December 12, 2022 01:28
Copy link
Contributor

@wezm wezm left a comment

Choose a reason for hiding this comment

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

I'll leave a full review of this to when Brendan returns from leave. Just noting one small issue with links in docs.

fathom/src/surface/elaboration/patterns/compile.rs Outdated Show resolved Hide resolved
@Kmeakin Kmeakin marked this pull request as draft December 14, 2022 01:35
Copy link
Member

@brendanzab brendanzab left a comment

Choose a reason for hiding this comment

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

Still need to look deeper into this to try to understand the algorithm… there’s a bit to take in but it’s looking neat!

fathom/src/core.rs Outdated Show resolved Hide resolved
fathom/src/surface/elaboration/patterns.rs Outdated Show resolved Hide resolved
fathom/tests/source_tests.rs Outdated Show resolved Hide resolved
fathom/src/surface/elaboration/patterns/compile.rs Outdated Show resolved Hide resolved
fathom/src/core.rs Outdated Show resolved Hide resolved
@brendanzab
Copy link
Member

We could maybe pull out the rust upgrade into a separate PR if it helps clean things up.

@Kmeakin
Copy link
Contributor Author

Kmeakin commented Dec 18, 2022

We could maybe pull out the rust upgrade into a separate PR if it helps clean things up.

That was the intention, not sure why github included those commits in the PR. Fixed it now.

@Kmeakin Kmeakin force-pushed the pattern-matching branch 3 times, most recently from 792176f to c31c1d1 Compare December 20, 2022 13:47
@Kmeakin Kmeakin marked this pull request as ready for review December 21, 2022 15:22
@Kmeakin Kmeakin requested a review from brendanzab December 21, 2022 15:22
@Kmeakin Kmeakin force-pushed the pattern-matching branch 2 times, most recently from 7003365 to 86aa0c6 Compare December 21, 2022 16:30
@Kmeakin Kmeakin force-pushed the pattern-matching branch 8 times, most recently from 8dbe29a to 25f66bc Compare January 17, 2023 03:09
fathom/src/surface.rs Outdated Show resolved Hide resolved
fathom/src/env.rs Show resolved Hide resolved
fathom/src/core/semantics.rs Outdated Show resolved Hide resolved
tests/fail/elaboration/boolean-literal/not-supported.snap Outdated Show resolved Hide resolved
Comment on lines 847 to 750
#[allow(clippy::type_complexity)]
fn match_if_then_else<'arena>(
branches: &'arena [(Const, core::Term<'arena>)],
default_branch: Option<(Option<StringId>, &'arena core::Term<'arena>)>,
) -> Option<(&'arena core::Term<'arena>, &'arena core::Term<'arena>)> {
) -> Option<(
(Option<Option<StringId>>, &'arena core::Term<'arena>),
(Option<Option<StringId>>, &'arena core::Term<'arena>),
)> {
Copy link
Member

Choose a reason for hiding this comment

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

I’m… not really understanding what’s going on with the Option<Option<StringId>>s for the then and else branches?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In cases of the form

match x {
    true => ...,
    _ => ...,
}

or

match x {
    false => ...,
    _ => ...,
}

We have to push _ onto local_names, or else we get confusing bugs in distillation output. Alternatively, we could only distill matches to if-then-else syntax if they are of the form

match x {
    true => ...,
    false => ...,
}

@brendanzab
Copy link
Member

Sorry for the slowness - taking a bit of time to get into this one

@Kmeakin Kmeakin force-pushed the pattern-matching branch 2 times, most recently from e91303c to cccdfb7 Compare January 17, 2023 06:11
@Kmeakin Kmeakin force-pushed the pattern-matching branch 4 times, most recently from e3ff50e to 4cef50e Compare January 23, 2023 14:38
@brendanzab
Copy link
Member

I’ve been looking at this more in depth locally. Doing a bit of messing around to understand it a bit more and tweaking the implementation a bit. While it’s big, I think it would be better to squash it into a single commit as it kind of only works all together.

One nit-pick: could we use the actual the actual type names rather than Self in impls and type definitions etc? I prefer to only use those when necessary in trait definitions.

@Kmeakin
Copy link
Contributor Author

Kmeakin commented Jan 27, 2023

One nit-pick: could we use the actual the actual type names rather than Self in impls and type definitions etc? I prefer to only use those when necessary in trait definitions.

I think the preferred Rust style is to use Self wherever possible: https://rust-lang.github.io/rust-clippy/master/#use_self. Personally I prefer Self because:

  • Usually less typing: most type names are more than 4 letters. Also allows you to avoid repeating lifetimes/type parameters
  • One less piece of information you need to keep track off when writing methods/impls. Never do something yourself that the compiler can do for you!
  • Type names may change frequently during development. Self means you don't have to update all the occurrences of the type name, and keeps diffs smaller

Comment on lines +654 to +656
let columns =
vec![(CheckedPattern::Placeholder(*range), scrut.clone()); ctor.arity()];
Copy link
Member

Choose a reason for hiding this comment

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

Why is it ok to duplicate these without updating scrut?

Copy link
Contributor Author

@Kmeakin Kmeakin Feb 1, 2023

Choose a reason for hiding this comment

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

A wildcard pattern leaves the scrutinee unchanged: it does not project further into it. It is duplicated ctor.arity() times because the algorithm relies on the matrix always being rectangular.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, was more wondering about the type of the scrutinee - does it need to be updated for each pattern (seeing as it seems like this is based on the arity of the constructor) or is that unecessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, updating the type is also unnecessary. The scrutinee is left completely unchanged by wildcard patterns because wildcard patterns match anything: they don't inspect or transform the scrutinee in any way

@Kmeakin Kmeakin force-pushed the pattern-matching branch 4 times, most recently from fdd2ba7 to 90af406 Compare February 1, 2023 00:42
@brendanzab
Copy link
Member

brendanzab commented Feb 6, 2023

I’ve looked into merging this, trying to do some cleaning up (see: Kmeakin/fathom@pattern-matching...brendanzab:fathom:pattern-matching-cleanups), but I don’t think it is ready yet. Some of the pattern matching compilation is self-contained and can be iterated on for improved clarity, but my big fear is how it impacts the handling of local bindings in the elaborator. The freshen_scrutinee and insert_extra_let methods are of particular concern, and I’m a little worried about taking on this burden going forward. Related to #488, it does make me think we might need a better approach to managing local bindings in the elaborator - eg. regarding adding/removing bindings, or with weakening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants