Skip to content

Rust: Remove nonsentical no-match CFG edges #18820

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

Merged
merged 6 commits into from
Feb 21, 2025

Conversation

paldepind
Copy link
Contributor

Cleans up the handling of patterns that can't fail and makes it more precise such that no-match edges that will never be taken are removed.

The added tests also exposed a bug for macro patterns. I haven't fixed that as it's orthogonal to this PR.

Here's an example. Previously we had a no-match edge out of MyStruct {...} but that is now gone as the struct pattern itself will never cause a match failure:

flowchart TD
1["enter fn struct_pattern"]
10["MyStruct {...}"]
11["1"]
11["1"]
13["0"]
14["MyStruct {...}"]
15["x"]
15["x"]
17["3"]
2["exit fn struct_pattern"]
3["exit fn struct_pattern (normal)"]
4["st"]
4["st"]
6["...: MyStruct"]
7["{ ... }"]
8["match st { ... }"]
9["st"]

1 --> 4
3 --> 2
4 -- match --> 6
4 --> 4
6 --> 9
7 --> 3
8 --> 7
9 --> 10
10 -- match --> 11
11 -- match --> 13
11 -- no-match --> 14
11 --> 11
13 --> 8
14 -- match --> 15
15 -- match --> 17
15 --> 15
17 --> 8
Loading

@github-actions github-actions bot added the Rust Pull requests that update Rust code label Feb 20, 2025
@paldepind paldepind changed the title Rust fewer no match Rust: Remove nonsentical no-match CFG edges Feb 20, 2025
@paldepind paldepind marked this pull request as ready for review February 20, 2025 10:06
@paldepind paldepind requested a review from hvitved February 20, 2025 10:48
Copy link
Contributor

@hvitved hvitved left a comment

Choose a reason for hiding this comment

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

Thanks a lot for doing this. Some small suggestions.

Comment on lines 21 to 22
* If this pattern is immediately nested within another pattern, then get the
* parent pattern.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* If this pattern is immediately nested within another pattern, then get the
* parent pattern.
* Gets the pattern under which this pattern is immediately nested, if any.

// Identifier patterns that are in fact path patterns can cause failures. For
// instance `None`. Only if a `@ ...` part is present can we be sure that it's
// an actual identifier pattern.
pat = any(IdentPat p | not p.hasPat())
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we reintroduce the and not p = any(Variable v).getPat() constraint? I realize that the variable logic makes its own assumptions about what might be a variable binding or path pattern though...

pat = parent.(TuplePat).getAField()
// NOTE: a `TupleStructPat` can cause a failure if it resolves to a an enum
// variant but not when it resolves to a tuple struct.
pat instanceof TupleStructPat
Copy link
Contributor

Choose a reason for hiding this comment

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

RecordPat also needs to be added; enum variants are allowed to use record fields.

Comment on lines +121 to +123
* Holds if `pat` can not _itself_ be the cause of a pattern match failure. This
* does not mean that `pat` is irrefutable, as its children might be the cause
* of a failure.
Copy link
Contributor

Choose a reason for hiding this comment

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

This QL doc seems to suggest the dual of what the predicate actually computes? I wonder if it is actually better to implement what the QL doc says, e.g.

private predicate cannotCauseMatchFailure(Pat pat) {
  pat = any(IdentPat p | p.hasPat())
  or
  pat instanceof BoxPat
  or
  pat instanceof RestPat
  or
  pat instanceof MacroPat
  or
  pat instanceof WildcardPat
  or
  pat instanceof RangePat
  or
  pat instanceof RefPat
  or
  pat instanceof SlicePat
  or
  pat instanceof TuplePat
  or
  pat instanceof ConstBlockPat
}

and then replace not canCauseMatchFailure(pat) with cannotCauseMatchFailure(pat) further down.

@paldepind paldepind merged commit 4ef64cd into github:main Feb 21, 2025
16 checks passed
@paldepind paldepind deleted the rust-fewer-no-match branch February 24, 2025 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Rust Pull requests that update Rust code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants