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

WIP: Initial implementation of or-pattern handling in MIR #63688

Closed
wants to merge 2 commits into from

Conversation

dlrobertson
Copy link
Contributor

@dlrobertson dlrobertson commented Aug 18, 2019

Building on #64508, #64111, #63693, and #61708, this PR adds:

  • Initial implementation of or-pattern lowering to MIR.
  • Basic ui tests for or-patterns

CC #54883

r? @matthewjasper

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 18, 2019
src/librustc_mir/build/matches/mod.rs Outdated Show resolved Hide resolved
src/librustc_mir/build/matches/test.rs Outdated Show resolved Hide resolved
src/librustc_mir/build/matches/test.rs Outdated Show resolved Hide resolved
src/librustc_mir/build/matches/test.rs Outdated Show resolved Hide resolved
src/librustc_mir/build/matches/test.rs Outdated Show resolved Hide resolved
src/test/ui/or-patterns/basic-switch.rs Show resolved Hide resolved
src/test/ui/or-patterns/basic-switchint.rs Outdated Show resolved Hide resolved
src/test/ui/or-patterns/basic-switchint.rs Show resolved Hide resolved
src/test/ui/or-patterns/mix-with-wild.rs Show resolved Hide resolved
@Centril Centril added the F-or_patterns `#![feature(or_patterns)]` label Aug 18, 2019
@dlrobertson
Copy link
Contributor Author

@Centril thanks for the comments! Updated to take into account your feedback. Let me know if I missed something.

@dlrobertson
Copy link
Contributor Author

ping @matthewjasper any thoughts on how I build the MIR for the or-pattern?

Copy link
Contributor

@matthewjasper matthewjasper left a comment

Choose a reason for hiding this comment

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

This seems like a reasonable first step. I think you might be better off using match_candidates for Or tests, since handling complex or patterns (e.g. (1, 1, _) | (_, 2, 2)) would require duplication of most of the remaining match_candidates code.

I've left a couple of comments for other things I noticed when looking through the changes.

pub struct FieldPattern<'tcx> {
pub field: Field,
pub pattern: Pattern<'tcx>,
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
Copy link
Contributor

Choose a reason for hiding this comment

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

I can't see where these PartialEq impls are used. What is the intended meaning of == here?

// `SwitchInt` (an `enum`).
// run-pass
#![feature(or_patterns)]
//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you allow this warning for the tests here?

@dlrobertson
Copy link
Contributor Author

@matthewjasper I couldn't figure out a way to use match_candidates that didn't result in a blow-up of code evaluated as noted in the RFC implementation notes. Given Foo(A | B, C | D) wouldn't we need to expand the or-pattern to the following candidates?

Candidate 1 match pairs:
  .0: A
  .1: C
Candidate 2 match pairs:
  .0: A
  .1: D
Candidate 3 match pairs:
  .0: B
  .1: C
Candidate 4 match pairs:
  .0: B
  .1: D

It may be that I overlooked something, so please let me know if there is another way to generate the correct candidates for an or-pattern, or if I am misunderstanding Candidates.

@matthewjasper
Copy link
Contributor

An or pattern would create a new set of candidates for just that pattern.

First Or pattern
Candidate 1 match pairs:
  .0: A
Candidate 2 match pairs:
  .0: B

Second or pattern
Candidate 1 match pairs:
  .1: C
Candidate 2 match pairs:
  .1: D

@dlrobertson
Copy link
Contributor Author

Ah I see... Yeah that could work. I'll try that out.

@wirelessringo

This comment has been minimized.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 6, 2019
@Centril
Copy link
Contributor

Centril commented Sep 6, 2019

@dlrobertson Now that #64111 landed, you might want to try tests with bindings as well if this PR would support that. See https://github.com/rust-lang/rust/pull/64111/files#diff-03c5a135508e329a1f3eae00e79f9ad4R42 for a relevant test.

@dlrobertson
Copy link
Contributor Author

Awesome! Thanks... I think it should work more or less without much effort once I move to using a Candidate instead of manually manipulating the CFG

@joelpalmer

This comment has been minimized.

@dlrobertson
Copy link
Contributor Author

Working on figuring out where the best place to put the expansion of candidates is (Placing it with match pair simplification would cause exponential blow-up). And we currently don't assume that the list of candidates is grow-able, so I'm also working on correctly handling that.

Centril added a commit to Centril/rust that referenced this pull request Sep 22, 2019
or-patterns: Push `PatKind/PatternKind::Or` at top level to HIR & HAIR

Following up on work in rust-lang#64111, rust-lang#63693, and rust-lang#61708, in this PR:

- We change `hair::Arm.patterns: Vec<Pattern<'_>>` into `hir::Arm.pattern: Pattern<'_>`.

   - `fn hair::Arm::top_pats_hack` is introduced as a temporary crutch in MIR building to avoid more changes.

- We change `hir::Arm.pats: HirVec<P<Pat>>` into `hir::Arm.pat: P<Pat>`.

   - The hacks in `rustc::hir::lowering` are removed since the representation hack is no longer necessary.

   - In some places, `fn hir::Arm::top_pats_hack` is introduced to leave some things as future work.

   - Misc changes: HIR pretty printing is adjusted to behave uniformly wrt. top/inner levels, rvalue promotion is adjusted, regionck, and dead_code is also.

   - Type checking is adjusted to uniformly handle or-patterns at top/inner levels.
      To make things compile, `p_0 | ... | p_n` is redefined as a "reference pattern" in [`fn is_non_ref_pat`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_typeck/check/struct.FnCtxt.html#method.is_non_ref_pat) for now. This is done so that reference types are not eagerly stripped from the `expected: Ty<'tcx>`.

    - Liveness is adjusted wrt. the `unused_variables` and `unused_assignments` lints to handle top/inner levels uniformly and the handling of `fn` parameters, `let` locals, and `match` arms are unified in this respect. This is not tested for now as exhaustiveness checks are reachable and will ICE.

    - In `check_match`, checking `@` and by-move bindings is adjusted. However, exhaustiveness checking is not adjusted the moment and is handled by @dlrobertson in rust-lang#63688.

    - AST borrowck (`construct.rs`) is not adjusted as AST borrowck will be removed soon.

r? @matthewjasper
cc @dlrobertson @varkor @oli-obk
@joelpalmer

This comment has been minimized.

bors added a commit that referenced this pull request Sep 23, 2019
or-patterns: Push `PatKind/PatternKind::Or` at top level to HIR & HAIR

Following up on work in #64111, #63693, and #61708, in this PR:

- We change `hair::Arm.patterns: Vec<Pattern<'_>>` into `hir::Arm.pattern: Pattern<'_>`.

   - `fn hair::Arm::top_pats_hack` is introduced as a temporary crutch in MIR building to avoid more changes.

- We change `hir::Arm.pats: HirVec<P<Pat>>` into `hir::Arm.pat: P<Pat>`.

   - The hacks in `rustc::hir::lowering` are removed since the representation hack is no longer necessary.

   - In some places, `fn hir::Arm::top_pats_hack` is introduced to leave some things as future work.

   - Misc changes: HIR pretty printing is adjusted to behave uniformly wrt. top/inner levels, rvalue promotion is adjusted, regionck, and dead_code is also.

   - Type checking is adjusted to uniformly handle or-patterns at top/inner levels.
      To make things compile, `p_0 | ... | p_n` is redefined as a "reference pattern" in [`fn is_non_ref_pat`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_typeck/check/struct.FnCtxt.html#method.is_non_ref_pat) for now. This is done so that reference types are not eagerly stripped from the `expected: Ty<'tcx>`.

    - Liveness is adjusted wrt. the `unused_variables` and `unused_assignments` lints to handle top/inner levels uniformly and the handling of `fn` parameters, `let` locals, and `match` arms are unified in this respect. This is not tested for now as exhaustiveness checks are reachable and will ICE.

    - In `check_match`, checking `@` and by-move bindings is adjusted. However, exhaustiveness checking is not adjusted the moment and is handled by @dlrobertson in #63688.

    - AST borrowck (`construct.rs`) is not adjusted as AST borrowck will be removed soon.

r? @matthewjasper
cc @dlrobertson @varkor @oli-obk
@dlrobertson
Copy link
Contributor Author

dlrobertson commented Sep 23, 2019

Still working on it. I've got single or patterns in a pattern working (Foo(A | B)), but I've got some work to do on (Foo(A | B, C | D)).

Also my current implementation is super hacky... Got a lot of cleanup to do.

Centril added a commit to Centril/rust that referenced this pull request Sep 25, 2019
or-patterns: Push `PatKind/PatternKind::Or` at top level to HIR & HAIR

Following up on work in rust-lang#64111, rust-lang#63693, and rust-lang#61708, in this PR:

- We change `hair::Arm.patterns: Vec<Pattern<'_>>` into `hir::Arm.pattern: Pattern<'_>`.

   - `fn hair::Arm::top_pats_hack` is introduced as a temporary crutch in MIR building to avoid more changes.

- We change `hir::Arm.pats: HirVec<P<Pat>>` into `hir::Arm.pat: P<Pat>`.

   - The hacks in `rustc::hir::lowering` are removed since the representation hack is no longer necessary.

   - In some places, `fn hir::Arm::top_pats_hack` is introduced to leave some things as future work.

   - Misc changes: HIR pretty printing is adjusted to behave uniformly wrt. top/inner levels, rvalue promotion is adjusted, regionck, and dead_code is also.

   - Type checking is adjusted to uniformly handle or-patterns at top/inner levels.
      To make things compile, `p_0 | ... | p_n` is redefined as a "reference pattern" in [`fn is_non_ref_pat`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_typeck/check/struct.FnCtxt.html#method.is_non_ref_pat) for now. This is done so that reference types are not eagerly stripped from the `expected: Ty<'tcx>`.

    - Liveness is adjusted wrt. the `unused_variables` and `unused_assignments` lints to handle top/inner levels uniformly and the handling of `fn` parameters, `let` locals, and `match` arms are unified in this respect. This is not tested for now as exhaustiveness checks are reachable and will ICE.

    - In `check_match`, checking `@` and by-move bindings is adjusted. However, exhaustiveness checking is not adjusted the moment and is handled by @dlrobertson in rust-lang#63688.

    - AST borrowck (`construct.rs`) is not adjusted as AST borrowck will be removed soon.

r? @matthewjasper
cc @dlrobertson @varkor @oli-obk
@bors

This comment has been minimized.

@Centril
Copy link
Contributor

Centril commented Sep 27, 2019

With #64508 merged, it should now be possible to unify the MIR building of or-patterns and link up exhaustiveness checking as well.

@JohnCSimon

This comment has been minimized.

@dlrobertson
Copy link
Contributor Author

This PR has sat idle for the last 9 days. And you please address the merge conflicts?

Yeah, working on a complete overhaul of the PR. It's gonna take a bit. The conflicts will be resolved when I push up the changes from the overhaul. While the initial implementation works, a more complete implementation will not directly manipulate the CFG (what I'm working on).

@dlrobertson dlrobertson changed the title Initial implementation of or-pattern handling in MIR WIP: Initial implementation of or-pattern handling in MIR Oct 6, 2019
@Dylan-DPC-zz

This comment has been minimized.

@Nadrieril
Copy link
Member

I was invited to work on the exhaustiveness checking part of this PR (and I'm very excited !). Is it possible to test the exhaustiveness part independently ? If not, how can we coordinate ?

@Dylan-DPC-zz

This comment has been minimized.

@Centril
Copy link
Contributor

Centril commented Oct 18, 2019

@Nadrieril I've made a Zulip thread for the work on or-patterns where we can coordinate.

Wrt. testing, I believe we can implement exhaustiveness checking for or-patterns independently of MIR building. We can also add tests for cases where the matches are non-exhaustive as this should never reach MIR building. However, for the exhaustive cases this should result in ICEs because MIR building is reachable and I'm not sure if we can test for those in the current rustbuild infrastructure (although I recall @oli-obk saying something about ways to do it). What we could try is to insert a non-exhaustive match that is unrelated to or-patterns just as a canary to make MIR building unreachable. In any case, some incremental progress would be great. :)

@dlrobertson
Copy link
Contributor Author

@Dylan-DPC posted an update in the Zulip thread.

@oli-obk
Copy link
Contributor

oli-obk commented Oct 18, 2019

However, for the exhaustive cases this should result in ICEs because MIR building is reachable and I'm not sure if we can test for those in the current rustbuild infrastructure (although I recall @oli-obk saying something about ways to do it).

Search for tests using -Ztreat-err-as-bug. There's a comment-flag that you need to add (not the -Ztreat-err-as-bug) in order for the exit code of an ICE to be accepted as making the test "pass".

@JohnCSimon

This comment has been minimized.

Handle or-patterns when building MIR by expanding the MatchPair into
n Candidates.
Add some basic run-pass ui tests for or-patterns.
@dlrobertson
Copy link
Contributor Author

dlrobertson commented Oct 28, 2019

Updated... It largely consists of hacks and the current code was written in a manner to make debugging easier on me. Things that I know of that have yet to be implemented/fixed:

  • completeness and unreachability checking (see the range pattern test warning)
  • <pat0>(q @ <pat1> | q @ <pat2>) currently causes and ICE or compiler error
  • Code cleanup

@JohnCSimon

This comment has been minimized.

// FIXME(dlrobertson): This could use some cleaning up.
if let PatKind::Or { ref pats } = *match_pair.pattern.kind {
let match_pairs = mem::take(&mut candidates.first_mut().unwrap().match_pairs);
let mut new_candidates = pats.iter().map(|pat| {
Copy link
Contributor

Choose a reason for hiding this comment

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

I was expecting these to be an entirely new set of candidates, containing only the match pairs that come from the or pattern. So this function would call match_candidates 3 times: once for the first candidate, once for the remaining candidates and once for the new candidates from the or pattern.

@JohnCSimon

This comment has been minimized.

@JohnCSimon

This comment has been minimized.

@bors

This comment has been minimized.

@JohnCSimon

This comment has been minimized.

@JohnCSimon JohnCSimon closed this Dec 7, 2019
@JohnCSimon JohnCSimon added the S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. label Dec 7, 2019
@dlrobertson
Copy link
Contributor Author

awesome sounds good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-or_patterns `#![feature(or_patterns)]` S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.