@@ -841,6 +841,45 @@ 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 :
863
+ typeDecl->getImplementationContext ()->getCurrentMembers ()) {
864
+ if (auto *var = dyn_cast<VarDecl>(member)) {
865
+ if (!callback (var))
866
+ return true ;
867
+ }
868
+
869
+ bool hadErrors = false ;
870
+ member->visitAuxiliaryDecls ([&](Decl *auxDecl) {
871
+ if (auto *auxVar = dyn_cast<VarDecl>(auxDecl)) {
872
+ hadErrors |= !callback (auxVar);
873
+ }
874
+ });
875
+
876
+ if (hadErrors)
877
+ return true ;
878
+ }
879
+
880
+ return false ;
881
+ }
882
+
844
883
bool AreAllStoredPropertiesDefaultInitableRequest::evaluate (
845
884
Evaluator &evaluator, NominalTypeDecl *decl) const {
846
885
assert (!hasClangImplementation (decl));
@@ -849,55 +888,61 @@ bool AreAllStoredPropertiesDefaultInitableRequest::evaluate(
849
888
decl->collectPropertiesInitializableByInitAccessors (
850
889
initializedViaInitAccessor);
851
890
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 ;
891
+ llvm::SmallPtrSet<PatternBindingDecl *, 4 > checked;
892
+ return !enumerateCurrentPropertiesAndAuxiliaryVars (
893
+ decl, [&](VarDecl *property) {
894
+ auto *pbd = property->getParentPatternBinding ();
895
+ if (!pbd || !checked.insert (pbd).second )
896
+ return true ;
897
+
898
+ // If a stored property lacks an initial value and if there is no way to
899
+ // synthesize an initial value (e.g. for an optional) then we suppress
900
+ // generation of the default initializer.
901
+
902
+ // Static variables are irrelevant.
903
+ if (pbd->isStatic ())
904
+ return true ;
905
+
906
+ for (auto idx : range (pbd->getNumPatternEntries ())) {
907
+ bool HasStorage = false ;
908
+ bool CheckDefaultInitializer = true ;
909
+ pbd->getPattern (idx)->forEachVariable ([&HasStorage,
910
+ &CheckDefaultInitializer,
911
+ &initializedViaInitAccessor](
912
+ VarDecl *VD) {
913
+ // If one of the bound variables is @NSManaged, go ahead no matter
914
+ // what.
915
+ if (VD->getAttrs ().hasAttribute <NSManagedAttr>())
916
+ CheckDefaultInitializer = false ;
917
+
918
+ // If this property is covered by one or more init accessor(s)
919
+ // check whether at least one of them is initializable.
920
+ auto initAccessorProperties =
921
+ llvm::make_range (initializedViaInitAccessor.equal_range (VD));
922
+ if (llvm::any_of (initAccessorProperties, [&](const auto &entry) {
923
+ auto *property = entry.second ->getParentPatternBinding ();
924
+ return property->isInitialized (0 );
925
+ }))
926
+ return ;
927
+
928
+ if (VD->hasStorageOrWrapsStorage ())
929
+ HasStorage = true ;
930
+ });
931
+
932
+ if (!HasStorage)
933
+ return true ;
934
+
935
+ if (pbd->isInitialized (idx))
936
+ return true ;
937
+
938
+ // If we cannot default initialize the property, we cannot
939
+ // synthesize a default initializer for the class.
940
+ if (CheckDefaultInitializer && !pbd->isDefaultInitializable ()) {
941
+ return false ;
942
+ }
943
+ }
944
+ return true ;
945
+ });
901
946
}
902
947
903
948
static bool areAllStoredPropertiesDefaultInitializable (Evaluator &eval,
@@ -1304,53 +1349,52 @@ HasMemberwiseInitRequest::evaluate(Evaluator &evaluator,
1304
1349
llvm::SmallPtrSet<VarDecl *, 4 > initializedProperties;
1305
1350
llvm::SmallVector<std::pair<VarDecl *, Identifier>> invalidOrderings;
1306
1351
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 ;
1352
+ if (enumerateCurrentPropertiesAndAuxiliaryVars (decl, [&](VarDecl *var) {
1353
+ if (var->isStatic ())
1354
+ return true ;
1316
1355
1317
- // Check whether use of init accessors results in access to uninitialized
1318
- // properties.
1356
+ if (var-> getOriginalWrappedProperty ())
1357
+ return true ;
1319
1358
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
- }
1359
+ if (!var->isMemberwiseInitialized (/* preferDeclaredProperties=*/ true ))
1360
+ return true ;
1327
1361
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 ;
1362
+ // Check whether use of init accessors results in access to
1363
+ // uninitialized properties.
1364
+ if (auto *initAccessor = var->getAccessor (AccessorKind::Init)) {
1365
+ // Make sure that all properties accessed by init accessor
1366
+ // are previously initialized.
1367
+ for (auto *property : initAccessor->getAccessedProperties ()) {
1368
+ if (!initializedProperties.count (property))
1369
+ invalidOrderings.push_back ({var, property->getName ()});
1370
+ }
1340
1371
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 ;
1372
+ // Record all of the properties initialized by calling init accessor.
1373
+ auto properties = initAccessor->getInitializedProperties ();
1374
+ initializedProperties.insert (var);
1375
+ initializedProperties.insert (properties.begin (), properties.end ());
1376
+ return true ;
1377
+ }
1345
1378
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
- }
1379
+ switch (initializedViaAccessor.count (var)) {
1380
+ // Not covered by an init accessor.
1381
+ case 0 :
1382
+ initializedProperties.insert (var);
1383
+ return true ;
1384
+
1385
+ // Covered by a single init accessor, we'll handle that
1386
+ // once we get to the property with init accessor.
1387
+ case 1 :
1388
+ return true ;
1389
+
1390
+ // Covered by more than one init accessor which means that we
1391
+ // cannot synthesize memberwise initializer due to intersecting
1392
+ // initializations.
1393
+ default :
1394
+ return false ;
1395
+ }
1396
+ }))
1397
+ return false ;
1354
1398
1355
1399
if (invalidOrderings.empty ())
1356
1400
return !initializedProperties.empty ();
0 commit comments