@@ -252,7 +252,7 @@ void LifetimeDependenceInfo::getConcatenatedData(
252
252
}
253
253
254
254
class LifetimeDependenceChecker {
255
- AbstractFunctionDecl *afd ;
255
+ ValueDecl *decl ;
256
256
257
257
DeclContext *dc;
258
258
ASTContext &ctx;
@@ -273,9 +273,8 @@ class LifetimeDependenceChecker {
273
273
bool performedDiagnostics = false ;
274
274
275
275
public:
276
- LifetimeDependenceChecker (AbstractFunctionDecl *afd):
277
- afd (afd), dc(afd->getDeclContext ()), ctx(dc->getASTContext ())
278
- {
276
+ LifetimeDependenceChecker (AbstractFunctionDecl *afd)
277
+ : decl(afd), dc(afd->getDeclContext ()), ctx(dc->getASTContext ()) {
279
278
auto resultTypeRepr = afd->getResultTypeRepr ();
280
279
returnLoc = resultTypeRepr ? resultTypeRepr->getLoc () : afd->getLoc ();
281
280
@@ -287,18 +286,25 @@ class LifetimeDependenceChecker {
287
286
}
288
287
}
289
288
289
+ LifetimeDependenceChecker (EnumElementDecl *eed)
290
+ : decl(eed), dc(eed->getDeclContext ()), ctx(dc->getASTContext ()) {
291
+ auto *paramList = eed->getParameterList ();
292
+ resultIndex = paramList ? eed->getParameterList ()->size () + 1 : 1 ;
293
+ }
294
+
290
295
std::optional<llvm::ArrayRef<LifetimeDependenceInfo>>
291
296
currentDependencies () const {
292
297
if (lifetimeDependencies.empty ()) {
293
298
return std::nullopt;
294
299
}
295
- return afd ->getASTContext ().AllocateCopy (lifetimeDependencies);
300
+ return decl ->getASTContext ().AllocateCopy (lifetimeDependencies);
296
301
}
297
302
298
303
std::optional<llvm::ArrayRef<LifetimeDependenceInfo>> checkFuncDecl () {
299
- assert (isa<FuncDecl>(afd ) || isa<ConstructorDecl>(afd ));
304
+ assert (isa<FuncDecl>(decl ) || isa<ConstructorDecl>(decl ));
300
305
assert (lifetimeDependencies.empty ());
301
306
307
+ auto *afd = cast<AbstractFunctionDecl>(decl);
302
308
// Handle Builtins first because, even though Builtins require
303
309
// LifetimeDependence, we don't force the experimental feature
304
310
// to be enabled when importing the Builtin module.
@@ -351,6 +357,52 @@ class LifetimeDependenceChecker {
351
357
return currentDependencies ();
352
358
}
353
359
360
+ std::optional<llvm::ArrayRef<LifetimeDependenceInfo>> checkEnumElementDecl () {
361
+ auto *eed = cast<EnumElementDecl>(decl);
362
+ auto *parentEnum = eed->getParentEnum ();
363
+ auto enumType =
364
+ parentEnum->mapTypeIntoContext (parentEnum->getDeclaredInterfaceType ());
365
+
366
+ // Add early bailout for imported enums.
367
+ if (parentEnum->hasClangNode ()) {
368
+ return std::nullopt;
369
+ }
370
+
371
+ // Escapable enum, bailout.
372
+ if (!isDiagnosedNonEscapable (enumType)) {
373
+ return std::nullopt;
374
+ }
375
+ auto *params = eed->getParameterList ();
376
+ // No payload, bailout.
377
+ if (!params) {
378
+ return std::nullopt;
379
+ }
380
+
381
+ auto resultIndex = params->size () + /* selfType*/ 1 ;
382
+ auto capacity = resultIndex + 1 ;
383
+ SmallBitVector inheritIndices (capacity);
384
+ SmallVector<LifetimeDependenceInfo, 1 > lifetimeDependencies;
385
+
386
+ // Add all indices of ~Escapable parameters as lifetime dependence sources.
387
+ for (size_t i = 0 ; i < params->size (); i++) {
388
+ auto paramType = params->get (i)->getTypeInContext ();
389
+ if (!isDiagnosedNonEscapable (paramType)) {
390
+ continue ;
391
+ }
392
+ inheritIndices.set (i);
393
+ }
394
+ if (inheritIndices.none ()) {
395
+ return std::nullopt;
396
+ }
397
+ auto lifetimeDependenceInfo = LifetimeDependenceInfo (
398
+ IndexSubset::get (eed->getASTContext (), inheritIndices), nullptr ,
399
+ resultIndex,
400
+ /* isImmortal*/ false );
401
+ lifetimeDependencies.push_back (lifetimeDependenceInfo);
402
+
403
+ return eed->getASTContext ().AllocateCopy (lifetimeDependencies);
404
+ }
405
+
354
406
protected:
355
407
template <typename ...ArgTypes>
356
408
InFlightDiagnostic diagnose (
@@ -367,9 +419,7 @@ class LifetimeDependenceChecker {
367
419
return ctx.Diags .diagnose (decl, Diagnostic (id, std::move (args)...));
368
420
}
369
421
370
- bool isInit () const {
371
- return isa<ConstructorDecl>(afd);
372
- }
422
+ bool isInit () const { return isa<ConstructorDecl>(decl); }
373
423
374
424
// For initializers, the implicit self parameter is ignored and instead shows
375
425
// up as the result type.
@@ -381,11 +431,13 @@ class LifetimeDependenceChecker {
381
431
// the extra formal self parameter, a dependency targeting the formal result
382
432
// index would incorrectly target the SIL metatype parameter.
383
433
bool hasImplicitSelfParam () const {
434
+ auto *afd = cast<AbstractFunctionDecl>(decl);
384
435
return !isInit () && afd->hasImplicitSelfDecl ();
385
436
}
386
437
387
438
// In SIL, implicit initializers and accessors become explicit.
388
439
bool isImplicitOrSIL () const {
440
+ auto *afd = cast<AbstractFunctionDecl>(decl);
389
441
if (afd->isImplicit ()) {
390
442
return true ;
391
443
}
@@ -404,7 +456,7 @@ class LifetimeDependenceChecker {
404
456
bool isInterfaceFile () const {
405
457
// TODO: remove this check once all compilers that are rev-locked to the
406
458
// stdlib print the 'copy' dependence kind in the interface (Aug '25)
407
- if (auto *sf = afd ->getParentSourceFile ()) {
459
+ if (auto *sf = decl-> getDeclContext () ->getParentSourceFile ()) {
408
460
if (sf->Kind == SourceFileKind::Interface) {
409
461
return true ;
410
462
}
@@ -419,6 +471,7 @@ class LifetimeDependenceChecker {
419
471
}
420
472
421
473
std::string diagnosticQualifier () const {
474
+ auto *afd = cast<AbstractFunctionDecl>(decl);
422
475
if (afd->isImplicit ()) {
423
476
if (isInit ()) {
424
477
return " an implicit initializer" ;
@@ -463,6 +516,7 @@ class LifetimeDependenceChecker {
463
516
// initializers, the inout self parameter is actually considered the result
464
517
// type so is not handled here.
465
518
void diagnoseMissingSelfDependencies (DiagID diagID) {
519
+ auto *afd = cast<AbstractFunctionDecl>(decl);
466
520
if (!hasImplicitSelfParam ()) {
467
521
return ;
468
522
}
@@ -483,6 +537,7 @@ class LifetimeDependenceChecker {
483
537
}
484
538
485
539
void diagnoseMissingInoutDependencies (DiagID diagID) {
540
+ auto *afd = cast<AbstractFunctionDecl>(decl);
486
541
unsigned paramIndex = 0 ;
487
542
for (auto *param : *afd->getParameters ()) {
488
543
SWIFT_DEFER { paramIndex++; };
@@ -529,6 +584,7 @@ class LifetimeDependenceChecker {
529
584
530
585
bool isCompatibleWithOwnership (LifetimeDependenceKind kind, Type type,
531
586
ValueOwnership ownership) const {
587
+ auto *afd = cast<AbstractFunctionDecl>(decl);
532
588
if (kind == LifetimeDependenceKind::Inherit) {
533
589
return true ;
534
590
}
@@ -569,6 +625,7 @@ class LifetimeDependenceChecker {
569
625
};
570
626
571
627
TargetDeps createDeps (unsigned targetIndex) {
628
+ auto *afd = cast<AbstractFunctionDecl>(decl);
572
629
unsigned capacity = afd->hasImplicitSelfDecl ()
573
630
? (afd->getParameters ()->size () + 1 )
574
631
: afd->getParameters ()->size ();
@@ -599,6 +656,7 @@ class LifetimeDependenceChecker {
599
656
}
600
657
601
658
Type getResultOrYield () const {
659
+ auto *afd = cast<AbstractFunctionDecl>(decl);
602
660
if (auto *accessor = dyn_cast<AccessorDecl>(afd)) {
603
661
if (accessor->isCoroutine ()) {
604
662
auto yieldTyInContext = accessor->mapTypeIntoContext (
@@ -618,11 +676,12 @@ class LifetimeDependenceChecker {
618
676
619
677
std::optional<LifetimeDependenceKind>
620
678
getDependenceKindFromDescriptor (LifetimeDescriptor descriptor,
621
- ParamDecl *decl) {
679
+ ParamDecl *paramDecl) {
680
+ auto *afd = cast<AbstractFunctionDecl>(decl);
622
681
auto loc = descriptor.getLoc ();
623
- auto type = decl ->getTypeInContext ();
682
+ auto type = paramDecl ->getTypeInContext ();
624
683
auto parsedLifetimeKind = descriptor.getParsedLifetimeDependenceKind ();
625
- auto ownership = decl ->getValueOwnership ();
684
+ auto ownership = paramDecl ->getValueOwnership ();
626
685
auto loweredOwnership = ownership != ValueOwnership::Default
627
686
? ownership
628
687
: getLoweredOwnership (afd);
@@ -704,6 +763,7 @@ class LifetimeDependenceChecker {
704
763
// Finds the ParamDecl* and its index from a LifetimeDescriptor
705
764
std::optional<std::pair<ParamDecl *, unsigned >>
706
765
getParamDeclFromDescriptor (LifetimeDescriptor descriptor) {
766
+ auto *afd = cast<AbstractFunctionDecl>(decl);
707
767
switch (descriptor.getDescriptorKind ()) {
708
768
case LifetimeDescriptor::DescriptorKind::Named: {
709
769
unsigned paramIndex = 0 ;
@@ -752,6 +812,7 @@ class LifetimeDependenceChecker {
752
812
}
753
813
754
814
std::optional<ArrayRef<LifetimeDependenceInfo>> checkAttribute () {
815
+ auto *afd = cast<AbstractFunctionDecl>(decl);
755
816
SmallVector<LifetimeDependenceInfo, 1 > lifetimeDependencies;
756
817
llvm::SmallSet<unsigned , 1 > lifetimeDependentTargets;
757
818
auto lifetimeAttrs = afd->getAttrs ().getAttributes <LifetimeAttr>();
@@ -776,6 +837,7 @@ class LifetimeDependenceChecker {
776
837
777
838
std::optional<LifetimeDependenceInfo>
778
839
checkAttributeEntry (LifetimeEntry *entry) {
840
+ auto *afd = cast<AbstractFunctionDecl>(decl);
779
841
auto capacity = afd->hasImplicitSelfDecl ()
780
842
? (afd->getParameters ()->size () + 1 )
781
843
: afd->getParameters ()->size ();
@@ -897,6 +959,7 @@ class LifetimeDependenceChecker {
897
959
// / If the current function is a mutating method and 'self' is non-Escapable,
898
960
// / return 'self's ParamDecl.
899
961
bool isMutatingNonEscapableSelf () {
962
+ auto *afd = cast<AbstractFunctionDecl>(decl);
900
963
if (!hasImplicitSelfParam ())
901
964
return false ;
902
965
@@ -914,6 +977,7 @@ class LifetimeDependenceChecker {
914
977
// Infer method dependence of result on self for
915
978
// methods, getters, and _modify accessors.
916
979
void inferNonEscapableResultOnSelf () {
980
+ auto *afd = cast<AbstractFunctionDecl>(decl);
917
981
Type selfTypeInContext = dc->getSelfTypeInContext ();
918
982
if (selfTypeInContext->hasError ()) {
919
983
return ;
@@ -980,6 +1044,7 @@ class LifetimeDependenceChecker {
980
1044
// stored property (for getters or initializers).
981
1045
std::optional<LifetimeDependenceKind>
982
1046
inferLifetimeDependenceKind (Type sourceType, ValueOwnership ownership) {
1047
+ auto *afd = cast<AbstractFunctionDecl>(decl);
983
1048
if (!sourceType->isEscapable ()) {
984
1049
return LifetimeDependenceKind::Inherit;
985
1050
}
@@ -1003,6 +1068,7 @@ class LifetimeDependenceChecker {
1003
1068
// to an implicit setter, because the implementation is simply an assignment
1004
1069
// to stored property.
1005
1070
void inferImplicitInit () {
1071
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1006
1072
if (afd->getParameters ()->size () == 0 ) {
1007
1073
// Empty ~Escapable types can be implicitly initialized without any
1008
1074
// dependencies. In SIL, implicit initializers become explicit. Set
@@ -1042,6 +1108,7 @@ class LifetimeDependenceChecker {
1042
1108
// inference if any exist, infer scoped dependency, or infer no
1043
1109
// dependency. Implicit setters for Escapable properties are not inferred.
1044
1110
void inferNonEscapableResultOnParam () {
1111
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1045
1112
// This is only called when there is no 'self' argument that can be the
1046
1113
// source of a dependence.
1047
1114
assert (!hasImplicitSelfParam ());
@@ -1091,6 +1158,7 @@ class LifetimeDependenceChecker {
1091
1158
// Lazy inference for .swiftinterface backward compatibility and
1092
1159
// experimentation. Inference cases can be added but not removed.
1093
1160
void lazillyInferNonEscapableResultOnParam () {
1161
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1094
1162
std::optional<unsigned > candidateParamIndex;
1095
1163
std::optional<LifetimeDependenceKind> candidateLifetimeKind;
1096
1164
unsigned paramIndex = 0 ;
@@ -1137,6 +1205,7 @@ class LifetimeDependenceChecker {
1137
1205
// Infer a mutating 'self' dependency when 'self' is non-Escapable and the
1138
1206
// result is 'void'.
1139
1207
void inferMutatingSelf () {
1208
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1140
1209
if (!isMutatingNonEscapableSelf ()) {
1141
1210
return ;
1142
1211
}
@@ -1166,7 +1235,7 @@ class LifetimeDependenceChecker {
1166
1235
// Infer dependence for an accessor whose non-escapable result depends on
1167
1236
// self. This includes _read and _modify.
1168
1237
void inferAccessor (AccessorDecl *accessor, Type selfTypeInContext) {
1169
- // Explicit accessors require explicit lifetime dependencies.
1238
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1170
1239
if (!isImplicitOrSIL () && !useLazyInference ()) {
1171
1240
return ;
1172
1241
}
@@ -1205,6 +1274,7 @@ class LifetimeDependenceChecker {
1205
1274
break ;
1206
1275
case AccessorKind::Set: {
1207
1276
const unsigned newValIdx = 0 ;
1277
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1208
1278
auto *param = afd->getParameters ()->get (newValIdx);
1209
1279
Type paramTypeInContext =
1210
1280
afd->mapTypeIntoContext (param->getInterfaceType ());
@@ -1285,6 +1355,7 @@ class LifetimeDependenceChecker {
1285
1355
}
1286
1356
}
1287
1357
}
1358
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1288
1359
// Either a Get or Modify without any wrapped accessor. Handle these like a
1289
1360
// read of the stored property.
1290
1361
return inferLifetimeDependenceKind (
@@ -1315,6 +1386,7 @@ class LifetimeDependenceChecker {
1315
1386
// Do not issue any diagnostics. This inference is triggered even when the
1316
1387
// feature is disabled!
1317
1388
void inferInoutParams () {
1389
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1318
1390
if (isMutatingNonEscapableSelf ()) {
1319
1391
return ;
1320
1392
}
@@ -1347,6 +1419,7 @@ class LifetimeDependenceChecker {
1347
1419
}
1348
1420
1349
1421
void inferUnambiguousInoutParams () {
1422
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1350
1423
if (afd->getParameters ()->size () != 1 ) {
1351
1424
return ;
1352
1425
}
@@ -1364,6 +1437,7 @@ class LifetimeDependenceChecker {
1364
1437
}
1365
1438
1366
1439
void inferBuiltin () {
1440
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1367
1441
// Normal inout parameter inference works for most generic Builtins.
1368
1442
inferUnambiguousInoutParams ();
1369
1443
if (!lifetimeDependencies.empty ()) {
@@ -1397,8 +1471,12 @@ class LifetimeDependenceChecker {
1397
1471
};
1398
1472
1399
1473
std::optional<llvm::ArrayRef<LifetimeDependenceInfo>>
1400
- LifetimeDependenceInfo::get (AbstractFunctionDecl *afd) {
1401
- return LifetimeDependenceChecker (afd).checkFuncDecl ();
1474
+ LifetimeDependenceInfo::get (ValueDecl *decl) {
1475
+ if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
1476
+ return LifetimeDependenceChecker (afd).checkFuncDecl ();
1477
+ }
1478
+ auto *eed = cast<EnumElementDecl>(decl);
1479
+ return LifetimeDependenceChecker (eed).checkEnumElementDecl ();
1402
1480
}
1403
1481
1404
1482
// This implements the logic for SIL type descriptors similar to source-level
0 commit comments