Skip to content

[6.2] Add support for inout lifetime dependencies #80645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 10, 2025
3 changes: 2 additions & 1 deletion include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -1086,8 +1086,9 @@ BridgedInlineAttr BridgedInlineAttr_createParsed(BridgedASTContext cContext,

enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedParsedLifetimeDependenceKind {
BridgedParsedLifetimeDependenceKindDefault,
BridgedParsedLifetimeDependenceKindScope,
BridgedParsedLifetimeDependenceKindBorrow,
BridgedParsedLifetimeDependenceKindInherit,
BridgedParsedLifetimeDependenceKindInout
};

class BridgedLifetimeDescriptor {
Expand Down
7 changes: 5 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -8169,8 +8169,11 @@ ERROR(lifetime_dependence_invalid_inherit_escapable_type, none,
"'@lifetime(borrow %0)' instead",
(StringRef))
ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none,
"invalid use of borrow dependence with consuming ownership",
())
"invalid use of %0 dependence with %1 ownership",
(StringRef, StringRef))
ERROR(lifetime_dependence_cannot_use_default_escapable_consuming, none,
"invalid lifetime dependence on an Escapable value with %0 ownership",
(StringRef))
ERROR(lifetime_dependence_cannot_use_parsed_borrow_inout, none,
"invalid use of borrow dependence on the same inout parameter",
())
Expand Down
38 changes: 7 additions & 31 deletions include/swift/AST/LifetimeDependence.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ class SILResultInfo;

enum class ParsedLifetimeDependenceKind : uint8_t {
Default = 0,
Scope,
Inherit // Only used with deserialized decls
Borrow,
Inherit, // Only used with deserialized decls
Inout
};

enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope };
Expand Down Expand Up @@ -182,6 +183,7 @@ class LifetimeEntry final
ArrayRef<LifetimeDescriptor> sources,
std::optional<LifetimeDescriptor> targetDescriptor = std::nullopt);

std::string getString() const;
SourceLoc getLoc() const { return startLoc; }
SourceLoc getStartLoc() const { return startLoc; }
SourceLoc getEndLoc() const { return endLoc; }
Expand All @@ -193,35 +195,6 @@ class LifetimeEntry final
std::optional<LifetimeDescriptor> getTargetDescriptor() const {
return targetDescriptor;
}

std::string getString() const {
std::string result = "@lifetime(";
if (targetDescriptor.has_value()) {
result += targetDescriptor->getString();
result += ": ";
}

bool firstElem = true;
for (auto source : getSources()) {
if (!firstElem) {
result += ", ";
}
switch (source.getParsedLifetimeDependenceKind()) {
case ParsedLifetimeDependenceKind::Scope:
result += "borrow ";
break;
case ParsedLifetimeDependenceKind::Inherit:
result += "copy ";
break;
default:
break;
}
result += source.getString();
firstElem = false;
}
result += ")";
return result;
}
};

class LifetimeDependenceInfo {
Expand Down Expand Up @@ -366,6 +339,9 @@ filterEscapableLifetimeDependencies(GenericSignature sig,
SmallVectorImpl<LifetimeDependenceInfo> &outputs,
llvm::function_ref<Type (unsigned targetIndex)> getSubstTargetType);

StringRef
getNameForParsedLifetimeDependenceKind(ParsedLifetimeDependenceKind kind);

} // namespace swift

#endif
3 changes: 3 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,9 @@ EXPERIMENTAL_FEATURE(StructLetDestructuring, true)
/// Enable returning non-escapable types from functions.
EXPERIMENTAL_FEATURE(LifetimeDependence, true)

/// Enable inout lifetime dependence - @lifetime(&arg)
EXPERIMENTAL_FEATURE(InoutLifetimeDependence, true)

/// Enable the `@_staticExclusiveOnly` attribute.
EXPERIMENTAL_FEATURE(StaticExclusiveOnly, true)

Expand Down
6 changes: 4 additions & 2 deletions lib/AST/Bridging/DeclAttributeBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,10 +470,12 @@ unbridged(BridgedParsedLifetimeDependenceKind kind) {
switch (kind) {
case BridgedParsedLifetimeDependenceKindDefault:
return swift::ParsedLifetimeDependenceKind::Default;
case BridgedParsedLifetimeDependenceKindScope:
return swift::ParsedLifetimeDependenceKind::Scope;
case BridgedParsedLifetimeDependenceKindBorrow:
return swift::ParsedLifetimeDependenceKind::Borrow;
case BridgedParsedLifetimeDependenceKindInherit:
return swift::ParsedLifetimeDependenceKind::Inherit;
case BridgedParsedLifetimeDependenceKindInout:
return swift::ParsedLifetimeDependenceKind::Inout;
}
llvm_unreachable("unhandled enum value");
}
Expand Down
23 changes: 23 additions & 0 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,29 @@ static bool usesFeatureLifetimeDependence(Decl *decl) {
return false;
}

static bool usesFeatureInoutLifetimeDependence(Decl *decl) {
auto hasInoutLifetimeDependence = [](Decl *decl) {
for (auto attr : decl->getAttrs().getAttributes<LifetimeAttr>()) {
for (auto source : attr->getLifetimeEntry()->getSources()) {
if (source.getParsedLifetimeDependenceKind() ==
ParsedLifetimeDependenceKind::Inout) {
return true;
}
}
}
return false;
};

switch (decl->getKind()) {
case DeclKind::Var: {
auto *var = cast<VarDecl>(decl);
return llvm::any_of(var->getAllAccessors(), hasInoutLifetimeDependence);
}
default:
return hasInoutLifetimeDependence(decl);
}
}

UNINTERESTING_FEATURE(DynamicActorIsolation)
UNINTERESTING_FEATURE(NonfrozenEnumExhaustivity)
UNINTERESTING_FEATURE(ClosureIsolation)
Expand Down
Loading