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

Wrong reordering of match arms with ranges #18060

Closed
lifthrasiir opened this issue Oct 15, 2014 · 10 comments
Closed

Wrong reordering of match arms with ranges #18060

lifthrasiir opened this issue Oct 15, 2014 · 10 comments
Labels
A-codegen Area: Code generation E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.

Comments

@lifthrasiir
Copy link
Contributor

Adopted and minimized from the HTTP method parsing routine of hyperium/hyper:

println!("{}", match (1u, 3u) { (0, 2...5) => 1, (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4u });
println!("{}", match (1u, 3u) {                  (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4u });
println!("{}", match (1u, 7u) { (0, 2...5) => 1, (1, 7) => 2, (_, 2...5) => 3, (_, _) => 4u });

All three lines should print 2, but the first line prints 3 on the current nightly (rustc 0.13.0-nightly (40b244973 2014-10-14 23:22:20 +0000)). The match trans apparantly groupped the second pattern even when it may result in the wrong result.

@ghost ghost self-assigned this Oct 15, 2014
@ghost
Copy link

ghost commented Oct 15, 2014

Broken in 0.11 and 0.12. Fine in 0.10 so I blame one of my refactors.

@reem
Copy link
Contributor

reem commented Oct 15, 2014

cc me

@edwardw
Copy link
Contributor

edwardw commented Oct 16, 2014

This is troublesome. As being mentioned in #13027 (comment), Marijn's article outlines how the pattern matching is compiled into a decision tree. In the test case illustrated here, the tree ends up like this:

                                  (0, 2...5) => 1
(0, 2...5) => 1                   (_, 2...5) => 3
(1, 3) => 2      pick column 1    (_, _) => 4u
(_, 2...5) => 3  ==============> and
(_, _) => 4u                      (1, 3) => 2
                                  (_, _) => 4u

So the match arms are not really reordered but rather grouped together. But never the less, the result here is simply wrong. Some fundamental assumptions of the algorithm could be wrong.

There's also a minor issue. The following code:

println!("{}", match (1u, 3u) { (0, 2...5) => 1, (1, 3) => 2, (_, 3) => 3, (_, _) => 4u });

gives the wrong answer 4. It has to do with what counts as a default wildcard arm as trans/_match.rs sees it. Right now only _ => foo is but a tuple pattern with all wildcard elements should be, too.

@ghost
Copy link

ghost commented Oct 16, 2014

The bug is that we consider the range 2..5 to be a "constructor" of the integer type being matched which is wrong (constructors must be disjoint much like variants of an enum). The right thing is to treat it as x if x >= 2 && x <= 5. Should be very easy to fix.

Not sure about the wild pattern but I do remember being surprised seeing that we'd only check for PatWild.

@edwardw
Copy link
Contributor

edwardw commented Oct 16, 2014

@jakub-, your assessment is more accurate. I have a fix for the minor issue I described. Not really worthy of a separated PR, so should I leave that to you too?

@ghost
Copy link

ghost commented Oct 16, 2014

@edwardw Thanks! Yes, I'm on it. :-)

@ghost
Copy link

ghost commented Nov 11, 2014

An update: I haven't forgotten about this, will look this week.

edwardw added a commit to edwardw/rust that referenced this issue Jan 21, 2015
If there are both range and literal patterns in the same column of a
match expression, rustc may generate incorrect code. This patch fixes
it.

Closes rust-lang#18060
@steveklabnik steveklabnik added the A-codegen Area: Code generation label Jan 29, 2015
@remram44
Copy link
Contributor

Still happens :(

eefriedman added a commit to eefriedman/rust that referenced this issue Jul 15, 2015
The old code was not well structured, difficult to understand,
and buggy.

The new implementation is completely naive, so there may be a slight
runtime performance loss. That said, adding optimizations on top of
a clear and correct implementation seems easier than trying to
fix the old mess.

Fixes issue rust-lang#19064.
Fixes issue rust-lang#26989.
Fixes issue rust-lang#26251.
Fixes issue rust-lang#18060.
Fixes issue rust-lang#24875.
Fixes issue rust-lang#23311.
Fixes issue rust-lang#20046.
@niconii
Copy link
Contributor

niconii commented Sep 21, 2016

This seems to be fixed as of beta?

@solson
Copy link
Member

solson commented Sep 21, 2016

Yes, this is already fixed in beta 1.12: https://is.gd/fwGJ30

@bluss bluss added E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. labels Sep 21, 2016
bors added a commit that referenced this issue Nov 6, 2016
Add test for issue 18060.

Closes #18060
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants