Skip to content

Commit 96f2a04

Browse files
authored
Merge pull request swiftlang#6490 from modocache/ast
[SR-2757][Sema] Mark VarDecl in capture lists
2 parents 10fd090 + 4108e1d commit 96f2a04

19 files changed

+152
-117
lines changed

include/swift/AST/Decl.h

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,13 @@ class alignas(1 << DeclAlignInBits) Decl {
232232
/// \brief Whether we've already performed early attribute validation.
233233
/// FIXME: This is ugly.
234234
unsigned EarlyAttrValidation : 1;
235-
235+
236236
/// \brief Whether this declaration is currently being validated.
237237
unsigned BeingValidated : 1;
238238
};
239239
enum { NumDeclBits = 11 };
240240
static_assert(NumDeclBits <= 32, "fits in an unsigned");
241-
241+
242242
class PatternBindingDeclBitfields {
243243
friend class PatternBindingDecl;
244244
unsigned : NumDeclBits;
@@ -284,7 +284,7 @@ class alignas(1 << DeclAlignInBits) Decl {
284284
class VarDeclBitfields {
285285
friend class VarDecl;
286286
unsigned : NumAbstractStorageDeclBits;
287-
287+
288288
/// \brief Whether this property is a type property (currently unfortunately
289289
/// called 'static').
290290
unsigned IsStatic : 1;
@@ -293,11 +293,14 @@ class alignas(1 << DeclAlignInBits) Decl {
293293
/// once (either in its declaration, or once later), making it immutable.
294294
unsigned IsLet : 1;
295295

296+
/// \brief Whether this declaration was an element of a capture list.
297+
unsigned IsCaptureList : 1;
298+
296299
/// \brief Whether this vardecl has an initial value bound to it in a way
297300
/// that isn't represented in the AST with an initializer in the pattern
298301
/// binding. This happens in cases like "for i in ...", switch cases, etc.
299302
unsigned HasNonPatternBindingInit : 1;
300-
303+
301304
/// \brief Whether this is a property used in expressions in the debugger.
302305
/// It is up to the debugger to instruct SIL how to access this variable.
303306
unsigned IsDebuggerVar : 1;
@@ -306,9 +309,9 @@ class alignas(1 << DeclAlignInBits) Decl {
306309
/// a.storage for lazy var a is a decl that cannot be accessed.
307310
unsigned IsUserAccessible : 1;
308311
};
309-
enum { NumVarDeclBits = NumAbstractStorageDeclBits + 5 };
312+
enum { NumVarDeclBits = NumAbstractStorageDeclBits + 6 };
310313
static_assert(NumVarDeclBits <= 32, "fits in an unsigned");
311-
314+
312315
class EnumElementDeclBitfields {
313316
friend class EnumElementDecl;
314317
unsigned : NumValueDeclBits;
@@ -4091,13 +4094,14 @@ class VarDecl : public AbstractStorageDecl {
40914094
protected:
40924095
llvm::PointerUnion<PatternBindingDecl*, Stmt*> ParentPattern;
40934096

4094-
VarDecl(DeclKind Kind, bool IsStatic, bool IsLet, SourceLoc NameLoc,
4095-
Identifier Name, Type Ty, DeclContext *DC)
4096-
: AbstractStorageDecl(Kind, DC, Name, NameLoc)
4097+
VarDecl(DeclKind Kind, bool IsStatic, bool IsLet, bool IsCaptureList,
4098+
SourceLoc NameLoc, Identifier Name, Type Ty, DeclContext *DC)
4099+
: AbstractStorageDecl(Kind, DC, Name, NameLoc)
40974100
{
40984101
VarDeclBits.IsUserAccessible = true;
40994102
VarDeclBits.IsStatic = IsStatic;
41004103
VarDeclBits.IsLet = IsLet;
4104+
VarDeclBits.IsCaptureList = IsCaptureList;
41014105
VarDeclBits.IsDebuggerVar = false;
41024106
VarDeclBits.HasNonPatternBindingInit = false;
41034107
setType(Ty);
@@ -4109,9 +4113,10 @@ class VarDecl : public AbstractStorageDecl {
41094113
Type typeInContext;
41104114

41114115
public:
4112-
VarDecl(bool IsStatic, bool IsLet, SourceLoc NameLoc, Identifier Name,
4113-
Type Ty, DeclContext *DC)
4114-
: VarDecl(DeclKind::Var, IsStatic, IsLet, NameLoc, Name, Ty, DC) { }
4116+
VarDecl(bool IsStatic, bool IsLet, bool IsCaptureList, SourceLoc NameLoc,
4117+
Identifier Name, Type Ty, DeclContext *DC)
4118+
: VarDecl(DeclKind::Var, IsStatic, IsLet, IsCaptureList, NameLoc, Name, Ty,
4119+
DC) {}
41154120

41164121
SourceRange getSourceRange() const;
41174122

@@ -4122,7 +4127,7 @@ class VarDecl : public AbstractStorageDecl {
41224127
bool isUserAccessible() const {
41234128
return VarDeclBits.IsUserAccessible;
41244129
}
4125-
4130+
41264131
TypeLoc &getTypeLoc() { return typeLoc; }
41274132
TypeLoc getTypeLoc() const { return typeLoc; }
41284133

@@ -4202,7 +4207,7 @@ class VarDecl : public AbstractStorageDecl {
42024207
return PBD->getPatternEntryForVarDecl(this).getInit();
42034208
return nullptr;
42044209
}
4205-
4210+
42064211
VarDecl *getOverriddenDecl() const {
42074212
return cast_or_null<VarDecl>(AbstractStorageDecl::getOverriddenDecl());
42084213
}
@@ -4221,6 +4226,9 @@ class VarDecl : public AbstractStorageDecl {
42214226
bool isLet() const { return VarDeclBits.IsLet; }
42224227
void setLet(bool IsLet) { VarDeclBits.IsLet = IsLet; }
42234228

4229+
/// Is this an element in a capture list?
4230+
bool isCaptureList() const { return VarDeclBits.IsCaptureList; }
4231+
42244232
/// Return true if this vardecl has an initial value bound to it in a way
42254233
/// that isn't represented in the AST with an initializer in the pattern
42264234
/// binding. This happens in cases like "for i in ...", switch cases, etc.

lib/AST/Decl.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3727,7 +3727,10 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const {
37273727

37283728
// Besides self, don't suggest mutability for explicit function parameters.
37293729
if (isa<ParamDecl>(this)) return;
3730-
3730+
3731+
// Don't suggest any fixes for capture list elements.
3732+
if (isCaptureList()) return;
3733+
37313734
// If this is a normal variable definition, then we can change 'let' to 'var'.
37323735
// We even are willing to suggest this for multi-variable binding, like
37333736
// "let (a,b) = "
@@ -3748,18 +3751,18 @@ ParamDecl::ParamDecl(bool isLet,
37483751
SourceLoc letVarInOutLoc, SourceLoc argumentNameLoc,
37493752
Identifier argumentName, SourceLoc parameterNameLoc,
37503753
Identifier parameterName, Type ty, DeclContext *dc)
3751-
: VarDecl(DeclKind::Param, /*IsStatic=*/false, isLet, parameterNameLoc,
3752-
parameterName, ty, dc),
3754+
: VarDecl(DeclKind::Param, /*IsStatic*/false, /*IsLet*/isLet,
3755+
/*IsCaptureList*/false, parameterNameLoc, parameterName, ty, dc),
37533756
ArgumentName(argumentName), ArgumentNameLoc(argumentNameLoc),
37543757
LetVarInOutLoc(letVarInOutLoc) {
37553758
}
37563759

37573760
/// Clone constructor, allocates a new ParamDecl identical to the first.
37583761
/// Intentionally not defined as a copy constructor to avoid accidental copies.
37593762
ParamDecl::ParamDecl(ParamDecl *PD)
3760-
: VarDecl(DeclKind::Param, /*IsStatic=*/false, PD->isLet(), PD->getNameLoc(),
3761-
PD->getName(), PD->hasType() ? PD->getType() : Type(),
3762-
PD->getDeclContext()),
3763+
: VarDecl(DeclKind::Param, /*IsStatic*/false, /*IsLet*/PD->isLet(),
3764+
/*IsCaptureList*/false, PD->getNameLoc(), PD->getName(),
3765+
PD->hasType() ? PD->getType() : Type(), PD->getDeclContext()),
37633766
ArgumentName(PD->getArgumentName()),
37643767
ArgumentNameLoc(PD->getArgumentNameLoc()),
37653768
LetVarInOutLoc(PD->getLetVarInOutLoc()),

lib/ClangImporter/ImportDecl.cpp

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,10 @@ createVarWithPattern(ASTContext &cxt, DeclContext *dc, Identifier name, Type ty,
123123
Accessibility setterAccessibility) {
124124
// Create a variable to store the underlying value.
125125
auto var = new (cxt) VarDecl(
126-
/*static*/ false,
127-
/*IsLet*/ isLet, SourceLoc(), name, ty, dc);
126+
/*IsStatic*/false,
127+
/*IsLet*/isLet,
128+
/*IsCaptureList*/false,
129+
SourceLoc(), name, ty, dc);
128130
if (isImplicit)
129131
var->setImplicit();
130132
var->setInterfaceType(ty);
@@ -1191,8 +1193,8 @@ static void makeStructRawValuedWithBridge(
11911193
//
11921194
// Create a computed value variable
11931195
auto computedVar = new (cxt) VarDecl(
1194-
/*static*/ false,
1195-
/*IsLet*/ false, SourceLoc(), computedVarName, bridgedType, structDecl);
1196+
/*IsStatic*/false, /*IsLet*/false, /*IsCaptureList*/false,
1197+
SourceLoc(), computedVarName, bridgedType, structDecl);
11961198
computedVar->setInterfaceType(bridgedType);
11971199
computedVar->setImplicit();
11981200
computedVar->setAccessibility(Accessibility::Public);
@@ -1496,8 +1498,8 @@ static bool addErrorDomain(NominalTypeDecl *swiftDecl,
14961498

14971499
// Make the property decl
14981500
auto errorDomainPropertyDecl = new (C) VarDecl(
1499-
isStatic,
1500-
/*IsLet=*/false, SourceLoc(), C.Id_nsErrorDomain, stringTy, swiftDecl);
1501+
/*IsStatic*/isStatic, /*IsLet*/false, /*IsCaptureList*/false,
1502+
SourceLoc(), C.Id_nsErrorDomain, stringTy, swiftDecl);
15011503
errorDomainPropertyDecl->setInterfaceType(stringTy);
15021504
errorDomainPropertyDecl->setAccessibility(Accessibility::Public);
15031505

@@ -2195,7 +2197,8 @@ namespace {
21952197
// Create the _nsError member.
21962198
// public let _nsError: NSError
21972199
auto nsErrorType = nsErrorDecl->getDeclaredInterfaceType();
2198-
auto nsErrorProp = new (C) VarDecl(/*static*/ false, /*IsLet*/ true,
2200+
auto nsErrorProp = new (C) VarDecl(/*IsStatic*/false, /*IsLet*/true,
2201+
/*IsCaptureList*/false,
21992202
loc, C.Id_nsError, nsErrorType,
22002203
errorWrapper);
22012204
nsErrorProp->setImplicit();
@@ -2261,10 +2264,10 @@ namespace {
22612264
auto rawValueConstructor = makeEnumRawValueConstructor(Impl, enumDecl);
22622265

22632266
auto varName = C.Id_rawValue;
2264-
auto rawValue = new (C) VarDecl(/*static*/ false,
2265-
/*IsLet*/ false,
2266-
SourceLoc(), varName,
2267-
underlyingType, enumDecl);
2267+
auto rawValue = new (C) VarDecl(/*IsStatic*/false, /*IsLet*/ false,
2268+
/*IsCaptureList*/false,
2269+
SourceLoc(), varName, underlyingType,
2270+
enumDecl);
22682271
rawValue->setImplicit();
22692272
rawValue->setAccessibility(Accessibility::Public);
22702273
rawValue->setSetterAccessibility(Accessibility::Private);
@@ -2789,7 +2792,8 @@ namespace {
27892792
// Map this indirect field to a Swift variable.
27902793
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
27912794
Accessibility::Public,
2792-
/*static*/ false, /*IsLet*/ false,
2795+
/*IsStatic*/false, /*IsLet*/ false,
2796+
/*IsCaptureList*/false,
27932797
Impl.importSourceLoc(decl->getLocStart()),
27942798
name, type, dc);
27952799
result->setInterfaceType(type);
@@ -2980,7 +2984,8 @@ namespace {
29802984

29812985
auto result =
29822986
Impl.createDeclWithClangNode<VarDecl>(decl, Accessibility::Public,
2983-
/*static*/ false, /*IsLet*/ false,
2987+
/*IsStatic*/ false, /*IsLet*/ false,
2988+
/*IsCaptureList*/false,
29842989
Impl.importSourceLoc(decl->getLocation()),
29852990
name, type, dc);
29862991
result->setInterfaceType(type);
@@ -3053,8 +3058,10 @@ namespace {
30533058
isStatic = true;
30543059

30553060
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
3056-
Accessibility::Public, isStatic,
3057-
Impl.shouldImportGlobalAsLet(decl->getType()),
3061+
Accessibility::Public,
3062+
/*IsStatic*/isStatic,
3063+
/*IsLet*/Impl.shouldImportGlobalAsLet(decl->getType()),
3064+
/*IsCaptureList*/false,
30583065
Impl.importSourceLoc(decl->getLocation()),
30593066
name, type, dc);
30603067
result->setInterfaceType(type);
@@ -4113,8 +4120,8 @@ namespace {
41134120

41144121
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
41154122
getOverridableAccessibility(dc),
4116-
decl->isClassProperty(), /*IsLet*/ false,
4117-
Impl.importSourceLoc(decl->getLocation()),
4123+
/*IsStatic*/decl->isClassProperty(), /*IsLet*/false,
4124+
/*IsCaptureList*/false, Impl.importSourceLoc(decl->getLocation()),
41184125
name, type, dc);
41194126
result->setInterfaceType(dc->mapTypeOutOfContext(type));
41204127

@@ -4987,8 +4994,8 @@ SwiftDeclConverter::getImplicitProperty(ImportedName importedName,
49874994
return nullptr;
49884995

49894996
auto property = Impl.createDeclWithClangNode<VarDecl>(
4990-
getter, Accessibility::Public, isStatic,
4991-
/*isLet=*/false, SourceLoc(), propertyName, swiftPropertyType, dc);
4997+
getter, Accessibility::Public, /*IsStatic*/isStatic, /*isLet*/false,
4998+
/*IsCaptureList*/false, SourceLoc(), propertyName, swiftPropertyType, dc);
49924999
property->setInterfaceType(swiftPropertyType);
49935000

49945001
// Note that we've formed this property.
@@ -7039,11 +7046,13 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc,
70397046
VarDecl *var = nullptr;
70407047
if (ClangN) {
70417048
var = createDeclWithClangNode<VarDecl>(ClangN, Accessibility::Public,
7042-
isStatic, /*IsLet*/ false,
7043-
SourceLoc(), name, type, dc);
7049+
/*IsStatic*/isStatic, /*IsLet*/false,
7050+
/*IsCaptureList*/false, SourceLoc(),
7051+
name, type, dc);
70447052
} else {
70457053
var = new (SwiftContext)
7046-
VarDecl(isStatic, /*IsLet*/ false, SourceLoc(), name, type, dc);
7054+
VarDecl(/*IsStatic*/isStatic, /*IsLet*/false, /*IsCaptureList*/false,
7055+
SourceLoc(), name, type, dc);
70477056
}
70487057

70497058
var->setInterfaceType(type);
@@ -7147,7 +7156,9 @@ createUnavailableDecl(Identifier name, DeclContext *dc, Type type,
71477156

71487157
// Create a new VarDecl with dummy type.
71497158
auto var = createDeclWithClangNode<VarDecl>(ClangN, Accessibility::Public,
7150-
isStatic, /*IsLet*/ false,
7159+
/*IsStatic*/isStatic,
7160+
/*IsLet*/false,
7161+
/*IsCaptureList*/false,
71517162
SourceLoc(), name, type, dc);
71527163
var->setInterfaceType(type);
71537164
markUnavailable(var, UnavailableMessage);

lib/Parse/ParseExpr.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,23 +2159,23 @@ parseClosureSignatureIfPresent(SmallVectorImpl<CaptureListEntry> &captureList,
21592159
// the initializer expression is evaluated before the closure is formed.
21602160
auto *VD = new (Context) VarDecl(/*isStatic*/false,
21612161
/*isLet*/ownershipKind !=Ownership::Weak,
2162+
/*isCaptureList*/true,
21622163
nameLoc, name, Type(), CurDeclContext);
2164+
21632165
// Attributes.
21642166
if (ownershipKind != Ownership::Strong)
21652167
VD->getAttrs().add(new (Context) OwnershipAttr(ownershipKind));
2166-
2168+
21672169
auto pattern = new (Context) NamedPattern(VD, /*implicit*/true);
2168-
2170+
21692171
auto *PBD = PatternBindingDecl::create(Context, /*staticloc*/SourceLoc(),
21702172
StaticSpellingKind::None,
21712173
nameLoc, pattern, initializer,
21722174
CurDeclContext);
2173-
2174-
2175-
2175+
21762176
captureList.push_back(CaptureListEntry(VD, PBD));
21772177
} while (consumeIf(tok::comma));
2178-
2178+
21792179
// The capture list needs to be closed off with a ']'.
21802180
if (!consumeIf(tok::r_square)) {
21812181
diagnose(Tok, diag::expected_capture_list_end_rsquare);

lib/Parse/ParsePattern.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,8 +819,9 @@ ParserResult<Pattern> Parser::parsePattern() {
819819

820820
Pattern *Parser::createBindingFromPattern(SourceLoc loc, Identifier name,
821821
bool isLet) {
822-
auto var = new (Context) VarDecl(/*static*/ false, /*IsLet*/ isLet,
823-
loc, name, Type(), CurDeclContext);
822+
auto var = new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/isLet,
823+
/*IsCaptureList*/false, loc, name, Type(),
824+
CurDeclContext);
824825
return new (Context) NamedPattern(var);
825826
}
826827

lib/Parse/ParseStmt.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -914,9 +914,9 @@ static void parseGuardedPattern(Parser &P, GuardedPattern &result,
914914
P.Tok.isAny(tok::l_brace, tok::kw_where)) {
915915
auto loc = P.Tok.getLoc();
916916
auto errorName = P.Context.Id_error;
917-
auto var = new (P.Context) VarDecl(/*static*/ false, /*IsLet*/true,
918-
loc, errorName, Type(),
919-
P.CurDeclContext);
917+
auto var = new (P.Context) VarDecl(/*IsStatic*/false, /*IsLet*/true,
918+
/*IsCaptureList*/false, loc, errorName,
919+
Type(), P.CurDeclContext);
920920
var->setImplicit();
921921
auto namePattern = new (P.Context) NamedPattern(var);
922922
auto varPattern = new (P.Context) VarPattern(loc, /*isLet*/true,

lib/Sema/CSDiag.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -670,8 +670,10 @@ static void diagnoseSubElementFailure(Expr *destExpr,
670670
std::string message = "'";
671671
message += VD->getName().str().str();
672672
message += "'";
673-
674-
if (VD->isImplicit())
673+
674+
if (VD->isCaptureList())
675+
message += " is an immutable capture";
676+
else if (VD->isImplicit())
675677
message += " is immutable";
676678
else if (VD->isLet())
677679
message += " is a 'let' constant";
@@ -684,7 +686,7 @@ static void diagnoseSubElementFailure(Expr *destExpr,
684686
}
685687
TC.diagnose(loc, diagID, message)
686688
.highlight(immInfo.first->getSourceRange());
687-
689+
688690
// If this is a simple variable marked with a 'let', emit a note to fixit
689691
// hint it to 'var'.
690692
VD->emitLetToVarNoteIfSimple(CS.DC);

0 commit comments

Comments
 (0)