@@ -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
}
@@ -418,6 +470,7 @@ class LifetimeDependenceChecker {
418
470
}
419
471
420
472
std::string diagnosticQualifier () const {
473
+ auto *afd = cast<AbstractFunctionDecl>(decl);
421
474
if (afd->isImplicit ()) {
422
475
if (isInit ()) {
423
476
return " an implicit initializer" ;
@@ -462,6 +515,7 @@ class LifetimeDependenceChecker {
462
515
// initializers, the inout self parameter is actually considered the result
463
516
// type so is not handled here.
464
517
void diagnoseMissingSelfDependencies (DiagID diagID) {
518
+ auto *afd = cast<AbstractFunctionDecl>(decl);
465
519
if (!hasImplicitSelfParam ()) {
466
520
return ;
467
521
}
@@ -482,6 +536,7 @@ class LifetimeDependenceChecker {
482
536
}
483
537
484
538
void diagnoseMissingInoutDependencies (DiagID diagID) {
539
+ auto *afd = cast<AbstractFunctionDecl>(decl);
485
540
unsigned paramIndex = 0 ;
486
541
for (auto *param : *afd->getParameters ()) {
487
542
SWIFT_DEFER { paramIndex++; };
@@ -528,6 +583,7 @@ class LifetimeDependenceChecker {
528
583
529
584
bool isCompatibleWithOwnership (LifetimeDependenceKind kind, Type type,
530
585
ValueOwnership ownership) const {
586
+ auto *afd = cast<AbstractFunctionDecl>(decl);
531
587
if (kind == LifetimeDependenceKind::Inherit) {
532
588
return true ;
533
589
}
@@ -568,6 +624,7 @@ class LifetimeDependenceChecker {
568
624
};
569
625
570
626
TargetDeps createDeps (unsigned targetIndex) {
627
+ auto *afd = cast<AbstractFunctionDecl>(decl);
571
628
unsigned capacity = afd->hasImplicitSelfDecl ()
572
629
? (afd->getParameters ()->size () + 1 )
573
630
: afd->getParameters ()->size ();
@@ -598,6 +655,7 @@ class LifetimeDependenceChecker {
598
655
}
599
656
600
657
Type getResultOrYield () const {
658
+ auto *afd = cast<AbstractFunctionDecl>(decl);
601
659
if (auto *accessor = dyn_cast<AccessorDecl>(afd)) {
602
660
if (accessor->isCoroutine ()) {
603
661
auto yieldTyInContext = accessor->mapTypeIntoContext (
@@ -617,11 +675,12 @@ class LifetimeDependenceChecker {
617
675
618
676
std::optional<LifetimeDependenceKind>
619
677
getDependenceKindFromDescriptor (LifetimeDescriptor descriptor,
620
- ParamDecl *decl) {
678
+ ParamDecl *paramDecl) {
679
+ auto *afd = cast<AbstractFunctionDecl>(decl);
621
680
auto loc = descriptor.getLoc ();
622
- auto type = decl ->getTypeInContext ();
681
+ auto type = paramDecl ->getTypeInContext ();
623
682
auto parsedLifetimeKind = descriptor.getParsedLifetimeDependenceKind ();
624
- auto ownership = decl ->getValueOwnership ();
683
+ auto ownership = paramDecl ->getValueOwnership ();
625
684
auto loweredOwnership = ownership != ValueOwnership::Default
626
685
? ownership
627
686
: getLoweredOwnership (afd);
@@ -703,6 +762,7 @@ class LifetimeDependenceChecker {
703
762
// Finds the ParamDecl* and its index from a LifetimeDescriptor
704
763
std::optional<std::pair<ParamDecl *, unsigned >>
705
764
getParamDeclFromDescriptor (LifetimeDescriptor descriptor) {
765
+ auto *afd = cast<AbstractFunctionDecl>(decl);
706
766
switch (descriptor.getDescriptorKind ()) {
707
767
case LifetimeDescriptor::DescriptorKind::Named: {
708
768
unsigned paramIndex = 0 ;
@@ -751,6 +811,7 @@ class LifetimeDependenceChecker {
751
811
}
752
812
753
813
std::optional<ArrayRef<LifetimeDependenceInfo>> checkAttribute () {
814
+ auto *afd = cast<AbstractFunctionDecl>(decl);
754
815
SmallVector<LifetimeDependenceInfo, 1 > lifetimeDependencies;
755
816
llvm::SmallSet<unsigned , 1 > lifetimeDependentTargets;
756
817
auto lifetimeAttrs = afd->getAttrs ().getAttributes <LifetimeAttr>();
@@ -775,6 +836,7 @@ class LifetimeDependenceChecker {
775
836
776
837
std::optional<LifetimeDependenceInfo>
777
838
checkAttributeEntry (LifetimeEntry *entry) {
839
+ auto *afd = cast<AbstractFunctionDecl>(decl);
778
840
auto capacity = afd->hasImplicitSelfDecl ()
779
841
? (afd->getParameters ()->size () + 1 )
780
842
: afd->getParameters ()->size ();
@@ -896,6 +958,7 @@ class LifetimeDependenceChecker {
896
958
// / If the current function is a mutating method and 'self' is non-Escapable,
897
959
// / return 'self's ParamDecl.
898
960
bool isMutatingNonEscapableSelf () {
961
+ auto *afd = cast<AbstractFunctionDecl>(decl);
899
962
if (!hasImplicitSelfParam ())
900
963
return false ;
901
964
@@ -912,6 +975,7 @@ class LifetimeDependenceChecker {
912
975
913
976
// Infer method dependence: result depends on self. This includes _modify.
914
977
void inferNonEscapableResultOnSelf () {
978
+ auto *afd = cast<AbstractFunctionDecl>(decl);
915
979
Type selfTypeInContext = dc->getSelfTypeInContext ();
916
980
if (selfTypeInContext->hasError ()) {
917
981
return ;
@@ -963,6 +1027,7 @@ class LifetimeDependenceChecker {
963
1027
964
1028
std::optional<LifetimeDependenceKind>
965
1029
inferLifetimeDependenceKind (Type sourceType, ValueOwnership ownership) {
1030
+ auto *afd = cast<AbstractFunctionDecl>(decl);
966
1031
if (!sourceType->isEscapable ()) {
967
1032
return LifetimeDependenceKind::Inherit;
968
1033
}
@@ -985,6 +1050,7 @@ class LifetimeDependenceChecker {
985
1050
// to an implicit setter, because the implementation is simply an assignment
986
1051
// to stored property.
987
1052
void inferImplicitInit () {
1053
+ auto *afd = cast<AbstractFunctionDecl>(decl);
988
1054
if (afd->getParameters ()->size () == 0 ) {
989
1055
// Empty ~Escapable types can be implicitly initialized without any
990
1056
// dependencies. In SIL, implicit initializers become explicit. Set
@@ -1024,6 +1090,7 @@ class LifetimeDependenceChecker {
1024
1090
// inference if any exist, infer scoped dependency, or infer no
1025
1091
// dependency. Implicit setters for Escapable properties are not inferred.
1026
1092
void inferNonEscapableResultOnParam () {
1093
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1027
1094
// This is only called when there is no 'self' argument that can be the
1028
1095
// source of a dependence.
1029
1096
assert (!hasImplicitSelfParam ());
@@ -1073,6 +1140,7 @@ class LifetimeDependenceChecker {
1073
1140
// Lazy inference for .swiftinterface backward compatibility and
1074
1141
// experimentation. Inference cases can be added but not removed.
1075
1142
void lazillyInferNonEscapableResultOnParam () {
1143
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1076
1144
std::optional<unsigned > candidateParamIndex;
1077
1145
std::optional<LifetimeDependenceKind> candidateLifetimeKind;
1078
1146
unsigned paramIndex = 0 ;
@@ -1119,6 +1187,7 @@ class LifetimeDependenceChecker {
1119
1187
// Infer a mutating 'self' dependency when 'self' is non-Escapable and the
1120
1188
// result is 'void'.
1121
1189
void inferMutatingSelf () {
1190
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1122
1191
if (!isMutatingNonEscapableSelf ()) {
1123
1192
return ;
1124
1193
}
@@ -1144,6 +1213,7 @@ class LifetimeDependenceChecker {
1144
1213
1145
1214
// Infer a mutating accessor's non-Escapable 'self' dependencies.
1146
1215
void inferMutatingAccessor (AccessorDecl *accessor) {
1216
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1147
1217
if (!isImplicitOrSIL () && !useLazyInference ()) {
1148
1218
// Explicit setters require explicit lifetime dependencies.
1149
1219
return ;
@@ -1231,6 +1301,7 @@ class LifetimeDependenceChecker {
1231
1301
// Do not issue any diagnostics. This inference is triggered even when the
1232
1302
// feature is disabled!
1233
1303
void inferInoutParams () {
1304
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1234
1305
if (isMutatingNonEscapableSelf ()) {
1235
1306
return ;
1236
1307
}
@@ -1263,6 +1334,7 @@ class LifetimeDependenceChecker {
1263
1334
}
1264
1335
1265
1336
void inferUnambiguousInoutParams () {
1337
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1266
1338
if (afd->getParameters ()->size () != 1 ) {
1267
1339
return ;
1268
1340
}
@@ -1280,6 +1352,7 @@ class LifetimeDependenceChecker {
1280
1352
}
1281
1353
1282
1354
void inferBuiltin () {
1355
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1283
1356
// Normal inout parameter inference works for most generic Builtins.
1284
1357
inferUnambiguousInoutParams ();
1285
1358
if (!lifetimeDependencies.empty ()) {
@@ -1313,8 +1386,12 @@ class LifetimeDependenceChecker {
1313
1386
};
1314
1387
1315
1388
std::optional<llvm::ArrayRef<LifetimeDependenceInfo>>
1316
- LifetimeDependenceInfo::get (AbstractFunctionDecl *afd) {
1317
- return LifetimeDependenceChecker (afd).checkFuncDecl ();
1389
+ LifetimeDependenceInfo::get (ValueDecl *decl) {
1390
+ if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
1391
+ return LifetimeDependenceChecker (afd).checkFuncDecl ();
1392
+ }
1393
+ auto *eed = cast<EnumElementDecl>(decl);
1394
+ return LifetimeDependenceChecker (eed).checkEnumElementDecl ();
1318
1395
}
1319
1396
1320
1397
// This implements the logic for SIL type descriptors similar to source-level
0 commit comments