@@ -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,62 +888,68 @@ 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
- }
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
+ property->isDefaultInitializable ();
926
+ }))
927
+ return ;
928
+
929
+ if (VD->hasStorageOrWrapsStorage ())
930
+ HasStorage = true ;
931
+
932
+ // Treat an init accessor property that doesn't initialize other
933
+ // properties as stored for initialization purposes.
934
+ if (auto *initAccessor = VD->getAccessor (AccessorKind::Init)) {
935
+ HasStorage |= initAccessor->getInitializedProperties ().empty ();
936
+ }
937
+ });
861
938
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
- property->isDefaultInitializable ();
882
- }))
883
- return ;
884
-
885
- if (VD->hasStorageOrWrapsStorage ())
886
- HasStorage = true ;
887
-
888
- // Treat an init accessor property that doesn't initialize other
889
- // properties as stored for initialization purposes.
890
- if (auto *initAccessor = VD->getAccessor (AccessorKind::Init)) {
891
- HasStorage |= initAccessor->getInitializedProperties ().empty ();
892
- }
893
- });
894
-
895
- if (!HasStorage) continue ;
896
-
897
- if (pbd->isInitialized (idx)) continue ;
898
-
899
- // If we cannot default initialize the property, we cannot
900
- // synthesize a default initializer for the class.
901
- if (CheckDefaultInitializer && !pbd->isDefaultInitializable ())
902
- return false ;
903
- }
904
- }
905
- }
939
+ if (!HasStorage)
940
+ return true ;
906
941
907
- return true ;
942
+ if (pbd->isInitialized (idx))
943
+ return true ;
944
+
945
+ // If we cannot default initialize the property, we cannot
946
+ // synthesize a default initializer for the class.
947
+ if (CheckDefaultInitializer && !pbd->isDefaultInitializable ()) {
948
+ return false ;
949
+ }
950
+ }
951
+ return true ;
952
+ });
908
953
}
909
954
910
955
static bool areAllStoredPropertiesDefaultInitializable (Evaluator &eval,
@@ -1311,53 +1356,52 @@ HasMemberwiseInitRequest::evaluate(Evaluator &evaluator,
1311
1356
llvm::SmallPtrSet<VarDecl *, 4 > initializedProperties;
1312
1357
llvm::SmallVector<std::pair<VarDecl *, Identifier>> invalidOrderings;
1313
1358
1314
- for (auto *member : decl->getMembers ()) {
1315
- if (auto *var = dyn_cast<VarDecl>(member)) {
1316
- // If this is a backing storage property for a property wrapper,
1317
- // skip it.
1318
- if (var->getOriginalWrappedProperty ())
1319
- continue ;
1320
-
1321
- if (!var->isMemberwiseInitialized (/* preferDeclaredProperties=*/ true ))
1322
- continue ;
1359
+ if (enumerateCurrentPropertiesAndAuxiliaryVars (decl, [&](VarDecl *var) {
1360
+ if (var->isStatic ())
1361
+ return true ;
1323
1362
1324
- // Check whether use of init accessors results in access to uninitialized
1325
- // properties.
1363
+ if (var-> getOriginalWrappedProperty ())
1364
+ return true ;
1326
1365
1327
- if (auto *initAccessor = var->getAccessor (AccessorKind::Init)) {
1328
- // Make sure that all properties accessed by init accessor
1329
- // are previously initialized.
1330
- for (auto *property : initAccessor->getAccessedProperties ()) {
1331
- if (!initializedProperties.count (property))
1332
- invalidOrderings.push_back ({var, property->getName ()});
1333
- }
1366
+ if (!var->isMemberwiseInitialized (/* preferDeclaredProperties=*/ true ))
1367
+ return true ;
1334
1368
1335
- // Record all of the properties initialized by calling init accessor.
1336
- auto properties = initAccessor->getInitializedProperties ();
1337
- initializedProperties.insert (var);
1338
- initializedProperties.insert (properties.begin (), properties.end ());
1339
- continue ;
1340
- }
1341
-
1342
- switch (initializedViaAccessor.count (var)) {
1343
- // Not covered by an init accessor.
1344
- case 0 :
1345
- initializedProperties.insert (var);
1346
- continue ;
1369
+ // Check whether use of init accessors results in access to
1370
+ // uninitialized properties.
1371
+ if (auto *initAccessor = var->getAccessor (AccessorKind::Init)) {
1372
+ // Make sure that all properties accessed by init accessor
1373
+ // are previously initialized.
1374
+ for (auto *property : initAccessor->getAccessedProperties ()) {
1375
+ if (!initializedProperties.count (property))
1376
+ invalidOrderings.push_back ({var, property->getName ()});
1377
+ }
1347
1378
1348
- // Covered by a single init accessor, we'll handle that
1349
- // once we get to the property with init accessor.
1350
- case 1 :
1351
- continue ;
1379
+ // Record all of the properties initialized by calling init accessor.
1380
+ auto properties = initAccessor->getInitializedProperties ();
1381
+ initializedProperties.insert (var);
1382
+ initializedProperties.insert (properties.begin (), properties.end ());
1383
+ return true ;
1384
+ }
1352
1385
1353
- // Covered by more than one init accessor which means that we
1354
- // cannot synthesize memberwise initializer due to intersecting
1355
- // initializations.
1356
- default :
1357
- return false ;
1358
- }
1359
- }
1360
- }
1386
+ switch (initializedViaAccessor.count (var)) {
1387
+ // Not covered by an init accessor.
1388
+ case 0 :
1389
+ initializedProperties.insert (var);
1390
+ return true ;
1391
+
1392
+ // Covered by a single init accessor, we'll handle that
1393
+ // once we get to the property with init accessor.
1394
+ case 1 :
1395
+ return true ;
1396
+
1397
+ // Covered by more than one init accessor which means that we
1398
+ // cannot synthesize memberwise initializer due to intersecting
1399
+ // initializations.
1400
+ default :
1401
+ return false ;
1402
+ }
1403
+ }))
1404
+ return false ;
1361
1405
1362
1406
if (invalidOrderings.empty ())
1363
1407
return !initializedProperties.empty ();
0 commit comments