Skip to content

Commit 06595f6

Browse files
authored
Merge pull request #60852 from tshortli/parse-has-symbol
AST: Parse `#_hasSymbol`
2 parents 9a28ae0 + f5f1d3c commit 06595f6

17 files changed

+265
-60
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -990,12 +990,6 @@ WARNING(parameter_unnamed_warn,none,
990990
ERROR(parameter_curry_syntax_removed,none,
991991
"cannot have more than one parameter list", ())
992992

993-
ERROR(availability_cannot_be_mixed,none,
994-
"#available and #unavailable cannot be in the same statement", ())
995-
996-
ERROR(false_available_is_called_unavailable,none,
997-
"#available cannot be used as an expression, did you mean to use '#unavailable'?", ())
998-
999993
ERROR(initializer_as_typed_pattern,none,
1000994
"unexpected initializer in pattern; did you mean to use '='?", ())
1001995

@@ -1286,7 +1280,7 @@ ERROR(string_literal_no_atsign,none,
12861280
ERROR(invalid_float_literal_missing_leading_zero,none,
12871281
"'.%0' is not a valid floating point literal; it must be written '0.%0'",
12881282
(StringRef))
1289-
ERROR(availability_query_outside_if_stmt_guard, none,
1283+
ERROR(special_condition_outside_if_stmt_guard, none,
12901284
"%0 may only be used as condition of an 'if', 'guard'"
12911285
" or 'while' statement", (StringRef))
12921286

@@ -1935,6 +1929,25 @@ ERROR(pound_available_package_description_not_allowed, none,
19351929
ERROR(availability_query_repeated_platform, none,
19361930
"version for '%0' already specified", (StringRef))
19371931

1932+
ERROR(availability_cannot_be_mixed,none,
1933+
"#available and #unavailable cannot be in the same statement", ())
1934+
1935+
ERROR(false_available_is_called_unavailable,none,
1936+
"#available cannot be used as an expression, did you mean to use '#unavailable'?", ())
1937+
1938+
//------------------------------------------------------------------------------
1939+
// MARK: #_hasSymbol query parsing diagnostics
1940+
//------------------------------------------------------------------------------
1941+
1942+
ERROR(has_symbol_expected_lparen,PointsToFirstBadToken,
1943+
"expected '(' in #_hasSymbol directive", ())
1944+
1945+
ERROR(has_symbol_expected_expr,PointsToFirstBadToken,
1946+
"expected expression in #_hasSymbol", ())
1947+
1948+
ERROR(has_symbol_expected_rparen,PointsToFirstBadToken,
1949+
"expected ')' in #_hasSymbol condition", ())
1950+
19381951
ERROR(attr_requires_concurrency, none,
19391952
"'%0' %select{attribute|modifier}1 is only valid when experimental "
19401953
"concurrency is enabled",

include/swift/AST/Stmt.h

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,39 @@ class alignas(8) PoundAvailableInfo final :
390390
bool isUnavailability() const { return _isUnavailability; }
391391
};
392392

393+
/// An expression that guards execution based on whether the symbols for the
394+
/// declaration identified by the given expression are non-null at run-time, e.g.
395+
///
396+
/// if #_hasSymbol(foo(_:)) { foo(42) }
397+
///
398+
class PoundHasSymbolInfo final : public ASTAllocated<PoundHasSymbolInfo> {
399+
Expr *SymbolExpr;
400+
401+
SourceLoc PoundLoc;
402+
SourceLoc LParenLoc;
403+
SourceLoc RParenLoc;
404+
405+
PoundHasSymbolInfo(SourceLoc PoundLoc, SourceLoc LParenLoc, Expr *SymbolExpr,
406+
SourceLoc RParenLoc)
407+
: SymbolExpr(SymbolExpr), PoundLoc(PoundLoc), LParenLoc(LParenLoc),
408+
RParenLoc(RParenLoc){};
409+
410+
public:
411+
static PoundHasSymbolInfo *create(ASTContext &Ctx, SourceLoc PoundLoc,
412+
SourceLoc LParenLoc, Expr *SymbolExpr,
413+
SourceLoc RParenLoc);
414+
415+
Expr *getSymbolExpr() const { return SymbolExpr; }
416+
void setSymbolExpr(Expr *E) { SymbolExpr = E; }
417+
418+
SourceLoc getLParenLoc() const { return LParenLoc; }
419+
SourceLoc getRParenLoc() const { return RParenLoc; }
420+
SourceLoc getStartLoc() const { return PoundLoc; }
421+
SourceLoc getEndLoc() const { return RParenLoc; }
422+
SourceRange getSourceRange() const {
423+
return SourceRange(getStartLoc(), getEndLoc());
424+
}
425+
};
393426

394427
/// This represents an entry in an "if" or "while" condition. Pattern bindings
395428
/// can bind any number of names in the pattern binding decl, and may have an
@@ -414,47 +447,55 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
414447
/// to this as an 'implicit' pattern.
415448
Pattern *ThePattern = nullptr;
416449

417-
/// This is either the boolean condition, the initializer for a pattern
418-
/// binding, or the #available information.
419-
llvm::PointerUnion<PoundAvailableInfo*, Expr *> CondInitOrAvailable;
450+
/// This is either the boolean condition, the #available information, or
451+
/// the #_hasSymbol information.
452+
llvm::PointerUnion<Expr *, PoundAvailableInfo *, PoundHasSymbolInfo *>
453+
Condition;
420454

421455
public:
422456
StmtConditionElement() {}
423-
StmtConditionElement(SourceLoc IntroducerLoc, Pattern *ThePattern,
424-
Expr *Init)
425-
: IntroducerLoc(IntroducerLoc), ThePattern(ThePattern),
426-
CondInitOrAvailable(Init) {}
427-
StmtConditionElement(Expr *cond) : CondInitOrAvailable(cond) {}
457+
StmtConditionElement(SourceLoc IntroducerLoc, Pattern *ThePattern, Expr *Init)
458+
: IntroducerLoc(IntroducerLoc), ThePattern(ThePattern), Condition(Init) {}
459+
StmtConditionElement(Expr *cond) : Condition(cond) {}
460+
461+
StmtConditionElement(PoundAvailableInfo *Info) : Condition(Info) {}
462+
463+
StmtConditionElement(PoundHasSymbolInfo *Info) : Condition(Info) {}
428464

429-
StmtConditionElement(PoundAvailableInfo *Info) : CondInitOrAvailable(Info) {}
430-
431465
SourceLoc getIntroducerLoc() const { return IntroducerLoc; }
432466
void setIntroducerLoc(SourceLoc loc) { IntroducerLoc = loc; }
433467

434468
/// ConditionKind - This indicates the sort of condition this is.
435469
enum ConditionKind {
436470
CK_Boolean,
437471
CK_PatternBinding,
438-
CK_Availability
472+
CK_Availability,
473+
CK_HasSymbol,
439474
};
440475

441476
ConditionKind getKind() const {
442-
if (ThePattern) return CK_PatternBinding;
443-
return CondInitOrAvailable.is<Expr*>() ? CK_Boolean : CK_Availability;
477+
if (ThePattern)
478+
return CK_PatternBinding;
479+
if (Condition.is<Expr *>())
480+
return CK_Boolean;
481+
if (Condition.is<PoundAvailableInfo *>())
482+
return CK_Availability;
483+
assert(Condition.is<PoundHasSymbolInfo *>());
484+
return CK_HasSymbol;
444485
}
445486

446487
/// Boolean Condition Accessors.
447488
Expr *getBooleanOrNull() const {
448-
return getKind() == CK_Boolean ? CondInitOrAvailable.get<Expr*>() : nullptr;
489+
return getKind() == CK_Boolean ? Condition.get<Expr *>() : nullptr;
449490
}
450491

451492
Expr *getBoolean() const {
452493
assert(getKind() == CK_Boolean && "Not a condition");
453-
return CondInitOrAvailable.get<Expr*>();
494+
return Condition.get<Expr *>();
454495
}
455496
void setBoolean(Expr *E) {
456497
assert(getKind() == CK_Boolean && "Not a condition");
457-
CondInitOrAvailable = E;
498+
Condition = E;
458499
}
459500

460501
/// Pattern Binding Accessors.
@@ -474,22 +515,33 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
474515

475516
Expr *getInitializer() const {
476517
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
477-
return CondInitOrAvailable.get<Expr*>();
518+
return Condition.get<Expr *>();
478519
}
479520
void setInitializer(Expr *E) {
480521
assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
481-
CondInitOrAvailable = E;
522+
Condition = E;
482523
}
483524

484525
// Availability Accessors
485526
PoundAvailableInfo *getAvailability() const {
486527
assert(getKind() == CK_Availability && "Not an #available condition");
487-
return CondInitOrAvailable.get<PoundAvailableInfo*>();
528+
return Condition.get<PoundAvailableInfo *>();
488529
}
489530

490531
void setAvailability(PoundAvailableInfo *Info) {
491532
assert(getKind() == CK_Availability && "Not an #available condition");
492-
CondInitOrAvailable = Info;
533+
Condition = Info;
534+
}
535+
536+
// #_hasSymbol Accessors
537+
PoundHasSymbolInfo *getHasSymbolInfo() const {
538+
assert(getKind() == CK_HasSymbol && "Not a #_hasSymbol condition");
539+
return Condition.get<PoundHasSymbolInfo *>();
540+
}
541+
542+
void setHasSymbolInfo(PoundHasSymbolInfo *Info) {
543+
assert(getKind() == CK_HasSymbol && "Not a #_hasSymbol condition");
544+
Condition = Info;
493545
}
494546

495547
SourceLoc getStartLoc() const;

include/swift/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,6 +1839,7 @@ class Parser {
18391839
ParserStatus parseStmtCondition(StmtCondition &Result, Diag<> ID,
18401840
StmtKind ParentKind);
18411841
ParserResult<PoundAvailableInfo> parseStmtConditionPoundAvailable();
1842+
ParserResult<PoundHasSymbolInfo> parseStmtConditionPoundHasSymbol();
18421843
ParserResult<Stmt> parseStmtIf(LabeledStmtInfo LabelInfo,
18431844
bool IfWasImplicitlyInserted = false);
18441845
ParserResult<Stmt> parseStmtGuard();

lib/AST/ASTDumper.cpp

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ static void printGenericParameters(raw_ostream &OS, GenericParamList *Params) {
123123
Params->print(OS);
124124
}
125125

126+
static void printSourceRange(raw_ostream &OS, const SourceRange R,
127+
const ASTContext &Ctx) {
128+
if (!R.isValid())
129+
return;
130+
131+
PrintWithColorRAII(OS, RangeColor) << " range=";
132+
R.print(PrintWithColorRAII(OS, RangeColor).getOS(), Ctx.SourceMgr,
133+
/*PrintText=*/false);
134+
}
126135

127136
static StringRef
128137
getSILFunctionTypeRepresentationString(SILFunctionType::Representation value) {
@@ -497,12 +506,7 @@ namespace {
497506
if (D->isHoisted())
498507
PrintWithColorRAII(OS, DeclModifierColor) << " hoisted";
499508

500-
auto R = D->getSourceRange();
501-
if (R.isValid()) {
502-
PrintWithColorRAII(OS, RangeColor) << " range=";
503-
R.print(PrintWithColorRAII(OS, RangeColor).getOS(),
504-
D->getASTContext().SourceMgr, /*PrintText=*/false);
505-
}
509+
printSourceRange(OS, D->getSourceRange(), D->getASTContext());
506510

507511
if (D->TrailingSemiLoc.isValid())
508512
PrintWithColorRAII(OS, DeclModifierColor) << " trailing_semi";
@@ -1018,12 +1022,7 @@ namespace {
10181022
ctx = &params->get(0)->getASTContext();
10191023

10201024
if (ctx) {
1021-
auto R = params->getSourceRange();
1022-
if (R.isValid()) {
1023-
PrintWithColorRAII(OS, RangeColor) << " range=";
1024-
R.print(PrintWithColorRAII(OS, RangeColor).getOS(),
1025-
ctx->SourceMgr, /*PrintText=*/false);
1026-
}
1025+
printSourceRange(OS, params->getSourceRange(), *ctx);
10271026
}
10281027

10291028
Indent += 2;
@@ -1488,6 +1487,18 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
14881487
PrintWithColorRAII(OS, ParenthesisColor) << ")";
14891488
Indent -= 2;
14901489
break;
1490+
case StmtConditionElement::CK_HasSymbol:
1491+
Indent += 2;
1492+
OS.indent(Indent);
1493+
PrintWithColorRAII(OS, ParenthesisColor) << '(';
1494+
OS << "#_hasSymbol";
1495+
if (Ctx)
1496+
printSourceRange(OS, C.getSourceRange(), *Ctx);
1497+
OS << "\n";
1498+
printRec(C.getHasSymbolInfo()->getSymbolExpr());
1499+
PrintWithColorRAII(OS, ParenthesisColor) << ")";
1500+
Indent -= 2;
1501+
break;
14911502
}
14921503
}
14931504

@@ -1499,14 +1510,8 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
14991510
if (S->isImplicit())
15001511
OS << " implicit";
15011512

1502-
if (Ctx) {
1503-
auto R = S->getSourceRange();
1504-
if (R.isValid()) {
1505-
PrintWithColorRAII(OS, RangeColor) << " range=";
1506-
R.print(PrintWithColorRAII(OS, RangeColor).getOS(),
1507-
Ctx->SourceMgr, /*PrintText=*/false);
1508-
}
1509-
}
1513+
if (Ctx)
1514+
printSourceRange(OS, S->getSourceRange(), *Ctx);
15101515

15111516
if (S->TrailingSemiLoc.isValid())
15121517
OS << " trailing_semi";
@@ -1560,9 +1565,10 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
15601565

15611566
void visitIfStmt(IfStmt *S) {
15621567
printCommon(S, "if_stmt") << '\n';
1563-
for (auto elt : S->getCond())
1568+
for (auto elt : S->getCond()) {
15641569
printRec(elt);
1565-
OS << '\n';
1570+
OS << "\n";
1571+
}
15661572
printRec(S->getThenStmt());
15671573
if (S->getElseStmt()) {
15681574
OS << '\n';
@@ -1831,12 +1837,7 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
18311837
L.print(PrintWithColorRAII(OS, LocationColor).getOS(), Ctx.SourceMgr);
18321838
}
18331839

1834-
auto R = E->getSourceRange();
1835-
if (R.isValid()) {
1836-
PrintWithColorRAII(OS, RangeColor) << " range=";
1837-
R.print(PrintWithColorRAII(OS, RangeColor).getOS(),
1838-
Ctx.SourceMgr, /*PrintText=*/false);
1839-
}
1840+
printSourceRange(OS, E->getSourceRange(), Ctx);
18401841
}
18411842

18421843
if (E->TrailingSemiLoc.isValid())

lib/AST/ASTScopeCreation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,7 @@ ASTScopeImpl *LabeledConditionalStmtScope::createNestedConditionalClauseScopes(
11721172
for (auto &sec : stmt->getCond()) {
11731173
switch (sec.getKind()) {
11741174
case StmtConditionElement::CK_Availability:
1175+
case StmtConditionElement::CK_HasSymbol:
11751176
break;
11761177
case StmtConditionElement::CK_Boolean:
11771178
scopeCreator.addToScopeTree(sec.getBoolean(), insertionPoint);

lib/AST/ASTVerifier.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,9 @@ class Verifier : public ASTWalker {
10301030

10311031
void checkConditionElement(const StmtConditionElement &elt) {
10321032
switch (elt.getKind()) {
1033-
case StmtConditionElement::CK_Availability: break;
1033+
case StmtConditionElement::CK_Availability:
1034+
case StmtConditionElement::CK_HasSymbol:
1035+
break;
10341036
case StmtConditionElement::CK_Boolean: {
10351037
auto *E = elt.getBoolean();
10361038
if (shouldVerifyChecked(E))

lib/AST/ASTWalker.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,9 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
13401340
bool doIt(const StmtCondition &C) {
13411341
for (auto &elt : C) {
13421342
switch (elt.getKind()) {
1343-
case StmtConditionElement::CK_Availability: break;
1343+
case StmtConditionElement::CK_Availability:
1344+
case StmtConditionElement::CK_HasSymbol:
1345+
break;
13441346
case StmtConditionElement::CK_Boolean: {
13451347
auto E = elt.getBoolean();
13461348
// Walk an expression condition normally.

lib/AST/Stmt.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ SourceRange StmtConditionElement::getSourceRange() const {
392392
return getBoolean()->getSourceRange();
393393
case StmtConditionElement::CK_Availability:
394394
return getAvailability()->getSourceRange();
395+
case StmtConditionElement::CK_HasSymbol:
396+
return getHasSymbolInfo()->getSourceRange();
395397
case StmtConditionElement::CK_PatternBinding:
396398
SourceLoc Start;
397399
if (IntroducerLoc.isValid())
@@ -410,6 +412,15 @@ SourceRange StmtConditionElement::getSourceRange() const {
410412
llvm_unreachable("Unhandled StmtConditionElement in switch.");
411413
}
412414

415+
PoundHasSymbolInfo *PoundHasSymbolInfo::create(ASTContext &Ctx,
416+
SourceLoc PoundLoc,
417+
SourceLoc LParenLoc,
418+
Expr *SymbolExpr,
419+
SourceLoc RParenLoc) {
420+
return new (Ctx)
421+
PoundHasSymbolInfo(PoundLoc, LParenLoc, SymbolExpr, RParenLoc);
422+
}
423+
413424
SourceLoc StmtConditionElement::getStartLoc() const {
414425
switch (getKind()) {
415426
case StmtConditionElement::CK_Boolean:
@@ -418,6 +429,8 @@ SourceLoc StmtConditionElement::getStartLoc() const {
418429
return getAvailability()->getStartLoc();
419430
case StmtConditionElement::CK_PatternBinding:
420431
return getSourceRange().Start;
432+
case StmtConditionElement::CK_HasSymbol:
433+
return getHasSymbolInfo()->getStartLoc();
421434
}
422435

423436
llvm_unreachable("Unhandled StmtConditionElement in switch.");
@@ -431,6 +444,8 @@ SourceLoc StmtConditionElement::getEndLoc() const {
431444
return getAvailability()->getEndLoc();
432445
case StmtConditionElement::CK_PatternBinding:
433446
return getSourceRange().End;
447+
case StmtConditionElement::CK_HasSymbol:
448+
return getHasSymbolInfo()->getEndLoc();
434449
}
435450

436451
llvm_unreachable("Unhandled StmtConditionElement in switch.");

0 commit comments

Comments
 (0)