19
19
#include " TypeCheckAvailability.h"
20
20
#include " TypeCheckType.h"
21
21
#include " swift/Basic/StringExtras.h"
22
- #include " swift/AST/ASTWalker.h"
23
22
#include " swift/AST/ASTVisitor.h"
24
- #include " swift/AST/SourceFile .h"
23
+ #include " swift/AST/ASTWalker .h"
25
24
#include " swift/AST/NameLookup.h"
25
+ #include " swift/AST/SourceFile.h"
26
26
#include " swift/AST/ParameterList.h"
27
27
#include " swift/AST/TypeCheckRequests.h"
28
28
#include " llvm/Support/SaveAndRestore.h"
29
29
#include < utility>
30
30
using namespace swift ;
31
31
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
+
32
99
// / If the given VarDecl is a computed property whose getter always returns a
33
100
// / particular enum element, return that element.
34
101
// /
@@ -78,7 +145,6 @@ filterForEnumElement(DeclContext *DC, SourceLoc UseLoc,
78
145
bool unqualifiedLookup, LookupResult foundElements) {
79
146
EnumElementDecl *foundElement = nullptr ;
80
147
VarDecl *foundConstant = nullptr ;
81
-
82
148
for (LookupResultEntry result : foundElements) {
83
149
ValueDecl *e = result.getValueDecl ();
84
150
assert (e);
@@ -135,13 +201,78 @@ lookupEnumMemberElement(DeclContext *DC, Type ty,
135
201
return nullptr ;
136
202
137
203
// FIXME: We should probably pay attention to argument labels someday.
138
- name = name.withoutArgumentLabels ();
204
+ DeclNameRef nameWithout = name.withoutArgumentLabels ();
139
205
140
206
// Look up the case inside the enum.
141
207
// FIXME: We should be able to tell if this is a private lookup.
142
208
NameLookupOptions lookupOptions = defaultMemberLookupOptions;
143
209
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
+
145
276
return filterForEnumElement (DC, UseLoc,
146
277
/* unqualifiedLookup=*/ false , foundElements);
147
278
}
@@ -443,13 +574,26 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
443
574
if (auto arg = ume->getArgument ()) {
444
575
subPattern = getSubExprPattern (arg);
445
576
}
446
-
577
+
447
578
if (ume->getName ().getBaseName ().isSpecial ())
448
579
return nullptr ;
449
580
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);
453
597
}
454
598
455
599
// Member syntax 'T.Element' forms a pattern if 'T' is an enum and the
@@ -473,25 +617,26 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
473
617
if (!enumDecl)
474
618
return nullptr ;
475
619
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 ());
478
623
if (!referencedElement)
479
624
return nullptr ;
480
625
481
626
// Build a TypeRepr from the head of the full path.
482
627
TypeLoc loc (repr);
483
628
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 );
487
632
}
488
633
489
634
// A DeclRef 'E' that refers to an enum element forms an EnumElementPattern.
490
635
Pattern *visitDeclRefExpr (DeclRefExpr *de) {
491
636
auto *elt = dyn_cast<EnumElementDecl>(de->getDecl ());
492
637
if (!elt)
493
638
return nullptr ;
494
-
639
+
495
640
// Use the type of the enum from context.
496
641
TypeLoc loc = TypeLoc::withoutLoc (
497
642
elt->getParentEnum ()->getDeclaredTypeInContext ());
@@ -511,9 +656,9 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
511
656
auto enumTy = enumDecl->getDeclaredTypeInContext ();
512
657
TypeLoc loc = TypeLoc::withoutLoc (enumTy);
513
658
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 );
517
662
}
518
663
519
664
@@ -1273,11 +1418,12 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
1273
1418
Optional<CheckedCastKind> castKind;
1274
1419
1275
1420
EnumElementDecl *elt = EEP->getElementDecl ();
1276
-
1421
+
1277
1422
Type enumTy;
1278
1423
if (!elt) {
1279
1424
elt = lookupEnumMemberElement (dc, type, EEP->getName (),
1280
1425
EEP->getLoc ());
1426
+
1281
1427
if (!elt) {
1282
1428
if (!type->hasError ()) {
1283
1429
// Lowercasing of Swift.Optional's cases is handled in the
@@ -1286,22 +1432,20 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
1286
1432
// isn't a static VarDecl, so the existing mechanics in
1287
1433
// extractEnumElement won't work.
1288
1434
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" ) {
1291
1437
SmallString<4 > Rename;
1292
- camel_case::toLowercaseWord (EEP->getName ()
1293
- .getBaseIdentifier ().str (),
1294
- Rename);
1438
+ camel_case::toLowercaseWord (
1439
+ EEP->getName ().getBaseIdentifier ().str (), Rename);
1295
1440
diags.diagnose (
1296
1441
EEP->getLoc (), diag::availability_decl_unavailable_rename,
1297
- /* "getter" prefix*/ 2 , EEP->getName ().getBaseName (),
1442
+ /* "getter" prefix*/ 2 , EEP->getName ().getBaseIdentifier (),
1298
1443
/* replaced*/ false , /* special kind*/ 0 , Rename.str (),
1299
- /* message*/ StringRef ())
1300
- .fixItReplace (EEP->getLoc (), Rename.str ());
1444
+ /* message*/ StringRef ());
1301
1445
1302
1446
return nullptr ;
1303
1447
}
1304
-
1448
+
1305
1449
// If we have the original expression parse tree, try reinterpreting
1306
1450
// it as an expr-pattern if enum element lookup failed, since `.foo`
1307
1451
// could also refer to a static member of the context type.
@@ -1427,18 +1571,33 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
1427
1571
1428
1572
// If there is a subpattern, push the enum element type down onto it.
1429
1573
auto argType = elt->getArgumentInterfaceType ();
1430
- if (EEP->hasSubPattern ()) {
1574
+ if (EEP->hasSubPattern () || EEP-> getName (). getArgumentNames (). size () > 0 ) {
1431
1575
Pattern *sub = EEP->getSubPattern ();
1432
1576
if (!elt->hasAssociatedValues ()) {
1433
1577
diags.diagnose (EEP->getLoc (),
1434
1578
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
+ ;
1439
1585
return nullptr ;
1440
1586
}
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
+
1442
1601
Type elementType;
1443
1602
if (argType)
1444
1603
elementType = enumTy->getTypeOfMember (elt->getModuleContext (),
0 commit comments