-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Fix SR-11159, better checking for enum elements with the same head and different labels #26741
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
Conversation
@swift-ci Please smoke test |
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 only had a very quick look, but here are some initial comments.
(btw, welcome to the project! 🎉)
ERROR(enum_element_pattern_assoc_values_using_labels,none, | ||
"using label to match to enum, enum element pattern cannot match against mixed labels and variable patterns.",()) | ||
ERROR(enum_element_pattern_assoc_values_using_var_patterns,none, | ||
"using variable patterns to match against enum, enum element pattern cannot match against mixed labels and variable patterns.",()) |
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.
Hmm, what's a "variable pattern"?
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.
In the proposal when doing an case statement you can't mix labels and variables. So in (a: _, let y)
the variable patterns is let y
. There's also something added in the Identifier to flag that it came from a variable pattern. I don't think that this method is the best position though.
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.
Still, I don't think we call them "variable patterns" in user-facing diagnostics.
lib/AST/NameLookup.cpp
Outdated
@@ -1442,12 +1443,14 @@ bool DeclContext::lookupQualified(Type type, | |||
assert(decls.empty() && "additive lookup not supported"); | |||
|
|||
// Handle AnyObject lookup. | |||
if (type->isAnyObject()) | |||
if (type->isAnyObject()){ |
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.
Could you remove these changes? There are a lot of them and are unrelated to your fix and makes the PR really long.
I would also suggest running git-clang-format
to format your changes.
lib/Sema/TypeCheckPattern.cpp
Outdated
continue; | ||
} | ||
bool addCandidate = true; | ||
if(queryParams.size() == 1){ |
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.
This condition would always be true, right? Since we continue
above if the size is not equal to 1.
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.
It isn't always true because it will continue only if the sizes are not equal and the size is not equal to 1. If both the case and the enum element are the same it should not continue. It should be ((enumElementParams.size() != queryParams.size()) && (queryParams.size() != 1))
for clarity.
lib/Sema/TypeCheckPattern.cpp
Outdated
bool enumHasLabels = false; | ||
for(size_t i = 0;i<enumElementParams.size();++i) | ||
enumHasLabels = enumHasLabels || !enumElementParams[i].empty(); | ||
if(foundElements.size() == 1 && !enumHasLabels){ |
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.
Hmm, if you only care about a single result, you can do foundElements .getSingleTypeResult()
(will return nullptr
if size() != 1
). Perhaps you can lift this check outside the for loop in that case?
I think this patch is trying to do a few separate things. I'd like to review the |
The SpaceEngine changes are to take care of exhaustivness/redundancy errors that pop up when the changes is added to the Enum typechecking. Should I try to resolve those issues just within the Enum checking? |
Yes. That change is easiest to take at this stage. |
SpaceEngine patch is now in #26754 |
8a12543
to
1a61a7f
Compare
4585997
to
03e9e8a
Compare
I've made a few changes to this after my last pull request to try to clean this up a bit and minimize changes. It currently passes both the standard and validation tests. |
03e9e8a
to
12779a4
Compare
The general approach looks good to me so far. I'm going to spend a little more time staring at the matching algorithm (it was the hardest part of this when I came along and tried to do it a while ago). In the mean time, could you please write a bunch of tests! |
Here's a good one to add as a test https://bugs.swift.org/browse/SR-11159 |
Added a few tests. I haven't added anything concerning warnings and exhaustiveness. There are some issues checking for this when the labels are created from the variable declaration in the constructor. It seems like that could be broken into its own issue. |
I was wondering what the current status of this pull request is? |
Give it a rebase and let’s see about getting it merged. |
… value, adding fix for if enum element has no var/let pattern but has associated values adding additional file removing print statement addition to identifier to identify from let or var, used to match against enum cases to avoid ambiguities removing optimization for exhaustiveness checking to work properly adding new functionality, removing debug statements removing stray iostream includes, enforcing 80 column width formatting corrections Update TypeCheckSwitchStmt.cpp committing column widths for TypeCheckPattern.cpp removing some sublime place brackets and extra lines Update TypeCheckStmt.cpp adding range based for loop strategies removing SpaceEngine changes to be put in different pull request fixing DeclName and Identifier problems fixing error where a label with no let/var pattern would not show error with wrong label, and so finding enum element if only one member with same head found Update TypeCheckStmt.cpp cleaning up code fixing full enum description being included and correct warnings clang format changes cleaning up code, Optional Bools, and removing unused code fix small bug, add fixmes and tests correcting changes from rebase clang format fixing tests
52ce73d
to
5415e94
Compare
Rebase should be complete, and passes the basic build script tests |
@swift-ci please test |
Build failed |
Build failed |
Hmm, maybe something broke:
|
|
||
// Do not crash | ||
enum Foo1 | ||
{ |
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.
Nit: Please match stdlib style in here.
@@ -557,6 +559,8 @@ namespace { | |||
PAIRCASE (SpaceKind::Constructor, SpaceKind::Constructor): { | |||
// Optimization: If the heads of the constructors don't match then | |||
// the two are disjoint and their difference is the first space. | |||
|
|||
// FIXME: Exhuastiveness checking for labelled Enums |
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.
Hold on: is this still not implemented properly?
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.
This has to do with extraneous warnings when there are labelled enums with the same base name. There wasn't a good solution developed in the last pull request, and it was sort of out of the scope of the initial bug report, I thought it could be fixed in a different pull request.
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.
Ah, OK. That's usually called "redundancy checking". Had a small heart attack at the thought we had regressed the exhaustiveness checker.
.diagnose(EEP->getLoc(), | ||
diag::enum_element_pattern_assoc_values_remove) | ||
.fixItRemove(sub->getSourceRange()); | ||
; |
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.
Nit: stray semicolon
@@ -1286,22 +1432,20 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern, | |||
// isn't a static VarDecl, so the existing mechanics in | |||
// extractEnumElement won't work. | |||
if (type->getAnyNominal() == Context.getOptionalDecl()) { | |||
if (EEP->getName().isSimpleName("None") || | |||
EEP->getName().isSimpleName("Some")) { | |||
if (EEP->getName().getBaseIdentifier().str() == "None" || |
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.
You shouldn't have to touch this code. The guard above checks if the nominal type we're dealing with is precisely Swift.Optional<T>
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.
If anything we oughta just get rid of it. These are Swift 2-3 migration guides.
return new (Context) EnumElementPattern( | ||
ume->getDotLoc(), ume->getNameLoc(), | ||
DeclNameRef( | ||
DeclName(Context, ume->getName().getBaseName(), namedParams)), |
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.
Nit: DeclName::withArgumentLabels is a touch cleaner here.
ParentType(ParentType), DotLoc(DotLoc), NameLoc(NameLoc), Name(Name), | ||
ElementDeclOrUnresolvedOriginalExpr(Element), | ||
SubPattern(SubPattern) { | ||
: Pattern(PatternKind::EnumElement), ParentType(ParentType), |
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.
Nothing seems to have changed in this file except whitespace. Can you revert this out?
params.push_back(Identifier()); | ||
else | ||
// Set None if not using labels, throw error if contradicts | ||
if (usingLabels == None) |
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.
This if-else tree and the one below it absolutely positively need explicit braces. I can't track anything here.
@@ -4731,6 +4731,10 @@ ERROR(empty_switch_stmt,none, | |||
"'switch' statement body must have at least one 'case' or 'default' " | |||
"block; do you want to add a default case?",()) | |||
ERROR(non_exhaustive_switch,none, "switch must be exhaustive", ()) | |||
ERROR(enum_element_pattern_assoc_values_using_labels,none, | |||
"using label to match to enum, enum element pattern cannot match against mixed labels and variable patterns.",()) |
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.
How about:
pattern matching case '%0' must specify all labels if it specifies any labels
and a nice note that rewrites things?
ERROR(enum_element_pattern_assoc_values_using_labels,none, | ||
"using label to match to enum, enum element pattern cannot match against mixed labels and variable patterns.",()) | ||
ERROR(enum_element_pattern_assoc_values_using_var_patterns,none, | ||
"using variable patterns to match against enum, enum element pattern cannot match against mixed labels and variable patterns.",()) |
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.
Same thing here as above.
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.
Left behind a bunch of nits. I have a high-level comment as well which is:
If the general idea is to rewrite patterns to have the appropriate label set, the only correct way to do that is to query the Type itself for that information and rewrite.
This patch also needs to make affordances for other language modes and provide compatibility warnings and notes to help fix these errors.
I think I may need to take a step back and try to go about this a different way. The fix is pretty different from the initial suggestion in SR-11159 and needs to solve a bigger problem than I thought it was initially (essentially adding Proposal 0155 in). |
This is a fix to SR-11159 which was a bug where having two enum elements with different named arguments could cause the compiler to crash in a switch statement. I do my best to follow the following swift evolution proposal . There are still a few errors surrounding error messages that I would help from if possible.
Resolves SR-11159.