Skip to content

Commit 42632b4

Browse files
committed
Update lifetime dependence syntax and inference as per changes in the pitch
Pitch - swiftlang/swift-evolution#2305 Changes highlights: @dependsOn(paramName) and @dependsOn(scoped argName) syntax @dependsOn(paramName) -> copy lifetime dependence for all parameters/self except when we have Escapable parameters/self, we assign scope lifetime dependence. Allow lifetime dependence on parameters without ownership modifier. Always infer copy lifetime dependence except when we have Escapable parameters/self, we infer scope lifetime dependence. Allow lifetime dependence inference on parameters without ownership modifier.
1 parent 0e24d44 commit 42632b4

34 files changed

+375
-345
lines changed

include/swift/AST/DiagnosticsSema.def

+15-15
Original file line numberDiff line numberDiff line change
@@ -7841,25 +7841,28 @@ ERROR(lifetime_dependence_invalid_param_name, none,
78417841
"invalid parameter name specified %0", (Identifier))
78427842
ERROR(lifetime_dependence_invalid_param_index, none,
78437843
"invalid parameter index specified %0", (unsigned))
7844-
ERROR(lifetime_dependence_invalid_self, none,
7845-
"invalid lifetime dependence specifier, self is valid in non-static "
7846-
"methods only", ())
7844+
ERROR(lifetime_dependence_invalid_self_in_static, none,
7845+
"invalid lifetime dependence specifier on non-existent self", ())
7846+
ERROR(lifetime_dependence_invalid_self_in_init, none,
7847+
"invalid lifetime dependence on self in an initializer", ())
78477848
ERROR(lifetime_dependence_duplicate_param_id, none,
78487849
"duplicate lifetime dependence specifier", ())
7849-
ERROR(lifetime_dependence_cannot_use_kind, none,
7850-
"invalid use of %0 lifetime dependence for %1 ownership",
7851-
(StringRef, StringRef))
7850+
ERROR(lifetime_dependence_cannot_use_parsed_scoped_consuming, none,
7851+
"invalid use of scoped lifetime dependence with consuming ownership",
7852+
())
7853+
ERROR(lifetime_dependence_cannot_use_inferred_scoped_consuming, none,
7854+
"invalid use of lifetime dependence on an Escapable parameter with "
7855+
"consuming ownership",
7856+
())
7857+
ERROR(lifetime_dependence_invalid_self_ownership, none,
7858+
"invalid scoped lifetime dependence on an Escapable self with consuming "
7859+
"ownership",
7860+
())
78527861
ERROR(lifetime_dependence_only_on_function_method_init_result, none,
78537862
"lifetime dependence specifiers may only be used on result of "
78547863
"functions, methods, initializers", ())
78557864
ERROR(lifetime_dependence_invalid_return_type, none,
78567865
"lifetime dependence can only be specified on ~Escapable results", ())
7857-
ERROR(lifetime_dependence_missing_ownership_modifier, none,
7858-
"lifetime dependence can only be specified on parameters with ownership "
7859-
"modifiers (borrowing, consuming, inout)", ())
7860-
ERROR(lifetime_dependence_cannot_infer_wo_ownership_modifier_on_method, none,
7861-
"cannot infer lifetime dependence, specify ownership modifier for the "
7862-
"method", ())
78637866
ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none,
78647867
"cannot infer lifetime dependence, multiple ~Escapable or ~Copyable "
78657868
"parameters with ownership modifiers, specify explicit lifetime "
@@ -7870,9 +7873,6 @@ ERROR(lifetime_dependence_cannot_infer_no_candidates, none,
78707873
ERROR(lifetime_dependence_ctor_non_self_or_nil_return, none,
78717874
"expected nil or self as return values in an initializer with "
78727875
"lifetime dependent specifiers", ())
7873-
ERROR(lifetime_dependence_cannot_use_infer, none,
7874-
"invalid use of %0 lifetime dependence on Escapable type",
7875-
(StringRef))
78767876
ERROR(lifetime_dependence_on_bitwise_copyable, none,
78777877
"invalid lifetime dependence on bitwise copyable type", ())
78787878
ERROR(lifetime_dependence_cannot_infer_implicit_init, none,

include/swift/AST/LifetimeDependence.h

+27-27
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,22 @@ namespace swift {
3131
class AbstractFunctionDecl;
3232
class LifetimeDependentReturnTypeRepr;
3333

34-
enum class LifetimeDependenceKind : uint8_t {
35-
Copy = 0,
36-
Consume,
37-
Borrow,
38-
Mutate
34+
enum class ParsedLifetimeDependenceKind : uint8_t {
35+
Default = 0,
36+
Scope,
37+
Inherit // Only used with deserialized decls
3938
};
4039

40+
enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope };
41+
4142
class LifetimeDependenceSpecifier {
4243
public:
4344
enum class SpecifierKind { Named, Ordered, Self };
4445

4546
private:
4647
SourceLoc loc;
4748
SpecifierKind specifierKind;
48-
LifetimeDependenceKind lifetimeDependenceKind;
49+
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind;
4950
union Value {
5051
struct {
5152
Identifier name;
@@ -60,35 +61,36 @@ class LifetimeDependenceSpecifier {
6061
Value() {}
6162
} value;
6263

63-
LifetimeDependenceSpecifier(SourceLoc loc, SpecifierKind specifierKind,
64-
LifetimeDependenceKind lifetimeDependenceKind,
65-
Value value)
64+
LifetimeDependenceSpecifier(
65+
SourceLoc loc, SpecifierKind specifierKind,
66+
ParsedLifetimeDependenceKind parsedLifetimeDependenceKind, Value value)
6667
: loc(loc), specifierKind(specifierKind),
67-
lifetimeDependenceKind(lifetimeDependenceKind), value(value) {}
68+
parsedLifetimeDependenceKind(parsedLifetimeDependenceKind),
69+
value(value) {}
6870

6971
public:
7072
static LifetimeDependenceSpecifier getNamedLifetimeDependenceSpecifier(
71-
SourceLoc loc, LifetimeDependenceKind kind, Identifier name) {
73+
SourceLoc loc, ParsedLifetimeDependenceKind kind, Identifier name) {
7274
return {loc, SpecifierKind::Named, kind, name};
7375
}
7476

7577
static LifetimeDependenceSpecifier getOrderedLifetimeDependenceSpecifier(
76-
SourceLoc loc, LifetimeDependenceKind kind, unsigned index) {
78+
SourceLoc loc, ParsedLifetimeDependenceKind kind, unsigned index) {
7779
return {loc, SpecifierKind::Ordered, kind, index};
7880
}
7981

8082
static LifetimeDependenceSpecifier
8183
getSelfLifetimeDependenceSpecifier(SourceLoc loc,
82-
LifetimeDependenceKind kind) {
84+
ParsedLifetimeDependenceKind kind) {
8385
return {loc, SpecifierKind::Self, kind, {}};
8486
}
8587

8688
SourceLoc getLoc() const { return loc; }
8789

8890
SpecifierKind getSpecifierKind() const { return specifierKind; }
8991

90-
LifetimeDependenceKind getLifetimeDependenceKind() const {
91-
return lifetimeDependenceKind;
92+
ParsedLifetimeDependenceKind getParsedLifetimeDependenceKind() const {
93+
return parsedLifetimeDependenceKind;
9294
}
9395

9496
Identifier getName() const {
@@ -113,19 +115,17 @@ class LifetimeDependenceSpecifier {
113115
llvm_unreachable("Invalid LifetimeDependenceSpecifier::SpecifierKind");
114116
}
115117

116-
StringRef getLifetimeDependenceKindString() const {
117-
switch (lifetimeDependenceKind) {
118-
case LifetimeDependenceKind::Borrow:
119-
return "_borrow";
120-
case LifetimeDependenceKind::Consume:
121-
return "_consume";
122-
case LifetimeDependenceKind::Copy:
123-
return "_copy";
124-
case LifetimeDependenceKind::Mutate:
125-
return "_mutate";
118+
std::string getLifetimeDependenceSpecifierString() const {
119+
switch (parsedLifetimeDependenceKind) {
120+
case ParsedLifetimeDependenceKind::Default:
121+
return "@dependsOn(" + getParamString() + ")";
122+
case ParsedLifetimeDependenceKind::Scope:
123+
return "@dependsOn(scoped " + getParamString() + ")";
124+
case ParsedLifetimeDependenceKind::Inherit:
125+
return "@dependsOn(inherited " + getParamString() + ")";
126126
}
127127
llvm_unreachable(
128-
"Invalid LifetimeDependenceSpecifier::LifetimeDependenceKind");
128+
"Invalid LifetimeDependenceSpecifier::ParsedLifetimeDependenceKind");
129129
}
130130
};
131131

@@ -136,7 +136,7 @@ class LifetimeDependenceInfo {
136136

137137
static LifetimeDependenceInfo getForParamIndex(AbstractFunctionDecl *afd,
138138
unsigned index,
139-
ValueOwnership ownership);
139+
LifetimeDependenceKind kind);
140140

141141
static std::optional<LifetimeDependenceInfo>
142142
fromTypeRepr(AbstractFunctionDecl *afd, Type resultType, bool allowIndex);

include/swift/Parse/Parser.h

+7-12
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,7 @@ class Parser {
12121212
return true;
12131213
if (Context.LangOpts.hasFeature(Feature::NonescapableTypes) &&
12141214
(Tok.isContextualKeyword("_resultDependsOn") ||
1215-
Tok.isLifetimeDependenceToken()))
1215+
(Tok.is(tok::at_sign) && peekToken().isLifetimeDependenceToken())))
12161216
return true;
12171217
return false;
12181218
}
@@ -1230,17 +1230,12 @@ class Parser {
12301230
// the following token is something that can introduce a type. Thankfully
12311231
// none of these tokens overlap with the set of tokens that can follow an
12321232
// identifier in a type production.
1233-
return Tok.is(tok::identifier)
1234-
&& peekToken().isAny(tok::at_sign,
1235-
tok::kw_inout,
1236-
tok::l_paren,
1237-
tok::identifier,
1238-
tok::l_square,
1239-
tok::kw_Any,
1240-
tok::kw_Self,
1241-
tok::kw__,
1242-
tok::kw_var,
1243-
tok::kw_let);
1233+
return (Tok.is(tok::identifier) &&
1234+
peekToken().isAny(tok::at_sign, tok::kw_inout, tok::l_paren,
1235+
tok::identifier, tok::l_square, tok::kw_Any,
1236+
tok::kw_Self, tok::kw__, tok::kw_var,
1237+
tok::kw_let)) ||
1238+
(Tok.is(tok::at_sign) && peekToken().isLifetimeDependenceToken());
12441239
}
12451240

12461241
struct ParsedTypeAttributeList {

include/swift/Parse/Token.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,7 @@ class Token {
268268
}
269269

270270
bool isLifetimeDependenceToken() const {
271-
return isContextualKeyword("_copy") || isContextualKeyword("_consume") ||
272-
isContextualKeyword("_borrow") || isContextualKeyword("_mutate");
271+
return isContextualKeyword("dependsOn");
273272
}
274273

275274
/// Count of extending escaping '#'.

lib/AST/ASTDumper.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -3535,8 +3535,7 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr, void, StringRef>,
35353535
for (auto &dep : T->getLifetimeDependencies()) {
35363536
printFieldRaw(
35373537
[&](raw_ostream &out) {
3538-
out << dep.getLifetimeDependenceKindString() << "(";
3539-
out << dep.getParamString() << ")";
3538+
out << " " << dep.getLifetimeDependenceSpecifierString() << " ";
35403539
},
35413540
"");
35423541
}

lib/AST/ASTMangler.cpp

+2-8
Original file line numberDiff line numberDiff line change
@@ -3259,20 +3259,14 @@ void ASTMangler::appendParameterTypeListElement(
32593259

32603260
void ASTMangler::appendLifetimeDependenceKind(LifetimeDependenceKind kind,
32613261
bool isSelfDependence) {
3262-
// If we converge on dependsOn(borrowed: paramName)/dependsOn(paramName)
3263-
// syntax, this can be a single case value check.
3264-
if (kind == LifetimeDependenceKind::Borrow ||
3265-
kind == LifetimeDependenceKind::Mutate) {
3262+
if (kind == LifetimeDependenceKind::Scope) {
32663263
if (isSelfDependence) {
32673264
appendOperator("YLs");
32683265
} else {
32693266
appendOperator("Yls");
32703267
}
32713268
} else {
3272-
// If we converge on dependsOn(borrowed: paramName)/dependsOn(paramName)
3273-
// syntax, this can be a single case value check.
3274-
assert(kind == LifetimeDependenceKind::Copy ||
3275-
kind == LifetimeDependenceKind::Consume);
3269+
assert(kind == LifetimeDependenceKind::Inherit);
32763270
if (isSelfDependence) {
32773271
appendOperator("YLi");
32783272
} else {

lib/AST/ASTPrinter.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -4136,8 +4136,7 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
41364136
if (auto *typeRepr = dyn_cast_or_null<LifetimeDependentReturnTypeRepr>(
41374137
decl->getResultTypeRepr())) {
41384138
for (auto &dep : typeRepr->getLifetimeDependencies()) {
4139-
Printer << " " << dep.getLifetimeDependenceKindString() << "(";
4140-
Printer << dep.getParamString() << ") ";
4139+
Printer << " " << dep.getLifetimeDependenceSpecifierString() << " ";
41414140
}
41424141
}
41434142
}
@@ -4377,8 +4376,7 @@ void PrintAST::visitConstructorDecl(ConstructorDecl *decl) {
43774376
auto *typeRepr =
43784377
cast<LifetimeDependentReturnTypeRepr>(decl->getResultTypeRepr());
43794378
for (auto &dep : typeRepr->getLifetimeDependencies()) {
4380-
Printer << dep.getLifetimeDependenceKindString() << "(";
4381-
Printer << dep.getParamString() << ") ";
4379+
Printer << dep.getLifetimeDependenceSpecifierString() << " ";
43824380
}
43834381
// TODO: Handle failable initializers with lifetime dependent returns
43844382
Printer << "Self";

lib/AST/TypeRepr.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -692,9 +692,9 @@ SourceLoc LifetimeDependentReturnTypeRepr::getLocImpl() const {
692692

693693
void LifetimeDependentReturnTypeRepr::printImpl(
694694
ASTPrinter &Printer, const PrintOptions &Opts) const {
695+
Printer << " ";
695696
for (auto &dep : getLifetimeDependencies()) {
696-
Printer << dep.getLifetimeDependenceKindString() << "(";
697-
Printer << dep.getParamString() << ")";
697+
Printer << dep.getLifetimeDependenceSpecifierString() << " ";
698698
}
699699

700700
printTypeRepr(getBase(), Printer, Opts);

lib/Parse/ParseDecl.cpp

+20-24
Original file line numberDiff line numberDiff line change
@@ -5046,33 +5046,17 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
50465046
llvm_unreachable("bad attribute kind");
50475047
}
50485048

5049-
static std::optional<LifetimeDependenceKind>
5050-
getLifetimeDependenceKind(const Token &T) {
5051-
if (T.isContextualKeyword("_copy")) {
5052-
return LifetimeDependenceKind::Copy;
5053-
}
5054-
if (T.isContextualKeyword("_consume")) {
5055-
return LifetimeDependenceKind::Consume;
5056-
}
5057-
if (T.isContextualKeyword("_borrow")) {
5058-
return LifetimeDependenceKind::Borrow;
5059-
}
5060-
if (T.isContextualKeyword("_mutate")) {
5061-
return LifetimeDependenceKind::Mutate;
5062-
}
5063-
return std::nullopt;
5064-
}
5065-
50665049
ParserStatus Parser::parseLifetimeDependenceSpecifiers(
50675050
SmallVectorImpl<LifetimeDependenceSpecifier> &specifierList) {
50685051
ParserStatus status;
50695052
// TODO: Add fixits for diagnostics in this function.
50705053
do {
5071-
auto lifetimeDependenceKind = getLifetimeDependenceKind(Tok);
5072-
if (!lifetimeDependenceKind.has_value()) {
5054+
if (!Tok.is(tok::at_sign) && !peekToken().isLifetimeDependenceToken()) {
50735055
break;
50745056
}
5075-
// consume the lifetime dependence kind
5057+
// consume @
5058+
consumeToken();
5059+
// consume dependsOn
50765060
consumeToken();
50775061

50785062
if (!Tok.isFollowingLParen()) {
@@ -5082,6 +5066,15 @@ ParserStatus Parser::parseLifetimeDependenceSpecifiers(
50825066
}
50835067
// consume the l_paren
50845068
auto lParenLoc = consumeToken();
5069+
5070+
auto lifetimeDependenceKind = ParsedLifetimeDependenceKind::Default;
5071+
// look for optional "scoped"
5072+
if (Tok.isContextualKeyword("scoped")) {
5073+
lifetimeDependenceKind = ParsedLifetimeDependenceKind::Scope;
5074+
// consume scoped
5075+
consumeToken();
5076+
}
5077+
50855078
SourceLoc rParenLoc;
50865079
bool foundParamId = false;
50875080
status = parseList(
@@ -5097,7 +5090,7 @@ ParserStatus Parser::parseLifetimeDependenceSpecifiers(
50975090
specifierList.push_back(
50985091
LifetimeDependenceSpecifier::
50995092
getNamedLifetimeDependenceSpecifier(
5100-
paramLoc, *lifetimeDependenceKind, paramName));
5093+
paramLoc, lifetimeDependenceKind, paramName));
51015094
break;
51025095
}
51035096
case tok::integer_literal: {
@@ -5112,14 +5105,14 @@ ParserStatus Parser::parseLifetimeDependenceSpecifiers(
51125105
specifierList.push_back(
51135106
LifetimeDependenceSpecifier::
51145107
getOrderedLifetimeDependenceSpecifier(
5115-
paramLoc, *lifetimeDependenceKind, paramNum));
5108+
paramLoc, lifetimeDependenceKind, paramNum));
51165109
break;
51175110
}
51185111
case tok::kw_self: {
51195112
auto paramLoc = consumeToken(tok::kw_self);
51205113
specifierList.push_back(
51215114
LifetimeDependenceSpecifier::getSelfLifetimeDependenceSpecifier(
5122-
paramLoc, *lifetimeDependenceKind));
5115+
paramLoc, lifetimeDependenceKind));
51235116
break;
51245117
}
51255118
default:
@@ -5454,7 +5447,7 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
54545447
continue;
54555448
}
54565449

5457-
if (Tok.isLifetimeDependenceToken()) {
5450+
if (Tok.is(tok::at_sign) && P.peekToken().isLifetimeDependenceToken()) {
54585451
if (!P.Context.LangOpts.hasFeature(Feature::NonescapableTypes)) {
54595452
P.diagnose(Tok, diag::requires_experimental_feature,
54605453
"lifetime dependence specifier", false,
@@ -5488,6 +5481,9 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
54885481
}
54895482

54905483
while (Tok.is(tok::at_sign)) {
5484+
// @dependsOn is handled like other type specifiers (borrowing, consuming,
5485+
// transferring etc).
5486+
assert(!P.peekToken().isLifetimeDependenceToken());
54915487
// Ignore @substituted in SIL mode and leave it for the type parser.
54925488
if (P.isInSILMode() && P.peekToken().getText() == "substituted")
54935489
return status;

0 commit comments

Comments
 (0)