Skip to content

Commit fdc9817

Browse files
authored
Merge pull request #64174 from hamishknight/pattern-requests
2 parents 947eefb + 9885596 commit fdc9817

25 files changed

+299
-184
lines changed

include/swift/AST/Pattern.h

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -508,25 +508,29 @@ class EnumElementPattern : public Pattern {
508508
DeclNameRef Name;
509509
PointerUnion<EnumElementDecl *, Expr*> ElementDeclOrUnresolvedOriginalExpr;
510510
Pattern /*nullable*/ *SubPattern;
511+
DeclContext *DC;
511512

512513
public:
513514
EnumElementPattern(TypeExpr *ParentType, SourceLoc DotLoc,
514515
DeclNameLoc NameLoc, DeclNameRef Name,
515-
EnumElementDecl *Element, Pattern *SubPattern)
516+
EnumElementDecl *Element, Pattern *SubPattern,
517+
DeclContext *DC)
516518
: Pattern(PatternKind::EnumElement), ParentType(ParentType),
517519
DotLoc(DotLoc), NameLoc(NameLoc), Name(Name),
518-
ElementDeclOrUnresolvedOriginalExpr(Element), SubPattern(SubPattern) {
520+
ElementDeclOrUnresolvedOriginalExpr(Element), SubPattern(SubPattern),
521+
DC(DC) {
519522
assert(ParentType && "Missing parent type?");
520523
}
521524

522525
/// Create an unresolved EnumElementPattern for a `.foo` pattern relying on
523526
/// contextual type.
524527
EnumElementPattern(SourceLoc DotLoc, DeclNameLoc NameLoc, DeclNameRef Name,
525-
Pattern *SubPattern, Expr *UnresolvedOriginalExpr)
528+
Pattern *SubPattern, Expr *UnresolvedOriginalExpr,
529+
DeclContext *DC)
526530
: Pattern(PatternKind::EnumElement), ParentType(nullptr), DotLoc(DotLoc),
527531
NameLoc(NameLoc), Name(Name),
528532
ElementDeclOrUnresolvedOriginalExpr(UnresolvedOriginalExpr),
529-
SubPattern(SubPattern) {}
533+
SubPattern(SubPattern), DC(DC) {}
530534

531535
bool hasSubPattern() const { return SubPattern; }
532536

@@ -540,6 +544,8 @@ class EnumElementPattern : public Pattern {
540544

541545
void setSubPattern(Pattern *p) { SubPattern = p; }
542546

547+
DeclContext *getDeclContext() const { return DC; }
548+
543549
DeclNameRef getName() const { return Name; }
544550

545551
EnumElementDecl *getElementDecl() const {
@@ -647,43 +653,59 @@ class OptionalSomePattern : public Pattern {
647653
class ExprPattern : public Pattern {
648654
llvm::PointerIntPair<Expr *, 1, bool> SubExprAndIsResolved;
649655

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;
656+
DeclContext *DC;
657+
658+
/// A synthesized call to the '~=' operator comparing the match expression
659+
/// on the left to the matched value on the right.
660+
mutable Expr *MatchExpr = nullptr;
661+
662+
/// An implicit variable used to represent the RHS value of the synthesized
663+
/// match expression.
664+
mutable VarDecl *MatchVar = nullptr;
654665

655-
/// An implicit variable used to represent the RHS value of the match.
656-
VarDecl *MatchVar = nullptr;
666+
ExprPattern(Expr *E, DeclContext *DC, bool isResolved)
667+
: Pattern(PatternKind::Expr), SubExprAndIsResolved(E, isResolved),
668+
DC(DC) {}
657669

658-
ExprPattern(Expr *E, bool isResolved)
659-
: Pattern(PatternKind::Expr), SubExprAndIsResolved(E, isResolved) {}
670+
friend class ExprPatternMatchRequest;
660671

661672
public:
662673
/// Create a new parsed unresolved ExprPattern.
663-
static ExprPattern *createParsed(ASTContext &ctx, Expr *E);
674+
static ExprPattern *createParsed(ASTContext &ctx, Expr *E, DeclContext *DC);
664675

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

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

672683
Expr *getSubExpr() const { return SubExprAndIsResolved.getPointer(); }
673684
void setSubExpr(Expr *e) { SubExprAndIsResolved.setPointer(e); }
674685

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

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-
687709
SourceLoc getLoc() const;
688710
SourceRange getSourceRange() const;
689711

@@ -851,6 +873,9 @@ class ContextualPattern {
851873
};
852874

853875
void simple_display(llvm::raw_ostream &out, const ContextualPattern &pattern);
876+
void simple_display(llvm::raw_ostream &out, const Pattern *pattern);
877+
878+
SourceLoc extractNearestSourceLoc(const Pattern *pattern);
854879

855880
} // end namespace swift
856881

include/swift/AST/TypeCheckRequests.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,6 +2219,74 @@ 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+
2268+
/// Creates a corresponding ExprPattern from the original Expr of an
2269+
/// EnumElementPattern. This needs to be a cached request to ensure we don't
2270+
/// generate multiple ExprPatterns along different constraint solver paths.
2271+
class EnumElementExprPatternRequest
2272+
: public SimpleRequest<EnumElementExprPatternRequest,
2273+
ExprPattern *(const EnumElementPattern *),
2274+
RequestFlags::Cached> {
2275+
public:
2276+
using SimpleRequest::SimpleRequest;
2277+
2278+
private:
2279+
friend SimpleRequest;
2280+
2281+
// Evaluation.
2282+
ExprPattern *evaluate(Evaluator &evaluator,
2283+
const EnumElementPattern *EEP) const;
2284+
2285+
public:
2286+
// Cached.
2287+
bool isCached() const { return true; }
2288+
};
2289+
22222290
class InterfaceTypeRequest :
22232291
public SimpleRequest<InterfaceTypeRequest,
22242292
Type (ValueDecl *),

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,12 @@ 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)
234+
SWIFT_REQUEST(TypeChecker, EnumElementExprPatternRequest,
235+
ExprPattern *(const EnumElementPattern *),
236+
Cached, NoLocationInfo)
231237
SWIFT_REQUEST(TypeChecker, OpaqueReadOwnershipRequest,
232238
OpaqueReadOwnership(AbstractStorageDecl *), SeparatelyCached,
233239
NoLocationInfo)

include/swift/Sema/ConstraintSystem.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,6 +1630,14 @@ class Solution {
16301630
return None;
16311631
}
16321632

1633+
Optional<SyntacticElementTarget>
1634+
getTargetFor(SyntacticElementTargetKey key) const {
1635+
auto known = targets.find(key);
1636+
if (known == targets.end())
1637+
return None;
1638+
return known->second;
1639+
}
1640+
16331641
ConstraintLocator *getCalleeLocator(ConstraintLocator *locator,
16341642
bool lookThroughApply = true) const;
16351643

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/ArgumentCompletion.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,18 @@ static bool isExpressionResultTypeUnconstrained(const Solution &S, Expr *E) {
9595
return true;
9696
}
9797
}
98-
auto targetIt = S.targets.find(E);
99-
if (targetIt == S.targets.end()) {
98+
auto target = S.getTargetFor(E);
99+
if (!target)
100100
return false;
101-
}
102-
auto target = targetIt->second;
103-
assert(target.kind == SyntacticElementTarget::Kind::expression);
104-
switch (target.getExprContextualTypePurpose()) {
101+
102+
assert(target->kind == SyntacticElementTarget::Kind::expression);
103+
switch (target->getExprContextualTypePurpose()) {
105104
case CTP_Unused:
106105
// If we aren't using the contextual type, its unconstrained by definition.
107106
return true;
108107
case CTP_Initialization: {
109108
// let x = <expr> is unconstrained
110-
auto contextualType = target.getExprContextualType();
109+
auto contextualType = target->getExprContextualType();
111110
return !contextualType || contextualType->is<UnresolvedType>();
112111
}
113112
default:

0 commit comments

Comments
 (0)