Skip to content

Commit 26733c2

Browse files
committed
[region-isolation] Add parsing/serialization/type system support for a transferring OwnershipSpecifier.
1 parent e7475c8 commit 26733c2

21 files changed

+162
-47
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,7 @@ enum ENUM_EXTENSIBILITY_ATTR(open) BridgedAttributedTypeSpecifier : size_t {
12351235
BridgedAttributedTypeSpecifierConst,
12361236
BridgedAttributedTypeSpecifierIsolated,
12371237
BridgedAttributedTypeSpecifierResultDependsOn,
1238+
BridgedAttributedTypeSpecifierTransferring,
12381239
};
12391240

12401241
SWIFT_NAME("BridgedSimpleIdentTypeRepr.createParsed(_:loc:name:)")

include/swift/AST/Attr.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,10 @@ SIMPLE_DECL_ATTR(_noObjCBridging, NoObjCBridging,
549549
CONTEXTUAL_SIMPLE_DECL_ATTR(_resultDependsOn, ResultDependsOn,
550550
OnParam | DeclModifier | UserInaccessible | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
551551
156)
552+
CONTEXTUAL_SIMPLE_DECL_ATTR(transferring, Transferring,
553+
OnParam | DeclModifier | UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIStableToRemove,
554+
157)
555+
552556
#undef TYPE_ATTR
553557
#undef DECL_ATTR_ALIAS
554558
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6718,6 +6718,7 @@ class ParamDecl : public VarDecl {
67186718
return true;
67196719
case Specifier::Consuming:
67206720
case Specifier::InOut:
6721+
case Specifier::Transferring:
67216722
return false;
67226723
}
67236724
llvm_unreachable("unhandled specifier");
@@ -6735,6 +6736,7 @@ class ParamDecl : public VarDecl {
67356736
case ParamSpecifier::LegacyShared:
67366737
return ValueOwnership::Shared;
67376738
case ParamSpecifier::Consuming:
6739+
case ParamSpecifier::Transferring:
67386740
case ParamSpecifier::LegacyOwned:
67396741
return ValueOwnership::Owned;
67406742
case ParamSpecifier::Default:

include/swift/AST/Types.h

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,7 +2213,11 @@ enum class ParamSpecifier : uint8_t {
22132213
/// `__shared`, a legacy spelling of `borrowing`.
22142214
LegacyShared = 4,
22152215
/// `__owned`, a legacy spelling of `consuming`.
2216-
LegacyOwned = 5
2216+
LegacyOwned = 5,
2217+
2218+
/// `transferring`. Indicating the transfer of a value from one isolation
2219+
/// domain to another.
2220+
Transferring = 6,
22172221
};
22182222

22192223
/// Provide parameter type relevant flags, i.e. variadic, autoclosure, and
@@ -2230,7 +2234,8 @@ class ParameterTypeFlags {
22302234
Isolated = 1 << 7,
22312235
CompileTimeConst = 1 << 8,
22322236
ResultDependsOn = 1 << 9,
2233-
NumBits = 10
2237+
Transferring = 1 << 10,
2238+
NumBits = 11
22342239
};
22352240
OptionSet<ParameterFlags> value;
22362241
static_assert(NumBits <= 8*sizeof(OptionSet<ParameterFlags>), "overflowed");
@@ -2245,20 +2250,22 @@ class ParameterTypeFlags {
22452250

22462251
ParameterTypeFlags(bool variadic, bool autoclosure, bool nonEphemeral,
22472252
ParamSpecifier specifier, bool isolated, bool noDerivative,
2248-
bool compileTimeConst, bool hasResultDependsOn)
2253+
bool compileTimeConst, bool hasResultDependsOn,
2254+
bool isTransferring)
22492255
: value((variadic ? Variadic : 0) | (autoclosure ? AutoClosure : 0) |
22502256
(nonEphemeral ? NonEphemeral : 0) |
22512257
uint8_t(specifier) << SpecifierShift | (isolated ? Isolated : 0) |
22522258
(noDerivative ? NoDerivative : 0) |
22532259
(compileTimeConst ? CompileTimeConst : 0) |
2254-
(hasResultDependsOn ? ResultDependsOn : 0)) {}
2260+
(hasResultDependsOn ? ResultDependsOn : 0) |
2261+
(isTransferring ? Transferring : 0)) {}
22552262

22562263
/// Create one from what's present in the parameter type
22572264
inline static ParameterTypeFlags
22582265
fromParameterType(Type paramTy, bool isVariadic, bool isAutoClosure,
22592266
bool isNonEphemeral, ParamSpecifier ownership,
22602267
bool isolated, bool isNoDerivative, bool compileTimeConst,
2261-
bool hasResultDependsOn);
2268+
bool hasResultDependsOn, bool isTransferring);
22622269

22632270
bool isNone() const { return !value; }
22642271
bool isVariadic() const { return value.contains(Variadic); }
@@ -2271,6 +2278,7 @@ class ParameterTypeFlags {
22712278
bool isCompileTimeConst() const { return value.contains(CompileTimeConst); }
22722279
bool isNoDerivative() const { return value.contains(NoDerivative); }
22732280
bool hasResultDependsOn() const { return value.contains(ResultDependsOn); }
2281+
bool isTransferring() const { return value.contains(Transferring); }
22742282

22752283
/// Get the spelling of the parameter specifier used on the parameter.
22762284
ParamSpecifier getOwnershipSpecifier() const {
@@ -2333,6 +2341,12 @@ class ParameterTypeFlags {
23332341
: value - ParameterTypeFlags::NoDerivative);
23342342
}
23352343

2344+
ParameterTypeFlags withTransferring(bool withTransferring) const {
2345+
return ParameterTypeFlags(withTransferring
2346+
? value | ParameterTypeFlags::Transferring
2347+
: value - ParameterTypeFlags::Transferring);
2348+
}
2349+
23362350
bool operator ==(const ParameterTypeFlags &other) const {
23372351
return value.toRaw() == other.value.toRaw();
23382352
}
@@ -2426,7 +2440,8 @@ class YieldTypeFlags {
24262440
/*nonEphemeral*/ false, getOwnershipSpecifier(),
24272441
/*isolated*/ false, /*noDerivative*/ false,
24282442
/*compileTimeConst*/ false,
2429-
/*hasResultDependsOn*/ false);
2443+
/*hasResultDependsOn*/ false,
2444+
/*is transferring*/ false);
24302445
}
24312446

24322447
bool operator ==(const YieldTypeFlags &other) const {
@@ -4113,6 +4128,9 @@ class SILParameterInfo {
41134128
/// - If the function type is `@differentiable`, the function is
41144129
/// differentiable with respect to this parameter.
41154130
NotDifferentiable = 0x1,
4131+
4132+
/// Set if the given parameter is transferring.
4133+
Transferring = 0x2,
41164134
};
41174135

41184136
using Options = OptionSet<Flag>;
@@ -7629,7 +7647,7 @@ inline TupleTypeElt TupleTypeElt::getWithType(Type T) const {
76297647
inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
76307648
Type paramTy, bool isVariadic, bool isAutoClosure, bool isNonEphemeral,
76317649
ParamSpecifier ownership, bool isolated, bool isNoDerivative,
7632-
bool compileTimeConst, bool hasResultDependsOn) {
7650+
bool compileTimeConst, bool hasResultDependsOn, bool isTransferring) {
76337651
// FIXME(Remove InOut): The last caller that needs this is argument
76347652
// decomposition. Start by enabling the assertion there and fixing up those
76357653
// callers, then remove this, then remove
@@ -7639,8 +7657,9 @@ inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
76397657
ownership == ParamSpecifier::InOut);
76407658
ownership = ParamSpecifier::InOut;
76417659
}
7642-
return {isVariadic, isAutoClosure, isNonEphemeral, ownership,
7643-
isolated, isNoDerivative, compileTimeConst, hasResultDependsOn};
7660+
return {isVariadic, isAutoClosure, isNonEphemeral,
7661+
ownership, isolated, isNoDerivative,
7662+
compileTimeConst, hasResultDependsOn, isTransferring};
76447663
}
76457664

76467665
inline const Type *BoundGenericType::getTrailingObjectsPointer() const {

lib/AST/ASTBridging.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,10 @@ BridgedSpecifierTypeRepr BridgedSpecifierTypeRepr_createParsed(
17051705
return new (context)
17061706
OwnershipTypeRepr(baseType, ParamSpecifier::LegacyOwned, loc);
17071707
}
1708+
case BridgedAttributedTypeSpecifierTransferring: {
1709+
return new (context)
1710+
OwnershipTypeRepr(baseType, ParamSpecifier::Transferring, loc);
1711+
}
17081712
case BridgedAttributedTypeSpecifierConst: {
17091713
return new (context) CompileTimeConstTypeRepr(baseType, loc);
17101714
}

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2891,7 +2891,8 @@ getParameterFlagsForMangling(ParameterTypeFlags flags,
28912891
// `inout` should already be specified in the flags.
28922892
case ParamSpecifier::InOut:
28932893
return flags;
2894-
2894+
2895+
case ParamSpecifier::Transferring:
28952896
case ParamSpecifier::Consuming:
28962897
case ParamSpecifier::Borrowing:
28972898
// Only mangle the ownership if it diverges from the default.

lib/AST/ASTPrinter.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3906,7 +3906,15 @@ static bool usesFeatureExtractConstantsFromMembers(Decl *decl) {
39063906

39073907
static bool usesFeatureBitwiseCopyable(Decl *decl) { return false; }
39083908

3909-
static bool usesFeatureTransferringArgsAndResults(Decl *decl) { return false; }
3909+
static bool usesFeatureTransferringArgsAndResults(Decl *decl) {
3910+
if (auto *pd = dyn_cast<ParamDecl>(decl))
3911+
if (pd->getSpecifier() == ParamSpecifier::Transferring)
3912+
return true;
3913+
3914+
// TODO: Results.
3915+
3916+
return false;
3917+
}
39103918

39113919
static bool usesFeaturePreconcurrencyConformances(Decl *decl) {
39123920
auto usesPreconcurrencyConformance = [&](const InheritedTypes &inherited) {
@@ -4567,6 +4575,8 @@ static void printParameterFlags(ASTPrinter &printer,
45674575
printer.printAttrName("@autoclosure ");
45684576
if (!options.excludeAttrKind(TAK_noDerivative) && flags.isNoDerivative())
45694577
printer.printAttrName("@noDerivative ");
4578+
if (flags.isTransferring())
4579+
printer.printAttrName("@transferring ");
45704580

45714581
switch (flags.getOwnershipSpecifier()) {
45724582
case ParamSpecifier::Default:
@@ -4587,6 +4597,9 @@ static void printParameterFlags(ASTPrinter &printer,
45874597
case ParamSpecifier::LegacyOwned:
45884598
printer.printKeyword("__owned", options, " ");
45894599
break;
4600+
case ParamSpecifier::Transferring:
4601+
printer.printKeyword("transferring", options, " ");
4602+
break;
45904603
}
45914604

45924605
if (flags.isIsolated())
@@ -8068,6 +8081,11 @@ void SILParameterInfo::print(ASTPrinter &Printer,
80688081
Printer << "@noDerivative ";
80698082
}
80708083

8084+
if (options.contains(SILParameterInfo::Transferring)) {
8085+
options -= SILParameterInfo::Transferring;
8086+
Printer << "@transferring ";
8087+
}
8088+
80718089
// If we did not handle a case in Options, this code was not updated
80728090
// appropriately.
80738091
assert(!bool(options) && "Code not updated for introduced option");

lib/AST/Decl.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7730,6 +7730,7 @@ void ParamDecl::setSpecifier(Specifier specifier) {
77307730
// `inout` and `consuming` parameters are locally mutable.
77317731
case ParamSpecifier::InOut:
77327732
case ParamSpecifier::Consuming:
7733+
case ParamSpecifier::Transferring:
77337734
introducer = VarDecl::Introducer::Var;
77347735
break;
77357736
}
@@ -7793,6 +7794,8 @@ StringRef ParamDecl::getSpecifierSpelling(ParamSpecifier specifier) {
77937794
return "__shared";
77947795
case ParamSpecifier::LegacyOwned:
77957796
return "__owned";
7797+
case ParamSpecifier::Transferring:
7798+
return "transferring";
77967799
}
77977800
llvm_unreachable("invalid ParamSpecifier");
77987801
}
@@ -8394,7 +8397,8 @@ AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const {
83948397
auto flags = ParameterTypeFlags::fromParameterType(
83958398
type, isVariadic(), isAutoClosure(), isNonEphemeral(), getSpecifier(),
83968399
isIsolated(), /*isNoDerivative*/ false, isCompileTimeConst(),
8397-
hasResultDependsOn());
8400+
hasResultDependsOn(),
8401+
getSpecifier() == ParamDecl::Specifier::Transferring /*is transferring*/);
83988402
return AnyFunctionType::Param(type, label, flags, internalLabel);
83998403
}
84008404

lib/Parse/ParseDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5139,6 +5139,7 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51395139
Tok.isContextualKeyword("isolated") ||
51405140
Tok.isContextualKeyword("consuming") ||
51415141
Tok.isContextualKeyword("borrowing") ||
5142+
Tok.isContextualKeyword("transferring") ||
51425143
Tok.isContextualKeyword("_const") ||
51435144
Tok.isContextualKeyword("_resultDependsOn")))) {
51445145

@@ -5166,6 +5167,15 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51665167
continue;
51675168
}
51685169

5170+
// Perform an extra check for transferring. Since it is a specifier, we use
5171+
// the actual parsing logic below.
5172+
if (Tok.isContextualKeyword("transferring")) {
5173+
if (!P.Context.LangOpts.hasFeature(Feature::TransferringArgsAndResults)) {
5174+
P.diagnose(Tok, diag::requires_experimental_feature, "transferring",
5175+
false, getFeatureName(Feature::TransferringArgsAndResults));
5176+
}
5177+
}
5178+
51695179
if (SpecifierLoc.isValid()) {
51705180
P.diagnose(Tok, diag::parameter_specifier_repeated)
51715181
.fixItRemove(SpecifierLoc);
@@ -5179,6 +5189,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51795189
Specifier = ParamDecl::Specifier::LegacyOwned;
51805190
} else if (Tok.getRawText().equals("borrowing")) {
51815191
Specifier = ParamDecl::Specifier::Borrowing;
5192+
} else if (Tok.getRawText().equals("transferring")) {
5193+
Specifier = ParamDecl::Specifier::Transferring;
51825194
} else if (Tok.getRawText().equals("consuming")) {
51835195
Specifier = ParamDecl::Specifier::Consuming;
51845196
}
@@ -7541,6 +7553,8 @@ static ParserStatus parseAccessorIntroducer(Parser &P,
75417553
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Consuming);
75427554
} else if (P.Tok.isContextualKeyword("borrowing")) {
75437555
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Borrowing);
7556+
} else if (P.Tok.isContextualKeyword("transferring")) {
7557+
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Transferring);
75447558
}
75457559
}
75467560

lib/Parse/ParsePattern.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ bool Parser::startsParameterName(bool isClosure) {
139139
!Tok.isContextualKeyword("__shared") &&
140140
!Tok.isContextualKeyword("__owned") &&
141141
!Tok.isContextualKeyword("borrowing") &&
142+
(!Context.LangOpts.hasFeature(Feature::TransferringArgsAndResults) ||
143+
!Tok.isContextualKeyword("transferring")) &&
142144
!Tok.isContextualKeyword("consuming") && !Tok.is(tok::kw_repeat) &&
143145
(!Context.LangOpts.hasFeature(Feature::NonescapableTypes) ||
144146
!Tok.isContextualKeyword("_resultDependsOn")))
@@ -236,7 +238,9 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
236238
Tok.isContextualKeyword("isolated") ||
237239
Tok.isContextualKeyword("_const") ||
238240
(Context.LangOpts.hasFeature(Feature::NonescapableTypes) &&
239-
Tok.isContextualKeyword("_resultDependsOn"))))) {
241+
Tok.isContextualKeyword("_resultDependsOn")) ||
242+
(Context.LangOpts.hasFeature(
243+
Feature::TransferringArgsAndResults))))) {
240244
// is this token the identifier of an argument label? `inout` is a
241245
// reserved keyword but the other modifiers are not.
242246
if (!Tok.is(tok::kw_inout)) {
@@ -288,7 +292,13 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
288292
} else if (Tok.isContextualKeyword("__owned")) {
289293
param.SpecifierKind = ParamDecl::Specifier::LegacyOwned;
290294
param.SpecifierLoc = consumeToken();
295+
} else if (Context.LangOpts.hasFeature(
296+
Feature::TransferringArgsAndResults) &&
297+
Tok.isContextualKeyword("transferring")) {
298+
param.SpecifierKind = ParamDecl::Specifier::Transferring;
299+
param.SpecifierLoc = consumeToken();
291300
}
301+
292302
hasSpecifier = true;
293303
} else {
294304
// Redundant specifiers are fairly common, recognize, reject, and

lib/Parse/ParseType.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
163163
Tok.getRawText().equals("consuming") ||
164164
Tok.getRawText().equals("borrowing") ||
165165
(Context.LangOpts.hasFeature(Feature::NonescapableTypes) &&
166-
Tok.getRawText().equals("resultDependsOn"))))) {
166+
Tok.getRawText().equals("resultDependsOn")) ||
167+
(Context.LangOpts.hasFeature(Feature::TransferringArgsAndResults) &&
168+
Tok.getRawText().equals("transferring"))))) {
167169
// Type specifier should already be parsed before here. This only happens
168170
// for construct like 'P1 & inout P2'.
169171
diagnose(Tok.getLoc(), diag::attr_only_on_parameters, Tok.getRawText());

0 commit comments

Comments
 (0)