Skip to content

Commit 5415e94

Browse files
add DeclName fix, checking for if duplicates are found to prune for 1 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
1 parent a34b044 commit 5415e94

File tree

5 files changed

+268
-40
lines changed

5 files changed

+268
-40
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4731,6 +4731,10 @@ ERROR(empty_switch_stmt,none,
47314731
"'switch' statement body must have at least one 'case' or 'default' "
47324732
"block; do you want to add a default case?",())
47334733
ERROR(non_exhaustive_switch,none, "switch must be exhaustive", ())
4734+
ERROR(enum_element_pattern_assoc_values_using_labels,none,
4735+
"using label to match to enum, enum element pattern cannot match against mixed labels and variable patterns.",())
4736+
ERROR(enum_element_pattern_assoc_values_using_var_patterns,none,
4737+
"using variable patterns to match against enum, enum element pattern cannot match against mixed labels and variable patterns.",())
47344738
ERROR(possibly_non_exhaustive_switch,none,
47354739
"the compiler is unable to check that this switch is exhaustive in reasonable time",
47364740
())

include/swift/AST/Pattern.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -513,14 +513,13 @@ class EnumElementPattern : public Pattern {
513513
EnumElementPattern(TypeLoc ParentType, SourceLoc DotLoc, DeclNameLoc NameLoc,
514514
DeclNameRef Name, EnumElementDecl *Element,
515515
Pattern *SubPattern, Optional<bool> Implicit = None)
516-
: Pattern(PatternKind::EnumElement),
517-
ParentType(ParentType), DotLoc(DotLoc), NameLoc(NameLoc), Name(Name),
518-
ElementDeclOrUnresolvedOriginalExpr(Element),
519-
SubPattern(SubPattern) {
516+
: Pattern(PatternKind::EnumElement), ParentType(ParentType),
517+
DotLoc(DotLoc), NameLoc(NameLoc), Name(Name),
518+
ElementDeclOrUnresolvedOriginalExpr(Element), SubPattern(SubPattern) {
520519
if (Implicit.hasValue() && *Implicit)
521520
setImplicit();
522521
}
523-
522+
524523
/// Create an unresolved EnumElementPattern for a `.foo` pattern relying on
525524
/// contextual type.
526525
EnumElementPattern(SourceLoc DotLoc,

lib/Sema/TypeCheckPattern.cpp

Lines changed: 193 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,83 @@
1919
#include "TypeCheckAvailability.h"
2020
#include "TypeCheckType.h"
2121
#include "swift/Basic/StringExtras.h"
22-
#include "swift/AST/ASTWalker.h"
2322
#include "swift/AST/ASTVisitor.h"
24-
#include "swift/AST/SourceFile.h"
23+
#include "swift/AST/ASTWalker.h"
2524
#include "swift/AST/NameLookup.h"
25+
#include "swift/AST/SourceFile.h"
2626
#include "swift/AST/ParameterList.h"
2727
#include "swift/AST/TypeCheckRequests.h"
2828
#include "llvm/Support/SaveAndRestore.h"
2929
#include <utility>
3030
using namespace swift;
3131

32+
llvm::SmallVector<Identifier, 4> extractArgsFromPattern(ASTContext &Context,
33+
Pattern *pattern) {
34+
auto &diags = Context.Diags;
35+
llvm::SmallVector<Identifier, 4> params;
36+
// Get Pattern kind
37+
switch (pattern->getKind()) {
38+
case PatternKind::Tuple: {
39+
// Walk through tuple to get argument names
40+
TuplePattern *tp = cast<TuplePattern>(pattern);
41+
Optional<bool> usingLabels = None;
42+
for (auto elem : tp->getElements()) {
43+
Identifier label = elem.getLabel();
44+
if (label.empty()) {
45+
if (elem.getPattern()->getKind() == PatternKind::Any)
46+
params.push_back(Identifier());
47+
else
48+
// Set None if not using labels, throw error if contradicts
49+
if (usingLabels == None)
50+
usingLabels = false;
51+
else if (usingLabels == true) {
52+
diags.diagnose(pattern->getLoc(),
53+
diag::enum_element_pattern_assoc_values_using_labels);
54+
}
55+
llvm::SmallVector<Identifier, 4> subParams =
56+
extractArgsFromPattern(Context, elem.getPattern());
57+
if (subParams.size() == 1)
58+
params.push_back(subParams[0]);
59+
else
60+
params.push_back(Identifier());
61+
} else {
62+
// Set None if using labels, throw error if contradicts
63+
if (usingLabels == None)
64+
usingLabels = true;
65+
else if (usingLabels == false) {
66+
diags.diagnose(
67+
pattern->getLoc(),
68+
diag::enum_element_pattern_assoc_values_using_var_patterns);
69+
}
70+
params.push_back(label);
71+
}
72+
}
73+
return params;
74+
break;
75+
}
76+
case PatternKind::Paren: {
77+
ParenPattern *pp = cast<ParenPattern>(pattern);
78+
return extractArgsFromPattern(Context, pp->getSubPattern());
79+
}
80+
case PatternKind::Var: {
81+
VarPattern *vp = cast<VarPattern>(pattern);
82+
return extractArgsFromPattern(Context, vp->getSubPattern());
83+
}
84+
// Relevant variable names are contained in elements in Tuple
85+
case PatternKind::Named: {
86+
// Get name and set argument to be from a variable
87+
NamedPattern *np = cast<NamedPattern>(pattern);
88+
Identifier id = np->getBoundName();
89+
params.push_back(id);
90+
return params;
91+
}
92+
default:
93+
params.push_back(Identifier());
94+
return params;
95+
}
96+
return params;
97+
}
98+
3299
/// If the given VarDecl is a computed property whose getter always returns a
33100
/// particular enum element, return that element.
34101
///
@@ -78,7 +145,6 @@ filterForEnumElement(DeclContext *DC, SourceLoc UseLoc,
78145
bool unqualifiedLookup, LookupResult foundElements) {
79146
EnumElementDecl *foundElement = nullptr;
80147
VarDecl *foundConstant = nullptr;
81-
82148
for (LookupResultEntry result : foundElements) {
83149
ValueDecl *e = result.getValueDecl();
84150
assert(e);
@@ -135,13 +201,78 @@ lookupEnumMemberElement(DeclContext *DC, Type ty,
135201
return nullptr;
136202

137203
// FIXME: We should probably pay attention to argument labels someday.
138-
name = name.withoutArgumentLabels();
204+
DeclNameRef nameWithout = name.withoutArgumentLabels();
139205

140206
// Look up the case inside the enum.
141207
// FIXME: We should be able to tell if this is a private lookup.
142208
NameLookupOptions lookupOptions = defaultMemberLookupOptions;
143209
LookupResult foundElements =
144-
TypeChecker::lookupMember(DC, ty, name, lookupOptions);
210+
TypeChecker::lookupMember(DC, ty, nameWithout, lookupOptions);
211+
212+
ArrayRef<Identifier> queryParams = name.getArgumentNames();
213+
214+
if (foundElements.size() != 1) {
215+
// Look up enum element only with base name
216+
foundElements = TypeChecker::lookupMember(
217+
DC, ty, name.withoutArgumentLabels(), lookupOptions);
218+
219+
int numFoundEntries = 0;
220+
LookupResult singleResult;
221+
for (LookupResultEntry resultEnt : foundElements) {
222+
auto *resultDecl = resultEnt.getValueDecl();
223+
if (isa<VarDecl>(resultDecl)) {
224+
singleResult.add(resultEnt, false);
225+
continue;
226+
}
227+
if (numFoundEntries == 0) {
228+
singleResult.add(resultEnt, false);
229+
}
230+
numFoundEntries++;
231+
}
232+
if (numFoundEntries == 1)
233+
return filterForEnumElement(DC, UseLoc,
234+
/*unqualifiedLookup=*/false, singleResult);
235+
236+
LookupResult revisedResult;
237+
// Prune results that don't match
238+
for (LookupResultEntry resultEnt : foundElements) {
239+
auto *e = resultEnt.getValueDecl();
240+
// Maintaining part of list list for filter results
241+
if (auto *var = dyn_cast<VarDecl>(e)) {
242+
revisedResult.add(resultEnt, false);
243+
continue;
244+
}
245+
DeclName enumElement = e->getFullName();
246+
ArrayRef<Identifier> enumElementParams = enumElement.getArgumentNames();
247+
248+
// If size is not the same, and query is not just a single value
249+
// do not consider
250+
if (enumElementParams.size() != queryParams.size())
251+
continue;
252+
bool addCandidate = true;
253+
for (auto index : indices(enumElementParams)) {
254+
// If enum empty, case must be empty or have let var form
255+
if (!enumElementParams[index].empty()) {
256+
// If element not empty, enum element can be empty or from var
257+
// if this is the only element found with basename
258+
if (queryParams[index].empty()) {
259+
addCandidate = false;
260+
break;
261+
}
262+
// must match the label
263+
if (!queryParams[index].compare(enumElementParams[index]))
264+
continue;
265+
addCandidate = false;
266+
break;
267+
}
268+
}
269+
if (addCandidate) {
270+
revisedResult.add(resultEnt, false);
271+
}
272+
}
273+
foundElements = revisedResult;
274+
}
275+
145276
return filterForEnumElement(DC, UseLoc,
146277
/*unqualifiedLookup=*/false, foundElements);
147278
}
@@ -443,13 +574,26 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
443574
if (auto arg = ume->getArgument()) {
444575
subPattern = getSubExprPattern(arg);
445576
}
446-
577+
447578
if (ume->getName().getBaseName().isSpecial())
448579
return nullptr;
449580

450-
return new (Context)
451-
EnumElementPattern(ume->getDotLoc(), ume->getNameLoc(), ume->getName(),
452-
subPattern, ume);
581+
// FIXME: Compound Name. <- Decide if this is covered
582+
if (subPattern) {
583+
ArrayRef<Identifier> namedParams =
584+
extractArgsFromPattern(Context, subPattern);
585+
586+
if (namedParams.size() != 0) {
587+
// FIXME: Compound names.
588+
return new (Context) EnumElementPattern(
589+
ume->getDotLoc(), ume->getNameLoc(),
590+
DeclNameRef(
591+
DeclName(Context, ume->getName().getBaseName(), namedParams)),
592+
subPattern, ume);
593+
}
594+
}
595+
return new (Context) EnumElementPattern(ume->getDotLoc(), ume->getNameLoc(),
596+
ume->getName(), subPattern, ume);
453597
}
454598

455599
// Member syntax 'T.Element' forms a pattern if 'T' is an enum and the
@@ -473,25 +617,26 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
473617
if (!enumDecl)
474618
return nullptr;
475619

476-
EnumElementDecl *referencedElement
477-
= lookupEnumMemberElement(DC, ty, ude->getName(), ude->getLoc());
620+
// FIXME: Argument labels?
621+
EnumElementDecl *referencedElement =
622+
lookupEnumMemberElement(DC, ty, ude->getName(), ude->getLoc());
478623
if (!referencedElement)
479624
return nullptr;
480625

481626
// Build a TypeRepr from the head of the full path.
482627
TypeLoc loc(repr);
483628
loc.setType(ty);
484-
return new (Context) EnumElementPattern(
485-
loc, ude->getDotLoc(), ude->getNameLoc(), ude->getName(),
486-
referencedElement, nullptr);
629+
return new (Context)
630+
EnumElementPattern(loc, ude->getDotLoc(), ude->getNameLoc(),
631+
ude->getName(), referencedElement, nullptr);
487632
}
488633

489634
// A DeclRef 'E' that refers to an enum element forms an EnumElementPattern.
490635
Pattern *visitDeclRefExpr(DeclRefExpr *de) {
491636
auto *elt = dyn_cast<EnumElementDecl>(de->getDecl());
492637
if (!elt)
493638
return nullptr;
494-
639+
495640
// Use the type of the enum from context.
496641
TypeLoc loc = TypeLoc::withoutLoc(
497642
elt->getParentEnum()->getDeclaredTypeInContext());
@@ -511,9 +656,9 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
511656
auto enumTy = enumDecl->getDeclaredTypeInContext();
512657
TypeLoc loc = TypeLoc::withoutLoc(enumTy);
513658

514-
return new (Context) EnumElementPattern(
515-
loc, SourceLoc(), ude->getNameLoc(), ude->getName(),
516-
referencedElement, nullptr);
659+
return new (Context)
660+
EnumElementPattern(loc, SourceLoc(), ude->getNameLoc(),
661+
ude->getName(), referencedElement, nullptr);
517662
}
518663

519664

@@ -1273,11 +1418,12 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
12731418
Optional<CheckedCastKind> castKind;
12741419

12751420
EnumElementDecl *elt = EEP->getElementDecl();
1276-
1421+
12771422
Type enumTy;
12781423
if (!elt) {
12791424
elt = lookupEnumMemberElement(dc, type, EEP->getName(),
12801425
EEP->getLoc());
1426+
12811427
if (!elt) {
12821428
if (!type->hasError()) {
12831429
// Lowercasing of Swift.Optional's cases is handled in the
@@ -1286,22 +1432,20 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
12861432
// isn't a static VarDecl, so the existing mechanics in
12871433
// extractEnumElement won't work.
12881434
if (type->getAnyNominal() == Context.getOptionalDecl()) {
1289-
if (EEP->getName().isSimpleName("None") ||
1290-
EEP->getName().isSimpleName("Some")) {
1435+
if (EEP->getName().getBaseIdentifier().str() == "None" ||
1436+
EEP->getName().getBaseIdentifier().str() == "Some") {
12911437
SmallString<4> Rename;
1292-
camel_case::toLowercaseWord(EEP->getName()
1293-
.getBaseIdentifier().str(),
1294-
Rename);
1438+
camel_case::toLowercaseWord(
1439+
EEP->getName().getBaseIdentifier().str(), Rename);
12951440
diags.diagnose(
12961441
EEP->getLoc(), diag::availability_decl_unavailable_rename,
1297-
/*"getter" prefix*/ 2, EEP->getName().getBaseName(),
1442+
/*"getter" prefix*/ 2, EEP->getName().getBaseIdentifier(),
12981443
/*replaced*/ false, /*special kind*/ 0, Rename.str(),
1299-
/*message*/ StringRef())
1300-
.fixItReplace(EEP->getLoc(), Rename.str());
1444+
/*message*/ StringRef());
13011445

13021446
return nullptr;
13031447
}
1304-
1448+
13051449
// If we have the original expression parse tree, try reinterpreting
13061450
// it as an expr-pattern if enum element lookup failed, since `.foo`
13071451
// could also refer to a static member of the context type.
@@ -1427,18 +1571,33 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
14271571

14281572
// If there is a subpattern, push the enum element type down onto it.
14291573
auto argType = elt->getArgumentInterfaceType();
1430-
if (EEP->hasSubPattern()) {
1574+
if (EEP->hasSubPattern() || EEP->getName().getArgumentNames().size() > 0) {
14311575
Pattern *sub = EEP->getSubPattern();
14321576
if (!elt->hasAssociatedValues()) {
14331577
diags.diagnose(EEP->getLoc(),
14341578
diag::enum_element_pattern_assoc_values_mismatch,
1435-
EEP->getName());
1436-
diags.diagnose(EEP->getLoc(),
1437-
diag::enum_element_pattern_assoc_values_remove)
1438-
.fixItRemove(sub->getSourceRange());
1579+
DeclNameRef(EEP->getName().getBaseName()));
1580+
diags
1581+
.diagnose(EEP->getLoc(),
1582+
diag::enum_element_pattern_assoc_values_remove)
1583+
.fixItRemove(sub->getSourceRange());
1584+
;
14391585
return nullptr;
14401586
}
1441-
1587+
1588+
if (!sub) {
1589+
SmallVector<TuplePatternElt, 8> elements;
1590+
for (auto &elt : EEP->getName().getArgumentNames()) {
1591+
auto *subPattern =
1592+
new (Context) AnyPattern(EEP->getNameLoc().getBaseNameLoc());
1593+
elements.push_back(TuplePatternElt(
1594+
elt, EEP->getNameLoc().getBaseNameLoc(), subPattern));
1595+
}
1596+
sub = TuplePattern::create(Context, EEP->getNameLoc().getBaseNameLoc(),
1597+
elements, EEP->getEndLoc(),
1598+
/*implicit*/ true);
1599+
}
1600+
14421601
Type elementType;
14431602
if (argType)
14441603
elementType = enumTy->getTypeOfMember(elt->getModuleContext(),

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,9 @@ namespace {
374374
// Optimization: If the constructor heads don't match, subspace is
375375
// impossible.
376376

377-
if (this->Head != other.Head) {
377+
// FIXME: Extraneous warnings for cases with labels
378+
if (this->Head.getBaseIdentifier() !=
379+
other.Head.getBaseIdentifier()) {
378380
return false;
379381
}
380382

@@ -557,6 +559,8 @@ namespace {
557559
PAIRCASE (SpaceKind::Constructor, SpaceKind::Constructor): {
558560
// Optimization: If the heads of the constructors don't match then
559561
// the two are disjoint and their difference is the first space.
562+
563+
// FIXME: Exhuastiveness checking for labelled Enums
560564
if (this->Head.getBaseIdentifier() !=
561565
other.Head.getBaseIdentifier()) {
562566
return *this;

0 commit comments

Comments
 (0)