diff --git a/include/swift/AST/ActorIsolation.h b/include/swift/AST/ActorIsolation.h index 3f6f9956fcdff..2adf24b7d87ea 100644 --- a/include/swift/AST/ActorIsolation.h +++ b/include/swift/AST/ActorIsolation.h @@ -160,6 +160,8 @@ class ActorIsolation { return getKind() == GlobalActor || getKind() == GlobalActorUnsafe; } + bool isMainActor() const; + bool isDistributedActor() const; Type getGlobalActor() const { diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index fbe06c6907106..b551089716d70 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3834,6 +3834,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext { /// Whether this nominal type qualifies as any actor (plain or distributed). bool isAnyActor() const; + /// Whether this nominal type is the `MainActor` global actor. + bool isMainActor() const; + /// Return the range of semantics attributes attached to this NominalTypeDecl. auto getSemanticsAttrs() const -> decltype(getAttrs().getSemanticsAttrs()) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 173429d81e85d..807b518385fea 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -4567,6 +4567,11 @@ bool NominalTypeDecl::isAnyActor() const { return isActor() || isDistributedActor(); } +bool NominalTypeDecl::isMainActor() const { + return getName().is("MainActor") && + getParentModule()->getName() == getASTContext().Id_Concurrency; +} + GenericTypeDecl::GenericTypeDecl(DeclKind K, DeclContext *DC, Identifier name, SourceLoc nameLoc, ArrayRef inherited, @@ -9614,6 +9619,15 @@ void swift::simple_display(llvm::raw_ostream &out, AnyFunctionRef fn) { out << "closure"; } +bool ActorIsolation::isMainActor() const { + if (isGlobalActor()) { + if (auto *nominal = getGlobalActor()->getAnyNominal()) + return nominal->isMainActor(); + } + + return false; +} + bool ActorIsolation::isDistributedActor() const { return getKind() == ActorInstance && getActor()->isDistributedActor(); } diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index bda5424e5c8dd..8ee6eddaaa110 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -576,18 +576,6 @@ static bool typeSpellingIsAmbiguous(Type type, return false; } -/// Determine whether this is the main actor type. -static bool isMainActor(Type type) { - if (auto nominal = type->getAnyNominal()) { - if (nominal->getName().is("MainActor") && - nominal->getParentModule()->getName() == - nominal->getASTContext().Id_Concurrency) - return true; - } - - return false; -} - void swift::printClangDeclName(const clang::NamedDecl *ND, llvm::raw_ostream &os) { ND->getNameForDiagnostic(os, ND->getASTContext().getPrintingPolicy(), false); @@ -841,10 +829,10 @@ static void formatDiagnosticArgument(StringRef Modifier, case ActorIsolation::GlobalActor: case ActorIsolation::GlobalActorUnsafe: { - Type globalActor = isolation.getGlobalActor(); - if (isMainActor(globalActor)) { + if (isolation.isMainActor()) { Out << "main actor-isolated"; } else { + Type globalActor = isolation.getGlobalActor(); Out << "global actor " << FormatOpts.OpeningQuotationMark << globalActor.getString() << FormatOpts.ClosingQuotationMark << "-isolated"; diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index 46cf9cd37b19a..b904b2bc764d7 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -712,6 +712,11 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo, !isInActorDestructor(FunctionDC) && !F.isDefer(); + // FIXME: Avoid loading and checking the expected executor if concurrency is + // unavailable. This is specifically relevant for MainActor isolated contexts, + // which are allowed to be available on OSes where concurrency is not + // available. rdar://106827064 + // Local function to load the expected executor from a local actor auto loadExpectedExecutorForLocalVar = [&](VarDecl *var) { auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation()); diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 3c2683e2cf48b..1938c28a8730f 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -1744,13 +1744,23 @@ class DeclAvailabilityChecker : public DeclVisitor { explicit DeclAvailabilityChecker(ExportContext where) : Where(where) {} + void checkGlobalActor(Decl *D) { + auto globalActor = D->getGlobalActorAttr(); + if (!globalActor) + return; + + // Avoid checking the availability for a @MainActor constraint since it does + // not carry an inherent ABI impact. + if (globalActor->second->isMainActor()) + return; + + auto customAttr = globalActor->first; + checkType(customAttr->getType(), customAttr->getTypeRepr(), D); + } + void visit(Decl *D) { DeclVisitor::visit(D); - - if (auto globalActor = D->getGlobalActorAttr()) { - auto customAttr = globalActor->first; - checkType(customAttr->getType(), customAttr->getTypeRepr(), D); - } + checkGlobalActor(D); } // Force all kinds to be handled at a lower level. diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 70c5c9335de7e..e49a3df47f07c 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -3538,15 +3538,6 @@ void AttributeChecker::visitFrozenAttr(FrozenAttr *attr) { } } -/// Determine whether this is the main actor type. -/// FIXME: the diagnostics engine and TypeCheckConcurrency both have a copy of -/// this -static bool isMainActor(NominalTypeDecl *nominal) { - return nominal->getName().is("MainActor") && - nominal->getParentModule()->getName() == - nominal->getASTContext().Id_Concurrency; -} - void AttributeChecker::visitCustomAttr(CustomAttr *attr) { auto dc = D->getDeclContext(); @@ -3582,7 +3573,7 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { return; } - if (isMainActor(nominal) && Ctx.LangOpts.isConcurrencyModelTaskToThread() && + if (nominal->isMainActor() && Ctx.LangOpts.isConcurrencyModelTaskToThread() && !AvailableAttr::isUnavailable(D)) { Ctx.Diags.diagnose(attr->getLocation(), diag::concurrency_task_to_thread_model_main_actor, diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index ee96876ca6fe8..9049885f95269 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -1193,14 +1193,9 @@ void swift::diagnoseMissingExplicitSendable(NominalTypeDecl *nominal) { } /// Determine whether this is the main actor type. -/// FIXME: the diagnostics engine has a copy of this. static bool isMainActor(Type type) { - if (auto nominal = type->getAnyNominal()) { - if (nominal->getName().is("MainActor") && - nominal->getParentModule()->getName() == - nominal->getASTContext().Id_Concurrency) - return true; - } + if (auto nominal = type->getAnyNominal()) + return nominal->isMainActor(); return false; } diff --git a/test/Sema/availability_main_actor.swift b/test/Sema/availability_main_actor.swift new file mode 100644 index 0000000000000..5acf60b46c71f --- /dev/null +++ b/test/Sema/availability_main_actor.swift @@ -0,0 +1,20 @@ +// RUN: %target-typecheck-verify-swift + +// REQUIRES: concurrency + +// This test is meant to verify that a @MainActor constraint is accepted without +// any availability restrictions for all targets. + +@MainActor +struct AlwaysAvailable {} + +@MainActor(unsafe) +struct AlwaysAvailableUnsafe {} + +@available(SwiftStdlib 5.1, *) +@MainActor +struct AvailableSwift5_1 {} + +@available(SwiftStdlib 5.1, *) +@MainActor(unsafe) +struct AvailableSwift5_1Unsafe {} diff --git a/validation-test/ParseableInterface/unsafe-mainactor.swift b/validation-test/ParseableInterface/unsafe-mainactor.swift new file mode 100644 index 0000000000000..e1f23fec22330 --- /dev/null +++ b/validation-test/ParseableInterface/unsafe-mainactor.swift @@ -0,0 +1,14 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-emit-module-interface(%t/Library.swiftinterface) %s -module-name Library +// RUN: %target-swift-typecheck-module-from-interface(%t/Library.swiftinterface) -module-name Library +// RUN: %FileCheck %s < %t/Library.swiftinterface + +// REQUIRES: OS=macosx + +import AppKit + +// CHECK: @objc @_inheritsConvenienceInitializers @_Concurrency.MainActor(unsafe) public class Subclass : AppKit.NSView { +public class Subclass: NSView { + // CHECK: @_Concurrency.MainActor(unsafe) @objc override dynamic public init(frame frameRect: Foundation.NSRect) + // CHECK: @_Concurrency.MainActor(unsafe) @objc required dynamic public init?(coder: Foundation.NSCoder) +}