Skip to content

Commit 9f9fe49

Browse files
committed
[reference-binding] Make InBindingState into a true type called PatternBindingState.
This cleans up the parser code a little bit around here and will make it easier for me to add inout.
1 parent 9dcf010 commit 9f9fe49

File tree

7 files changed

+220
-102
lines changed

7 files changed

+220
-102
lines changed

include/swift/AST/Pattern.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, PatternKind kind);
5353
/// Pattern - Base class for all patterns in Swift.
5454
class alignas(8) Pattern : public ASTAllocated<Pattern> {
5555
protected:
56+
// clang-format off
5657
union { uint64_t OpaqueBits;
5758

5859
SWIFT_INLINE_BITFIELD_BASE(Pattern, bitmax(NumPatternKindBits,8)+1+1,
@@ -84,6 +85,7 @@ class alignas(8) Pattern : public ASTAllocated<Pattern> {
8485
IsAsyncLet : 1);
8586

8687
} Bits;
88+
// clang-format on
8789

8890
Pattern(PatternKind kind) {
8991
Bits.OpaqueBits = 0;

include/swift/Parse/Parser.h

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,20 @@
1919

2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/ASTNode.h"
22-
#include "swift/AST/Expr.h"
2322
#include "swift/AST/DiagnosticsParse.h"
23+
#include "swift/AST/Expr.h"
2424
#include "swift/AST/LayoutConstraint.h"
2525
#include "swift/AST/ParseRequests.h"
2626
#include "swift/AST/Pattern.h"
2727
#include "swift/AST/Stmt.h"
2828
#include "swift/Basic/OptionSet.h"
29+
#include "swift/Config.h"
2930
#include "swift/Parse/Lexer.h"
30-
#include "swift/Parse/PersistentParserState.h"
31-
#include "swift/Parse/Token.h"
3231
#include "swift/Parse/ParserPosition.h"
3332
#include "swift/Parse/ParserResult.h"
34-
#include "swift/Config.h"
33+
#include "swift/Parse/PatternBindingState.h"
34+
#include "swift/Parse/PersistentParserState.h"
35+
#include "swift/Parse/Token.h"
3536
#include "llvm/ADT/IntrusiveRefCntPtr.h"
3637

3738
namespace llvm {
@@ -142,30 +143,7 @@ class Parser {
142143

143144
void recordTokenHash(StringRef token);
144145

145-
enum {
146-
/// InVarOrLetPattern has this value when not parsing a pattern.
147-
IVOLP_NotInVarOrLet,
148-
149-
/// InVarOrLetPattern has this value when we're in a matching pattern, but
150-
/// not within a var/let pattern. In this phase, identifiers are references
151-
/// to the enclosing scopes, not a variable binding.
152-
IVOLP_InMatchingPattern,
153-
154-
/// InVarOrLetPattern has this value when parsing a pattern in which bound
155-
/// variables are implicitly immutable, but allowed to be marked mutable by
156-
/// using a 'var' pattern. This happens in for-each loop patterns.
157-
IVOLP_ImplicitlyImmutable,
158-
159-
/// When InVarOrLetPattern has this value, bound variables are mutable, and
160-
/// nested let/var patterns are not permitted. This happens when parsing a
161-
/// 'var' decl or when parsing inside a 'var' pattern.
162-
IVOLP_InVar,
163-
164-
/// When InVarOrLetPattern has this value, bound variables are immutable,and
165-
/// nested let/var patterns are not permitted. This happens when parsing a
166-
/// 'let' decl or when parsing inside a 'let' pattern.
167-
IVOLP_InLet
168-
} InVarOrLetPattern = IVOLP_NotInVarOrLet;
146+
PatternBindingState InBindingPattern = PatternBindingState::NotInBinding;
169147

170148
/// Whether this context has an async attribute.
171149
bool InPatternWithAsyncAttribute = false;
@@ -1608,10 +1586,9 @@ class Parser {
16081586
ParserResult<Pattern>
16091587
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P);
16101588
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
1611-
ParserResult<Pattern> parseMatchingPatternAsLetOrVar(bool isLet,
1612-
SourceLoc VarLoc,
1613-
bool isExprBasic);
1614-
1589+
ParserResult<Pattern>
1590+
parseMatchingPatternAsBinding(PatternBindingState newState, SourceLoc VarLoc,
1591+
bool isExprBasic);
16151592

16161593
Pattern *createBindingFromPattern(SourceLoc loc, Identifier name,
16171594
VarDecl::Introducer introducer);
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//===--- PatternBindingState.h --------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_PARSE_PATTERNBINDINGSTATE_H
14+
#define SWIFT_PARSE_PATTERNBINDINGSTATE_H
15+
16+
#include "swift/AST/Decl.h"
17+
#include "swift/Parse/Token.h"
18+
19+
namespace swift {
20+
21+
class Token;
22+
23+
struct PatternBindingState {
24+
enum Kind {
25+
/// InBindingPattern has this value when not parsing a pattern.
26+
NotInBinding,
27+
28+
/// InBindingPattern has this value when we're in a matching pattern, but
29+
/// not within a var/let pattern. In this phase, identifiers are references
30+
/// to the enclosing scopes, not a variable binding.
31+
InMatchingPattern,
32+
33+
/// InBindingPattern has this value when parsing a pattern in which bound
34+
/// variables are implicitly immutable, but allowed to be marked mutable by
35+
/// using a 'var' pattern. This happens in for-each loop patterns.
36+
ImplicitlyImmutable,
37+
38+
/// When InBindingPattern has this value, bound variables are mutable, and
39+
/// nested let/var patterns are not permitted. This happens when parsing a
40+
/// 'var' decl or when parsing inside a 'var' pattern.
41+
InVar,
42+
43+
/// When InBindingPattern has this value, bound variables are immutable,and
44+
/// nested let/var patterns are not permitted. This happens when parsing a
45+
/// 'let' decl or when parsing inside a 'let' pattern.
46+
InLet,
47+
};
48+
49+
Kind kind;
50+
51+
PatternBindingState(Kind kind) : kind(kind) {}
52+
53+
operator bool() const { return kind != Kind::NotInBinding; }
54+
55+
operator Kind() const { return kind; }
56+
57+
static Optional<PatternBindingState> get(StringRef str) {
58+
auto kind = llvm::StringSwitch<Kind>(str)
59+
.Case("let", Kind::InLet)
60+
.Case("var", Kind::InVar)
61+
.Default(Kind::NotInBinding);
62+
return PatternBindingState(kind);
63+
}
64+
65+
/// Try to explicitly find the new pattern binding state from a token.
66+
explicit PatternBindingState(Token tok) : kind(NotInBinding) {
67+
switch (tok.getKind()) {
68+
case tok::kw_let:
69+
kind = InLet;
70+
break;
71+
case tok::kw_var:
72+
kind = InVar;
73+
break;
74+
default:
75+
break;
76+
}
77+
}
78+
79+
/// Explicitly initialize from a VarDecl::Introducer.
80+
explicit PatternBindingState(VarDecl::Introducer introducer)
81+
: kind(NotInBinding) {
82+
switch (introducer) {
83+
case VarDecl::Introducer::Let:
84+
kind = InLet;
85+
break;
86+
case VarDecl::Introducer::Var:
87+
kind = InVar;
88+
break;
89+
}
90+
}
91+
92+
/// If there is a direct introducer associated with this pattern binding
93+
/// state, return that. Return none otherwise.
94+
Optional<VarDecl::Introducer> getIntroducer() const {
95+
switch (kind) {
96+
case Kind::NotInBinding:
97+
case Kind::InMatchingPattern:
98+
case Kind::ImplicitlyImmutable:
99+
return None;
100+
case Kind::InVar:
101+
return VarDecl::Introducer::Var;
102+
case Kind::InLet:
103+
return VarDecl::Introducer::Let;
104+
}
105+
}
106+
107+
PatternBindingState
108+
getPatternBindingStateForIntroducer(VarDecl::Introducer defaultValue) {
109+
return PatternBindingState(getIntroducer().getValueOr(defaultValue));
110+
}
111+
112+
Optional<unsigned> getSelectIndexForIntroducer() const {
113+
switch (kind) {
114+
case Kind::InLet:
115+
return 0;
116+
case Kind::InVar:
117+
return 1;
118+
default:
119+
return None;
120+
}
121+
}
122+
123+
bool isLet() const { return kind == Kind::InLet; }
124+
};
125+
126+
} // namespace swift
127+
128+
#endif

lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7501,8 +7501,9 @@ Parser::parseDeclVar(ParseDeclOptions Flags,
75017501
Pattern *pattern;
75027502
{
75037503
// In our recursive parse, remember that we're in a var/let pattern.
7504-
llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
7505-
T(InVarOrLetPattern, isLet ? IVOLP_InLet : IVOLP_InVar);
7504+
llvm::SaveAndRestore<decltype(InBindingPattern)> T(
7505+
InBindingPattern,
7506+
isLet ? PatternBindingState::InLet : PatternBindingState::InVar);
75067507

75077508
// Track whether we are parsing an 'async let' pattern.
75087509
const auto hasAsyncAttr = Attributes.hasAttribute<AsyncAttr>();
@@ -8189,8 +8190,8 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags,
81898190
// "case" label.
81908191
{
81918192
CancellableBacktrackingScope backtrack(*this);
8192-
llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
8193-
T(InVarOrLetPattern, Parser::IVOLP_InMatchingPattern);
8193+
llvm::SaveAndRestore<decltype(InBindingPattern)> T(
8194+
InBindingPattern, PatternBindingState::InMatchingPattern);
81948195
parseMatchingPattern(/*isExprBasic*/false);
81958196

81968197
// Reset async attribute in parser context.

lib/Parse/ParseExpr.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ ParserResult<Expr> Parser::parseExprImpl(Diag<> Message,
4747
// Only do this if we're parsing a pattern, to improve QoI on malformed
4848
// expressions followed by (e.g.) let/var decls.
4949
//
50-
if (InVarOrLetPattern && isOnlyStartOfMatchingPattern()) {
50+
if (InBindingPattern && isOnlyStartOfMatchingPattern()) {
5151
ParserResult<Pattern> pattern = parseMatchingPattern(/*isExprBasic*/false);
5252
if (pattern.hasCodeCompletion())
5353
return makeParserCodeCompletionResult<Expr>();
5454
if (pattern.isNull())
5555
return nullptr;
5656
return makeParserResult(new (Context) UnresolvedPatternExpr(pattern.get()));
5757
}
58-
58+
5959
return parseExprSequence(Message, isExprBasic,
6060
/*forConditionalDirective*/false);
6161
}
@@ -275,7 +275,7 @@ ParserResult<Expr> Parser::parseExprSequence(Diag<> Message,
275275
// pattern, then an assignment doesn't make sense. In a "if let"
276276
// statement the equals is the start of the condition, so don't parse it
277277
// as a binary operator.
278-
if (InVarOrLetPattern)
278+
if (InBindingPattern)
279279
goto done;
280280
SourceLoc equalsLoc = consumeToken();
281281
auto *assign = new (Context) AssignExpr(equalsLoc);
@@ -1634,18 +1634,19 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
16341634
// Parse and return this as an UnresolvedPatternExpr around a binding. This
16351635
// will be resolved (or rejected) by sema when the overall refutable pattern
16361636
// it transformed from an expression into a pattern.
1637-
if ((InVarOrLetPattern == IVOLP_ImplicitlyImmutable ||
1638-
InVarOrLetPattern == IVOLP_InVar ||
1639-
InVarOrLetPattern == IVOLP_InLet) &&
1637+
if ((InBindingPattern == PatternBindingState::ImplicitlyImmutable ||
1638+
InBindingPattern == PatternBindingState::InVar ||
1639+
InBindingPattern == PatternBindingState::InLet) &&
16401640
// If we have "case let x." or "case let x(", we parse x as a normal
16411641
// name, not a binding, because it is the start of an enum pattern or
16421642
// call pattern.
16431643
peekToken().isNot(tok::period, tok::period_prefix, tok::l_paren)) {
16441644
Identifier name;
16451645
SourceLoc loc = consumeIdentifier(name, /*diagnoseDollarPrefix=*/false);
1646-
auto introducer = (InVarOrLetPattern != IVOLP_InVar
1647-
? VarDecl::Introducer::Let
1648-
: VarDecl::Introducer::Var);
1646+
// If we have an inout/let/var, set that as our introducer. otherwise
1647+
// default to Let.
1648+
auto introducer =
1649+
InBindingPattern.getIntroducer().getValueOr(VarDecl::Introducer::Let);
16491650
auto pattern = createBindingFromPattern(loc, name, introducer);
16501651
return makeParserResult(new (Context) UnresolvedPatternExpr(pattern));
16511652
}
@@ -1799,7 +1800,8 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
17991800
Result.setHasCodeCompletionAndIsError();
18001801
if (IDECallbacks &&
18011802
// We cannot code complete anything after var/let.
1802-
(!InVarOrLetPattern || InVarOrLetPattern == IVOLP_InMatchingPattern)) {
1803+
(!InBindingPattern ||
1804+
InBindingPattern == PatternBindingState::InMatchingPattern)) {
18031805
if (InPoundIfEnvironment) {
18041806
IDECallbacks->completePlatformCondition();
18051807
} else {
@@ -2785,8 +2787,8 @@ ParserResult<Expr> Parser::parseExprClosure() {
27852787
ParserStatus Status;
27862788
// We may be parsing this closure expr in a matching pattern context. If so,
27872789
// reset our state to not be in a pattern for any recursive pattern parses.
2788-
llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
2789-
T(InVarOrLetPattern, IVOLP_NotInVarOrLet);
2790+
llvm::SaveAndRestore<decltype(InBindingPattern)> T(
2791+
InBindingPattern, PatternBindingState::NotInBinding);
27902792

27912793
// Reset async attribute in parser context.
27922794
llvm::SaveAndRestore<bool> AsyncAttr(InPatternWithAsyncAttribute, false);

0 commit comments

Comments
 (0)