Skip to content

Commit 5ec4c1c

Browse files
authored
Merge pull request #21520 from slavapestov/clean-up-storage-validation
Clean up AbstractStorageDecl validation
2 parents a4496d5 + 6bcdc4b commit 5ec4c1c

File tree

5 files changed

+78
-80
lines changed

5 files changed

+78
-80
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 14 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,31 +2356,29 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
23562356
ConstraintLocator *Locator;
23572357

23582358
/// The type of the initializer.
2359-
llvm::PointerIntPair<Type, 1, bool> InitTypeAndInOut;
2359+
Type initType;
23602360

23612361
public:
23622362
explicit BindingListener(Pattern *&pattern, Expr *&initializer)
23632363
: pattern(pattern), initializer(initializer),
2364-
Locator(nullptr), InitTypeAndInOut(Type(), false) { }
2364+
Locator(nullptr) { }
23652365

2366-
Type getInitType() const { return InitTypeAndInOut.getPointer(); }
2367-
bool isInOut() const { return InitTypeAndInOut.getInt(); }
2366+
Type getInitType() const { return initType; }
23682367

23692368
bool builtConstraints(ConstraintSystem &cs, Expr *expr) override {
2369+
assert(!expr->isSemanticallyInOutExpr());
2370+
23702371
// Save the locator we're using for the expression.
23712372
Locator = cs.getConstraintLocator(expr);
23722373

23732374
// Collect constraints from the pattern.
2374-
InitTypeAndInOut.setPointer(cs.generateConstraints(pattern, Locator));
2375-
InitTypeAndInOut.setInt(expr->isSemanticallyInOutExpr());
2376-
if (!InitTypeAndInOut.getPointer())
2375+
initType = cs.generateConstraints(pattern, Locator);
2376+
if (!initType)
23772377
return true;
23782378

2379-
assert(!InitTypeAndInOut.getPointer()->is<InOutType>());
23802379
// Add a conversion constraint between the types.
23812380
cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
2382-
InitTypeAndInOut.getPointer(), Locator,
2383-
/*isFavored*/true);
2381+
initType, Locator, /*isFavored*/true);
23842382

23852383
// The expression has been pre-checked; save it in case we fail later.
23862384
initializer = expr;
@@ -2389,25 +2387,21 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
23892387

23902388
Expr *foundSolution(Solution &solution, Expr *expr) override {
23912389
// Figure out what type the constraints decided on.
2392-
auto ty = solution.simplifyType(InitTypeAndInOut.getPointer());
2393-
InitTypeAndInOut.setPointer(
2394-
ty->getRValueType()->reconstituteSugar(/*recursive =*/false));
2395-
InitTypeAndInOut.setInt(expr->isSemanticallyInOutExpr());
2390+
auto ty = solution.simplifyType(initType);
2391+
initType = ty->getRValueType()->reconstituteSugar(/*recursive =*/false);
23962392

23972393
// Just keep going.
23982394
return expr;
23992395
}
24002396

24012397
Expr *appliedSolution(Solution &solution, Expr *expr) override {
24022398
// Convert the initializer to the type of the pattern.
2403-
// ignoreTopLevelInjection = Binding->isConditional()
2404-
expr = solution.coerceToType(expr, InitTypeAndInOut.getPointer(), Locator,
2399+
expr = solution.coerceToType(expr, initType, Locator,
24052400
false /* ignoreTopLevelInjection */);
2406-
if (!expr) {
2401+
if (!expr)
24072402
return nullptr;
2408-
}
24092403

2410-
assert(solution.getConstraintSystem().getType(expr)->isEqual(InitTypeAndInOut.getPointer()));
2404+
assert(solution.getConstraintSystem().getType(expr)->isEqual(initType));
24112405

24122406
initializer = expr;
24132407
return expr;
@@ -2442,7 +2436,6 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
24422436
// Type-check the initializer.
24432437
auto resultTy = typeCheckExpression(initializer, DC, contextualType,
24442438
contextualPurpose, flags, &listener);
2445-
assert(!listener.isInOut());
24462439

24472440
if (resultTy) {
24482441
TypeResolutionOptions options =
@@ -2491,7 +2484,6 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
24912484

24922485
bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
24932486
unsigned patternNumber) {
2494-
auto &ctx = PBD->getASTContext();
24952487
const auto &pbe = PBD->getPatternList()[patternNumber];
24962488
Pattern *pattern = PBD->getPattern(patternNumber);
24972489
Expr *init = PBD->getInit(patternNumber);
@@ -2514,30 +2506,8 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
25142506
PBD->setPattern(patternNumber, pattern, initContext);
25152507
PBD->setInit(patternNumber, init);
25162508

2517-
// Add the attribute that preserves the "has an initializer" value across
2518-
// module generation, as required for TBDGen.
2519-
PBD->getPattern(patternNumber)->forEachVariable([&](VarDecl *VD) {
2520-
if (VD->hasStorage() && !VD->getAttrs().hasAttribute<HasInitialValueAttr>())
2521-
VD->getAttrs().add(new (ctx) HasInitialValueAttr(/*IsImplicit=*/true));
2522-
});
2523-
2524-
if (!hadError) {
2525-
// If we're performing an binding to a weak or unowned variable from a
2526-
// constructor call, emit a warning that the instance will be immediately
2527-
// deallocated.
2528-
diagnoseUnownedImmediateDeallocation(*this, pattern, pbe.getEqualLoc(),
2529-
init);
2530-
2531-
// If we entered an initializer context, contextualize any
2532-
// auto-closures we might have created.
2533-
if (initContext) {
2534-
// Check safety of error-handling in the declaration, too.
2535-
checkInitializerErrorHandling(initContext, init);
2536-
(void)contextualizeInitializer(initContext, init);
2537-
}
2538-
} else {
2509+
if (hadError)
25392510
PBD->setInvalid();
2540-
}
25412511

25422512
PBD->setInitializerChecked(patternNumber);
25432513
return hadError;

lib/Sema/TypeCheckDecl.cpp

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/AST/ForeignErrorConvention.h"
3131
#include "swift/AST/GenericEnvironment.h"
3232
#include "swift/AST/GenericSignatureBuilder.h"
33+
#include "swift/AST/Initializer.h"
3334
#include "swift/AST/NameLookup.h"
3435
#include "swift/AST/PrettyStackTrace.h"
3536
#include "swift/AST/ProtocolConformance.h"
@@ -2120,14 +2121,17 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
21202121
}
21212122

21222123
void visitBoundVariable(VarDecl *VD) {
2124+
// WARNING: Anything you put in this function will only be run when the
2125+
// VarDecl is fully type-checked within its own file. It will NOT be run
2126+
// when the VarDecl is merely used from another file.
21232127
TC.validateDecl(VD);
21242128

2125-
// Set up accessors.
2129+
// Set up accessors, also lowering lazy and @NSManaged properties.
21262130
maybeAddAccessorsToStorage(VD);
21272131

2128-
// WARNING: Anything you put in this function will only be run when the
2129-
// VarDecl is fully type-checked within its own file. It will NOT be run
2130-
// when the VarDecl is merely used from another file.
2132+
// Add the '@_hasStorage' attribute if this property is stored.
2133+
if (VD->hasStorage() && !VD->getAttrs().hasAttribute<HasStorageAttr>())
2134+
VD->getAttrs().add(new (TC.Context) HasStorageAttr(/*isImplicit=*/true));
21312135

21322136
// Reject cases where this is a variable that has storage but it isn't
21332137
// allowed.
@@ -2223,16 +2227,17 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22232227
.fixItRemove(attr->getRange());
22242228
}
22252229
}
2226-
}
22272230

2231+
if (VD->getAttrs().hasAttribute<DynamicReplacementAttr>())
2232+
TC.checkDynamicReplacementAttribute(VD);
2233+
}
22282234

22292235
void visitBoundVars(Pattern *P) {
22302236
P->forEachVariable([&] (VarDecl *VD) { this->visitBoundVariable(VD); });
22312237
}
22322238

22332239
void visitPatternBindingDecl(PatternBindingDecl *PBD) {
2234-
if (PBD->isBeingValidated())
2235-
return;
2240+
DeclContext *DC = PBD->getDeclContext();
22362241

22372242
// Check all the pattern/init pairs in the PBD.
22382243
validatePatternBindingEntries(TC, PBD);
@@ -2250,10 +2255,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22502255
PBD->getPattern(i)->hasStorage() &&
22512256
!PBD->getPattern(i)->getType()->hasError()) {
22522257

2253-
// If we have a type-adjusting attribute (like ownership), apply it now.
2254-
if (auto var = PBD->getSingleVar())
2255-
TC.checkTypeModifyingDeclAttributes(var);
2256-
22572258
// Decide whether we should suppress default initialization.
22582259
//
22592260
// Note: Swift 4 had a bug where properties with a desugared optional
@@ -2280,15 +2281,27 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22802281
// If we got a default initializer, install it and re-type-check it
22812282
// to make sure it is properly coerced to the pattern type.
22822283
PBD->setInit(i, defaultInit);
2283-
TC.typeCheckPatternBinding(PBD, i);
22842284
}
22852285
}
2286+
2287+
if (PBD->getInit(i)) {
2288+
// Add the attribute that preserves the "has an initializer" value across
2289+
// module generation, as required for TBDGen.
2290+
PBD->getPattern(i)->forEachVariable([&](VarDecl *VD) {
2291+
if (VD->hasStorage() &&
2292+
!VD->getAttrs().hasAttribute<HasInitialValueAttr>()) {
2293+
auto *attr = new (TC.Context) HasInitialValueAttr(
2294+
/*IsImplicit=*/true);
2295+
VD->getAttrs().add(attr);
2296+
}
2297+
});
2298+
}
22862299
}
22872300

22882301
bool isInSILMode = false;
2289-
if (auto sourceFile = PBD->getDeclContext()->getParentSourceFile())
2302+
if (auto sourceFile = DC->getParentSourceFile())
22902303
isInSILMode = sourceFile->Kind == SourceFileKind::SIL;
2291-
bool isTypeContext = PBD->getDeclContext()->isTypeContext();
2304+
bool isTypeContext = DC->isTypeContext();
22922305

22932306
// If this is a declaration without an initializer, reject code if
22942307
// uninitialized vars are not allowed.
@@ -2305,8 +2318,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
23052318
if (var->isInvalid() || PBD->isInvalid())
23062319
return;
23072320

2308-
auto *varDC = var->getDeclContext();
2309-
23102321
auto markVarAndPBDInvalid = [PBD, var] {
23112322
PBD->setInvalid();
23122323
var->setInvalid();
@@ -2324,9 +2335,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
23242335

23252336
// Static/class declarations require an initializer unless in a
23262337
// protocol.
2327-
if (var->isStatic() && !isa<ProtocolDecl>(varDC)) {
2338+
if (var->isStatic() && !isa<ProtocolDecl>(DC)) {
23282339
// ...but don't enforce this for SIL or parseable interface files.
2329-
switch (varDC->getParentSourceFile()->Kind) {
2340+
switch (DC->getParentSourceFile()->Kind) {
23302341
case SourceFileKind::Interface:
23312342
case SourceFileKind::SIL:
23322343
return;
@@ -2343,8 +2354,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
23432354
}
23442355

23452356
// Global variables require an initializer in normal source files.
2346-
if (varDC->isModuleScopeContext()) {
2347-
switch (varDC->getParentSourceFile()->Kind) {
2357+
if (DC->isModuleScopeContext()) {
2358+
switch (DC->getParentSourceFile()->Kind) {
23482359
case SourceFileKind::Main:
23492360
case SourceFileKind::REPL:
23502361
case SourceFileKind::Interface:
@@ -2368,8 +2379,35 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
23682379

23692380
// If the initializers in the PBD aren't checked yet, do so now.
23702381
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i) {
2371-
if (!PBD->isInitializerChecked(i) && PBD->getInit(i))
2382+
if (!PBD->getInit(i))
2383+
continue;
2384+
2385+
if (!PBD->isInitializerChecked(i))
23722386
TC.typeCheckPatternBinding(PBD, i);
2387+
2388+
if (!PBD->isInvalid()) {
2389+
auto &entry = PBD->getPatternList()[i];
2390+
auto *init = PBD->getInit(i);
2391+
2392+
// If we're performing an binding to a weak or unowned variable from a
2393+
// constructor call, emit a warning that the instance will be immediately
2394+
// deallocated.
2395+
diagnoseUnownedImmediateDeallocation(TC, PBD->getPattern(i),
2396+
entry.getEqualLoc(),
2397+
init);
2398+
2399+
// If we entered an initializer context, contextualize any
2400+
// auto-closures we might have created.
2401+
if (!DC->isLocalContext()) {
2402+
auto *initContext = cast_or_null<PatternBindingInitializer>(
2403+
entry.getInitContext());
2404+
if (initContext) {
2405+
// Check safety of error-handling in the declaration, too.
2406+
TC.checkInitializerErrorHandling(initContext, init);
2407+
(void) TC.contextualizeInitializer(initContext, init);
2408+
}
2409+
}
2410+
}
23732411
}
23742412
}
23752413

@@ -2845,12 +2883,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
28452883
void visitVarDecl(VarDecl *VD) {
28462884
// Delay type-checking on VarDecls until we see the corresponding
28472885
// PatternBindingDecl.
2848-
2849-
// Except if there is a dynamic replacement attribute.
2850-
if (VD->getAttrs().hasAttribute<DynamicReplacementAttr>()) {
2851-
TC.validateDecl(VD);
2852-
TC.checkDynamicReplacementAttribute(VD);
2853-
}
28542886
}
28552887

28562888
/// Determine whether the given declaration requires a definition.
@@ -3699,10 +3731,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
36993731
auto *VD = cast<VarDecl>(D);
37003732
auto *PBD = VD->getParentPatternBinding();
37013733

3702-
// Add the '@_hasStorage' attribute if this property is stored.
3703-
if (VD->hasStorage() && !VD->getAttrs().hasAttribute<HasStorageAttr>())
3704-
VD->getAttrs().add(new (Context) HasStorageAttr(/*isImplicit=*/true));
3705-
37063734
// Note that we need to handle the fact that some VarDecls don't
37073735
// have a PatternBindingDecl, for example the iterator in a
37083736
// 'for ... in ...' loop.

test/SIL/Parser/final.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
22

33
// CHECK: final class Rect
4-
// CHECK: @_hasInitialValue @_hasStorage final var orgx: Double
4+
// CHECK: @_hasStorage @_hasInitialValue final var orgx: Double
55
final class Rect {
66
var orgx = 0.0
77
}

test/attr/attr_objc.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ class infer_instanceVar1 {
839839
}
840840

841841
var observingAccessorsVar1: Int {
842-
// CHECK: @_hasStorage @objc var observingAccessorsVar1: Int {
842+
// CHECK: @objc @_hasStorage var observingAccessorsVar1: Int {
843843
willSet {}
844844
// CHECK-NEXT: {{^}} @objc get
845845
didSet {}
@@ -1709,7 +1709,7 @@ class HasNSManaged {
17091709

17101710
@NSManaged
17111711
var goodManaged: Class_ObjC1
1712-
// CHECK-LABEL: {{^}} @objc @NSManaged @_hasStorage dynamic var goodManaged: Class_ObjC1 {
1712+
// CHECK-LABEL: {{^}} @objc @NSManaged dynamic var goodManaged: Class_ObjC1 {
17131713
// CHECK-NEXT: {{^}} @objc get
17141714
// CHECK-NEXT: {{^}} @objc set
17151715
// CHECK-NEXT: {{^}} }
@@ -1719,7 +1719,7 @@ class HasNSManaged {
17191719
// expected-error@-1 {{property cannot be marked @NSManaged because its type cannot be represented in Objective-C}}
17201720
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
17211721
// expected-error@-3{{'dynamic' property 'badManaged' must also be '@objc'}}
1722-
// CHECK-LABEL: {{^}} @NSManaged @_hasStorage var badManaged: PlainStruct {
1722+
// CHECK-LABEL: {{^}} @NSManaged var badManaged: PlainStruct {
17231723
// CHECK-NEXT: {{^}} get
17241724
// CHECK-NEXT: {{^}} set
17251725
// CHECK-NEXT: {{^}} }

test/attr/hasInitialValue.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class C {
1212
// CHECK: {{^}} @_implicitly_unwrapped_optional @_hasInitialValue var iuo: Int!
1313
var iuo: Int!
1414

15-
// CHECK: {{^}} @_hasStorage lazy var lazyIsntARealInit: Int
15+
// CHECK: {{^}} lazy var lazyIsntARealInit: Int
1616
lazy var lazyIsntARealInit: Int = 0
1717

1818
init() {

0 commit comments

Comments
 (0)