Skip to content

Commit f02a01e

Browse files
committed
Add @_unsafeMainActor corresponding to @mainactor
1 parent ed7372b commit f02a01e

File tree

12 files changed

+88
-27
lines changed

12 files changed

+88
-27
lines changed

include/swift/AST/Attr.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,11 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(_unsafeSendable, UnsafeSendable,
642642
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
643643
113)
644644

645+
CONTEXTUAL_SIMPLE_DECL_ATTR(_unsafeMainActor, UnsafeMainActor,
646+
OnParam | UserInaccessible |
647+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove,
648+
114)
649+
645650
#undef TYPE_ATTR
646651
#undef DECL_ATTR_ALIAS
647652
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Expr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3983,7 +3983,7 @@ class ClosureExpr : public AbstractClosureExpr {
39833983
UnsafeConcurrencyBits::MainActor;
39843984
}
39853985

3986-
void setContextuallyConcurrent(bool sendable, bool forMainActor) {
3986+
void setUnsafeConcurrent(bool sendable, bool forMainActor) {
39873987
uint8_t bits = 0;
39883988
if (sendable)
39893989
bits |= UnsafeConcurrencyBits::Sendable;

include/swift/AST/Types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3344,6 +3344,7 @@ struct ParameterListInfo {
33443344
SmallBitVector acceptsUnlabeledTrailingClosures;
33453345
SmallBitVector propertyWrappers;
33463346
SmallBitVector unsafeSendable;
3347+
SmallBitVector unsafeMainActor;
33473348

33483349
public:
33493350
ParameterListInfo() { }
@@ -3367,6 +3368,11 @@ struct ParameterListInfo {
33673368
/// features.
33683369
bool isUnsafeSendable(unsigned paramIdx) const;
33693370

3371+
/// Whether the given parameter is unsafe MainActor, meaning that
3372+
/// we will treat it as being part of the main actor but that it is not
3373+
/// part of the type system.
3374+
bool isUnsafeMainActor(unsigned paramIdx) const;
3375+
33703376
/// Retrieve the number of non-defaulted parameters.
33713377
unsigned numNonDefaultedParameters() const {
33723378
return defaultArguments.count();

lib/AST/Type.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,7 @@ ParameterListInfo::ParameterListInfo(
942942
defaultArguments.resize(params.size());
943943
propertyWrappers.resize(params.size());
944944
unsafeSendable.resize(params.size());
945+
unsafeMainActor.resize(params.size());
945946

946947
// No parameter owner means no parameter list means no default arguments
947948
// - hand back the zeroed bitvector.
@@ -997,6 +998,10 @@ ParameterListInfo::ParameterListInfo(
997998
if (isParamUnsafeSendable(param)) {
998999
unsafeSendable.set(i);
9991000
}
1001+
1002+
if (param->getAttrs().hasAttribute<UnsafeMainActorAttr>()) {
1003+
unsafeMainActor.set(i);
1004+
}
10001005
}
10011006
}
10021007

@@ -1021,6 +1026,12 @@ bool ParameterListInfo::isUnsafeSendable(unsigned paramIdx) const {
10211026
: false;
10221027
}
10231028

1029+
bool ParameterListInfo::isUnsafeMainActor(unsigned paramIdx) const {
1030+
return paramIdx < unsafeMainActor.size()
1031+
? unsafeMainActor[paramIdx]
1032+
: false;
1033+
}
1034+
10241035
/// Turn a param list into a symbolic and printable representation that does not
10251036
/// include the types, something like (_:, b:, c:)
10261037
std::string swift::getParamListAsString(ArrayRef<AnyFunctionType::Param> params) {

lib/ClangImporter/ImportType.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,7 +1711,8 @@ static Type applyToFunctionType(
17111711
}
17121712

17131713
Type ClangImporter::Implementation::applyParamAttributes(
1714-
const clang::ParmVarDecl *param, Type type, bool &isUnsafeSendable) {
1714+
const clang::ParmVarDecl *param, Type type, bool &isUnsafeSendable,
1715+
bool &isUnsafeMainActor) {
17151716
if (!param->hasAttrs())
17161717
return type;
17171718

@@ -1754,6 +1755,12 @@ Type ClangImporter::Implementation::applyParamAttributes(
17541755
isUnsafeSendable = true;
17551756
continue;
17561757
}
1758+
1759+
// Map @_unsafeMainActor.
1760+
if (swiftAttr->getAttribute() == "@_unsafeMainActor") {
1761+
isUnsafeMainActor = true;
1762+
continue;
1763+
}
17571764
}
17581765

17591766
return type;
@@ -1935,7 +1942,9 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
19351942

19361943
// Apply attributes to the type.
19371944
bool isUnsafeSendable = false;
1938-
swiftParamTy = applyParamAttributes(param, swiftParamTy, isUnsafeSendable);
1945+
bool isUnsafeMainActor = false;
1946+
swiftParamTy = applyParamAttributes(
1947+
param, swiftParamTy, isUnsafeSendable, isUnsafeMainActor);
19391948

19401949
// Figure out the name for this parameter.
19411950
Identifier bodyName = importFullName(param, CurrentVersion)
@@ -1956,7 +1965,8 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
19561965
paramInfo->setSpecifier(ParamSpecifier::Default);
19571966
paramInfo->setInterfaceType(swiftParamTy);
19581967
recordImplicitUnwrapForDecl(paramInfo, isParamTypeImplicitlyUnwrapped);
1959-
recordUnsafeSendableForDecl(paramInfo, isUnsafeSendable);
1968+
recordUnsafeConcurrencyForDecl(
1969+
paramInfo, isUnsafeSendable, isUnsafeMainActor);
19601970
parameters.push_back(paramInfo);
19611971
++index;
19621972
}
@@ -2435,7 +2445,9 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(
24352445

24362446
// Apply Clang attributes to the parameter type.
24372447
bool isUnsafeSendable = false;
2438-
swiftParamTy = applyParamAttributes(param, swiftParamTy, isUnsafeSendable);
2448+
bool isUnsafeMainActor = false;
2449+
swiftParamTy = applyParamAttributes(
2450+
param, swiftParamTy, isUnsafeSendable, isUnsafeMainActor);
24392451

24402452
// Figure out the name for this parameter.
24412453
Identifier bodyName = importFullName(param, CurrentVersion)
@@ -2459,7 +2471,8 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(
24592471
paramInfo->setSpecifier(ParamSpecifier::Default);
24602472
paramInfo->setInterfaceType(swiftParamTy);
24612473
recordImplicitUnwrapForDecl(paramInfo, paramIsIUO);
2462-
recordUnsafeSendableForDecl(paramInfo, isUnsafeSendable);
2474+
recordUnsafeConcurrencyForDecl(
2475+
paramInfo, isUnsafeSendable, isUnsafeMainActor);
24632476

24642477
// Determine whether we have a default argument.
24652478
if (kind == SpecialMethodKind::Regular ||

lib/ClangImporter/ImporterImpl.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -683,12 +683,17 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
683683
decl->setImplicitlyUnwrappedOptional(true);
684684
}
685685

686-
void recordUnsafeSendableForDecl(ValueDecl *decl, bool isUnsafeSendable) {
687-
if (!isUnsafeSendable)
688-
return;
686+
void recordUnsafeConcurrencyForDecl(
687+
ValueDecl *decl, bool isUnsafeSendable, bool isUnsafeMainActor) {
688+
if (isUnsafeSendable) {
689+
decl->getAttrs().add(
690+
new (SwiftContext) UnsafeSendableAttr(/*implicit=*/true));
691+
}
689692

690-
decl->getAttrs().add(
691-
new (SwiftContext) UnsafeSendableAttr(/*implicit=*/true));
693+
if (isUnsafeMainActor) {
694+
decl->getAttrs().add(
695+
new (SwiftContext) UnsafeMainActorAttr(/*implicit=*/true));
696+
}
692697
}
693698

694699
/// Retrieve the Clang AST context.
@@ -842,7 +847,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
842847
const clang::ObjCContainerDecl *NewContext = nullptr);
843848

844849
Type applyParamAttributes(const clang::ParmVarDecl *param, Type type,
845-
bool &isUnsafeSendable);
850+
bool &isUnsafeSendable, bool &isUnsafeMainActor);
846851

847852
/// If we already imported a given decl, return the corresponding Swift decl.
848853
/// Otherwise, return nullptr.

lib/Sema/CSApply.cpp

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5709,15 +5709,15 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee,
57095709
}
57105710

57115711
/// Apply the contextually Sendable flag to the given expression,
5712-
static void applyContextuallyConcurrent(
5712+
static void applyUnsafeConcurrent(
57135713
Expr *expr, bool sendable, bool forMainActor) {
57145714
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
5715-
closure->setContextuallyConcurrent(sendable, forMainActor);
5715+
closure->setUnsafeConcurrent(sendable, forMainActor);
57165716
return;
57175717
}
57185718

57195719
if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
5720-
applyContextuallyConcurrent(
5720+
applyUnsafeConcurrent(
57215721
captureList->getClosureBody(), sendable, forMainActor);
57225722
}
57235723
}
@@ -5972,18 +5972,14 @@ Expr *ExprRewriter::coerceCallArguments(
59725972
// Save the original label location.
59735973
newLabelLocs.push_back(getLabelLoc(argIdx));
59745974

5975-
// If the parameter is contextually Sendable and we are in a
5976-
// context that has adopted concurrency, apply contextual Sendable
5977-
// to the closure (if there is one).
5978-
if (paramInfo.isUnsafeSendable(paramIdx)) {
5979-
bool forMainActor = false;
5980-
if (apply) {
5981-
forMainActor = isMainDispatchQueue(apply->getFn());
5982-
}
5983-
5984-
applyContextuallyConcurrent(
5985-
arg, contextUsesConcurrencyFeatures(dc), forMainActor);
5986-
}
5975+
// Determine whether the parameter is unsafe Sendable or MainActor, and
5976+
// record it as such.
5977+
bool isUnsafeSendable = paramInfo.isUnsafeSendable(paramIdx);
5978+
bool isMainActor = paramInfo.isUnsafeMainActor(paramIdx) ||
5979+
(isUnsafeSendable && apply && isMainDispatchQueue(apply->getFn()));
5980+
applyUnsafeConcurrent(
5981+
arg, isUnsafeSendable && contextUsesConcurrencyFeatures(dc),
5982+
isMainActor);
59875983

59885984
// If the types exactly match, this is easy.
59895985
auto paramType = param.getOldType();

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
136136
IGNORED_ATTR(AtRethrows)
137137
IGNORED_ATTR(AtReasync)
138138
IGNORED_ATTR(UnsafeSendable)
139+
IGNORED_ATTR(UnsafeMainActor)
139140
#undef IGNORED_ATTR
140141

141142
void visitAlignmentAttr(AlignmentAttr *attr) {

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,7 @@ namespace {
15451545
UNINTERESTING_ATTR(AtReasync)
15461546
UNINTERESTING_ATTR(Nonisolated)
15471547
UNINTERESTING_ATTR(UnsafeSendable)
1548+
UNINTERESTING_ATTR(UnsafeMainActor)
15481549

15491550
#undef UNINTERESTING_ATTR
15501551

test/ClangImporter/objc_async.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ func testSlowServerSynchronous(slowServer: SlowServer) {
7272
print(s)
7373
onlyOnMainActor() // okay because runOnMainThread has a @MainActor closure
7474
}
75+
76+
slowServer.overridableButRunsOnMainThread { s in
77+
print(s)
78+
onlyOnMainActor() // okay because parameter has @_unsafeMainActor
79+
}
80+
81+
let _: Int = slowServer.overridableButRunsOnMainThread // expected-error{{cannot convert value of type '(((String) -> Void)?) -> Void' to specified type 'Int'}}
7582
}
7683

7784
func testSlowServerOldSchool(slowServer: SlowServer) {

0 commit comments

Comments
 (0)