Skip to content

Commit 3b3bdaf

Browse files
committed
enforce correctness rules about isolated parameters
This covers function types, closures, and function declarations: - only one `isolated` parameter - no global-actor + `isolated` parameter - no `nonisolated` + `isolated`. all diagnostics are warnings until Swift 6
1 parent e94aa36 commit 3b3bdaf

File tree

6 files changed

+266
-42
lines changed

6 files changed

+266
-42
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4832,9 +4832,22 @@ NOTE(protocol_isolated_to_global_actor_here,none,
48324832

48334833
ERROR(isolated_parameter_not_actor,none,
48344834
"'isolated' parameter has non-actor type %0", (Type))
4835-
ERROR(isolated_parameter_second_isolated_param,none,
4836-
"function cannot have more than one 'isolated' parameter (%0 and %1)",
4837-
(DeclName, DeclName))
4835+
ERROR(isolated_parameter_duplicate,none,
4836+
"cannot have more than one 'isolated' parameter", ())
4837+
ERROR(isolated_parameter_duplicate_type,none,
4838+
"function type cannot have more than one 'isolated' parameter", ())
4839+
NOTE(isolated_parameter_previous_note,none,
4840+
"previous 'isolated' parameter %0", (DeclName))
4841+
ERROR(isolated_parameter_combined_global_actor_attr,none,
4842+
"%0 with 'isolated' parameter cannot have a global actor",
4843+
(DescriptiveDeclKind))
4844+
ERROR(isolated_parameter_closure_combined_global_actor_attr,none,
4845+
"closure with 'isolated' parameter %0 cannot have a global actor", (DeclName))
4846+
ERROR(isolated_parameter_global_actor_type,none,
4847+
"function type cannot have global actor and 'isolated' parameter", ())
4848+
ERROR(isolated_parameter_combined_nonisolated,none,
4849+
"%0 with 'isolated' parameter cannot be 'nonisolated'",
4850+
(DescriptiveDeclKind))
48384851

48394852
WARNING(non_sendable_param_type,none,
48404853
"non-sendable type %0 %select{passed in call to %4 %2 %3|"

lib/Sema/TypeCheckAttr.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6960,8 +6960,24 @@ class ClosureAttributeChecker
69606960
// Check whether this custom attribute is the global actor attribute.
69616961
auto globalActorAttr = evaluateOrDefault(
69626962
ctx.evaluator, GlobalActorAttributeRequest{closure}, None);
6963-
if (globalActorAttr && globalActorAttr->first == attr)
6964-
return;
6963+
6964+
if (globalActorAttr && globalActorAttr->first == attr) {
6965+
// if there is an `isolated` parameter, then this global-actor attribute
6966+
// is invalid.
6967+
for (auto param : *closure->getParameters()) {
6968+
if (param->isIsolated()) {
6969+
param->diagnose(
6970+
diag::isolated_parameter_closure_combined_global_actor_attr,
6971+
param->getName())
6972+
.fixItRemove(attr->getRangeWithAt())
6973+
.warnUntilSwiftVersion(6);
6974+
attr->setInvalid();
6975+
break; // don't need to complain about this more than once.
6976+
}
6977+
}
6978+
6979+
return; // it's OK
6980+
}
69656981

69666982
// Otherwise, it's an error.
69676983
std::string typeName;

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3086,30 +3086,6 @@ void swift::checkTopLevelActorIsolation(TopLevelCodeDecl *decl) {
30863086
body->walk(checker);
30873087
}
30883088

3089-
static bool checkDuplicateIsolatedParameter(AbstractFunctionDecl *decl) {
3090-
// If we have already seen at least one 'isolated' parameter,
3091-
// and we see another one, this is invalid as only one 'isolated' param
3092-
// per function is allowed.
3093-
// See:
3094-
// https://github.com/apple/swift-evolution/blob/main/proposals/0313-actor-isolation-control.md#multiple-isolated-parameters
3095-
ParamDecl* previousIsolatedParam = nullptr;
3096-
for (size_t i = 0; i < decl->getParameters()->size(); ++i) {
3097-
auto param = decl->getParameters()->get(i);
3098-
if (param->isIsolated()) {
3099-
if (auto previous = previousIsolatedParam) {
3100-
decl->diagnose(diag::isolated_parameter_second_isolated_param,
3101-
previous->getParameterName(),
3102-
param->getParameterName());
3103-
return true;
3104-
}
3105-
3106-
previousIsolatedParam = const_cast<ParamDecl*>(param);
3107-
}
3108-
}
3109-
3110-
return false;
3111-
}
3112-
31133089
void swift::checkFunctionActorIsolation(AbstractFunctionDecl *decl) {
31143090
// Disable this check for @LLDBDebuggerFunction functions.
31153091
if (decl->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>())
@@ -3124,7 +3100,6 @@ void swift::checkFunctionActorIsolation(AbstractFunctionDecl *decl) {
31243100
superInit->walk(checker);
31253101
}
31263102

3127-
checkDuplicateIsolatedParameter(decl);
31283103
if (decl->getAttrs().hasAttribute<DistributedActorAttr>()) {
31293104
if (auto func = dyn_cast<FuncDecl>(decl)) {
31303105
checkDistributedFunction(func);
@@ -3734,6 +3709,39 @@ static Optional<unsigned> getIsolatedParamIndex(ValueDecl *value) {
37343709
return None;
37353710
}
37363711

3712+
/// Verifies rules about `isolated` parameters for the given decl. There is more
3713+
/// checking about these in TypeChecker::checkParameterList.
3714+
///
3715+
/// This function is focused on rules that apply when it's a declaration with
3716+
/// an isolated parameter, rather than some generic parameter list in a
3717+
/// DeclContext.
3718+
///
3719+
/// This function assumes the value already contains an isolated parameter.
3720+
static void checkDeclWithIsolatedParameter(ValueDecl *value) {
3721+
// assume there is an isolated parameter.
3722+
assert(getIsolatedParamIndex(value));
3723+
3724+
// Suggest removing global-actor attributes written on it, as its ignored.
3725+
if (auto attr = value->getGlobalActorAttr()) {
3726+
if (!attr->first->isImplicit()) {
3727+
value->diagnose(diag::isolated_parameter_combined_global_actor_attr,
3728+
value->getDescriptiveKind())
3729+
.fixItRemove(attr->first->getRangeWithAt())
3730+
.warnUntilSwiftVersion(6);
3731+
}
3732+
}
3733+
3734+
// Suggest removing `nonisolated` as it is also ignored
3735+
if (auto attr = value->getAttrs().getAttribute<NonisolatedAttr>()) {
3736+
if (!attr->isImplicit()) {
3737+
value->diagnose(diag::isolated_parameter_combined_nonisolated,
3738+
value->getDescriptiveKind())
3739+
.fixItRemove(attr->getRangeWithAt())
3740+
.warnUntilSwiftVersion(6);
3741+
}
3742+
}
3743+
}
3744+
37373745
ActorIsolation ActorIsolationRequest::evaluate(
37383746
Evaluator &evaluator, ValueDecl *value) const {
37393747
// If this declaration has actor-isolated "self", it's isolated to that
@@ -3747,6 +3755,8 @@ ActorIsolation ActorIsolationRequest::evaluate(
37473755
// If this declaration has an isolated parameter, it's isolated to that
37483756
// parameter.
37493757
if (auto paramIdx = getIsolatedParamIndex(value)) {
3758+
checkDeclWithIsolatedParameter(value);
3759+
37503760
// FIXME: This doesn't allow us to find an Actor or DistributedActor
37513761
// bound on the parameter type effectively.
37523762
auto param = getParameterList(value)->get(*paramIdx);

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3480,6 +3480,8 @@ void TypeChecker::typeCheckDecl(Decl *D, bool LeaveClosureBodiesUnchecked) {
34803480

34813481
void TypeChecker::checkParameterList(ParameterList *params,
34823482
DeclContext *owner) {
3483+
Optional<ParamDecl*> firstIsolatedParam;
3484+
bool diagnosedDuplicateIsolatedParam = false;
34833485
for (auto param: *params) {
34843486
checkDeclAttributes(param);
34853487

@@ -3496,6 +3498,32 @@ void TypeChecker::checkParameterList(ParameterList *params,
34963498
}
34973499
}
34983500

3501+
// check for well-formed isolated parameters.
3502+
if (!diagnosedDuplicateIsolatedParam) {
3503+
if (param->isIsolated()) {
3504+
if (firstIsolatedParam) {
3505+
// cannot have more than one isolated parameter (SE-0313)
3506+
param->diagnose(diag::isolated_parameter_duplicate)
3507+
.highlight(param->getSourceRange())
3508+
.warnUntilSwiftVersion(6);
3509+
// I'd love to describe the context in which there is an isolated parameter,
3510+
// we had a DescriptiveDeclContextKind, but that only
3511+
// exists for Decls.
3512+
3513+
auto prevIso = firstIsolatedParam.value();
3514+
prevIso
3515+
->diagnose(diag::isolated_parameter_previous_note,
3516+
prevIso->getName())
3517+
.highlight(prevIso->getSourceRange());
3518+
3519+
// no need to complain about any further `isolated` params
3520+
diagnosedDuplicateIsolatedParam = true;
3521+
} else {
3522+
firstIsolatedParam = param; // save first one we've seen.
3523+
}
3524+
}
3525+
}
3526+
34993527
// Opaque types cannot occur in parameter position.
35003528
Type interfaceType = param->getInterfaceType();
35013529
if (interfaceType->hasTypeParameter()) {

lib/Sema/TypeCheckType.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2516,6 +2516,20 @@ TypeResolver::resolveOpenedExistentialArchetype(
25162516
return archetypeType;
25172517
}
25182518

2519+
/// \returns true iff the # of isolated params is > \c lowerBound
2520+
static bool hasMoreIsolatedParamsThan(FunctionTypeRepr* fnTy, unsigned lowerBound) {
2521+
unsigned count = 0;
2522+
for (auto arg : fnTy->getArgsTypeRepr()->getElements()) {
2523+
if (isa<IsolatedTypeRepr>(arg.Type))
2524+
count += 1;
2525+
2526+
if (count > lowerBound)
2527+
break;
2528+
}
2529+
2530+
return count > lowerBound;
2531+
}
2532+
25192533
NeverNullType
25202534
TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
25212535
TypeResolutionOptions options) {
@@ -2545,7 +2559,7 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
25452559
// Resolve global actor.
25462560
CustomAttr *globalActorAttr = nullptr;
25472561
Type globalActor;
2548-
if (isa<FunctionTypeRepr>(repr)) {
2562+
if (auto fnTy = dyn_cast<FunctionTypeRepr>(repr)) {
25492563
auto foundGlobalActor = checkGlobalActorAttributes(
25502564
repr->getLoc(), getDeclContext(),
25512565
std::vector<CustomAttr *>(
@@ -2555,6 +2569,15 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
25552569
globalActor = resolveType(globalActorAttr->getTypeRepr(), options);
25562570
if (globalActor->hasError())
25572571
globalActor = Type();
2572+
2573+
// make sure there is no `isolated` parameter in the type
2574+
if (globalActorAttr->isValid()) {
2575+
if (globalActor && hasMoreIsolatedParamsThan(fnTy, 0)) {
2576+
diagnose(repr->getLoc(), diag::isolated_parameter_global_actor_type)
2577+
.warnUntilSwiftVersion(6);
2578+
globalActorAttr->setInvalid();
2579+
}
2580+
}
25582581
}
25592582
}
25602583

@@ -3298,6 +3321,17 @@ NeverNullType TypeResolver::resolveASTFunctionType(
32983321
if (auto *genericParams = repr->getGenericParams())
32993322
saveGenericParams.emplace(this->genericParams, genericParams);
33003323

3324+
// can't have more than 1 isolated parameter.
3325+
if (!repr->isWarnedAbout() && hasMoreIsolatedParamsThan(repr, 1)) {
3326+
diagnose(repr->getLoc(), diag::isolated_parameter_duplicate_type)
3327+
.warnUntilSwiftVersion(6);
3328+
3329+
if (getASTContext().LangOpts.isSwiftVersionAtLeast(6))
3330+
return ErrorType::get(getASTContext());
3331+
else
3332+
repr->setWarned();
3333+
}
3334+
33013335
// Diagnose a couple of things that we can parse in SIL mode but we don't
33023336
// allow in formal types.
33033337
if (auto patternParams = repr->getPatternGenericParams()) {

0 commit comments

Comments
 (0)