Skip to content

Commit acca735

Browse files
committed
[transferring] Make async let take a transferring result if its result is non-Sendable.
Some notes: 1. If the result is non-Sendable and we didn't infer something that is transferring, we still emit the current sema error that says that one cannot assign a non-Sendable value to an async let. 2. When region isolation is enabled, but transferring args and results are disabled, we leave the async let semantics alone. This means that the async let closure is still @sendable and one cannot pass in non-Sendable values to it.
1 parent 8ed2e05 commit acca735

15 files changed

+340
-122
lines changed

include/swift/AST/Builtins.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(GetCurrentAsyncTask, "getCurrentAsyncTask", "
884884
BUILTIN_MISC_OPERATION_WITH_SILGEN(CancelAsyncTask, "cancelAsyncTask", "", Special)
885885

886886
/// startAsyncLet()<T>: (
887-
/// __owned @Sendable @escaping () async throws -> T
887+
/// __owned @escaping () async throws -> transferring T
888888
/// ) -> Builtin.RawPointer
889889
///
890890
/// DEPRECATED. startAsyncLetWithLocalBuffer is used instead.
@@ -894,7 +894,7 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(CancelAsyncTask, "cancelAsyncTask", "", Speci
894894
BUILTIN_MISC_OPERATION(StartAsyncLet, "startAsyncLet", "", Special)
895895

896896
/// startAsyncLetWithLocalBuffer()<T>: (
897-
/// __owned @Sendable @escaping () async throws -> T,
897+
/// __owned @escaping () async throws -> transferring T,
898898
/// _ resultBuf: Builtin.RawPointer
899899
/// ) -> Builtin.RawPointer
900900
///

include/swift/SIL/ApplySite.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -811,13 +811,18 @@ class FullApplySite : public ApplySite {
811811
}
812812
}
813813

814-
/// Return the applied argument without indirect results.
815-
unsigned getAppliedArgIndexWithoutIndirectResult(const Operand &oper) const {
814+
/// Return the applied argument index for the given operand ignoring indirect
815+
/// results.
816+
///
817+
/// So for instance:
818+
///
819+
/// apply %f(%result, %0, %1, %2, ...).
820+
unsigned getAppliedArgIndexWithoutIndirectResults(const Operand &oper) const {
816821
assert(oper.getUser() == **this);
817822
assert(isArgumentOperand(oper));
818823

819-
return oper.getOperandNumber() - getOperandIndexOfFirstArgument() -
820-
getNumIndirectSILResults() - getNumIndirectSILErrorResults();
824+
return getAppliedArgIndex(oper) - getNumIndirectSILResults() -
825+
getNumIndirectSILErrorResults();
821826
}
822827

823828
static FullApplySite getFromOpaqueValue(void *p) { return FullApplySite(p); }

include/swift/SIL/SILDeclRef.h

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ struct SILDeclRef {
197197
BackDeploymentKind backDeploymentKind : 2;
198198
/// The default argument index for a default argument getter.
199199
unsigned defaultArgIndex : 10;
200+
/// Set if this is for an async let closure.
201+
unsigned isAsyncLetClosure : 1;
200202

201203
PointerUnion<AutoDiffDerivativeFunctionIdentifier *,
202204
const GenericSignatureImpl *, CustomAttr *>
@@ -229,9 +231,10 @@ struct SILDeclRef {
229231

230232
/// Produces a null SILDeclRef.
231233
SILDeclRef()
232-
: loc(), kind(Kind::Func), isForeign(0),
233-
isDistributed(0), isKnownToBeLocal(0), isRuntimeAccessible(0),
234-
backDeploymentKind(BackDeploymentKind::None), defaultArgIndex(0) {}
234+
: loc(), kind(Kind::Func), isForeign(0), isDistributed(0),
235+
isKnownToBeLocal(0), isRuntimeAccessible(0),
236+
backDeploymentKind(BackDeploymentKind::None), defaultArgIndex(0),
237+
isAsyncLetClosure(0) {}
235238

236239
/// Produces a SILDeclRef of the given kind for the given decl.
237240
explicit SILDeclRef(
@@ -397,19 +400,18 @@ struct SILDeclRef {
397400

398401
/// Return the hash code for the SIL declaration.
399402
friend llvm::hash_code hash_value(const SILDeclRef &ref) {
400-
return llvm::hash_combine(ref.loc.getOpaqueValue(),
401-
static_cast<int>(ref.kind),
402-
ref.isForeign, ref.isDistributed,
403-
ref.defaultArgIndex);
403+
return llvm::hash_combine(
404+
ref.loc.getOpaqueValue(), static_cast<int>(ref.kind), ref.isForeign,
405+
ref.isDistributed, ref.defaultArgIndex, ref.isAsyncLetClosure);
404406
}
405407

406408
bool operator==(SILDeclRef rhs) const {
407409
return loc.getOpaqueValue() == rhs.loc.getOpaqueValue() &&
408410
kind == rhs.kind && isForeign == rhs.isForeign &&
409411
isDistributed == rhs.isDistributed &&
410412
backDeploymentKind == rhs.backDeploymentKind &&
411-
defaultArgIndex == rhs.defaultArgIndex &&
412-
pointer == rhs.pointer;
413+
defaultArgIndex == rhs.defaultArgIndex && pointer == rhs.pointer &&
414+
isAsyncLetClosure == rhs.isAsyncLetClosure;
413415
}
414416
bool operator!=(SILDeclRef rhs) const {
415417
return !(*this == rhs);
@@ -427,20 +429,17 @@ struct SILDeclRef {
427429
/*foreign=*/foreign,
428430
/*distributed=*/false,
429431
/*knownToBeLocal=*/false,
430-
/*runtimeAccessible=*/false,
431-
backDeploymentKind,
432-
defaultArgIndex,
432+
/*runtimeAccessible=*/false, backDeploymentKind,
433+
defaultArgIndex, isAsyncLetClosure,
433434
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
434435
}
435436
/// Returns the distributed entry point corresponding to the same decl.
436437
SILDeclRef asDistributed(bool distributed = true) const {
437438
return SILDeclRef(loc.getOpaqueValue(), kind,
438439
/*foreign=*/false,
439440
/*distributed=*/distributed,
440-
/*knownToBeLocal=*/false,
441-
isRuntimeAccessible,
442-
backDeploymentKind,
443-
defaultArgIndex,
441+
/*knownToBeLocal=*/false, isRuntimeAccessible,
442+
backDeploymentKind, defaultArgIndex, isAsyncLetClosure,
444443
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
445444
}
446445

@@ -451,9 +450,8 @@ struct SILDeclRef {
451450
/*foreign=*/false,
452451
/*distributed=*/false,
453452
/*distributedKnownToBeLocal=*/isLocal,
454-
isRuntimeAccessible,
455-
backDeploymentKind,
456-
defaultArgIndex,
453+
isRuntimeAccessible, backDeploymentKind, defaultArgIndex,
454+
isAsyncLetClosure,
457455
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
458456
}
459457

@@ -466,13 +464,9 @@ struct SILDeclRef {
466464

467465
/// Returns a copy of the decl with the given back deployment kind.
468466
SILDeclRef asBackDeploymentKind(BackDeploymentKind backDeploymentKind) const {
469-
return SILDeclRef(loc.getOpaqueValue(), kind,
470-
isForeign,
471-
isDistributed,
472-
isKnownToBeLocal,
473-
isRuntimeAccessible,
474-
backDeploymentKind,
475-
defaultArgIndex,
467+
return SILDeclRef(loc.getOpaqueValue(), kind, isForeign, isDistributed,
468+
isKnownToBeLocal, isRuntimeAccessible, backDeploymentKind,
469+
defaultArgIndex, isAsyncLetClosure,
476470
pointer.get<AutoDiffDerivativeFunctionIdentifier *>());
477471
}
478472

@@ -606,21 +600,18 @@ struct SILDeclRef {
606600
private:
607601
friend struct llvm::DenseMapInfo<swift::SILDeclRef>;
608602
/// Produces a SILDeclRef from an opaque value.
609-
explicit SILDeclRef(void *opaqueLoc, Kind kind,
610-
bool isForeign,
611-
bool isDistributed,
612-
bool isKnownToBeLocal,
603+
explicit SILDeclRef(void *opaqueLoc, Kind kind, bool isForeign,
604+
bool isDistributed, bool isKnownToBeLocal,
613605
bool isRuntimeAccessible,
614606
BackDeploymentKind backDeploymentKind,
615-
unsigned defaultArgIndex,
607+
unsigned defaultArgIndex, bool isAsyncLetClosure,
616608
AutoDiffDerivativeFunctionIdentifier *derivativeId)
617609
: loc(Loc::getFromOpaqueValue(opaqueLoc)), kind(kind),
618-
isForeign(isForeign),
619-
isDistributed(isDistributed),
610+
isForeign(isForeign), isDistributed(isDistributed),
620611
isKnownToBeLocal(isKnownToBeLocal),
621612
isRuntimeAccessible(isRuntimeAccessible),
622613
backDeploymentKind(backDeploymentKind),
623-
defaultArgIndex(defaultArgIndex),
614+
defaultArgIndex(defaultArgIndex), isAsyncLetClosure(isAsyncLetClosure),
624615
pointer(derivativeId) {}
625616
};
626617

@@ -644,11 +635,13 @@ template<> struct DenseMapInfo<swift::SILDeclRef> {
644635

645636
static SILDeclRef getEmptyKey() {
646637
return SILDeclRef(PointerInfo::getEmptyKey(), Kind::Func, false, false,
647-
false, false, BackDeploymentKind::None, 0, nullptr);
638+
false, false, BackDeploymentKind::None, 0, false,
639+
nullptr);
648640
}
649641
static SILDeclRef getTombstoneKey() {
650642
return SILDeclRef(PointerInfo::getTombstoneKey(), Kind::Func, false, false,
651-
false, false, BackDeploymentKind::None, 0, nullptr);
643+
false, false, BackDeploymentKind::None, 0, false,
644+
nullptr);
652645
}
653646
static unsigned getHashValue(swift::SILDeclRef Val) {
654647
unsigned h1 = PointerInfo::getHashValue(Val.loc.getOpaqueValue());

lib/AST/Builtins.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,8 +1639,23 @@ static ValueDecl *getStartAsyncLet(ASTContext &ctx, Identifier id) {
16391639
// TaskOptionRecord*
16401640
builder.addParameter(makeConcrete(OptionalType::get(ctx.TheRawPointerType)));
16411641

1642-
// operation async function pointer: () async throws -> T
1643-
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().withNoEscape().build();
1642+
// If transferring results are enabled, make async let return a transferring
1643+
// value.
1644+
//
1645+
// NOTE: If our actual returned function does not return something that is
1646+
// transferring, we will emit an error in Sema. In the case of SILGen, we just
1647+
// in such a case want to thunk and not emit an error. So in such a case, we
1648+
// always make this builtin take a transferring result.
1649+
bool hasTransferringResult =
1650+
ctx.LangOpts.hasFeature(Feature::TransferringArgsAndResults);
1651+
1652+
// operation async function pointer: () async throws -> transferring T
1653+
auto extInfo = ASTExtInfoBuilder()
1654+
.withAsync()
1655+
.withThrows()
1656+
.withNoEscape()
1657+
.withTransferringResult(hasTransferringResult)
1658+
.build();
16441659
builder.addParameter(
16451660
makeConcrete(FunctionType::get({ }, genericParam, extInfo)));
16461661

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,17 +127,17 @@ SILDeclRef::SILDeclRef(ValueDecl *vd, SILDeclRef::Kind kind, bool isForeign,
127127
bool isRuntimeAccessible,
128128
SILDeclRef::BackDeploymentKind backDeploymentKind,
129129
AutoDiffDerivativeFunctionIdentifier *derivativeId)
130-
: loc(vd), kind(kind), isForeign(isForeign),
131-
isDistributed(isDistributed), isKnownToBeLocal(isKnownToBeLocal),
130+
: loc(vd), kind(kind), isForeign(isForeign), isDistributed(isDistributed),
131+
isKnownToBeLocal(isKnownToBeLocal),
132132
isRuntimeAccessible(isRuntimeAccessible),
133133
backDeploymentKind(backDeploymentKind), defaultArgIndex(0),
134-
pointer(derivativeId) {}
134+
isAsyncLetClosure(0), pointer(derivativeId) {}
135135

136136
SILDeclRef::SILDeclRef(SILDeclRef::Loc baseLoc, bool asForeign,
137137
bool asDistributed, bool asDistributedKnownToBeLocal)
138138
: isRuntimeAccessible(false),
139139
backDeploymentKind(SILDeclRef::BackDeploymentKind::None),
140-
defaultArgIndex(0),
140+
defaultArgIndex(0), isAsyncLetClosure(0),
141141
pointer((AutoDiffDerivativeFunctionIdentifier *)nullptr) {
142142
if (auto *vd = baseLoc.dyn_cast<ValueDecl*>()) {
143143
if (auto *fd = dyn_cast<FuncDecl>(vd)) {
@@ -170,6 +170,13 @@ SILDeclRef::SILDeclRef(SILDeclRef::Loc baseLoc, bool asForeign,
170170
} else if (auto *ACE = baseLoc.dyn_cast<AbstractClosureExpr *>()) {
171171
loc = ACE;
172172
kind = Kind::Func;
173+
if (ACE->getASTContext().LangOpts.hasFeature(
174+
Feature::TransferringArgsAndResults)) {
175+
if (auto *autoClosure = dyn_cast<AutoClosureExpr>(ACE)) {
176+
isAsyncLetClosure =
177+
autoClosure->getThunkKind() == AutoClosureExpr::Kind::AsyncLet;
178+
}
179+
}
173180
} else {
174181
llvm_unreachable("impossible SILDeclRef loc");
175182
}

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,6 +1998,8 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
19981998
convention = ParameterConvention::Direct_Guaranteed;
19991999
}
20002000
SILParameterInfo param(loweredTy.getASTType(), convention, options);
2001+
if (function.isAsyncLetClosure)
2002+
param = param.addingOption(SILParameterInfo::Transferring);
20012003
inputs.push_back(param);
20022004
break;
20032005
}
@@ -2013,6 +2015,8 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20132015
/*mutable*/ true);
20142016
auto convention = ParameterConvention::Direct_Guaranteed;
20152017
auto param = SILParameterInfo(boxTy, convention, options);
2018+
if (function.isAsyncLetClosure)
2019+
param = param.addingOption(SILParameterInfo::Transferring);
20162020
inputs.push_back(param);
20172021
break;
20182022
}
@@ -2028,6 +2032,8 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20282032
/*mutable*/ false);
20292033
auto convention = ParameterConvention::Direct_Guaranteed;
20302034
auto param = SILParameterInfo(boxTy, convention, options);
2035+
if (function.isAsyncLetClosure)
2036+
param = param.addingOption(SILParameterInfo::Transferring);
20312037
inputs.push_back(param);
20322038
break;
20332039
}
@@ -2037,6 +2043,8 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20372043
auto param = SILParameterInfo(
20382044
ty.getASTType(), ParameterConvention::Indirect_InoutAliasable,
20392045
options);
2046+
if (function.isAsyncLetClosure)
2047+
param = param.addingOption(SILParameterInfo::Transferring);
20402048
inputs.push_back(param);
20412049
break;
20422050
}
@@ -2047,6 +2055,8 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20472055
auto param = SILParameterInfo(ty.getASTType(),
20482056
ParameterConvention::Indirect_In_Guaranteed,
20492057
options);
2058+
if (function.isAsyncLetClosure)
2059+
param = param.addingOption(SILParameterInfo::Transferring);
20502060
inputs.push_back(param);
20512061
break;
20522062
}

0 commit comments

Comments
 (0)