Skip to content

Commit 9513d29

Browse files
committed
[region-isolation] Add parsing/serialization/type system support for a transferring OwnershipSpecifier.
1 parent 728d680 commit 9513d29

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
@@ -6727,6 +6727,7 @@ class ParamDecl : public VarDecl {
67276727
return true;
67286728
case Specifier::Consuming:
67296729
case Specifier::InOut:
6730+
case Specifier::Transferring:
67306731
return false;
67316732
}
67326733
llvm_unreachable("unhandled specifier");
@@ -6744,6 +6745,7 @@ class ParamDecl : public VarDecl {
67446745
case ParamSpecifier::LegacyShared:
67456746
return ValueOwnership::Shared;
67466747
case ParamSpecifier::Consuming:
6748+
case ParamSpecifier::Transferring:
67476749
case ParamSpecifier::LegacyOwned:
67486750
return ValueOwnership::Owned;
67496751
case ParamSpecifier::Default:

include/swift/AST/Types.h

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

22172221
/// Provide parameter type relevant flags, i.e. variadic, autoclosure, and
@@ -2228,7 +2232,8 @@ class ParameterTypeFlags {
22282232
Isolated = 1 << 7,
22292233
CompileTimeConst = 1 << 8,
22302234
ResultDependsOn = 1 << 9,
2231-
NumBits = 10
2235+
Transferring = 1 << 10,
2236+
NumBits = 11
22322237
};
22332238
OptionSet<ParameterFlags> value;
22342239
static_assert(NumBits <= 8*sizeof(OptionSet<ParameterFlags>), "overflowed");
@@ -2243,20 +2248,22 @@ class ParameterTypeFlags {
22432248

22442249
ParameterTypeFlags(bool variadic, bool autoclosure, bool nonEphemeral,
22452250
ParamSpecifier specifier, bool isolated, bool noDerivative,
2246-
bool compileTimeConst, bool hasResultDependsOn)
2251+
bool compileTimeConst, bool hasResultDependsOn,
2252+
bool isTransferring)
22472253
: value((variadic ? Variadic : 0) | (autoclosure ? AutoClosure : 0) |
22482254
(nonEphemeral ? NonEphemeral : 0) |
22492255
uint8_t(specifier) << SpecifierShift | (isolated ? Isolated : 0) |
22502256
(noDerivative ? NoDerivative : 0) |
22512257
(compileTimeConst ? CompileTimeConst : 0) |
2252-
(hasResultDependsOn ? ResultDependsOn : 0)) {}
2258+
(hasResultDependsOn ? ResultDependsOn : 0) |
2259+
(isTransferring ? Transferring : 0)) {}
22532260

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

22612268
bool isNone() const { return !value; }
22622269
bool isVariadic() const { return value.contains(Variadic); }
@@ -2269,6 +2276,7 @@ class ParameterTypeFlags {
22692276
bool isCompileTimeConst() const { return value.contains(CompileTimeConst); }
22702277
bool isNoDerivative() const { return value.contains(NoDerivative); }
22712278
bool hasResultDependsOn() const { return value.contains(ResultDependsOn); }
2279+
bool isTransferring() const { return value.contains(Transferring); }
22722280

22732281
/// Get the spelling of the parameter specifier used on the parameter.
22742282
ParamSpecifier getOwnershipSpecifier() const {
@@ -2331,6 +2339,12 @@ class ParameterTypeFlags {
23312339
: value - ParameterTypeFlags::NoDerivative);
23322340
}
23332341

2342+
ParameterTypeFlags withTransferring(bool withTransferring) const {
2343+
return ParameterTypeFlags(withTransferring
2344+
? value | ParameterTypeFlags::Transferring
2345+
: value - ParameterTypeFlags::Transferring);
2346+
}
2347+
23342348
bool operator ==(const ParameterTypeFlags &other) const {
23352349
return value.toRaw() == other.value.toRaw();
23362350
}
@@ -2424,7 +2438,8 @@ class YieldTypeFlags {
24242438
/*nonEphemeral*/ false, getOwnershipSpecifier(),
24252439
/*isolated*/ false, /*noDerivative*/ false,
24262440
/*compileTimeConst*/ false,
2427-
/*hasResultDependsOn*/ false);
2441+
/*hasResultDependsOn*/ false,
2442+
/*is transferring*/ false);
24282443
}
24292444

24302445
bool operator ==(const YieldTypeFlags &other) const {
@@ -4111,6 +4126,9 @@ class SILParameterInfo {
41114126
/// - If the function type is `@differentiable`, the function is
41124127
/// differentiable with respect to this parameter.
41134128
NotDifferentiable = 0x1,
4129+
4130+
/// Set if the given parameter is transferring.
4131+
Transferring = 0x2,
41144132
};
41154133

41164134
using Options = OptionSet<Flag>;
@@ -7627,7 +7645,7 @@ inline TupleTypeElt TupleTypeElt::getWithType(Type T) const {
76277645
inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
76287646
Type paramTy, bool isVariadic, bool isAutoClosure, bool isNonEphemeral,
76297647
ParamSpecifier ownership, bool isolated, bool isNoDerivative,
7630-
bool compileTimeConst, bool hasResultDependsOn) {
7648+
bool compileTimeConst, bool hasResultDependsOn, bool isTransferring) {
76317649
// FIXME(Remove InOut): The last caller that needs this is argument
76327650
// decomposition. Start by enabling the assertion there and fixing up those
76337651
// callers, then remove this, then remove
@@ -7637,8 +7655,9 @@ inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
76377655
ownership == ParamSpecifier::InOut);
76387656
ownership = ParamSpecifier::InOut;
76397657
}
7640-
return {isVariadic, isAutoClosure, isNonEphemeral, ownership,
7641-
isolated, isNoDerivative, compileTimeConst, hasResultDependsOn};
7658+
return {isVariadic, isAutoClosure, isNonEphemeral,
7659+
ownership, isolated, isNoDerivative,
7660+
compileTimeConst, hasResultDependsOn, isTransferring};
76427661
}
76437662

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

lib/AST/ASTBridging.cpp

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

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2875,7 +2875,8 @@ getParameterFlagsForMangling(ParameterTypeFlags flags,
28752875
// `inout` should already be specified in the flags.
28762876
case ParamSpecifier::InOut:
28772877
return flags;
2878-
2878+
2879+
case ParamSpecifier::Transferring:
28792880
case ParamSpecifier::Consuming:
28802881
case ParamSpecifier::Borrowing:
28812882
// 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
@@ -7746,6 +7746,7 @@ void ParamDecl::setSpecifier(Specifier specifier) {
77467746
// `inout` and `consuming` parameters are locally mutable.
77477747
case ParamSpecifier::InOut:
77487748
case ParamSpecifier::Consuming:
7749+
case ParamSpecifier::Transferring:
77497750
introducer = VarDecl::Introducer::Var;
77507751
break;
77517752
}
@@ -7809,6 +7810,8 @@ StringRef ParamDecl::getSpecifierSpelling(ParamSpecifier specifier) {
78097810
return "__shared";
78107811
case ParamSpecifier::LegacyOwned:
78117812
return "__owned";
7813+
case ParamSpecifier::Transferring:
7814+
return "transferring";
78127815
}
78137816
llvm_unreachable("invalid ParamSpecifier");
78147817
}
@@ -8410,7 +8413,8 @@ AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const {
84108413
auto flags = ParameterTypeFlags::fromParameterType(
84118414
type, isVariadic(), isAutoClosure(), isNonEphemeral(), getSpecifier(),
84128415
isIsolated(), /*isNoDerivative*/ false, isCompileTimeConst(),
8413-
hasResultDependsOn());
8416+
hasResultDependsOn(),
8417+
getSpecifier() == ParamDecl::Specifier::Transferring /*is transferring*/);
84148418
return AnyFunctionType::Param(type, label, flags, internalLabel);
84158419
}
84168420

lib/Parse/ParseDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5137,6 +5137,7 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51375137
Tok.isContextualKeyword("isolated") ||
51385138
Tok.isContextualKeyword("consuming") ||
51395139
Tok.isContextualKeyword("borrowing") ||
5140+
Tok.isContextualKeyword("transferring") ||
51405141
Tok.isContextualKeyword("_const") ||
51415142
Tok.isContextualKeyword("_resultDependsOn")))) {
51425143

@@ -5164,6 +5165,15 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51645165
continue;
51655166
}
51665167

5168+
// Perform an extra check for transferring. Since it is a specifier, we use
5169+
// the actual parsing logic below.
5170+
if (Tok.isContextualKeyword("transferring")) {
5171+
if (!P.Context.LangOpts.hasFeature(Feature::TransferringArgsAndResults)) {
5172+
P.diagnose(Tok, diag::requires_experimental_feature, "transferring",
5173+
false, getFeatureName(Feature::TransferringArgsAndResults));
5174+
}
5175+
}
5176+
51675177
if (SpecifierLoc.isValid()) {
51685178
P.diagnose(Tok, diag::parameter_specifier_repeated)
51695179
.fixItRemove(SpecifierLoc);
@@ -5177,6 +5187,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51775187
Specifier = ParamDecl::Specifier::LegacyOwned;
51785188
} else if (Tok.getRawText().equals("borrowing")) {
51795189
Specifier = ParamDecl::Specifier::Borrowing;
5190+
} else if (Tok.getRawText().equals("transferring")) {
5191+
Specifier = ParamDecl::Specifier::Transferring;
51805192
} else if (Tok.getRawText().equals("consuming")) {
51815193
Specifier = ParamDecl::Specifier::Consuming;
51825194
}
@@ -7539,6 +7551,8 @@ static ParserStatus parseAccessorIntroducer(Parser &P,
75397551
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Consuming);
75407552
} else if (P.Tok.isContextualKeyword("borrowing")) {
75417553
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Borrowing);
7554+
} else if (P.Tok.isContextualKeyword("transferring")) {
7555+
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Transferring);
75427556
}
75437557
}
75447558

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)