@@ -464,6 +464,7 @@ class LifetimeDependenceChecker {
464
464
return false ;
465
465
}
466
466
467
+ // Infer ambiguous cases for backward compatibility.
467
468
bool useLazyInference () const {
468
469
return isInterfaceFile ()
469
470
|| ctx.LangOpts .EnableExperimentalLifetimeDependenceInference ;
@@ -935,7 +936,7 @@ class LifetimeDependenceChecker {
935
936
// Infer non-Escapable results.
936
937
if (isDiagnosedNonEscapable (getResultOrYield ())) {
937
938
if (hasImplicitSelfParam ()) {
938
- // Methods and accessors that return or yield a non-Escapable value.
939
+ // Methods that return a non-Escapable value.
939
940
inferNonEscapableResultOnSelf ();
940
941
return ;
941
942
}
@@ -973,32 +974,43 @@ class LifetimeDependenceChecker {
973
974
return true ;
974
975
}
975
976
976
- // Infer method dependence: result depends on self. This includes _modify.
977
+ // Infer method dependence of result on self for
978
+ // methods, getters, and _modify accessors.
977
979
void inferNonEscapableResultOnSelf () {
978
980
auto *afd = cast<AbstractFunctionDecl>(decl);
979
981
Type selfTypeInContext = dc->getSelfTypeInContext ();
980
982
if (selfTypeInContext->hasError ()) {
981
983
return ;
982
984
}
983
- bool nonEscapableSelf = isDiagnosedNonEscapable (selfTypeInContext);
984
985
985
- // Avoid diagnosing inference on mutating methods when 'self' is
986
- // non-Escapable. The inout 'self' also needs an inferred dependence on
987
- // itself. This will be diagnosed when checking for missing dependencies.
988
- if (nonEscapableSelf && afd->getImplicitSelfDecl ()->isInOut ()) {
989
- if (auto accessor = dyn_cast<AccessorDecl>(afd)) {
990
- inferMutatingAccessor (accessor);
986
+ bool nonEscapableSelf = isDiagnosedNonEscapable (selfTypeInContext);
987
+ if (auto accessor = dyn_cast<AccessorDecl>(afd)) {
988
+ if (isImplicitOrSIL () || useLazyInference ()) {
989
+ if (nonEscapableSelf && afd->getImplicitSelfDecl ()->isInOut ()) {
990
+ // Implicit accessors that return or yield a non-Escapable value may
991
+ // infer dependency on both self and result.
992
+ inferMutatingAccessor (accessor);
993
+ }
994
+ // Infer the result dependency on self based on the kind of accessor
995
+ // that is wrapped by this synthesized accessors.
996
+ if (auto dependenceKind =
997
+ getAccessorDependence (accessor, selfTypeInContext)) {
998
+ pushDeps (createDeps (resultIndex).add (selfIndex, *dependenceKind));
999
+ }
1000
+ return ;
991
1001
}
1002
+ // Explicit accessors are inferred the same way as regular methods.
1003
+ }
1004
+ // Do infer the result of a mutating method when 'self' is
1005
+ // non-Escapable. The missing dependence on inout 'self' will be diagnosed
1006
+ // later anyway, so an explicit annotation will still be needed.
1007
+ if (nonEscapableSelf && afd->getImplicitSelfDecl ()->isInOut ()) {
992
1008
return ;
993
1009
}
994
-
995
1010
// Methods with parameters only apply to lazy inference.
996
1011
if (!useLazyInference () && afd->getParameters ()->size () > 0 ) {
997
1012
return ;
998
1013
}
999
- // Allow inference for implicit getters, which simply return a stored,
1000
- // property, and for implicit _read/_modify, which cannot be defined
1001
- // explicitly alongside a regular getter.
1002
1014
if (!useLazyInference () && !isImplicitOrSIL ()) {
1003
1015
// Require explicit @_lifetime(borrow self) for UnsafePointer-like self.
1004
1016
if (!nonEscapableSelf && isBitwiseCopyable (selfTypeInContext, ctx)) {
@@ -1014,9 +1026,12 @@ class LifetimeDependenceChecker {
1014
1026
return ;
1015
1027
}
1016
1028
}
1029
+ // Infer based on ownership if possible for either explicit accessors or
1030
+ // methods as long as they pass preceding ambiguity checks.
1017
1031
auto kind = inferLifetimeDependenceKind (
1018
1032
selfTypeInContext, afd->getImplicitSelfDecl ()->getValueOwnership ());
1019
1033
if (!kind) {
1034
+ // Special diagnostic for an attempt to depend on a consuming parameter.
1020
1035
diagnose (returnLoc,
1021
1036
diag::lifetime_dependence_cannot_infer_scope_ownership,
1022
1037
" self" , diagnosticQualifier ());
@@ -1025,6 +1040,8 @@ class LifetimeDependenceChecker {
1025
1040
pushDeps (createDeps (resultIndex).add (selfIndex, *kind));
1026
1041
}
1027
1042
1043
+ // Infer the kind of dependence that makes sense for reading or writing a
1044
+ // stored property (for getters or initializers).
1028
1045
std::optional<LifetimeDependenceKind>
1029
1046
inferLifetimeDependenceKind (Type sourceType, ValueOwnership ownership) {
1030
1047
auto *afd = cast<AbstractFunctionDecl>(decl);
@@ -1039,8 +1056,9 @@ class LifetimeDependenceChecker {
1039
1056
auto loweredOwnership = ownership != ValueOwnership::Default
1040
1057
? ownership
1041
1058
: getLoweredOwnership (afd);
1042
- if (loweredOwnership != ValueOwnership::Shared &&
1043
- loweredOwnership != ValueOwnership::InOut) {
1059
+ // It is impossible to depend on a consumed Escapable value (unless it is
1060
+ // BitwiseCopyable as checked above).
1061
+ if (loweredOwnership == ValueOwnership::Owned) {
1044
1062
return std::nullopt;
1045
1063
}
1046
1064
return LifetimeDependenceKind::Scope;
@@ -1194,7 +1212,10 @@ class LifetimeDependenceChecker {
1194
1212
// Handle implicit setters before diagnosing mutating methods. This
1195
1213
// does not include global accessors, which have no implicit 'self'.
1196
1214
if (auto accessor = dyn_cast<AccessorDecl>(afd)) {
1197
- inferMutatingAccessor (accessor);
1215
+ // Explicit setters require explicit lifetime dependencies.
1216
+ if (isImplicitOrSIL () || useLazyInference ()) {
1217
+ inferMutatingAccessor (accessor);
1218
+ }
1198
1219
return ;
1199
1220
}
1200
1221
if (afd->getParameters ()->size () > 0 ) {
@@ -1211,13 +1232,31 @@ class LifetimeDependenceChecker {
1211
1232
LifetimeDependenceKind::Inherit));
1212
1233
}
1213
1234
1214
- // Infer a mutating accessor's non-Escapable 'self' dependencies.
1215
- void inferMutatingAccessor (AccessorDecl *accessor) {
1235
+ // Infer dependence for an accessor whose non-escapable result depends on
1236
+ // self. This includes _read and _modify.
1237
+ void inferAccessor (AccessorDecl *accessor, Type selfTypeInContext) {
1238
+ // Explicit accessors require explicit lifetime dependencies.
1216
1239
auto *afd = cast<AbstractFunctionDecl>(decl);
1217
1240
if (!isImplicitOrSIL () && !useLazyInference ()) {
1218
- // Explicit setters require explicit lifetime dependencies.
1219
1241
return ;
1220
1242
}
1243
+ bool nonEscapableSelf = isDiagnosedNonEscapable (selfTypeInContext);
1244
+ if (nonEscapableSelf && afd->getImplicitSelfDecl ()->isInOut ()) {
1245
+ // First, infer the dependency on the inout non-Escapable self. This may
1246
+ // result in two inferred dependencies for accessors.
1247
+ inferMutatingAccessor (accessor);
1248
+ }
1249
+ // Infer the result dependency on self based on the kind of accessor that
1250
+ // is wrapped by this synthesized accessors.
1251
+ if (auto dependenceKind =
1252
+ getAccessorDependence (accessor, selfTypeInContext)) {
1253
+ pushDeps (createDeps (resultIndex).add (selfIndex, *dependenceKind));
1254
+ }
1255
+ }
1256
+
1257
+ // Infer a mutating accessor's non-Escapable 'self' dependencies.
1258
+ void inferMutatingAccessor (AccessorDecl *accessor) {
1259
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1221
1260
switch (accessor->getAccessorKind ()) {
1222
1261
case AccessorKind::Read:
1223
1262
case AccessorKind::Read2:
@@ -1234,8 +1273,6 @@ class LifetimeDependenceChecker {
1234
1273
// _modify for them even though it won't be emitted.
1235
1274
pushDeps (createDeps (selfIndex).add (selfIndex,
1236
1275
LifetimeDependenceKind::Inherit));
1237
- pushDeps (createDeps (resultIndex).add (selfIndex,
1238
- LifetimeDependenceKind::Scope));
1239
1276
break ;
1240
1277
case AccessorKind::Set: {
1241
1278
const unsigned newValIdx = 0 ;
@@ -1255,7 +1292,7 @@ class LifetimeDependenceChecker {
1255
1292
// dependency, so the setter cannot depend on 'newValue'.
1256
1293
if (!paramTypeInContext->isEscapable ()) {
1257
1294
targetDeps = std::move (targetDeps)
1258
- .add (newValIdx, LifetimeDependenceKind::Inherit);
1295
+ .add (newValIdx, LifetimeDependenceKind::Inherit);
1259
1296
}
1260
1297
pushDeps (std::move (targetDeps));
1261
1298
break ;
@@ -1277,6 +1314,55 @@ class LifetimeDependenceChecker {
1277
1314
}
1278
1315
}
1279
1316
1317
+ // Implicit accessors must be consistent with the accessor that they
1318
+ // wrap. Otherwise, the sythesized implementation will report a diagnostic
1319
+ // error.
1320
+ std::optional<LifetimeDependenceKind>
1321
+ getAccessorDependence (AccessorDecl *accessor, Type selfTypeInContext) {
1322
+ auto *afd = cast<AbstractFunctionDecl>(decl);
1323
+ std::optional<AccessorKind> wrappedAccessorKind = std::nullopt;
1324
+ switch (accessor->getAccessorKind ()) {
1325
+ case AccessorKind::Read:
1326
+ case AccessorKind::Read2:
1327
+ case AccessorKind::Modify:
1328
+ case AccessorKind::Modify2:
1329
+ // read/modify are syntesized as calls to the getter.
1330
+ wrappedAccessorKind = AccessorKind::Get;
1331
+ break ;
1332
+ case AccessorKind::Get:
1333
+ // getters are synthesized as access to a stored property.
1334
+ break ;
1335
+ default :
1336
+ // Unknown synthesized accessor.
1337
+ // Setters are handled in inferMutatingAccessor() because they don't
1338
+ // return a value.
1339
+ return std::nullopt;
1340
+ }
1341
+ if (wrappedAccessorKind) {
1342
+ auto *var = cast<VarDecl>(accessor->getStorage ());
1343
+ for (auto *wrappedAccessor : var->getAllAccessors ()) {
1344
+ if (wrappedAccessor->isImplicit ())
1345
+ continue ;
1346
+ if (wrappedAccessor->getAccessorKind () == wrappedAccessorKind) {
1347
+ if (auto deps = wrappedAccessor->getLifetimeDependencies ()) {
1348
+ for (auto &dep : *deps) {
1349
+ if (dep.getTargetIndex () != resultIndex)
1350
+ continue ;
1351
+ if (dep.checkInherit (selfIndex))
1352
+ return LifetimeDependenceKind::Inherit;
1353
+ if (dep.checkScope (selfIndex))
1354
+ return LifetimeDependenceKind::Scope;
1355
+ }
1356
+ }
1357
+ }
1358
+ }
1359
+ }
1360
+ // Either a Get or Modify without any wrapped accessor. Handle these like a
1361
+ // read of the stored property.
1362
+ return inferLifetimeDependenceKind (
1363
+ selfTypeInContext, afd->getImplicitSelfDecl ()->getValueOwnership ());
1364
+ }
1365
+
1280
1366
// Infer 'inout' parameter dependency when the only parameter is
1281
1367
// non-Escapable.
1282
1368
//
0 commit comments