-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Rust: Include parameters and patterns in the CFG #17686
Changes from 4 commits
665da39
f6f54c6
2f14ec9
756affa
ffd6b98
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,7 +62,7 @@ abstract class ConditionalCompletion extends NormalCompletion { | |
abstract ConditionalCompletion getDual(); | ||
} | ||
|
||
/** Holds if node `le` has the Boolean constant value `value`. */ | ||
/** Holds if node `le` has the constant Boolean value `value`. */ | ||
private predicate isBooleanConstant(LiteralExpr le, Boolean value) { | ||
le.getTextValue() = value.toString() | ||
} | ||
|
@@ -117,13 +117,61 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion { | |
override string toString() { result = "boolean(" + value + ")" } | ||
} | ||
|
||
/** Holds if node `pat` has the constant match value `value`. */ | ||
pragma[nomagic] | ||
private predicate isMatchConstant(Pat pat, boolean value) { | ||
value = true and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps remove the |
||
( | ||
pat instanceof WildcardPat | ||
or | ||
pat = any(IdentPat ip | not ip.hasPat() and ip = any(Variable v).getPat()) | ||
or | ||
pat instanceof RestPat | ||
or | ||
// `let` statements without an `else` branch must be exhaustive | ||
pat = any(LetStmt let | not let.hasLetElse()).getPat() | ||
or | ||
// `match` expressions must be exhaustive, so last arm cannot fail | ||
pat = any(MatchExpr me).getLastArm().getPat() | ||
or | ||
// parameter patterns must be exhaustive | ||
pat = any(Param p).getPat() | ||
) and | ||
not pat = any(ForExpr for).getPat() // workaround until `for` loops are desugared | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I understand why you exclude patterns in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thats because of how we currently model |
||
or | ||
exists(Pat parent | isMatchConstant(parent, value) | | ||
pat = parent.(BoxPat).getPat() | ||
or | ||
pat = parent.(IdentPat).getPat() | ||
or | ||
pat = parent.(ParenPat).getPat() | ||
or | ||
pat = parent.(RecordPat).getRecordPatFieldList().getField(_).getPat() | ||
or | ||
pat = parent.(RefPat).getPat() | ||
or | ||
pat = parent.(TuplePat).getAField() | ||
or | ||
pat = parent.(TupleStructPat).getAField() | ||
or | ||
pat = parent.(OrPat).getLastPat() | ||
) | ||
} | ||
|
||
/** | ||
* A completion that represents the result of a pattern match. | ||
*/ | ||
class MatchCompletion extends TMatchCompletion, ConditionalCompletion { | ||
MatchCompletion() { this = TMatchCompletion(value) } | ||
|
||
override predicate isValidForSpecific(AstNode e) { e instanceof Pat } | ||
override predicate isValidForSpecific(AstNode e) { | ||
e instanceof Pat and | ||
( | ||
isMatchConstant(e, value) | ||
or | ||
not isMatchConstant(e, _) | ||
) | ||
} | ||
|
||
override MatchSuccessor getAMatchingSuccessorType() { result.getValue() = value } | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Rust use the term
irrefutable
pattern for a pattern that cannot fail.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is correct use of "irrefutable". Irrefutable is property of a pattern, but this predicate is a property of a pattern as an AST node and considers the surrounding AST context as well.
For instance, in
this predicate holds for
None
(since the last pattern in amatch
arm is guaranteed to succeed due to exhaustiveness) butNone
is not an irrefutable pattern.I think we should rename this predicate (not sure to what though). We could also extract a proper
isIrrefutablePattern
predicate from this predicate (but it will probably be a conservative approximation as refutability for custom types depends on the type definition. E.g. the patternFoo(a)
is irrefutable ifFoo
the only case in theenum
and refutable otherwise).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you're right. Perhaps
isExhaustiveMatch
or similar. An irrefutable pattern is exhaustive on its own, and a last pattern inmatch
should be exhaustive.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a great name to me. I'll do a PR :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, PR is here #17751