Skip to content

Commit f32572b

Browse files
committed
Apply @_predatesConcurrency adjustments to variables, subscripts.
1 parent 5cc00c2 commit f32572b

File tree

4 files changed

+122
-48
lines changed

4 files changed

+122
-48
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,9 @@ Type ConstraintSystem::getUnopenedTypeOfReference(
11071107
Type requestedType =
11081108
getType(value)->getWithoutSpecifierType()->getReferenceStorageReferent();
11091109

1110+
// Adjust the type for concurrency.
1111+
requestedType = adjustVarTypeForConcurrency(requestedType, value, UseDC);
1112+
11101113
// If we're dealing with contextual types, and we referenced this type from
11111114
// a different context, map the type.
11121115
if (!wantInterfaceType && requestedType->hasArchetype()) {
@@ -1757,7 +1760,11 @@ ConstraintSystem::getTypeOfMemberReference(
17571760
->castTo<AnyFunctionType>()->getParams();
17581761
// FIXME: Verify ExtInfo state is correct, not working by accident.
17591762
FunctionType::ExtInfo info;
1760-
refType = FunctionType::get(indices, elementTy, info);
1763+
auto *refFnType = FunctionType::get(indices, elementTy, info);
1764+
1765+
refType = adjustFunctionTypeForConcurrency(
1766+
refFnType, subscript, useDC, /*numApplies=*/1,
1767+
/*isMainDispatchQueue=*/false);
17611768
} else {
17621769
refType = getUnopenedTypeOfReference(cast<VarDecl>(value), baseTy, useDC,
17631770
locator,
@@ -2051,14 +2058,17 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
20512058
->castTo<AnyFunctionType>()->getParams();
20522059
// FIXME: Verify ExtInfo state is correct, not working by accident.
20532060
FunctionType::ExtInfo info;
2054-
type = FunctionType::get(indices, elementTy, info);
2061+
type = adjustFunctionTypeForConcurrency(
2062+
FunctionType::get(indices, elementTy, info),
2063+
subscript, useDC, /*numApplies=*/1, /*isMainDispatchQueue=*/false);
20552064
} else if (auto var = dyn_cast<VarDecl>(decl)) {
20562065
type = var->getValueInterfaceType();
20572066
if (doesStorageProduceLValue(var, overload.getBaseType(), useDC)) {
20582067
type = LValueType::get(type);
20592068
} else if (type->hasDynamicSelfType()) {
20602069
type = withDynamicSelfResultReplaced(type, /*uncurryLevel=*/0);
20612070
}
2071+
type = adjustVarTypeForConcurrency(type, var, useDC);
20622072
} else if (isa<AbstractFunctionDecl>(decl) || isa<EnumElementDecl>(decl)) {
20632073
if (decl->isInstanceMember() &&
20642074
(!overload.getBaseType() ||
@@ -2087,7 +2097,10 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
20872097
}
20882098
}
20892099

2090-
type = type->castTo<FunctionType>()->getResult();
2100+
type = adjustFunctionTypeForConcurrency(
2101+
type->castTo<FunctionType>(),
2102+
subscript, useDC, /*numApplies=*/2, /*isMainDispatchQueue=*/false)
2103+
->getResult();
20912104
}
20922105
}
20932106

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 77 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4032,33 +4032,32 @@ static Type applyUnsafeConcurrencyToParameterType(
40324032
.withGlobalActor(globalActor));
40334033
}
40344034

4035-
/// Strip concurrency from the type of the given parameter.
4036-
static Type stripConcurrencyFromParameterType(
4037-
Type paramType, bool dropGlobalActor) {
4035+
/// Strip concurrency from the given type.
4036+
static Type stripConcurrencyFromType(Type type, bool dropGlobalActor) {
40384037
// Look through optionals.
4039-
if (Type optionalObject = paramType->getOptionalObjectType()) {
4038+
if (Type optionalObject = type->getOptionalObjectType()) {
40404039
Type newOptionalObject =
4041-
stripConcurrencyFromParameterType(optionalObject, dropGlobalActor);
4040+
stripConcurrencyFromType(optionalObject, dropGlobalActor);
40424041
if (optionalObject->isEqual(newOptionalObject))
4043-
return paramType;
4042+
return type;
40444043

40454044
return OptionalType::get(newOptionalObject);
40464045
}
40474046

40484047
// For function types, strip off Sendable and possibly the global actor.
4049-
if (auto fnType = paramType->getAs<FunctionType>()) {
4048+
if (auto fnType = type->getAs<FunctionType>()) {
40504049
auto extInfo = fnType->getExtInfo().withConcurrent(false);
40514050
if (dropGlobalActor)
40524051
extInfo = extInfo.withGlobalActor(Type());
40534052
auto newFnType = FunctionType::get(
40544053
fnType->getParams(), fnType->getResult(), extInfo);
4055-
if (newFnType->isEqual(paramType))
4056-
return paramType;
4054+
if (newFnType->isEqual(type))
4055+
return type;
40574056

40584057
return newFnType;
40594058
}
40604059

4061-
return paramType;
4060+
return type;
40624061
}
40634062

40644063
/// Determine whether the given name is that of a DispatchQueue operation that
@@ -4094,18 +4093,42 @@ static bool hasKnownUnsafeSendableFunctionParams(AbstractFunctionDecl *func) {
40944093
return false;
40954094
}
40964095

4096+
Type swift::adjustVarTypeForConcurrency(
4097+
Type type, VarDecl *var, DeclContext *dc) {
4098+
if (!var->predatesConcurrency())
4099+
return type;
4100+
4101+
if (contextUsesConcurrencyFeatures(dc))
4102+
return type;
4103+
4104+
bool isLValue = false;
4105+
if (auto *lvalueType = type->getAs<LValueType>()) {
4106+
type = lvalueType->getObjectType();
4107+
isLValue = true;
4108+
}
4109+
4110+
type = stripConcurrencyFromType(type, /*dropGlobalActor=*/true);
4111+
4112+
if (isLValue)
4113+
type = LValueType::get(type);
4114+
4115+
return type;
4116+
}
4117+
40974118
/// Adjust a function type for @_unsafeSendable, @_unsafeMainActor, and
40984119
/// @_predatesConcurrency.
40994120
static AnyFunctionType *applyUnsafeConcurrencyToFunctionType(
4100-
AnyFunctionType *fnType, ValueDecl *funcOrEnum,
4121+
AnyFunctionType *fnType, ValueDecl *decl,
41014122
bool inConcurrencyContext, unsigned numApplies, bool isMainDispatchQueue) {
4102-
// Only functions can have @_unsafeSendable/@_unsafeMainActor parameters.
4103-
auto func = dyn_cast<AbstractFunctionDecl>(funcOrEnum);
4104-
if (!func)
4123+
// Functions/subscripts/enum elements have function types to adjust.
4124+
auto func = dyn_cast_or_null<AbstractFunctionDecl>(decl);
4125+
auto subscript = dyn_cast_or_null<SubscriptDecl>(decl);
4126+
4127+
if (!func && !subscript)
41054128
return fnType;
41064129

41074130
AnyFunctionType *outerFnType = nullptr;
4108-
if (func->hasImplicitSelfDecl()) {
4131+
if (func && func->hasImplicitSelfDecl()) {
41094132
outerFnType = fnType;
41104133
fnType = outerFnType->getResult()->castTo<AnyFunctionType>();
41114134

@@ -4115,15 +4138,13 @@ static AnyFunctionType *applyUnsafeConcurrencyToFunctionType(
41154138

41164139
SmallVector<AnyFunctionType::Param, 4> newTypeParams;
41174140
auto typeParams = fnType->getParams();
4118-
auto paramDecls = func->getParameters();
4141+
auto paramDecls = func ? func->getParameters() : subscript->getIndices();
41194142
assert(typeParams.size() == paramDecls->size());
4120-
bool knownUnsafeParams = hasKnownUnsafeSendableFunctionParams(func);
4143+
bool knownUnsafeParams = func && hasKnownUnsafeSendableFunctionParams(func);
41214144
bool stripConcurrency =
4122-
funcOrEnum->predatesConcurrency() &&
4123-
!inConcurrencyContext;
4145+
decl->predatesConcurrency() && !inConcurrencyContext;
41244146
for (unsigned index : indices(typeParams)) {
41254147
auto param = typeParams[index];
4126-
auto paramDecl = (*paramDecls)[index];
41274148

41284149
// Determine whether the resulting parameter should be @Sendable or
41294150
// @MainActor. @Sendable occurs only in concurrency contents, while
@@ -4138,7 +4159,7 @@ static AnyFunctionType *applyUnsafeConcurrencyToFunctionType(
41384159
newParamType = applyUnsafeConcurrencyToParameterType(
41394160
param.getPlainType(), addSendable, addMainActor);
41404161
} else if (stripConcurrency) {
4141-
newParamType = stripConcurrencyFromParameterType(
4162+
newParamType = stripConcurrencyFromType(
41424163
param.getPlainType(), numApplies == 0);
41434164
}
41444165

@@ -4160,14 +4181,25 @@ static AnyFunctionType *applyUnsafeConcurrencyToFunctionType(
41604181
newTypeParams.push_back(param.withType(newParamType));
41614182
}
41624183

4184+
// Compute the new result type.
4185+
Type newResultType = fnType->getResult();
4186+
if (stripConcurrency) {
4187+
newResultType = stripConcurrencyFromType(
4188+
newResultType, /*dropGlobalActor=*/true);
4189+
4190+
if (!newResultType->isEqual(fnType->getResult()) && newTypeParams.empty()) {
4191+
newTypeParams.append(typeParams.begin(), typeParams.end());
4192+
}
4193+
}
4194+
41634195
// If we didn't change any parameters, we're done.
4164-
if (newTypeParams.empty()) {
4196+
if (newTypeParams.empty() && newResultType->isEqual(fnType->getResult())) {
41654197
return outerFnType ? outerFnType : fnType;
41664198
}
41674199

41684200
// Rebuild the (inner) function type.
41694201
fnType = FunctionType::get(
4170-
newTypeParams, fnType->getResult(), fnType->getExtInfo());
4202+
newTypeParams, newResultType, fnType->getExtInfo());
41714203

41724204
if (!outerFnType)
41734205
return fnType;
@@ -4184,39 +4216,41 @@ static AnyFunctionType *applyUnsafeConcurrencyToFunctionType(
41844216
}
41854217

41864218
AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
4187-
AnyFunctionType *fnType, ValueDecl *funcOrEnum, DeclContext *dc,
4219+
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
41884220
unsigned numApplies, bool isMainDispatchQueue) {
41894221
// Apply unsafe concurrency features to the given function type.
41904222
fnType = applyUnsafeConcurrencyToFunctionType(
4191-
fnType, funcOrEnum, contextUsesConcurrencyFeatures(dc), numApplies,
4223+
fnType, decl, contextUsesConcurrencyFeatures(dc), numApplies,
41924224
isMainDispatchQueue);
41934225

41944226
Type globalActorType;
4195-
switch (auto isolation = getActorIsolation(funcOrEnum)) {
4196-
case ActorIsolation::ActorInstance:
4197-
case ActorIsolation::DistributedActorInstance:
4198-
case ActorIsolation::Independent:
4199-
case ActorIsolation::Unspecified:
4200-
return fnType;
4201-
4202-
case ActorIsolation::GlobalActorUnsafe:
4203-
// Only treat as global-actor-qualified within code that has adopted
4204-
// Swift Concurrency features.
4205-
if (!contextUsesConcurrencyFeatures(dc))
4227+
if (decl) {
4228+
switch (auto isolation = getActorIsolation(decl)) {
4229+
case ActorIsolation::ActorInstance:
4230+
case ActorIsolation::DistributedActorInstance:
4231+
case ActorIsolation::Independent:
4232+
case ActorIsolation::Unspecified:
42064233
return fnType;
42074234

4208-
LLVM_FALLTHROUGH;
4235+
case ActorIsolation::GlobalActorUnsafe:
4236+
// Only treat as global-actor-qualified within code that has adopted
4237+
// Swift Concurrency features.
4238+
if (!contextUsesConcurrencyFeatures(dc))
4239+
return fnType;
42094240

4210-
case ActorIsolation::GlobalActor:
4211-
globalActorType = isolation.getGlobalActor();
4212-
break;
4241+
LLVM_FALLTHROUGH;
4242+
4243+
case ActorIsolation::GlobalActor:
4244+
globalActorType = isolation.getGlobalActor();
4245+
break;
4246+
}
42134247
}
42144248

42154249
// If there's no implicit "self" declaration, apply the global actor to
42164250
// the outermost function type.
4217-
bool hasImplicitSelfDecl = isa<EnumElementDecl>(funcOrEnum) ||
4218-
(isa<AbstractFunctionDecl>(funcOrEnum) &&
4219-
cast<AbstractFunctionDecl>(funcOrEnum)->hasImplicitSelfDecl());
4251+
bool hasImplicitSelfDecl = decl && (isa<EnumElementDecl>(decl) ||
4252+
(isa<AbstractFunctionDecl>(decl) &&
4253+
cast<AbstractFunctionDecl>(decl)->hasImplicitSelfDecl()));
42204254
if (!hasImplicitSelfDecl) {
42214255
return fnType->withExtInfo(
42224256
fnType->getExtInfo().withGlobalActor(globalActorType));

lib/Sema/TypeCheckConcurrency.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,15 @@ checkGlobalActorAttributes(
310310
/// Get the explicit global actor specified for a closure.
311311
Type getExplicitGlobalActor(ClosureExpr *closure);
312312

313+
/// Adjust the type of the variable for concurrency.
314+
Type adjustVarTypeForConcurrency(Type type, VarDecl *var, DeclContext *dc);
315+
316+
/// Adjust the function type of a function / subscript / enum case for
317+
/// concurrency.
318+
AnyFunctionType *adjustFunctionTypeForConcurrency(
319+
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
320+
unsigned numApplies, bool isMainDispatchQueue);
321+
313322
/// Adjust the given function type to account for concurrency-specific
314323
/// attributes whose affect on the type might differ based on context.
315324
/// This includes adjustments for unsafe parameter attributes like

test/Concurrency/predates_concurrency.swift

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,18 @@
99

1010
struct X {
1111
@_predatesConcurrency func unsafelyDoEverythingClosure(_ closure: @MainActor @Sendable () -> Void) { }
12+
13+
@_predatesConcurrency var sendableVar: @Sendable () -> Void
14+
@_predatesConcurrency var mainActorVar: @MainActor () -> Void
15+
16+
@_predatesConcurrency
17+
subscript(_: @MainActor () -> Void) -> (@Sendable () -> Void) { {} }
18+
19+
@_predatesConcurrency
20+
static subscript(statically _: @MainActor () -> Void) -> (@Sendable () -> Void) { { } }
1221
}
1322

23+
@MainActor func onMainActor() { }
1424

1525
func testInAsync(x: X) async {
1626
let _: Int = unsafelySendableClosure // expected-error{{type '(@Sendable () -> Void) -> ()'}}
@@ -19,6 +29,12 @@ func testInAsync(x: X) async {
1929
let _: Int = x.unsafelyDoEverythingClosure // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
2030
let _: Int = X.unsafelyDoEverythingClosure // expected-error{{type '(X) -> (@MainActor @Sendable () -> Void) -> ()'}}
2131
let _: Int = (X.unsafelyDoEverythingClosure)(x) // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
32+
33+
let _: Int = x.sendableVar // expected-error{{type '@Sendable () -> Void'}}
34+
let _: Int = x.mainActorVar // expected-error{{type '@MainActor () -> Void'}}
35+
36+
let _: Int = x[{ onMainActor() }] // expected-error{{type '@Sendable () -> Void'}}
37+
let _: Int = X[statically: { onMainActor() }] // expected-error{{type '@Sendable () -> Void'}}
2238
}
2339

2440
func testElsewhere(x: X) {
@@ -28,10 +44,12 @@ func testElsewhere(x: X) {
2844
let _: Int = x.unsafelyDoEverythingClosure // expected-error{{type '(() -> Void) -> ()'}}
2945
let _: Int = X.unsafelyDoEverythingClosure // expected-error{{type '(X) -> (() -> Void) -> ()'}}
3046
let _: Int = (X.unsafelyDoEverythingClosure)(x) // expected-error{{type '(() -> Void) -> ()'}}
47+
let _: Int = x.sendableVar // expected-error{{type '() -> Void'}}
48+
let _: Int = x.mainActorVar // expected-error{{type '() -> Void'}}
49+
let _: Int = x[{ onMainActor() }] // expected-error{{type '() -> Void'}}
50+
let _: Int = X[statically: { onMainActor() }] // expected-error{{type '() -> Void'}}
3151
}
3252

33-
@MainActor func onMainActor() { }
34-
3553
@MainActor @_predatesConcurrency func onMainActorAlways() { }
3654

3755
@_predatesConcurrency @MainActor class MyModelClass {

0 commit comments

Comments
 (0)