Skip to content

[6.2] AST, Sema: Cherry-pick 4 NonisolatedNonsendingByDefault bug fixes #81573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -8634,23 +8634,23 @@ GROUPED_WARNING(
attr_execution_nonisolated_behavior_will_change_decl, NonisolatedNonsendingByDefault,
none,
"feature '%0' will cause nonisolated async %kindbase1 to run on the "
"caller's actor; use %2 to preserve behavior",
(StringRef, const AbstractFunctionDecl *, DeclAttribute))
"caller's actor; use '@concurrent' to preserve behavior",
(StringRef, const AbstractFunctionDecl *))

GROUPED_WARNING(
attr_execution_nonisolated_behavior_will_change_closure,
NonisolatedNonsendingByDefault, none,
"feature '%0' will cause nonisolated async closure to run on the caller's "
"actor; use %1 to preserve behavior",
(StringRef, DeclAttribute))
"actor; use '@concurrent' to preserve behavior",
(StringRef))

GROUPED_WARNING(
attr_execution_nonisolated_behavior_will_change_typerepr,
NonisolatedNonsendingByDefault, none,
"feature '%0' will cause nonisolated async function type to be treated as "
"specified to run on the caller's actor; use %1 to preserve "
"specified to run on the caller's actor; use '@concurrent' to preserve "
"behavior",
(StringRef, DeclAttribute))
(StringRef))

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
20 changes: 11 additions & 9 deletions lib/AST/DiagnosticEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,15 +393,17 @@ InFlightDiagnostic::fixItAddAttribute(const DeclAttribute *Attr,
const ClosureExpr *E) {
ASSERT(!E->isImplicit());

SourceLoc insertionLoc;

if (auto *paramList = E->getParameters()) {
// HACK: Don't set insertion loc to param list start loc if it's equal to
// closure start loc (meaning it's implicit).
// FIXME: Don't set the start loc of an implicit param list, or put an
// isImplicit bit on ParameterList.
if (paramList->getStartLoc() != E->getStartLoc()) {
insertionLoc = paramList->getStartLoc();
SourceLoc insertionLoc = E->getBracketRange().Start;

if (insertionLoc.isInvalid()) {
if (auto *paramList = E->getParameters()) {
// HACK: Don't set insertion loc to param list start loc if it's equal to
// closure start loc (meaning it's implicit).
// FIXME: Don't set the start loc of an implicit param list, or put an
// isImplicit bit on ParameterList.
if (paramList->getStartLoc() != E->getStartLoc()) {
insertionLoc = paramList->getStartLoc();
}
}
}

Expand Down
13 changes: 7 additions & 6 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1414,11 +1414,6 @@ FunctionType::ExtInfo ClosureEffectsRequest::evaluate(
bool async = expr->getAsyncLoc().isValid();
bool sendable = expr->getAttrs().hasAttribute<SendableAttr>();

// `@concurrent` attribute is only valid on asynchronous function types.
if (expr->getAttrs().hasAttribute<ConcurrentAttr>()) {
async = true;
}

if (throws || async) {
return ASTExtInfoBuilder()
.withThrows(throws, /*FIXME:*/Type())
Expand All @@ -1432,11 +1427,17 @@ FunctionType::ExtInfo ClosureEffectsRequest::evaluate(
if (!body)
return ASTExtInfoBuilder().withSendable(sendable).build();

// `@concurrent` attribute is only valid on asynchronous function types.
bool asyncFromAttr = false;
if (expr->getAttrs().hasAttribute<ConcurrentAttr>()) {
asyncFromAttr = true;
}

auto throwFinder = FindInnerThrows(expr);
body->walk(throwFinder);
return ASTExtInfoBuilder()
.withThrows(throwFinder.foundThrow(), /*FIXME:*/Type())
.withAsync(bool(findAsyncNode(expr)))
.withAsync(asyncFromAttr || bool(findAsyncNode(expr)))
.withSendable(sendable)
.build();
}
Expand Down
6 changes: 3 additions & 3 deletions lib/Sema/NonisolatedNonsendingByDefaultMigration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,21 +168,21 @@ void NonisolatedNonsendingByDefaultMigrationTarget::diagnose() const {
ctx.Diags
.diagnose(functionDecl->getLoc(),
diag::attr_execution_nonisolated_behavior_will_change_decl,
featureName, functionDecl, &attr)
featureName, functionDecl)
.fixItInsertAttribute(
decl->getAttributeInsertionLoc(/*forModifier=*/false), &attr);
} else if (closure) {
ctx.Diags
.diagnose(closure->getLoc(),
diag::attr_execution_nonisolated_behavior_will_change_closure,
featureName, &attr)
featureName)
.fixItAddAttribute(&attr, closure);
} else {
ctx.Diags
.diagnose(
functionRepr->getStartLoc(),
diag::attr_execution_nonisolated_behavior_will_change_typerepr,
featureName, &attr)
featureName)
.fixItInsertAttribute(functionRepr->getStartLoc(), &attr);
}
}
Expand Down
58 changes: 45 additions & 13 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2418,6 +2418,11 @@ namespace {
class TypeAttrSet {
const ASTContext &ctx;

/// FIXME:
/// `nonisolated(nonsending)` is modeled as a separate `TypeRepr`, but
/// needs to be considered together with subsequent attributes.
CallerIsolatedTypeRepr *nonisolatedNonsendingAttr;

llvm::TinyPtrVector<CustomAttr*> customAttrs;
EnumMap<TypeAttrKind, TypeAttribute *> typeAttrs;

Expand All @@ -2429,7 +2434,9 @@ namespace {
#endif

public:
TypeAttrSet(const ASTContext &ctx) : ctx(ctx) {}
TypeAttrSet(const ASTContext &ctx,
CallerIsolatedTypeRepr *nonisolatedNonsendingAttr = nullptr)
: ctx(ctx), nonisolatedNonsendingAttr(nonisolatedNonsendingAttr) {}

TypeAttrSet(const TypeAttrSet &) = delete;
TypeAttrSet &operator=(const TypeAttrSet &) = delete;
Expand All @@ -2448,6 +2455,10 @@ namespace {
/// will be diagnosed.
void accumulate(ArrayRef<TypeOrCustomAttr> attrs);

CallerIsolatedTypeRepr *getNonisolatedNonsendingAttr() const {
return nonisolatedNonsendingAttr;
}

/// Return all of the custom attributes.
ArrayRef<CustomAttr*> getCustomAttrs() const {
return customAttrs;
Expand Down Expand Up @@ -2547,9 +2558,17 @@ namespace {
}

template <class AttrClass>
AttrClass *getWithoutClaiming(TypeAttrSet *attrs) {
std::enable_if_t<std::is_base_of_v<TypeAttribute, AttrClass>, AttrClass *>
getWithoutClaiming(TypeAttrSet *attrs) {
return (attrs ? getWithoutClaiming<AttrClass>(*attrs) : nullptr);
}

template <class AttrClass>
std::enable_if_t<std::is_same_v<AttrClass, CallerIsolatedTypeRepr>,
CallerIsolatedTypeRepr *>
getWithoutClaiming(TypeAttrSet *attrs) {
return attrs ? attrs->getNonisolatedNonsendingAttr() : nullptr;
}
} // end anonymous namespace

Type TypeResolution::resolveContextualType(
Expand Down Expand Up @@ -4247,10 +4266,19 @@ NeverNullType TypeResolver::resolveASTFunctionType(
};

if (auto concurrentAttr = claim<ConcurrentTypeAttr>(attrs)) {
if (auto *nonisolatedNonsendingAttr =
getWithoutClaiming<CallerIsolatedTypeRepr>(attrs)) {
diagnoseInvalid(
nonisolatedNonsendingAttr, nonisolatedNonsendingAttr->getStartLoc(),
diag::cannot_use_nonisolated_nonsending_together_with_concurrent,
nonisolatedNonsendingAttr);
}

checkExecutionBehaviorAttribute(concurrentAttr);

if (!repr->isInvalid())
isolation = FunctionTypeIsolation::forNonIsolated();
} else {
} else if (!getWithoutClaiming<CallerIsolatedTypeRepr>(attrs)) {
if (ctx.LangOpts.getFeatureState(Feature::NonisolatedNonsendingByDefault)
.isEnabledForMigration()) {
// Diagnose only in the interface stage, which is run once.
Expand Down Expand Up @@ -5281,7 +5309,20 @@ TypeResolver::resolveSendingTypeRepr(SendingTypeRepr *repr,
NeverNullType
TypeResolver::resolveCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *repr,
TypeResolutionOptions options) {
Type type = resolveType(repr->getBase(), options);
Type type;
{
TypeAttrSet attrs(getASTContext(), repr);

auto *baseRepr = repr->getBase();
if (auto *attrRepr = dyn_cast<AttributedTypeRepr>(baseRepr)) {
baseRepr = attrs.accumulate(attrRepr);
}

type = resolveAttributedType(baseRepr, options, attrs);

attrs.diagnoseUnclaimed(resolution, options, type);
}

if (type->hasError())
return ErrorType::get(getASTContext());

Expand All @@ -5297,15 +5338,6 @@ TypeResolver::resolveCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *repr,
diag::nonisolated_nonsending_only_on_async, repr);
}

if (auto *ATR = dyn_cast<AttributedTypeRepr>(repr->getBase())) {
if (ATR->get(TypeAttrKind::Concurrent)) {
diagnoseInvalid(
repr, repr->getStartLoc(),
diag::cannot_use_nonisolated_nonsending_together_with_concurrent,
repr);
}
}

switch (fnType->getIsolation().getKind()) {
case FunctionTypeIsolation::Kind::NonIsolated:
break;
Expand Down
Loading