@@ -412,6 +412,7 @@ class LifetimeDependenceChecker {
412
412
return false ;
413
413
}
414
414
415
+ // Infer ambiguous cases for backward compatibility.
415
416
bool useLazyInference () const {
416
417
return isInterfaceFile ()
417
418
|| ctx.LangOpts .EnableExperimentalLifetimeDependenceInference ;
@@ -873,7 +874,7 @@ class LifetimeDependenceChecker {
873
874
// Infer non-Escapable results.
874
875
if (isDiagnosedNonEscapable (getResultOrYield ())) {
875
876
if (hasImplicitSelfParam ()) {
876
- // Methods and accessors that return or yield a non-Escapable value.
877
+ // Methods that return a non-Escapable value.
877
878
inferNonEscapableResultOnSelf ();
878
879
return ;
879
880
}
@@ -910,31 +911,42 @@ class LifetimeDependenceChecker {
910
911
return true ;
911
912
}
912
913
913
- // Infer method dependence: result depends on self. This includes _modify.
914
+ // Infer method dependence of result on self for
915
+ // methods, getters, and _modify accessors.
914
916
void inferNonEscapableResultOnSelf () {
915
917
Type selfTypeInContext = dc->getSelfTypeInContext ();
916
918
if (selfTypeInContext->hasError ()) {
917
919
return ;
918
920
}
919
- bool nonEscapableSelf = isDiagnosedNonEscapable (selfTypeInContext);
920
921
921
- // Avoid diagnosing inference on mutating methods when 'self' is
922
- // non-Escapable. The inout 'self' also needs an inferred dependence on
923
- // itself. This will be diagnosed when checking for missing dependencies.
924
- if (nonEscapableSelf && afd->getImplicitSelfDecl ()->isInOut ()) {
925
- if (auto accessor = dyn_cast<AccessorDecl>(afd)) {
926
- inferMutatingAccessor (accessor);
922
+ bool nonEscapableSelf = isDiagnosedNonEscapable (selfTypeInContext);
923
+ if (auto accessor = dyn_cast<AccessorDecl>(afd)) {
924
+ if (isImplicitOrSIL () || useLazyInference ()) {
925
+ if (nonEscapableSelf && afd->getImplicitSelfDecl ()->isInOut ()) {
926
+ // Implicit accessors that return or yield a non-Escapable value may
927
+ // infer dependency on both self and result.
928
+ inferMutatingAccessor (accessor);
929
+ }
930
+ // Infer the result dependency on self based on the kind of accessor
931
+ // that is wrapped by this synthesized accessors.
932
+ if (auto dependenceKind =
933
+ getAccessorDependence (accessor, selfTypeInContext)) {
934
+ pushDeps (createDeps (resultIndex).add (selfIndex, *dependenceKind));
935
+ }
936
+ return ;
927
937
}
938
+ // Explicit accessors are inferred the same way as regular methods.
939
+ }
940
+ // Do infer the result of a mutating method when 'self' is
941
+ // non-Escapable. The missing dependence on inout 'self' will be diagnosed
942
+ // later anyway, so an explicit annotation will still be needed.
943
+ if (nonEscapableSelf && afd->getImplicitSelfDecl ()->isInOut ()) {
928
944
return ;
929
945
}
930
-
931
946
// Methods with parameters only apply to lazy inference.
932
947
if (!useLazyInference () && afd->getParameters ()->size () > 0 ) {
933
948
return ;
934
949
}
935
- // Allow inference for implicit getters, which simply return a stored,
936
- // property, and for implicit _read/_modify, which cannot be defined
937
- // explicitly alongside a regular getter.
938
950
if (!useLazyInference () && !isImplicitOrSIL ()) {
939
951
// Require explicit @_lifetime(borrow self) for UnsafePointer-like self.
940
952
if (!nonEscapableSelf && isBitwiseCopyable (selfTypeInContext, ctx)) {
@@ -950,9 +962,12 @@ class LifetimeDependenceChecker {
950
962
return ;
951
963
}
952
964
}
965
+ // Infer based on ownership if possible for either explicit accessors or
966
+ // methods as long as they pass preceding ambiguity checks.
953
967
auto kind = inferLifetimeDependenceKind (
954
968
selfTypeInContext, afd->getImplicitSelfDecl ()->getValueOwnership ());
955
969
if (!kind) {
970
+ // Special diagnostic for an attempt to depend on a consuming parameter.
956
971
diagnose (returnLoc,
957
972
diag::lifetime_dependence_cannot_infer_scope_ownership,
958
973
" self" , diagnosticQualifier ());
@@ -961,6 +976,8 @@ class LifetimeDependenceChecker {
961
976
pushDeps (createDeps (resultIndex).add (selfIndex, *kind));
962
977
}
963
978
979
+ // Infer the kind of dependence that makes sense for reading or writing a
980
+ // stored property (for getters or initializers).
964
981
std::optional<LifetimeDependenceKind>
965
982
inferLifetimeDependenceKind (Type sourceType, ValueOwnership ownership) {
966
983
if (!sourceType->isEscapable ()) {
@@ -974,8 +991,9 @@ class LifetimeDependenceChecker {
974
991
auto loweredOwnership = ownership != ValueOwnership::Default
975
992
? ownership
976
993
: getLoweredOwnership (afd);
977
- if (loweredOwnership != ValueOwnership::Shared &&
978
- loweredOwnership != ValueOwnership::InOut) {
994
+ // It is impossible to depend on a consumed Escapable value (unless it is
995
+ // BitwiseCopyable as checked above).
996
+ if (loweredOwnership == ValueOwnership::Owned) {
979
997
return std::nullopt;
980
998
}
981
999
return LifetimeDependenceKind::Scope;
@@ -1125,7 +1143,10 @@ class LifetimeDependenceChecker {
1125
1143
// Handle implicit setters before diagnosing mutating methods. This
1126
1144
// does not include global accessors, which have no implicit 'self'.
1127
1145
if (auto accessor = dyn_cast<AccessorDecl>(afd)) {
1128
- inferMutatingAccessor (accessor);
1146
+ // Explicit setters require explicit lifetime dependencies.
1147
+ if (isImplicitOrSIL () || useLazyInference ()) {
1148
+ inferMutatingAccessor (accessor);
1149
+ }
1129
1150
return ;
1130
1151
}
1131
1152
if (afd->getParameters ()->size () > 0 ) {
@@ -1142,12 +1163,29 @@ class LifetimeDependenceChecker {
1142
1163
LifetimeDependenceKind::Inherit));
1143
1164
}
1144
1165
1145
- // Infer a mutating accessor's non-Escapable 'self' dependencies.
1146
- void inferMutatingAccessor (AccessorDecl *accessor) {
1166
+ // Infer dependence for an accessor whose non-escapable result depends on
1167
+ // self. This includes _read and _modify.
1168
+ void inferAccessor (AccessorDecl *accessor, Type selfTypeInContext) {
1169
+ // Explicit accessors require explicit lifetime dependencies.
1147
1170
if (!isImplicitOrSIL () && !useLazyInference ()) {
1148
- // Explicit setters require explicit lifetime dependencies.
1149
1171
return ;
1150
1172
}
1173
+ bool nonEscapableSelf = isDiagnosedNonEscapable (selfTypeInContext);
1174
+ if (nonEscapableSelf && afd->getImplicitSelfDecl ()->isInOut ()) {
1175
+ // First, infer the dependency on the inout non-Escapable self. This may
1176
+ // result in two inferred dependencies for accessors.
1177
+ inferMutatingAccessor (accessor);
1178
+ }
1179
+ // Infer the result dependency on self based on the kind of accessor that
1180
+ // is wrapped by this synthesized accessors.
1181
+ if (auto dependenceKind =
1182
+ getAccessorDependence (accessor, selfTypeInContext)) {
1183
+ pushDeps (createDeps (resultIndex).add (selfIndex, *dependenceKind));
1184
+ }
1185
+ }
1186
+
1187
+ // Infer a mutating accessor's non-Escapable 'self' dependencies.
1188
+ void inferMutatingAccessor (AccessorDecl *accessor) {
1151
1189
switch (accessor->getAccessorKind ()) {
1152
1190
case AccessorKind::Read:
1153
1191
case AccessorKind::Read2:
@@ -1164,8 +1202,6 @@ class LifetimeDependenceChecker {
1164
1202
// _modify for them even though it won't be emitted.
1165
1203
pushDeps (createDeps (selfIndex).add (selfIndex,
1166
1204
LifetimeDependenceKind::Inherit));
1167
- pushDeps (createDeps (resultIndex).add (selfIndex,
1168
- LifetimeDependenceKind::Scope));
1169
1205
break ;
1170
1206
case AccessorKind::Set: {
1171
1207
const unsigned newValIdx = 0 ;
@@ -1185,7 +1221,7 @@ class LifetimeDependenceChecker {
1185
1221
// dependency, so the setter cannot depend on 'newValue'.
1186
1222
if (!paramTypeInContext->isEscapable ()) {
1187
1223
targetDeps = std::move (targetDeps)
1188
- .add (newValIdx, LifetimeDependenceKind::Inherit);
1224
+ .add (newValIdx, LifetimeDependenceKind::Inherit);
1189
1225
}
1190
1226
pushDeps (std::move (targetDeps));
1191
1227
break ;
@@ -1207,6 +1243,54 @@ class LifetimeDependenceChecker {
1207
1243
}
1208
1244
}
1209
1245
1246
+ // Implicit accessors must be consistent with the accessor that they
1247
+ // wrap. Otherwise, the sythesized implementation will report a diagnostic
1248
+ // error.
1249
+ std::optional<LifetimeDependenceKind>
1250
+ getAccessorDependence (AccessorDecl *accessor, Type selfTypeInContext) {
1251
+ std::optional<AccessorKind> wrappedAccessorKind = std::nullopt;
1252
+ switch (accessor->getAccessorKind ()) {
1253
+ case AccessorKind::Read:
1254
+ case AccessorKind::Read2:
1255
+ case AccessorKind::Modify:
1256
+ case AccessorKind::Modify2:
1257
+ // read/modify are syntesized as calls to the getter.
1258
+ wrappedAccessorKind = AccessorKind::Get;
1259
+ break ;
1260
+ case AccessorKind::Get:
1261
+ // getters are synthesized as access to a stored property.
1262
+ break ;
1263
+ default :
1264
+ // Unknown synthesized accessor.
1265
+ // Setters are handled in inferMutatingAccessor() because they don't
1266
+ // return a value.
1267
+ return std::nullopt;
1268
+ }
1269
+ if (wrappedAccessorKind) {
1270
+ auto *var = cast<VarDecl>(accessor->getStorage ());
1271
+ for (auto *wrappedAccessor : var->getAllAccessors ()) {
1272
+ if (wrappedAccessor->isImplicit ())
1273
+ continue ;
1274
+ if (wrappedAccessor->getAccessorKind () == wrappedAccessorKind) {
1275
+ if (auto deps = wrappedAccessor->getLifetimeDependencies ()) {
1276
+ for (auto &dep : *deps) {
1277
+ if (dep.getTargetIndex () != resultIndex)
1278
+ continue ;
1279
+ if (dep.checkInherit (selfIndex))
1280
+ return LifetimeDependenceKind::Inherit;
1281
+ if (dep.checkScope (selfIndex))
1282
+ return LifetimeDependenceKind::Scope;
1283
+ }
1284
+ }
1285
+ }
1286
+ }
1287
+ }
1288
+ // Either a Get or Modify without any wrapped accessor. Handle these like a
1289
+ // read of the stored property.
1290
+ return inferLifetimeDependenceKind (
1291
+ selfTypeInContext, afd->getImplicitSelfDecl ()->getValueOwnership ());
1292
+ }
1293
+
1210
1294
// Infer 'inout' parameter dependency when the only parameter is
1211
1295
// non-Escapable.
1212
1296
//
0 commit comments