Skip to content

Commit b15c4c9

Browse files
committed
[region-isolation] Add parsing/serialization/type system support for a transferring OwnershipSpecifier.
1 parent 22d9e85 commit b15c4c9

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
@@ -1234,6 +1234,7 @@ enum ENUM_EXTENSIBILITY_ATTR(open) BridgedAttributedTypeSpecifier : size_t {
12341234
BridgedAttributedTypeSpecifierConst,
12351235
BridgedAttributedTypeSpecifierIsolated,
12361236
BridgedAttributedTypeSpecifierResultDependsOn,
1237+
BridgedAttributedTypeSpecifierTransferring,
12371238
};
12381239

12391240
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
@@ -548,6 +548,10 @@ SIMPLE_DECL_ATTR(_noObjCBridging, NoObjCBridging,
548548
CONTEXTUAL_SIMPLE_DECL_ATTR(_resultDependsOn, ResultDependsOn,
549549
OnParam | DeclModifier | UserInaccessible | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
550550
156)
551+
CONTEXTUAL_SIMPLE_DECL_ATTR(transferring, Transferring,
552+
OnParam | DeclModifier | UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIStableToRemove,
553+
157)
554+
551555
#undef TYPE_ATTR
552556
#undef DECL_ATTR_ALIAS
553557
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6714,6 +6714,7 @@ class ParamDecl : public VarDecl {
67146714
return true;
67156715
case Specifier::Consuming:
67166716
case Specifier::InOut:
6717+
case Specifier::Transferring:
67176718
return false;
67186719
}
67196720
llvm_unreachable("unhandled specifier");
@@ -6731,6 +6732,7 @@ class ParamDecl : public VarDecl {
67316732
case ParamSpecifier::LegacyShared:
67326733
return ValueOwnership::Shared;
67336734
case ParamSpecifier::Consuming:
6735+
case ParamSpecifier::Transferring:
67346736
case ParamSpecifier::LegacyOwned:
67356737
return ValueOwnership::Owned;
67366738
case ParamSpecifier::Default:

include/swift/AST/Types.h

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

22152219
/// Provide parameter type relevant flags, i.e. variadic, autoclosure, and
@@ -2226,7 +2230,8 @@ class ParameterTypeFlags {
22262230
Isolated = 1 << 7,
22272231
CompileTimeConst = 1 << 8,
22282232
ResultDependsOn = 1 << 9,
2229-
NumBits = 10
2233+
Transferring = 1 << 10,
2234+
NumBits = 11
22302235
};
22312236
OptionSet<ParameterFlags> value;
22322237
static_assert(NumBits <= 8*sizeof(OptionSet<ParameterFlags>), "overflowed");
@@ -2241,20 +2246,22 @@ class ParameterTypeFlags {
22412246

22422247
ParameterTypeFlags(bool variadic, bool autoclosure, bool nonEphemeral,
22432248
ParamSpecifier specifier, bool isolated, bool noDerivative,
2244-
bool compileTimeConst, bool hasResultDependsOn)
2249+
bool compileTimeConst, bool hasResultDependsOn,
2250+
bool isTransferring)
22452251
: value((variadic ? Variadic : 0) | (autoclosure ? AutoClosure : 0) |
22462252
(nonEphemeral ? NonEphemeral : 0) |
22472253
uint8_t(specifier) << SpecifierShift | (isolated ? Isolated : 0) |
22482254
(noDerivative ? NoDerivative : 0) |
22492255
(compileTimeConst ? CompileTimeConst : 0) |
2250-
(hasResultDependsOn ? ResultDependsOn : 0)) {}
2256+
(hasResultDependsOn ? ResultDependsOn : 0) |
2257+
(isTransferring ? Transferring : 0)) {}
22512258

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

22592266
bool isNone() const { return !value; }
22602267
bool isVariadic() const { return value.contains(Variadic); }
@@ -2267,6 +2274,7 @@ class ParameterTypeFlags {
22672274
bool isCompileTimeConst() const { return value.contains(CompileTimeConst); }
22682275
bool isNoDerivative() const { return value.contains(NoDerivative); }
22692276
bool hasResultDependsOn() const { return value.contains(ResultDependsOn); }
2277+
bool isTransferring() const { return value.contains(Transferring); }
22702278

22712279
/// Get the spelling of the parameter specifier used on the parameter.
22722280
ParamSpecifier getOwnershipSpecifier() const {
@@ -2329,6 +2337,12 @@ class ParameterTypeFlags {
23292337
: value - ParameterTypeFlags::NoDerivative);
23302338
}
23312339

2340+
ParameterTypeFlags withTransferring(bool withTransferring) const {
2341+
return ParameterTypeFlags(withTransferring
2342+
? value | ParameterTypeFlags::Transferring
2343+
: value - ParameterTypeFlags::Transferring);
2344+
}
2345+
23322346
bool operator ==(const ParameterTypeFlags &other) const {
23332347
return value.toRaw() == other.value.toRaw();
23342348
}
@@ -2422,7 +2436,8 @@ class YieldTypeFlags {
24222436
/*nonEphemeral*/ false, getOwnershipSpecifier(),
24232437
/*isolated*/ false, /*noDerivative*/ false,
24242438
/*compileTimeConst*/ false,
2425-
/*hasResultDependsOn*/ false);
2439+
/*hasResultDependsOn*/ false,
2440+
/*is transferring*/ false);
24262441
}
24272442

24282443
bool operator ==(const YieldTypeFlags &other) const {
@@ -4109,6 +4124,9 @@ class SILParameterInfo {
41094124
/// - If the function type is `@differentiable`, the function is
41104125
/// differentiable with respect to this parameter.
41114126
NotDifferentiable = 0x1,
4127+
4128+
/// Set if the given parameter is transferring.
4129+
Transferring = 0x2,
41124130
};
41134131

41144132
using Options = OptionSet<Flag>;
@@ -7624,7 +7642,7 @@ inline TupleTypeElt TupleTypeElt::getWithType(Type T) const {
76247642
inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
76257643
Type paramTy, bool isVariadic, bool isAutoClosure, bool isNonEphemeral,
76267644
ParamSpecifier ownership, bool isolated, bool isNoDerivative,
7627-
bool compileTimeConst, bool hasResultDependsOn) {
7645+
bool compileTimeConst, bool hasResultDependsOn, bool isTransferring) {
76287646
// FIXME(Remove InOut): The last caller that needs this is argument
76297647
// decomposition. Start by enabling the assertion there and fixing up those
76307648
// callers, then remove this, then remove
@@ -7634,8 +7652,9 @@ inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
76347652
ownership == ParamSpecifier::InOut);
76357653
ownership = ParamSpecifier::InOut;
76367654
}
7637-
return {isVariadic, isAutoClosure, isNonEphemeral, ownership,
7638-
isolated, isNoDerivative, compileTimeConst, hasResultDependsOn};
7655+
return {isVariadic, isAutoClosure, isNonEphemeral,
7656+
ownership, isolated, isNoDerivative,
7657+
compileTimeConst, hasResultDependsOn, isTransferring};
76397658
}
76407659

76417660
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
@@ -3887,7 +3887,15 @@ static bool usesFeatureExtractConstantsFromMembers(Decl *decl) {
38873887

38883888
static bool usesFeatureBitwiseCopyable(Decl *decl) { return false; }
38893889

3890-
static bool usesFeatureTransferringArgsAndResults(Decl *decl) { return false; }
3890+
static bool usesFeatureTransferringArgsAndResults(Decl *decl) {
3891+
if (auto *pd = dyn_cast<ParamDecl>(decl))
3892+
if (pd->getSpecifier() == ParamSpecifier::Transferring)
3893+
return true;
3894+
3895+
// TODO: Results.
3896+
3897+
return false;
3898+
}
38913899

38923900
/// Suppress the printing of a particular feature.
38933901
static void suppressingFeature(PrintOptions &options, Feature feature,
@@ -4524,6 +4532,8 @@ static void printParameterFlags(ASTPrinter &printer,
45244532
printer.printAttrName("@autoclosure ");
45254533
if (!options.excludeAttrKind(TAK_noDerivative) && flags.isNoDerivative())
45264534
printer.printAttrName("@noDerivative ");
4535+
if (flags.isTransferring())
4536+
printer.printAttrName("@transferring ");
45274537

45284538
switch (flags.getOwnershipSpecifier()) {
45294539
case ParamSpecifier::Default:
@@ -4544,6 +4554,9 @@ static void printParameterFlags(ASTPrinter &printer,
45444554
case ParamSpecifier::LegacyOwned:
45454555
printer.printKeyword("__owned", options, " ");
45464556
break;
4557+
case ParamSpecifier::Transferring:
4558+
printer.printKeyword("transferring", options, " ");
4559+
break;
45474560
}
45484561

45494562
if (flags.isIsolated())
@@ -8016,6 +8029,11 @@ void SILParameterInfo::print(ASTPrinter &Printer,
80168029
Printer << "@noDerivative ";
80178030
}
80188031

8032+
if (options.contains(SILParameterInfo::Transferring)) {
8033+
options -= SILParameterInfo::Transferring;
8034+
Printer << "@transferring ";
8035+
}
8036+
80198037
// If we did not handle a case in Options, this code was not updated
80208038
// appropriately.
80218039
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
@@ -7702,6 +7702,7 @@ void ParamDecl::setSpecifier(Specifier specifier) {
77027702
// `inout` and `consuming` parameters are locally mutable.
77037703
case ParamSpecifier::InOut:
77047704
case ParamSpecifier::Consuming:
7705+
case ParamSpecifier::Transferring:
77057706
introducer = VarDecl::Introducer::Var;
77067707
break;
77077708
}
@@ -7765,6 +7766,8 @@ StringRef ParamDecl::getSpecifierSpelling(ParamSpecifier specifier) {
77657766
return "__shared";
77667767
case ParamSpecifier::LegacyOwned:
77677768
return "__owned";
7769+
case ParamSpecifier::Transferring:
7770+
return "transferring";
77687771
}
77697772
llvm_unreachable("invalid ParamSpecifier");
77707773
}
@@ -8366,7 +8369,8 @@ AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const {
83668369
auto flags = ParameterTypeFlags::fromParameterType(
83678370
type, isVariadic(), isAutoClosure(), isNonEphemeral(), getSpecifier(),
83688371
isIsolated(), /*isNoDerivative*/ false, isCompileTimeConst(),
8369-
hasResultDependsOn());
8372+
hasResultDependsOn(),
8373+
getSpecifier() == ParamDecl::Specifier::Transferring /*is transferring*/);
83708374
return AnyFunctionType::Param(type, label, flags, internalLabel);
83718375
}
83728376

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)