Skip to content

Commit e37d855

Browse files
committed
Introduce ExprPatternMatchRequest
This replaces `synthesizeTildeEqualsOperatorApplication`, and synthesizes the match expression and var on-demand.
1 parent 5601e31 commit e37d855

17 files changed

+203
-135
lines changed

include/swift/AST/Pattern.h

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -647,43 +647,59 @@ class OptionalSomePattern : public Pattern {
647647
class ExprPattern : public Pattern {
648648
llvm::PointerIntPair<Expr *, 1, bool> SubExprAndIsResolved;
649649

650-
/// An expression constructed during type-checking that produces a call to the
651-
/// '~=' operator comparing the match expression on the left to the matched
652-
/// value on the right.
653-
Expr *MatchExpr = nullptr;
650+
DeclContext *DC;
654651

655-
/// An implicit variable used to represent the RHS value of the match.
656-
VarDecl *MatchVar = nullptr;
652+
/// A synthesized call to the '~=' operator comparing the match expression
653+
/// on the left to the matched value on the right.
654+
mutable Expr *MatchExpr = nullptr;
657655

658-
ExprPattern(Expr *E, bool isResolved)
659-
: Pattern(PatternKind::Expr), SubExprAndIsResolved(E, isResolved) {}
656+
/// An implicit variable used to represent the RHS value of the synthesized
657+
/// match expression.
658+
mutable VarDecl *MatchVar = nullptr;
659+
660+
ExprPattern(Expr *E, DeclContext *DC, bool isResolved)
661+
: Pattern(PatternKind::Expr), SubExprAndIsResolved(E, isResolved),
662+
DC(DC) {}
663+
664+
friend class ExprPatternMatchRequest;
660665

661666
public:
662667
/// Create a new parsed unresolved ExprPattern.
663-
static ExprPattern *createParsed(ASTContext &ctx, Expr *E);
668+
static ExprPattern *createParsed(ASTContext &ctx, Expr *E, DeclContext *DC);
664669

665670
/// Create a new resolved ExprPattern. This should be used in cases
666671
/// where a user-written expression should be treated as an ExprPattern.
667-
static ExprPattern *createResolved(ASTContext &ctx, Expr *E);
672+
static ExprPattern *createResolved(ASTContext &ctx, Expr *E, DeclContext *DC);
668673

669674
/// Create a new implicit resolved ExprPattern.
670-
static ExprPattern *createImplicit(ASTContext &ctx, Expr *E);
675+
static ExprPattern *createImplicit(ASTContext &ctx, Expr *E, DeclContext *DC);
671676

672677
Expr *getSubExpr() const { return SubExprAndIsResolved.getPointer(); }
673678
void setSubExpr(Expr *e) { SubExprAndIsResolved.setPointer(e); }
674679

675-
Expr *getMatchExpr() const { return MatchExpr; }
680+
DeclContext *getDeclContext() const { return DC; }
681+
682+
/// The match expression if it has been computed, \c nullptr otherwise.
683+
/// Should only be used by the ASTDumper and ASTWalker.
684+
Expr *getCachedMatchExpr() const { return MatchExpr; }
685+
686+
/// The match variable if it has been computed, \c nullptr otherwise.
687+
/// Should only be used by the ASTDumper and ASTWalker.
688+
VarDecl *getCachedMatchVar() const { return MatchVar; }
689+
690+
/// A synthesized call to the '~=' operator comparing the match expression
691+
/// on the left to the matched value on the right.
692+
Expr *getMatchExpr() const;
693+
694+
/// An implicit variable used to represent the RHS value of the synthesized
695+
/// match expression.
696+
VarDecl *getMatchVar() const;
697+
676698
void setMatchExpr(Expr *e) {
677-
assert(isResolved() && "cannot set match fn for unresolved expr patter");
699+
assert(MatchExpr && "Should only update an existing MatchExpr");
678700
MatchExpr = e;
679701
}
680702

681-
VarDecl *getMatchVar() const { return MatchVar; }
682-
void setMatchVar(VarDecl *v) {
683-
assert(isResolved() && "cannot set match var for unresolved expr patter");
684-
MatchVar = v;
685-
}
686-
687703
SourceLoc getLoc() const;
688704
SourceRange getSourceRange() const;
689705

@@ -851,6 +867,9 @@ class ContextualPattern {
851867
};
852868

853869
void simple_display(llvm::raw_ostream &out, const ContextualPattern &pattern);
870+
void simple_display(llvm::raw_ostream &out, const Pattern *pattern);
871+
872+
SourceLoc extractNearestSourceLoc(const Pattern *pattern);
854873

855874
} // end namespace swift
856875

include/swift/AST/TypeCheckRequests.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,6 +2219,52 @@ class NamingPatternRequest
22192219
void cacheResult(NamedPattern *P) const;
22202220
};
22212221

2222+
class ExprPatternMatchResult {
2223+
VarDecl *MatchVar;
2224+
Expr *MatchExpr;
2225+
2226+
friend class ExprPattern;
2227+
2228+
// Should only be used as the default value for the request, as the caching
2229+
// logic assumes the request always produces a non-null result.
2230+
ExprPatternMatchResult(llvm::NoneType)
2231+
: MatchVar(nullptr), MatchExpr(nullptr) {}
2232+
2233+
public:
2234+
ExprPatternMatchResult(VarDecl *matchVar, Expr *matchExpr)
2235+
: MatchVar(matchVar), MatchExpr(matchExpr) {
2236+
// Note the caching logic currently requires the request to produce a
2237+
// non-null result.
2238+
assert(matchVar && matchExpr);
2239+
}
2240+
2241+
VarDecl *getMatchVar() const { return MatchVar; }
2242+
Expr *getMatchExpr() const { return MatchExpr; }
2243+
};
2244+
2245+
/// Compute the match VarDecl and expression for an ExprPattern, which applies
2246+
/// the \c ~= operator.
2247+
class ExprPatternMatchRequest
2248+
: public SimpleRequest<ExprPatternMatchRequest,
2249+
ExprPatternMatchResult(const ExprPattern *),
2250+
RequestFlags::SeparatelyCached> {
2251+
public:
2252+
using SimpleRequest::SimpleRequest;
2253+
2254+
private:
2255+
friend SimpleRequest;
2256+
2257+
// Evaluation.
2258+
ExprPatternMatchResult evaluate(Evaluator &evaluator,
2259+
const ExprPattern *EP) const;
2260+
2261+
public:
2262+
// Separate caching.
2263+
bool isCached() const { return true; }
2264+
Optional<ExprPatternMatchResult> getCachedResult() const;
2265+
void cacheResult(ExprPatternMatchResult result) const;
2266+
};
2267+
22222268
class InterfaceTypeRequest :
22232269
public SimpleRequest<InterfaceTypeRequest,
22242270
Type (ValueDecl *),

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ SWIFT_REQUEST(TypeChecker, ModuleImplicitImportsRequest,
228228
ImplicitImportList(ModuleDecl *), Cached, NoLocationInfo)
229229
SWIFT_REQUEST(TypeChecker, NamingPatternRequest,
230230
NamedPattern *(VarDecl *), SeparatelyCached, NoLocationInfo)
231+
SWIFT_REQUEST(TypeChecker, ExprPatternMatchRequest,
232+
ExprPatternMatchResult(const ExprPattern *),
233+
SeparatelyCached, NoLocationInfo)
231234
SWIFT_REQUEST(TypeChecker, OpaqueReadOwnershipRequest,
232235
OpaqueReadOwnership(AbstractStorageDecl *), SeparatelyCached,
233236
NoLocationInfo)

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ namespace {
472472
void visitExprPattern(ExprPattern *P) {
473473
printCommon(P, "pattern_expr");
474474
OS << '\n';
475-
if (auto m = P->getMatchExpr())
475+
if (auto m = P->getCachedMatchExpr())
476476
printRec(m);
477477
else
478478
printRec(P->getSubExpr());

lib/AST/ASTWalker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,8 +1980,8 @@ Pattern *Traversal::visitEnumElementPattern(EnumElementPattern *P) {
19801980
Pattern *Traversal::visitExprPattern(ExprPattern *P) {
19811981
// If the pattern has been type-checked, walk the match expression, which
19821982
// includes the explicit subexpression.
1983-
if (P->getMatchExpr()) {
1984-
if (Expr *newMatch = doIt(P->getMatchExpr())) {
1983+
if (auto *match = P->getCachedMatchExpr()) {
1984+
if (Expr *newMatch = doIt(match)) {
19851985
P->setMatchExpr(newMatch);
19861986
return P;
19871987
}

lib/AST/Pattern.cpp

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/ASTWalker.h"
2020
#include "swift/AST/Expr.h"
2121
#include "swift/AST/GenericEnvironment.h"
22+
#include "swift/AST/TypeCheckRequests.h"
2223
#include "swift/AST/TypeLoc.h"
2324
#include "swift/AST/TypeRepr.h"
2425
#include "swift/Basic/Statistic.h"
@@ -333,9 +334,8 @@ EnumElementDecl *OptionalSomePattern::getElementDecl() const {
333334
/// Return true if this is a non-resolved ExprPattern which is syntactically
334335
/// irrefutable.
335336
static bool isIrrefutableExprPattern(const ExprPattern *EP) {
336-
// If the pattern has a registered match expression, it's
337-
// a type-checked ExprPattern.
338-
if (EP->getMatchExpr()) return false;
337+
// If the pattern is resolved, it must be irrefutable.
338+
if (EP->isResolved()) return false;
339339

340340
auto expr = EP->getSubExpr();
341341
while (true) {
@@ -501,20 +501,35 @@ void IsPattern::setCastType(Type type) {
501501

502502
TypeRepr *IsPattern::getCastTypeRepr() const { return CastType->getTypeRepr(); }
503503

504-
ExprPattern *ExprPattern::createParsed(ASTContext &ctx, Expr *E) {
505-
return new (ctx) ExprPattern(E, /*isResolved*/ false);
504+
ExprPattern *ExprPattern::createParsed(ASTContext &ctx, Expr *E,
505+
DeclContext *DC) {
506+
return new (ctx) ExprPattern(E, DC, /*isResolved*/ false);
506507
}
507508

508-
ExprPattern *ExprPattern::createResolved(ASTContext &ctx, Expr *E) {
509-
return new (ctx) ExprPattern(E, /*isResolved*/ true);
509+
ExprPattern *ExprPattern::createResolved(ASTContext &ctx, Expr *E,
510+
DeclContext *DC) {
511+
return new (ctx) ExprPattern(E, DC, /*isResolved*/ true);
510512
}
511513

512-
ExprPattern *ExprPattern::createImplicit(ASTContext &ctx, Expr *E) {
513-
auto *EP = ExprPattern::createResolved(ctx, E);
514+
ExprPattern *ExprPattern::createImplicit(ASTContext &ctx, Expr *E,
515+
DeclContext *DC) {
516+
auto *EP = ExprPattern::createResolved(ctx, E, DC);
514517
EP->setImplicit();
515518
return EP;
516519
}
517520

521+
Expr *ExprPattern::getMatchExpr() const {
522+
auto &eval = DC->getASTContext().evaluator;
523+
return evaluateOrDefault(eval, ExprPatternMatchRequest{this}, None)
524+
.getMatchExpr();
525+
}
526+
527+
VarDecl *ExprPattern::getMatchVar() const {
528+
auto &eval = DC->getASTContext().evaluator;
529+
return evaluateOrDefault(eval, ExprPatternMatchRequest{this}, None)
530+
.getMatchVar();
531+
}
532+
518533
SourceLoc EnumElementPattern::getStartLoc() const {
519534
return (ParentType && !ParentType->isImplicit())
520535
? ParentType->getSourceRange().Start
@@ -616,5 +631,13 @@ bool ContextualPattern::allowsInference() const {
616631

617632
void swift::simple_display(llvm::raw_ostream &out,
618633
const ContextualPattern &pattern) {
619-
out << "(pattern @ " << pattern.getPattern() << ")";
634+
simple_display(out, pattern.getPattern());
635+
}
636+
637+
void swift::simple_display(llvm::raw_ostream &out, const Pattern *pattern) {
638+
out << "(pattern @ " << pattern << ")";
639+
}
640+
641+
SourceLoc swift::extractNearestSourceLoc(const Pattern *pattern) {
642+
return pattern->getLoc();
620643
}

lib/AST/TypeCheckRequests.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,25 @@ void NamingPatternRequest::cacheResult(NamedPattern *value) const {
10111011
VD->NamingPattern = value;
10121012
}
10131013

1014+
//----------------------------------------------------------------------------//
1015+
// ExprPatternMatchRequest caching.
1016+
//----------------------------------------------------------------------------//
1017+
1018+
Optional<ExprPatternMatchResult>
1019+
ExprPatternMatchRequest::getCachedResult() const {
1020+
auto *EP = std::get<0>(getStorage());
1021+
if (!EP->MatchVar)
1022+
return None;
1023+
1024+
return ExprPatternMatchResult(EP->MatchVar, EP->MatchExpr);
1025+
}
1026+
1027+
void ExprPatternMatchRequest::cacheResult(ExprPatternMatchResult result) const {
1028+
auto *EP = std::get<0>(getStorage());
1029+
EP->MatchVar = result.getMatchVar();
1030+
EP->MatchExpr = result.getMatchExpr();
1031+
}
1032+
10141033
//----------------------------------------------------------------------------//
10151034
// InterfaceTypeRequest computation.
10161035
//----------------------------------------------------------------------------//

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,11 +1185,15 @@ class ExprContextAnalyzer {
11851185
switch (P->getKind()) {
11861186
case PatternKind::Expr: {
11871187
auto ExprPat = cast<ExprPattern>(P);
1188-
if (auto D = ExprPat->getMatchVar()) {
1189-
if (D->hasInterfaceType())
1190-
recordPossibleType(
1191-
D->getDeclContext()->mapTypeIntoContext(D->getInterfaceType()));
1192-
}
1188+
if (!ExprPat->isResolved())
1189+
break;
1190+
1191+
auto D = ExprPat->getMatchVar();
1192+
if (!D || !D->hasInterfaceType())
1193+
break;
1194+
1195+
auto *DC = D->getDeclContext();
1196+
recordPossibleType(DC->mapTypeIntoContext(D->getInterfaceType()));
11931197
break;
11941198
}
11951199
default:

lib/Parse/ParsePattern.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@ ParserResult<Pattern> Parser::parseMatchingPattern(bool isExprBasic) {
13391339
if (auto *UPE = dyn_cast<UnresolvedPatternExpr>(subExpr.get()))
13401340
return makeParserResult(status, UPE->getSubPattern());
13411341

1342-
auto *EP = ExprPattern::createParsed(Context, subExpr.get());
1342+
auto *EP = ExprPattern::createParsed(Context, subExpr.get(), CurDeclContext);
13431343
return makeParserResult(status, EP);
13441344
}
13451345

lib/Parse/ParseStmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,8 @@ static void parseGuardedPattern(Parser &P, GuardedPattern &result,
10951095
// Do some special-case code completion for the start of the pattern.
10961096
if (P.Tok.is(tok::code_complete)) {
10971097
auto CCE = new (P.Context) CodeCompletionExpr(P.Tok.getLoc());
1098-
result.ThePattern = ExprPattern::createParsed(P.Context, CCE);
1098+
result.ThePattern =
1099+
ExprPattern::createParsed(P.Context, CCE, P.CurDeclContext);
10991100
if (P.IDECallbacks) {
11001101
switch (parsingContext) {
11011102
case GuardedPatternContext::Case:

lib/Sema/CSSimplify.cpp

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9926,24 +9926,11 @@ static bool inferEnumMemberThroughTildeEqualsOperator(
99269926

99279927
// Slots for expression and variable are going to be filled via
99289928
// synthesizing ~= operator application.
9929-
auto *EP =
9930-
ExprPattern::createResolved(ctx, pattern->getUnresolvedOriginalExpr());
9931-
9932-
auto tildeEqualsApplication =
9933-
TypeChecker::synthesizeTildeEqualsOperatorApplication(EP, DC, enumTy);
9934-
9935-
if (!tildeEqualsApplication)
9936-
return true;
9937-
9938-
VarDecl *matchVar;
9939-
Expr *matchCall;
9940-
9941-
std::tie(matchVar, matchCall) = *tildeEqualsApplication;
9942-
9943-
cs.setType(matchVar, enumTy);
9944-
cs.setType(EP, enumTy);
9929+
auto *EP = ExprPattern::createResolved(
9930+
ctx, pattern->getUnresolvedOriginalExpr(), DC);
99459931

99469932
// result of ~= operator is always a `Bool`.
9933+
auto *matchCall = EP->getMatchExpr();
99479934
auto target = SyntacticElementTarget::forExprPattern(
99489935
matchCall, DC, EP, ctx.getBoolDecl()->getDeclaredInterfaceType());
99499936

@@ -9960,6 +9947,8 @@ static bool inferEnumMemberThroughTildeEqualsOperator(
99609947
return true;
99619948
}
99629949
}
9950+
cs.setType(EP->getMatchVar(), enumTy);
9951+
cs.setType(EP, enumTy);
99639952

99649953
if (cs.generateConstraints(target))
99659954
return true;
@@ -9969,12 +9958,7 @@ static bool inferEnumMemberThroughTildeEqualsOperator(
99699958
cs.addConstraint(ConstraintKind::Conversion, cs.getType(EP->getSubExpr()),
99709959
elementTy, cs.getConstraintLocator(EP));
99719960

9972-
// Store the $match variable and binary expression for solution application.
9973-
EP->setMatchVar(matchVar);
9974-
EP->setMatchExpr(matchCall);
9975-
99769961
cs.setTargetFor(pattern, target);
9977-
99789962
return false;
99799963
}
99809964

lib/Sema/DerivedConformanceCodingKey.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ deriveBodyCodingKey_init_stringValue(AbstractFunctionDecl *initDecl, void *) {
277277
for (auto *elt : elements) {
278278
auto *litExpr = new (C) StringLiteralExpr(elt->getNameStr(), SourceRange(),
279279
/*Implicit=*/true);
280-
auto *litPat = ExprPattern::createImplicit(C, litExpr);
280+
auto *litPat = ExprPattern::createImplicit(C, litExpr, /*DC*/ initDecl);
281281

282282
auto labelItem = CaseLabelItem(litPat);
283283

lib/Sema/DerivedConformanceRawRepresentable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl, void *) {
323323
stringExprs.push_back(litExpr);
324324
litExpr = IntegerLiteralExpr::createFromUnsigned(C, Idx, SourceLoc());
325325
}
326-
auto *litPat = ExprPattern::createImplicit(C, litExpr);
326+
auto *litPat = ExprPattern::createImplicit(C, litExpr, /*DC*/ initDecl);
327327

328328
/// Statements in the body of this case.
329329
SmallVector<ASTNode, 2> stmts;

0 commit comments

Comments
 (0)