Skip to content

Commit f3edb57

Browse files
committed
[transferring] Add support for transferring results.
rdar://121324697
1 parent bf2ec7e commit f3edb57

22 files changed

+395
-68
lines changed

include/swift/AST/Decl.h

+16-2
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
507507
);
508508

509509
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl,
510-
1+1+2+1+1+NumSelfAccessKindBits+1,
510+
1+1+2+1+1+NumSelfAccessKindBits+1+1,
511511
/// Whether we've computed the 'static' flag yet.
512512
IsStaticComputed : 1,
513513

@@ -529,7 +529,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
529529
/// Whether this is a top-level function which should be treated
530530
/// as if it were in local context for the purposes of capture
531531
/// analysis.
532-
HasTopLevelLocalContextCaptures : 1
532+
HasTopLevelLocalContextCaptures : 1,
533+
534+
/// Set to true if this FuncDecl has a transferring result.
535+
HasTransferringResult : 1
533536
);
534537

535538
SWIFT_INLINE_BITFIELD(AccessorDecl, FuncDecl, 4 + 1 + 1,
@@ -7787,6 +7790,7 @@ class FuncDecl : public AbstractFunctionDecl {
77877790
Bits.FuncDecl.IsStaticComputed = false;
77887791
Bits.FuncDecl.IsStatic = false;
77897792
Bits.FuncDecl.HasTopLevelLocalContextCaptures = false;
7793+
Bits.FuncDecl.HasTransferringResult = false;
77907794
}
77917795

77927796
void setResultInterfaceType(Type type);
@@ -7943,6 +7947,16 @@ class FuncDecl : public AbstractFunctionDecl {
79437947
Bits.FuncDecl.ForcedStaticDispatch = flag;
79447948
}
79457949

7950+
/// Returns true if this FuncDecl has a transferring result... returns false
7951+
/// otherwise.
7952+
bool hasTransferringResult() const {
7953+
return Bits.FuncDecl.HasTransferringResult;
7954+
}
7955+
7956+
void setTransferringResult(bool newValue = true) {
7957+
Bits.FuncDecl.HasTransferringResult = newValue;
7958+
}
7959+
79467960
static bool classof(const Decl *D) {
79477961
return D->getKind() == DeclKind::Func ||
79487962
D->getKind() == DeclKind::Accessor;

include/swift/AST/DiagnosticsSema.def

+6
Original file line numberDiff line numberDiff line change
@@ -7845,5 +7845,11 @@ ERROR(lifetime_dependence_ctor_non_self_or_nil_return, none,
78457845
ERROR(transferring_unsupported_param_specifier, none,
78467846
"'%0' cannot be applied to a 'transferring' parameter", (StringRef))
78477847

7848+
ERROR(transferring_only_on_parameters_and_results, none,
7849+
"'transferring' may only be used on parameters and results", ())
7850+
ERROR(transferring_cannot_be_applied_to_tuple_elt, none,
7851+
"'transferring' cannot be applied to tuple elements", ())
7852+
7853+
78487854
#define UNDEFINE_DIAGNOSTIC_MACROS
78497855
#include "DefineDiagnosticMacros.h"

include/swift/AST/ExtInfo.h

+77-22
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,8 @@ class ASTExtInfoBuilder {
439439
// If bits are added or removed, then TypeBase::NumAFTExtInfoBits
440440
// and NumMaskBits must be updated, and they must match.
441441
//
442-
// |representation|noEscape|concurrent|async|throws|isolation|differentiability|
443-
// | 0 .. 3 | 4 | 5 | 6 | 7 | 8 .. 10 | 11 .. 13 |
442+
// |representation|noEscape|concurrent|async|throws|isolation|differentiability| TransferringResult |
443+
// | 0 .. 3 | 4 | 5 | 6 | 7 | 8 .. 10 | 11 .. 13 | 14 |
444444
//
445445
enum : unsigned {
446446
RepresentationMask = 0xF << 0,
@@ -452,7 +452,8 @@ class ASTExtInfoBuilder {
452452
IsolationMask = 0x7 << IsolationMaskOffset,
453453
DifferentiabilityMaskOffset = 11,
454454
DifferentiabilityMask = 0x7 << DifferentiabilityMaskOffset,
455-
NumMaskBits = 14
455+
TransferringResultMask = 1 << 14,
456+
NumMaskBits = 15
456457
};
457458

458459
static_assert(FunctionTypeIsolation::Mask == 0x7, "update mask manually");
@@ -485,26 +486,30 @@ class ASTExtInfoBuilder {
485486
: ASTExtInfoBuilder(Representation::Swift, false, false, Type(),
486487
DifferentiabilityKind::NonDifferentiable, nullptr,
487488
FunctionTypeIsolation::forNonIsolated(),
488-
LifetimeDependenceInfo()) {}
489+
LifetimeDependenceInfo(),
490+
false /*transferringResult*/) {}
489491

490492
// Constructor for polymorphic type.
491493
ASTExtInfoBuilder(Representation rep, bool throws, Type thrownError)
492494
: ASTExtInfoBuilder(rep, false, throws, thrownError,
493495
DifferentiabilityKind::NonDifferentiable, nullptr,
494496
FunctionTypeIsolation::forNonIsolated(),
495-
LifetimeDependenceInfo()) {}
497+
LifetimeDependenceInfo(),
498+
false /*transferringResult*/) {}
496499

497500
// Constructor with no defaults.
498501
ASTExtInfoBuilder(Representation rep, bool isNoEscape, bool throws,
499502
Type thrownError, DifferentiabilityKind diffKind,
500503
const clang::Type *type, FunctionTypeIsolation isolation,
501-
LifetimeDependenceInfo lifetimeDependenceInfo)
504+
LifetimeDependenceInfo lifetimeDependenceInfo,
505+
bool transferringResult)
502506
: ASTExtInfoBuilder(
503507
((unsigned)rep) | (isNoEscape ? NoEscapeMask : 0) |
504508
(throws ? ThrowsMask : 0) |
505509
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
506510
DifferentiabilityMask) |
507-
(unsigned(isolation.getKind()) << IsolationMaskOffset),
511+
(unsigned(isolation.getKind()) << IsolationMaskOffset) |
512+
(transferringResult ? TransferringResultMask : 0),
508513
ClangTypeInfo(type), isolation.getOpaqueType(), thrownError,
509514
lifetimeDependenceInfo) {}
510515

@@ -526,6 +531,10 @@ class ASTExtInfoBuilder {
526531

527532
constexpr bool isThrowing() const { return bits & ThrowsMask; }
528533

534+
constexpr bool hasTransferringResult() const {
535+
return bits & TransferringResultMask;
536+
}
537+
529538
constexpr DifferentiabilityKind getDifferentiabilityKind() const {
530539
return DifferentiabilityKind((bits & DifferentiabilityMask) >>
531540
DifferentiabilityMaskOffset);
@@ -630,10 +639,20 @@ class ASTExtInfoBuilder {
630639
throws ? (bits | ThrowsMask) : (bits & ~ThrowsMask), clangTypeInfo,
631640
globalActor, thrownError, lifetimeDependenceInfo);
632641
}
642+
633643
[[nodiscard]]
634644
ASTExtInfoBuilder withThrows() const {
635645
return withThrows(true, Type());
636646
}
647+
648+
[[nodiscard]] ASTExtInfoBuilder
649+
withTransferringResult(bool transferring = true) const {
650+
return ASTExtInfoBuilder(transferring ? (bits | TransferringResultMask)
651+
: (bits & ~TransferringResultMask),
652+
clangTypeInfo, globalActor, thrownError,
653+
lifetimeDependenceInfo);
654+
}
655+
637656
[[nodiscard]]
638657
ASTExtInfoBuilder
639658
withDifferentiabilityKind(DifferentiabilityKind differentiability) const {
@@ -747,6 +766,10 @@ class ASTExtInfo {
747766

748767
constexpr bool isThrowing() const { return builder.isThrowing(); }
749768

769+
constexpr bool hasTransferringResult() const {
770+
return builder.hasTransferringResult();
771+
}
772+
750773
constexpr DifferentiabilityKind getDifferentiabilityKind() const {
751774
return builder.getDifferentiabilityKind();
752775
}
@@ -816,6 +839,11 @@ class ASTExtInfo {
816839
return builder.withAsync(async).build();
817840
}
818841

842+
[[nodiscard]] ASTExtInfo
843+
withTransferringResult(bool transferring = true) const {
844+
return builder.withTransferringResult(transferring).build();
845+
}
846+
819847
[[nodiscard]]
820848
ASTExtInfo withIsolation(FunctionTypeIsolation isolation) const {
821849
return builder.withIsolation(isolation).build();
@@ -908,7 +936,8 @@ class SILExtInfoBuilder {
908936
DifferentiabilityMask = 0x7 << DifferentiabilityMaskOffset,
909937
UnimplementableMask = 1 << 12,
910938
ErasedIsolationMask = 1 << 13,
911-
NumMaskBits = 14
939+
TransferringResultMask = 1 << 14,
940+
NumMaskBits = 15
912941
};
913942

914943
unsigned bits; // Naturally sized for speed.
@@ -929,16 +958,17 @@ class SILExtInfoBuilder {
929958
bool isNoEscape, bool isSendable,
930959
bool isAsync, bool isUnimplementable,
931960
SILFunctionTypeIsolation isolation,
961+
bool hasTransferringResult,
932962
DifferentiabilityKind diffKind) {
933963
return ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) |
934-
(isNoEscape ? NoEscapeMask : 0) |
935-
(isSendable ? SendableMask : 0) |
964+
(isNoEscape ? NoEscapeMask : 0) | (isSendable ? SendableMask : 0) |
936965
(isAsync ? AsyncMask : 0) |
937966
(isUnimplementable ? UnimplementableMask : 0) |
938967
(isolation == SILFunctionTypeIsolation::Erased
939968
? ErasedIsolationMask : 0) |
940969
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
941-
DifferentiabilityMask);
970+
DifferentiabilityMask) |
971+
(hasTransferringResult ? TransferringResultMask : 0);
942972
}
943973

944974
public:
@@ -947,18 +977,19 @@ class SILExtInfoBuilder {
947977
SILExtInfoBuilder()
948978
: SILExtInfoBuilder(makeBits(SILFunctionTypeRepresentation::Thick, false,
949979
false, false, false, false,
950-
SILFunctionTypeIsolation::Unknown,
980+
SILFunctionTypeIsolation::Unknown, false,
951981
DifferentiabilityKind::NonDifferentiable),
952982
ClangTypeInfo(nullptr), LifetimeDependenceInfo()) {}
953983

954984
SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape,
955985
bool isSendable, bool isAsync, bool isUnimplementable,
956986
SILFunctionTypeIsolation isolation,
957987
DifferentiabilityKind diffKind, const clang::Type *type,
958-
LifetimeDependenceInfo lifetimeDependenceInfo)
988+
LifetimeDependenceInfo lifetimeDependenceInfo,
989+
bool hasTransferringResult)
959990
: SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape, isSendable,
960-
isAsync, isUnimplementable,
961-
isolation, diffKind),
991+
isAsync, isUnimplementable, isolation,
992+
hasTransferringResult, diffKind),
962993
ClangTypeInfo(type), lifetimeDependenceInfo) {}
963994

964995
// Constructor for polymorphic type.
@@ -967,8 +998,9 @@ class SILExtInfoBuilder {
967998
info.isNoEscape(), info.isSendable(),
968999
info.isAsync(), /*unimplementable*/ false,
9691000
info.getIsolation().isErased()
970-
? SILFunctionTypeIsolation::Erased
971-
: SILFunctionTypeIsolation::Unknown,
1001+
? SILFunctionTypeIsolation::Erased
1002+
: SILFunctionTypeIsolation::Unknown,
1003+
/*has transferring result*/ false,
9721004
info.getDifferentiabilityKind()),
9731005
info.getClangTypeInfo(),
9741006
info.getLifetimeDependenceInfo()) {}
@@ -998,6 +1030,10 @@ class SILExtInfoBuilder {
9981030

9991031
constexpr bool isAsync() const { return bits & AsyncMask; }
10001032

1033+
constexpr bool hasTransferringResult() const {
1034+
return bits & TransferringResultMask;
1035+
}
1036+
10011037
constexpr DifferentiabilityKind getDifferentiabilityKind() const {
10021038
return DifferentiabilityKind((bits & DifferentiabilityMask) >>
10031039
DifferentiabilityMaskOffset);
@@ -1101,11 +1137,13 @@ class SILExtInfoBuilder {
11011137
: (bits & ~SendableMask),
11021138
clangTypeInfo, lifetimeDependenceInfo);
11031139
}
1140+
11041141
[[nodiscard]]
11051142
SILExtInfoBuilder withAsync(bool isAsync = true) const {
11061143
return SILExtInfoBuilder(isAsync ? (bits | AsyncMask) : (bits & ~AsyncMask),
11071144
clangTypeInfo, lifetimeDependenceInfo);
11081145
}
1146+
11091147
[[nodiscard]]
11101148
SILExtInfoBuilder withErasedIsolation(bool erased = true) const {
11111149
return SILExtInfoBuilder(erased ? (bits | ErasedIsolationMask)
@@ -1128,6 +1166,15 @@ class SILExtInfoBuilder {
11281166
: (bits & ~UnimplementableMask),
11291167
clangTypeInfo, lifetimeDependenceInfo);
11301168
}
1169+
1170+
[[nodiscard]] SILExtInfoBuilder
1171+
withTransferringResult(bool hasTransferringResult = true) const {
1172+
return SILExtInfoBuilder(hasTransferringResult
1173+
? (bits | TransferringResultMask)
1174+
: (bits & ~TransferringResultMask),
1175+
clangTypeInfo, lifetimeDependenceInfo);
1176+
}
1177+
11311178
[[nodiscard]]
11321179
SILExtInfoBuilder
11331180
withDifferentiabilityKind(DifferentiabilityKind differentiability) const {
@@ -1193,11 +1240,11 @@ class SILExtInfo {
11931240

11941241
/// A default ExtInfo but with a Thin convention.
11951242
static SILExtInfo getThin() {
1196-
return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false,
1197-
false, false, false, false,
1198-
SILFunctionTypeIsolation::Unknown,
1199-
DifferentiabilityKind::NonDifferentiable, nullptr,
1200-
LifetimeDependenceInfo())
1243+
return SILExtInfoBuilder(
1244+
SILExtInfoBuilder::Representation::Thin, false, false, false,
1245+
false, false, SILFunctionTypeIsolation::Unknown,
1246+
DifferentiabilityKind::NonDifferentiable, nullptr,
1247+
LifetimeDependenceInfo(), false /*transferring result*/)
12011248
.build();
12021249
}
12031250

@@ -1235,6 +1282,10 @@ class SILExtInfo {
12351282
return builder.getIsolation();
12361283
}
12371284

1285+
constexpr bool hasTransferringResult() const {
1286+
return builder.hasTransferringResult();
1287+
}
1288+
12381289
constexpr DifferentiabilityKind getDifferentiabilityKind() const {
12391290
return builder.getDifferentiabilityKind();
12401291
}
@@ -1281,6 +1332,10 @@ class SILExtInfo {
12811332
return builder.withUnimplementable(isUnimplementable).build();
12821333
}
12831334

1335+
SILExtInfo withTransferringResult(bool hasTransferringResult = true) const {
1336+
return builder.withTransferringResult(hasTransferringResult).build();
1337+
}
1338+
12841339
void Profile(llvm::FoldingSetNodeID &ID) const { builder.Profile(ID); }
12851340

12861341
bool isEqualTo(SILExtInfo other, bool useClangTypes) const {

include/swift/AST/Types.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,8 @@ class alignas(1 << TypeAlignInBits) TypeBase
383383
}
384384

385385
protected:
386-
enum { NumAFTExtInfoBits = 14 };
387-
enum { NumSILExtInfoBits = 14 };
386+
enum { NumAFTExtInfoBits = 15 };
387+
enum { NumSILExtInfoBits = 15 };
388388

389389
// clang-format off
390390
union { uint64_t OpaqueBits;
@@ -3644,6 +3644,10 @@ class AnyFunctionType : public TypeBase {
36443644

36453645
bool isThrowing() const { return getExtInfo().isThrowing(); }
36463646

3647+
bool hasTransferringResult() const {
3648+
return getExtInfo().hasTransferringResult();
3649+
}
3650+
36473651
bool hasEffect(EffectKind kind) const;
36483652

36493653
bool isDifferentiable() const { return getExtInfo().isDifferentiable(); }
@@ -4889,6 +4893,9 @@ class SILFunctionType final
48894893
SILFunctionTypeIsolation getIsolation() const {
48904894
return getExtInfo().getIsolation();
48914895
}
4896+
bool hasTransferringResult() const {
4897+
return getExtInfo().hasTransferringResult();
4898+
}
48924899

48934900
/// Return the array of all the yields.
48944901
ArrayRef<SILYieldInfo> getYields() const {

include/swift/SILOptimizer/Utils/PartitionUtils.h

+6
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,12 @@ struct PartitionOpEvaluator {
11171117
if (isActorDerived(op.getOpArgs()[0]))
11181118
return handleTransferNonTransferrable(op, op.getOpArgs()[0]);
11191119

1120+
// NOTE: We purposely do not check here if a transferred value is already
1121+
// transferred. Callers are expected to put a require for that
1122+
// purpose. This ensures that if we pass the same argument multiple times
1123+
// to the same transferring function as weakly transferred arguments, we
1124+
// do not get an error.
1125+
11201126
// While we are checking for actor derived, also check if our value or any
11211127
// value in our region is closure captured and propagate that bit in our
11221128
// transferred inst.

lib/AST/ASTDemangler.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -469,14 +469,13 @@ Type ASTBuilder::createFunctionType(
469469
representation);
470470

471471
// TODO: Handle LifetimeDependenceInfo here.
472-
auto einfo =
473-
FunctionType::ExtInfoBuilder(representation, noescape, flags.isThrowing(),
474-
thrownError, resultDiffKind,
475-
clangFunctionType, isolation,
476-
LifetimeDependenceInfo())
477-
.withAsync(flags.isAsync())
478-
.withConcurrent(flags.isSendable())
479-
.build();
472+
auto einfo = FunctionType::ExtInfoBuilder(
473+
representation, noescape, flags.isThrowing(), thrownError,
474+
resultDiffKind, clangFunctionType, isolation,
475+
LifetimeDependenceInfo(), false /*is transferring*/)
476+
.withAsync(flags.isAsync())
477+
.withConcurrent(flags.isSendable())
478+
.build();
480479

481480
return FunctionType::get(funcParams, output, einfo);
482481
}
@@ -659,7 +658,8 @@ Type ASTBuilder::createImplFunctionType(
659658
auto einfo = SILFunctionType::ExtInfoBuilder(
660659
representation, flags.isPseudogeneric(), !flags.isEscaping(),
661660
flags.isSendable(), flags.isAsync(), unimplementable,
662-
isolation, diffKind, clangFnType, LifetimeDependenceInfo())
661+
isolation, diffKind, clangFnType, LifetimeDependenceInfo(),
662+
false /*has transferring result*/)
663663
.build();
664664

665665
return SILFunctionType::get(genericSig, einfo, funcCoroutineKind,

0 commit comments

Comments
 (0)