Skip to content

Commit 7c58752

Browse files
authored
Merge pull request #64012 from gottesmm/reference-bindings-part-1
[reference-binding] Parser support for inout bindings
2 parents 68378b8 + 2be59b3 commit 7c58752

22 files changed

+361
-157
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,9 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
388388
IsStatic : 1
389389
);
390390

391-
SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+1+1+1+1+1,
391+
SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 2+1+1+1+1+1,
392392
/// Encodes whether this is a 'let' binding.
393-
Introducer : 1,
393+
Introducer : 2,
394394

395395
/// Whether this declaration captures the 'self' param under the same name.
396396
IsSelfParamCapture : 1,
@@ -5498,7 +5498,8 @@ class VarDecl : public AbstractStorageDecl {
54985498
public:
54995499
enum class Introducer : uint8_t {
55005500
Let = 0,
5501-
Var = 1
5501+
Var = 1,
5502+
InOut = 2,
55025503
};
55035504

55045505
protected:

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,8 +964,8 @@ ERROR(no_default_arg_closure,none,
964964
ERROR(no_default_arg_curried,none,
965965
"default arguments are not allowed in curried parameter lists", ())
966966
ERROR(var_pattern_in_var,none,
967-
"'%select{var|let}0' cannot appear nested inside another 'var' or "
968-
"'let' pattern", (unsigned))
967+
"'%select{let|inout|var}0' cannot appear nested inside another 'var', "
968+
"'let', or 'inout' pattern", (unsigned))
969969
ERROR(extra_var_in_multiple_pattern_list,none,
970970
"%0 must be bound in every pattern", (Identifier))
971971
ERROR(let_pattern_in_immutable_context,none,

include/swift/AST/Pattern.h

Lines changed: 31 additions & 8 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,
@@ -74,16 +75,17 @@ class alignas(8) Pattern : public ASTAllocated<Pattern> {
7475
Value : 1
7576
);
7677

77-
SWIFT_INLINE_BITFIELD(BindingPattern, Pattern, 1,
78-
/// True if this is a let pattern, false if a var pattern.
79-
IsLet : 1
78+
SWIFT_INLINE_BITFIELD(BindingPattern, Pattern, 2,
79+
/// Corresponds to VarDecl::Introducer
80+
Introducer : 2
8081
);
8182

8283
SWIFT_INLINE_BITFIELD(AnyPattern, Pattern, 1,
8384
/// True if this is an "async let _" pattern.
8485
IsAsyncLet : 1);
8586

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

8890
Pattern(PatternKind kind) {
8991
Bits.OpaqueBits = 0;
@@ -701,20 +703,41 @@ class ExprPattern : public Pattern {
701703
class BindingPattern : public Pattern {
702704
SourceLoc VarLoc;
703705
Pattern *SubPattern;
706+
704707
public:
705-
BindingPattern(SourceLoc loc, bool isLet, Pattern *sub)
708+
BindingPattern(SourceLoc loc, VarDecl::Introducer introducer, Pattern *sub)
706709
: Pattern(PatternKind::Binding), VarLoc(loc), SubPattern(sub) {
707-
Bits.BindingPattern.IsLet = isLet;
710+
setIntroducer(introducer);
711+
}
712+
713+
VarDecl::Introducer getIntroducer() const {
714+
return VarDecl::Introducer(Bits.BindingPattern.Introducer);
708715
}
709716

710-
static BindingPattern *createImplicit(ASTContext &Ctx, bool isLet,
717+
void setIntroducer(VarDecl::Introducer introducer) {
718+
Bits.BindingPattern.Introducer = uint8_t(introducer);
719+
}
720+
721+
static BindingPattern *createImplicit(ASTContext &Ctx,
722+
VarDecl::Introducer introducer,
711723
Pattern *sub) {
712-
auto *VP = new (Ctx) BindingPattern(SourceLoc(), isLet, sub);
724+
auto *VP = new (Ctx) BindingPattern(SourceLoc(), introducer, sub);
713725
VP->setImplicit();
714726
return VP;
715727
}
716728

717-
bool isLet() const { return Bits.BindingPattern.IsLet; }
729+
bool isLet() const { return getIntroducer() == VarDecl::Introducer::Let; }
730+
731+
StringRef getIntroducerStringRef() const {
732+
switch (getIntroducer()) {
733+
case VarDecl::Introducer::Let:
734+
return "let";
735+
case VarDecl::Introducer::Var:
736+
return "var";
737+
case VarDecl::Introducer::InOut:
738+
return "inout";
739+
}
740+
}
718741

719742
SourceLoc getLoc() const { return VarLoc; }
720743
SourceRange getSourceRange() const {

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;
@@ -1609,10 +1587,9 @@ class Parser {
16091587
ParserResult<Pattern>
16101588
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P);
16111589
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
1612-
ParserResult<Pattern> parseMatchingPatternAsLetOrVar(bool isLet,
1613-
SourceLoc VarLoc,
1614-
bool isExprBasic);
1615-
1590+
ParserResult<Pattern>
1591+
parseMatchingPatternAsBinding(PatternBindingState newState, SourceLoc VarLoc,
1592+
bool isExprBasic);
16161593

16171594
Pattern *createBindingFromPattern(SourceLoc loc, Identifier name,
16181595
VarDecl::Introducer introducer);
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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+
/// When InBindingPattern has this value, bound variables are mutable, and
49+
/// nested let/var/inout patterns are not permitted. This happens when
50+
/// parsing an 'inout' decl or when parsing inside an 'inout' pattern.
51+
InInOut,
52+
};
53+
54+
Kind kind;
55+
56+
PatternBindingState(Kind kind) : kind(kind) {}
57+
58+
operator bool() const { return kind != Kind::NotInBinding; }
59+
60+
operator Kind() const { return kind; }
61+
62+
static Optional<PatternBindingState> get(StringRef str) {
63+
auto kind = llvm::StringSwitch<Kind>(str)
64+
.Case("let", Kind::InLet)
65+
.Case("var", Kind::InVar)
66+
.Case("inout", Kind::InInOut)
67+
.Default(Kind::NotInBinding);
68+
return PatternBindingState(kind);
69+
}
70+
71+
/// Try to explicitly find the new pattern binding state from a token.
72+
explicit PatternBindingState(Token tok) : kind(NotInBinding) {
73+
switch (tok.getKind()) {
74+
case tok::kw_let:
75+
kind = InLet;
76+
break;
77+
case tok::kw_var:
78+
kind = InVar;
79+
break;
80+
case tok::kw_inout:
81+
kind = InInOut;
82+
break;
83+
default:
84+
break;
85+
}
86+
}
87+
88+
/// Explicitly initialize from a VarDecl::Introducer.
89+
explicit PatternBindingState(VarDecl::Introducer introducer)
90+
: kind(NotInBinding) {
91+
switch (introducer) {
92+
case VarDecl::Introducer::Let:
93+
kind = InLet;
94+
break;
95+
case VarDecl::Introducer::Var:
96+
kind = InVar;
97+
break;
98+
case VarDecl::Introducer::InOut:
99+
kind = InInOut;
100+
break;
101+
}
102+
}
103+
104+
/// If there is a direct introducer associated with this pattern binding
105+
/// state, return that. Return none otherwise.
106+
Optional<VarDecl::Introducer> getIntroducer() const {
107+
switch (kind) {
108+
case Kind::NotInBinding:
109+
case Kind::InMatchingPattern:
110+
case Kind::ImplicitlyImmutable:
111+
return None;
112+
case Kind::InVar:
113+
return VarDecl::Introducer::Var;
114+
case Kind::InLet:
115+
return VarDecl::Introducer::Let;
116+
case Kind::InInOut:
117+
return VarDecl::Introducer::InOut;
118+
}
119+
}
120+
121+
PatternBindingState
122+
getPatternBindingStateForIntroducer(VarDecl::Introducer defaultValue) {
123+
return PatternBindingState(getIntroducer().getValueOr(defaultValue));
124+
}
125+
126+
Optional<unsigned> getSelectIndexForIntroducer() const {
127+
switch (kind) {
128+
case Kind::InLet:
129+
return 0;
130+
case Kind::InInOut:
131+
return 1;
132+
case Kind::InVar:
133+
return 2;
134+
default:
135+
return None;
136+
}
137+
}
138+
139+
bool isLet() const { return kind == Kind::InLet; }
140+
};
141+
142+
} // namespace swift
143+
144+
#endif

0 commit comments

Comments
 (0)