@@ -841,6 +841,44 @@ static void diagnoseMissingRequiredInitializer(
841
841
diag::required_initializer_here);
842
842
}
843
843
844
+ // / FIXME: This is temporary until we come up with a way to overcome circularity
845
+ // / issues.
846
+ // /
847
+ // / This method is intended to be used only in places that expect
848
+ // / lazy and property wrapper backing storage synthesis has happened
849
+ // / or can tolerate absence of such properties.
850
+ // /
851
+ // / \param typeDecl The nominal type to enumerate current properties and their
852
+ // / auxiliary vars for.
853
+ // /
854
+ // / \param callback The callback to be called for each property and auxiliary
855
+ // / var associated with the given type. The callback should return `true` to
856
+ // / indicate that enumeration should continue and `false` otherwise.
857
+ // /
858
+ // / \returns true which indicates "failure" if callback returns `false`
859
+ // / at least once.
860
+ static bool enumerateCurrentPropertiesAndAuxiliaryVars (
861
+ NominalTypeDecl *typeDecl, llvm::function_ref<bool (VarDecl *)> callback) {
862
+ for (auto *member : typeDecl->getCurrentMembers ()) {
863
+ if (auto *var = dyn_cast<VarDecl>(member)) {
864
+ if (!callback (var))
865
+ return true ;
866
+ }
867
+
868
+ bool hadErrors = false ;
869
+ member->visitAuxiliaryDecls ([&](Decl *auxDecl) {
870
+ if (auto *auxVar = dyn_cast<VarDecl>(auxDecl)) {
871
+ hadErrors |= !callback (auxVar);
872
+ }
873
+ });
874
+
875
+ if (hadErrors)
876
+ return true ;
877
+ }
878
+
879
+ return false ;
880
+ }
881
+
844
882
bool AreAllStoredPropertiesDefaultInitableRequest::evaluate (
845
883
Evaluator &evaluator, NominalTypeDecl *decl) const {
846
884
assert (!hasClangImplementation (decl));
@@ -849,55 +887,61 @@ bool AreAllStoredPropertiesDefaultInitableRequest::evaluate(
849
887
decl->collectPropertiesInitializableByInitAccessors (
850
888
initializedViaInitAccessor);
851
889
852
- for (auto member : decl->getImplementationContext ()->getMembers ()) {
853
- // If a stored property lacks an initial value and if there is no way to
854
- // synthesize an initial value (e.g. for an optional) then we suppress
855
- // generation of the default initializer.
856
- if (auto pbd = dyn_cast<PatternBindingDecl>(member)) {
857
- // Static variables are irrelevant.
858
- if (pbd->isStatic ()) {
859
- continue ;
860
- }
861
-
862
- for (auto idx : range (pbd->getNumPatternEntries ())) {
863
- bool HasStorage = false ;
864
- bool CheckDefaultInitializer = true ;
865
- pbd->getPattern (idx)->forEachVariable (
866
- [&HasStorage, &CheckDefaultInitializer,
867
- &initializedViaInitAccessor](VarDecl *VD) {
868
- // If one of the bound variables is @NSManaged, go ahead no matter
869
- // what.
870
- if (VD->getAttrs ().hasAttribute <NSManagedAttr>())
871
- CheckDefaultInitializer = false ;
872
-
873
- // If this property is covered by one or more init accessor(s)
874
- // check whether at least one of them is initializable.
875
- auto initAccessorProperties =
876
- llvm::make_range (initializedViaInitAccessor.equal_range (VD));
877
- if (llvm::any_of (initAccessorProperties, [&](const auto &entry) {
878
- auto *property =
879
- entry.second ->getParentPatternBinding ();
880
- return property->isInitialized (0 );
881
- }))
882
- return ;
883
-
884
- if (VD->hasStorageOrWrapsStorage ())
885
- HasStorage = true ;
886
- });
887
-
888
- if (!HasStorage) continue ;
889
-
890
- if (pbd->isInitialized (idx)) continue ;
891
-
892
- // If we cannot default initialize the property, we cannot
893
- // synthesize a default initializer for the class.
894
- if (CheckDefaultInitializer && !pbd->isDefaultInitializable ())
895
- return false ;
896
- }
897
- }
898
- }
899
-
900
- return true ;
890
+ llvm::SmallPtrSet<PatternBindingDecl *, 4 > checked;
891
+ return !enumerateCurrentPropertiesAndAuxiliaryVars (
892
+ decl, [&](VarDecl *property) {
893
+ auto *pbd = property->getParentPatternBinding ();
894
+ if (!pbd || !checked.insert (pbd).second )
895
+ return true ;
896
+
897
+ // If a stored property lacks an initial value and if there is no way to
898
+ // synthesize an initial value (e.g. for an optional) then we suppress
899
+ // generation of the default initializer.
900
+
901
+ // Static variables are irrelevant.
902
+ if (pbd->isStatic ())
903
+ return true ;
904
+
905
+ for (auto idx : range (pbd->getNumPatternEntries ())) {
906
+ bool HasStorage = false ;
907
+ bool CheckDefaultInitializer = true ;
908
+ pbd->getPattern (idx)->forEachVariable ([&HasStorage,
909
+ &CheckDefaultInitializer,
910
+ &initializedViaInitAccessor](
911
+ VarDecl *VD) {
912
+ // If one of the bound variables is @NSManaged, go ahead no matter
913
+ // what.
914
+ if (VD->getAttrs ().hasAttribute <NSManagedAttr>())
915
+ CheckDefaultInitializer = false ;
916
+
917
+ // If this property is covered by one or more init accessor(s)
918
+ // check whether at least one of them is initializable.
919
+ auto initAccessorProperties =
920
+ llvm::make_range (initializedViaInitAccessor.equal_range (VD));
921
+ if (llvm::any_of (initAccessorProperties, [&](const auto &entry) {
922
+ auto *property = entry.second ->getParentPatternBinding ();
923
+ return property->isInitialized (0 );
924
+ }))
925
+ return ;
926
+
927
+ if (VD->hasStorageOrWrapsStorage ())
928
+ HasStorage = true ;
929
+ });
930
+
931
+ if (!HasStorage)
932
+ return true ;
933
+
934
+ if (pbd->isInitialized (idx))
935
+ return true ;
936
+
937
+ // If we cannot default initialize the property, we cannot
938
+ // synthesize a default initializer for the class.
939
+ if (CheckDefaultInitializer && !pbd->isDefaultInitializable ()) {
940
+ return false ;
941
+ }
942
+ }
943
+ return true ;
944
+ });
901
945
}
902
946
903
947
static bool areAllStoredPropertiesDefaultInitializable (Evaluator &eval,
@@ -1304,53 +1348,52 @@ HasMemberwiseInitRequest::evaluate(Evaluator &evaluator,
1304
1348
llvm::SmallPtrSet<VarDecl *, 4 > initializedProperties;
1305
1349
llvm::SmallVector<std::pair<VarDecl *, Identifier>> invalidOrderings;
1306
1350
1307
- for (auto *member : decl->getMembers ()) {
1308
- if (auto *var = dyn_cast<VarDecl>(member)) {
1309
- // If this is a backing storage property for a property wrapper,
1310
- // skip it.
1311
- if (var->getOriginalWrappedProperty ())
1312
- continue ;
1313
-
1314
- if (!var->isMemberwiseInitialized (/* preferDeclaredProperties=*/ true ))
1315
- continue ;
1351
+ if (enumerateCurrentPropertiesAndAuxiliaryVars (decl, [&](VarDecl *var) {
1352
+ if (var->isStatic ())
1353
+ return true ;
1316
1354
1317
- // Check whether use of init accessors results in access to uninitialized
1318
- // properties.
1355
+ if (var-> getOriginalWrappedProperty ())
1356
+ return true ;
1319
1357
1320
- if (auto *initAccessor = var->getAccessor (AccessorKind::Init)) {
1321
- // Make sure that all properties accessed by init accessor
1322
- // are previously initialized.
1323
- for (auto *property : initAccessor->getAccessedProperties ()) {
1324
- if (!initializedProperties.count (property))
1325
- invalidOrderings.push_back ({var, property->getName ()});
1326
- }
1358
+ if (!var->isMemberwiseInitialized (/* preferDeclaredProperties=*/ true ))
1359
+ return true ;
1327
1360
1328
- // Record all of the properties initialized by calling init accessor.
1329
- auto properties = initAccessor->getInitializedProperties ();
1330
- initializedProperties.insert (var);
1331
- initializedProperties.insert (properties.begin (), properties.end ());
1332
- continue ;
1333
- }
1334
-
1335
- switch (initializedViaAccessor.count (var)) {
1336
- // Not covered by an init accessor.
1337
- case 0 :
1338
- initializedProperties.insert (var);
1339
- continue ;
1361
+ // Check whether use of init accessors results in access to
1362
+ // uninitialized properties.
1363
+ if (auto *initAccessor = var->getAccessor (AccessorKind::Init)) {
1364
+ // Make sure that all properties accessed by init accessor
1365
+ // are previously initialized.
1366
+ for (auto *property : initAccessor->getAccessedProperties ()) {
1367
+ if (!initializedProperties.count (property))
1368
+ invalidOrderings.push_back ({var, property->getName ()});
1369
+ }
1340
1370
1341
- // Covered by a single init accessor, we'll handle that
1342
- // once we get to the property with init accessor.
1343
- case 1 :
1344
- continue ;
1371
+ // Record all of the properties initialized by calling init accessor.
1372
+ auto properties = initAccessor->getInitializedProperties ();
1373
+ initializedProperties.insert (var);
1374
+ initializedProperties.insert (properties.begin (), properties.end ());
1375
+ return true ;
1376
+ }
1345
1377
1346
- // Covered by more than one init accessor which means that we
1347
- // cannot synthesize memberwise initializer due to intersecting
1348
- // initializations.
1349
- default :
1350
- return false ;
1351
- }
1352
- }
1353
- }
1378
+ switch (initializedViaAccessor.count (var)) {
1379
+ // Not covered by an init accessor.
1380
+ case 0 :
1381
+ initializedProperties.insert (var);
1382
+ return true ;
1383
+
1384
+ // Covered by a single init accessor, we'll handle that
1385
+ // once we get to the property with init accessor.
1386
+ case 1 :
1387
+ return true ;
1388
+
1389
+ // Covered by more than one init accessor which means that we
1390
+ // cannot synthesize memberwise initializer due to intersecting
1391
+ // initializations.
1392
+ default :
1393
+ return false ;
1394
+ }
1395
+ }))
1396
+ return false ;
1354
1397
1355
1398
if (invalidOrderings.empty ())
1356
1399
return !initializedProperties.empty ();
0 commit comments