@@ -252,7 +252,7 @@ void LifetimeDependenceInfo::getConcatenatedData(
252252}
253253
254254class LifetimeDependenceChecker {
255- AbstractFunctionDecl *afd ;
255+ ValueDecl *decl ;
256256
257257 DeclContext *dc;
258258 ASTContext &ctx;
@@ -273,9 +273,8 @@ class LifetimeDependenceChecker {
273273 bool performedDiagnostics = false ;
274274
275275public:
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 ()) {
279278 auto resultTypeRepr = afd->getResultTypeRepr ();
280279 returnLoc = resultTypeRepr ? resultTypeRepr->getLoc () : afd->getLoc ();
281280
@@ -287,18 +286,25 @@ class LifetimeDependenceChecker {
287286 }
288287 }
289288
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+
290295 std::optional<llvm::ArrayRef<LifetimeDependenceInfo>>
291296 currentDependencies () const {
292297 if (lifetimeDependencies.empty ()) {
293298 return std::nullopt ;
294299 }
295- return afd ->getASTContext ().AllocateCopy (lifetimeDependencies);
300+ return decl ->getASTContext ().AllocateCopy (lifetimeDependencies);
296301 }
297302
298303 std::optional<llvm::ArrayRef<LifetimeDependenceInfo>> checkFuncDecl () {
299- assert (isa<FuncDecl>(afd ) || isa<ConstructorDecl>(afd ));
304+ assert (isa<FuncDecl>(decl ) || isa<ConstructorDecl>(decl ));
300305 assert (lifetimeDependencies.empty ());
301306
307+ auto *afd = cast<AbstractFunctionDecl>(decl);
302308 // Handle Builtins first because, even though Builtins require
303309 // LifetimeDependence, we don't force the experimental feature
304310 // to be enabled when importing the Builtin module.
@@ -351,6 +357,52 @@ class LifetimeDependenceChecker {
351357 return currentDependencies ();
352358 }
353359
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+
354406protected:
355407 template <typename ...ArgTypes>
356408 InFlightDiagnostic diagnose (
@@ -367,9 +419,7 @@ class LifetimeDependenceChecker {
367419 return ctx.Diags .diagnose (decl, Diagnostic (id, std::move (args)...));
368420 }
369421
370- bool isInit () const {
371- return isa<ConstructorDecl>(afd);
372- }
422+ bool isInit () const { return isa<ConstructorDecl>(decl); }
373423
374424 // For initializers, the implicit self parameter is ignored and instead shows
375425 // up as the result type.
@@ -381,11 +431,13 @@ class LifetimeDependenceChecker {
381431 // the extra formal self parameter, a dependency targeting the formal result
382432 // index would incorrectly target the SIL metatype parameter.
383433 bool hasImplicitSelfParam () const {
434+ auto *afd = cast<AbstractFunctionDecl>(decl);
384435 return !isInit () && afd->hasImplicitSelfDecl ();
385436 }
386437
387438 // In SIL, implicit initializers and accessors become explicit.
388439 bool isImplicitOrSIL () const {
440+ auto *afd = cast<AbstractFunctionDecl>(decl);
389441 if (afd->isImplicit ()) {
390442 return true ;
391443 }
@@ -404,7 +456,7 @@ class LifetimeDependenceChecker {
404456 bool isInterfaceFile () const {
405457 // TODO: remove this check once all compilers that are rev-locked to the
406458 // stdlib print the 'copy' dependence kind in the interface (Aug '25)
407- if (auto *sf = afd ->getParentSourceFile ()) {
459+ if (auto *sf = decl-> getDeclContext () ->getParentSourceFile ()) {
408460 if (sf->Kind == SourceFileKind::Interface) {
409461 return true ;
410462 }
@@ -418,6 +470,7 @@ class LifetimeDependenceChecker {
418470 }
419471
420472 std::string diagnosticQualifier () const {
473+ auto *afd = cast<AbstractFunctionDecl>(decl);
421474 if (afd->isImplicit ()) {
422475 if (isInit ()) {
423476 return " an implicit initializer" ;
@@ -462,6 +515,7 @@ class LifetimeDependenceChecker {
462515 // initializers, the inout self parameter is actually considered the result
463516 // type so is not handled here.
464517 void diagnoseMissingSelfDependencies (DiagID diagID) {
518+ auto *afd = cast<AbstractFunctionDecl>(decl);
465519 if (!hasImplicitSelfParam ()) {
466520 return ;
467521 }
@@ -482,6 +536,7 @@ class LifetimeDependenceChecker {
482536 }
483537
484538 void diagnoseMissingInoutDependencies (DiagID diagID) {
539+ auto *afd = cast<AbstractFunctionDecl>(decl);
485540 unsigned paramIndex = 0 ;
486541 for (auto *param : *afd->getParameters ()) {
487542 SWIFT_DEFER { paramIndex++; };
@@ -528,6 +583,7 @@ class LifetimeDependenceChecker {
528583
529584 bool isCompatibleWithOwnership (LifetimeDependenceKind kind, Type type,
530585 ValueOwnership ownership) const {
586+ auto *afd = cast<AbstractFunctionDecl>(decl);
531587 if (kind == LifetimeDependenceKind::Inherit) {
532588 return true ;
533589 }
@@ -568,6 +624,7 @@ class LifetimeDependenceChecker {
568624 };
569625
570626 TargetDeps createDeps (unsigned targetIndex) {
627+ auto *afd = cast<AbstractFunctionDecl>(decl);
571628 unsigned capacity = afd->hasImplicitSelfDecl ()
572629 ? (afd->getParameters ()->size () + 1 )
573630 : afd->getParameters ()->size ();
@@ -598,6 +655,7 @@ class LifetimeDependenceChecker {
598655 }
599656
600657 Type getResultOrYield () const {
658+ auto *afd = cast<AbstractFunctionDecl>(decl);
601659 if (auto *accessor = dyn_cast<AccessorDecl>(afd)) {
602660 if (accessor->isCoroutine ()) {
603661 auto yieldTyInContext = accessor->mapTypeIntoContext (
@@ -617,11 +675,12 @@ class LifetimeDependenceChecker {
617675
618676 std::optional<LifetimeDependenceKind>
619677 getDependenceKindFromDescriptor (LifetimeDescriptor descriptor,
620- ParamDecl *decl) {
678+ ParamDecl *paramDecl) {
679+ auto *afd = cast<AbstractFunctionDecl>(decl);
621680 auto loc = descriptor.getLoc ();
622- auto type = decl ->getTypeInContext ();
681+ auto type = paramDecl ->getTypeInContext ();
623682 auto parsedLifetimeKind = descriptor.getParsedLifetimeDependenceKind ();
624- auto ownership = decl ->getValueOwnership ();
683+ auto ownership = paramDecl ->getValueOwnership ();
625684 auto loweredOwnership = ownership != ValueOwnership::Default
626685 ? ownership
627686 : getLoweredOwnership (afd);
@@ -703,6 +762,7 @@ class LifetimeDependenceChecker {
703762 // Finds the ParamDecl* and its index from a LifetimeDescriptor
704763 std::optional<std::pair<ParamDecl *, unsigned >>
705764 getParamDeclFromDescriptor (LifetimeDescriptor descriptor) {
765+ auto *afd = cast<AbstractFunctionDecl>(decl);
706766 switch (descriptor.getDescriptorKind ()) {
707767 case LifetimeDescriptor::DescriptorKind::Named: {
708768 unsigned paramIndex = 0 ;
@@ -751,6 +811,7 @@ class LifetimeDependenceChecker {
751811 }
752812
753813 std::optional<ArrayRef<LifetimeDependenceInfo>> checkAttribute () {
814+ auto *afd = cast<AbstractFunctionDecl>(decl);
754815 SmallVector<LifetimeDependenceInfo, 1 > lifetimeDependencies;
755816 llvm::SmallSet<unsigned , 1 > lifetimeDependentTargets;
756817 auto lifetimeAttrs = afd->getAttrs ().getAttributes <LifetimeAttr>();
@@ -775,6 +836,7 @@ class LifetimeDependenceChecker {
775836
776837 std::optional<LifetimeDependenceInfo>
777838 checkAttributeEntry (LifetimeEntry *entry) {
839+ auto *afd = cast<AbstractFunctionDecl>(decl);
778840 auto capacity = afd->hasImplicitSelfDecl ()
779841 ? (afd->getParameters ()->size () + 1 )
780842 : afd->getParameters ()->size ();
@@ -896,6 +958,7 @@ class LifetimeDependenceChecker {
896958 // / If the current function is a mutating method and 'self' is non-Escapable,
897959 // / return 'self's ParamDecl.
898960 bool isMutatingNonEscapableSelf () {
961+ auto *afd = cast<AbstractFunctionDecl>(decl);
899962 if (!hasImplicitSelfParam ())
900963 return false ;
901964
@@ -912,6 +975,7 @@ class LifetimeDependenceChecker {
912975
913976 // Infer method dependence: result depends on self. This includes _modify.
914977 void inferNonEscapableResultOnSelf () {
978+ auto *afd = cast<AbstractFunctionDecl>(decl);
915979 Type selfTypeInContext = dc->getSelfTypeInContext ();
916980 if (selfTypeInContext->hasError ()) {
917981 return ;
@@ -963,6 +1027,7 @@ class LifetimeDependenceChecker {
9631027
9641028 std::optional<LifetimeDependenceKind>
9651029 inferLifetimeDependenceKind (Type sourceType, ValueOwnership ownership) {
1030+ auto *afd = cast<AbstractFunctionDecl>(decl);
9661031 if (!sourceType->isEscapable ()) {
9671032 return LifetimeDependenceKind::Inherit;
9681033 }
@@ -985,6 +1050,7 @@ class LifetimeDependenceChecker {
9851050 // to an implicit setter, because the implementation is simply an assignment
9861051 // to stored property.
9871052 void inferImplicitInit () {
1053+ auto *afd = cast<AbstractFunctionDecl>(decl);
9881054 if (afd->getParameters ()->size () == 0 ) {
9891055 // Empty ~Escapable types can be implicitly initialized without any
9901056 // dependencies. In SIL, implicit initializers become explicit. Set
@@ -1024,6 +1090,7 @@ class LifetimeDependenceChecker {
10241090 // inference if any exist, infer scoped dependency, or infer no
10251091 // dependency. Implicit setters for Escapable properties are not inferred.
10261092 void inferNonEscapableResultOnParam () {
1093+ auto *afd = cast<AbstractFunctionDecl>(decl);
10271094 // This is only called when there is no 'self' argument that can be the
10281095 // source of a dependence.
10291096 assert (!hasImplicitSelfParam ());
@@ -1073,6 +1140,7 @@ class LifetimeDependenceChecker {
10731140 // Lazy inference for .swiftinterface backward compatibility and
10741141 // experimentation. Inference cases can be added but not removed.
10751142 void lazillyInferNonEscapableResultOnParam () {
1143+ auto *afd = cast<AbstractFunctionDecl>(decl);
10761144 std::optional<unsigned > candidateParamIndex;
10771145 std::optional<LifetimeDependenceKind> candidateLifetimeKind;
10781146 unsigned paramIndex = 0 ;
@@ -1119,6 +1187,7 @@ class LifetimeDependenceChecker {
11191187 // Infer a mutating 'self' dependency when 'self' is non-Escapable and the
11201188 // result is 'void'.
11211189 void inferMutatingSelf () {
1190+ auto *afd = cast<AbstractFunctionDecl>(decl);
11221191 if (!isMutatingNonEscapableSelf ()) {
11231192 return ;
11241193 }
@@ -1144,6 +1213,7 @@ class LifetimeDependenceChecker {
11441213
11451214 // Infer a mutating accessor's non-Escapable 'self' dependencies.
11461215 void inferMutatingAccessor (AccessorDecl *accessor) {
1216+ auto *afd = cast<AbstractFunctionDecl>(decl);
11471217 if (!isImplicitOrSIL () && !useLazyInference ()) {
11481218 // Explicit setters require explicit lifetime dependencies.
11491219 return ;
@@ -1231,6 +1301,7 @@ class LifetimeDependenceChecker {
12311301 // Do not issue any diagnostics. This inference is triggered even when the
12321302 // feature is disabled!
12331303 void inferInoutParams () {
1304+ auto *afd = cast<AbstractFunctionDecl>(decl);
12341305 if (isMutatingNonEscapableSelf ()) {
12351306 return ;
12361307 }
@@ -1263,6 +1334,7 @@ class LifetimeDependenceChecker {
12631334 }
12641335
12651336 void inferUnambiguousInoutParams () {
1337+ auto *afd = cast<AbstractFunctionDecl>(decl);
12661338 if (afd->getParameters ()->size () != 1 ) {
12671339 return ;
12681340 }
@@ -1280,6 +1352,7 @@ class LifetimeDependenceChecker {
12801352 }
12811353
12821354 void inferBuiltin () {
1355+ auto *afd = cast<AbstractFunctionDecl>(decl);
12831356 // Normal inout parameter inference works for most generic Builtins.
12841357 inferUnambiguousInoutParams ();
12851358 if (!lifetimeDependencies.empty ()) {
@@ -1313,8 +1386,12 @@ class LifetimeDependenceChecker {
13131386};
13141387
13151388std::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 ();
13181395}
13191396
13201397// This implements the logic for SIL type descriptors similar to source-level
0 commit comments