diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 88434b3103a18..7349a21aa9dbd 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -2693,9 +2693,13 @@ enum class CustomAttrTypeKind { /// any contextual type parameters. NonGeneric, - /// Property delegates have some funky rules, like allowing + /// Property wrappers have some funky rules, like allowing /// unbound generic types. - PropertyDelegate, + PropertyWrapper, + + /// Global actors are represented as custom type attributes. They don't + /// have any particularly interesting semantics. + GlobalActor, }; void simple_display(llvm::raw_ostream &out, CustomAttrTypeKind value); diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index b72542686e9c4..214a1473f87e5 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -1427,8 +1427,12 @@ void swift::simple_display(llvm::raw_ostream &out, CustomAttrTypeKind value) { out << "non-generic"; return; - case CustomAttrTypeKind::PropertyDelegate: - out << "property-delegate"; + case CustomAttrTypeKind::PropertyWrapper: + out << "property-wrapper"; + return; + + case CustomAttrTypeKind::GlobalActor: + out << "global-actor"; return; } llvm_unreachable("bad kind"); diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 474512979861c..28ba235fb2542 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -25,6 +25,24 @@ using namespace swift; +/// Determine whether it makes sense to infer an attribute in the given +/// context. +static bool shouldInferAttributeInContext(const DeclContext *dc) { + auto sourceFile = dc->getParentSourceFile(); + if (!sourceFile) + return false; + + switch (sourceFile->Kind) { + case SourceFileKind::Interface: + case SourceFileKind::SIL: + return false; + + case SourceFileKind::Library: + case SourceFileKind::Main: + return true; + } +} + /// Check whether the @asyncHandler attribute can be applied to the given /// function declaration. /// @@ -108,7 +126,7 @@ bool IsAsyncHandlerRequest::evaluate( return true; } - if (!func->getASTContext().LangOpts.EnableExperimentalConcurrency) + if (!shouldInferAttributeInContext(func->getDeclContext())) return false; // Are we in a context where inference is possible? @@ -1013,15 +1031,18 @@ static Optional getIsolationFromAttributes(Decl *decl) { // If the declaration is marked with a global actor, report it as being // part of that global actor. if (globalActorAttr) { - TypeResolutionOptions options(TypeResolverContext::None); - TypeResolution resolver = TypeResolution::forInterface( - decl->getInnermostDeclContext(), options, nullptr); - Type globalActorType = resolver.resolveType( - globalActorAttr->first->getTypeRepr(), nullptr); + ASTContext &ctx = decl->getASTContext(); + auto dc = decl->getInnermostDeclContext(); + Type globalActorType = evaluateOrDefault( + ctx.evaluator, + CustomAttrTypeRequest{ + globalActorAttr->first, dc, CustomAttrTypeKind::GlobalActor}, + Type()); if (!globalActorType || globalActorType->hasError()) return ActorIsolation::forUnspecified(); - return ActorIsolation::forGlobalActor(globalActorType); + return ActorIsolation::forGlobalActor( + globalActorType->mapTypeOutOfContext()); } llvm_unreachable("Forgot about an attribute?"); @@ -1135,23 +1156,32 @@ ActorIsolation ActorIsolationRequest::evaluate( } // Disable inference of actor attributes outside of normal Swift source files. - if (auto sourceFile = value->getDeclContext()->getParentSourceFile()) { - switch (sourceFile->Kind) { - case SourceFileKind::Interface: - case SourceFileKind::SIL: - return defaultIsolation; - - case SourceFileKind::Library: - case SourceFileKind::Main: - // Attempt inference below. - break; - } - } else { + if (!shouldInferAttributeInContext(value->getDeclContext())) return defaultIsolation; - } // Function used when returning an inferred isolation. auto inferredIsolation = [&](ActorIsolation inferred) { + // Add an implicit attribute to capture the actor isolation that was + // inferred, so that (e.g.) it will be printed and serialized. + ASTContext &ctx = value->getASTContext(); + switch (inferred) { + case ActorIsolation::Independent: + value->getAttrs().add(new (ctx) ActorIndependentAttr(true)); + break; + + case ActorIsolation::GlobalActor: { + auto typeExpr = TypeExpr::createImplicit(inferred.getGlobalActor(), ctx); + auto attr = CustomAttr::create( + ctx, SourceLoc(), typeExpr, /*implicit=*/true); + value->getAttrs().add(attr); + break; + } + + case ActorIsolation::ActorInstance: + case ActorIsolation::Unspecified: + // Nothing to do. + break; + } return inferred; }; diff --git a/lib/Sema/TypeCheckPropertyWrapper.cpp b/lib/Sema/TypeCheckPropertyWrapper.cpp index 14f18c8a4f412..9529b61d06270 100644 --- a/lib/Sema/TypeCheckPropertyWrapper.cpp +++ b/lib/Sema/TypeCheckPropertyWrapper.cpp @@ -513,7 +513,7 @@ Type AttachedPropertyWrapperTypeRequest::evaluate(Evaluator &evaluator, auto ty = evaluateOrDefault( evaluator, CustomAttrTypeRequest{customAttr, var->getDeclContext(), - CustomAttrTypeKind::PropertyDelegate}, + CustomAttrTypeKind::PropertyWrapper}, Type()); if (!ty || ty->hasError()) { return ErrorType::get(var->getASTContext()); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 2a2040fc26505..4fd9b91dbda8c 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -3974,7 +3974,7 @@ Type CustomAttrTypeRequest::evaluate(Evaluator &eval, CustomAttr *attr, OpenUnboundGenericTypeFn unboundTyOpener = nullptr; // Property delegates allow their type to be an unbound generic. - if (typeKind == CustomAttrTypeKind::PropertyDelegate) { + if (typeKind == CustomAttrTypeKind::PropertyWrapper) { unboundTyOpener = [](auto unboundTy) { // FIXME: Don't let unbound generic types // escape type resolution. For now, just diff --git a/test/ModuleInterface/actor_isolation.swift b/test/ModuleInterface/actor_isolation.swift new file mode 100644 index 0000000000000..dd565f4fc4bfe --- /dev/null +++ b/test/ModuleInterface/actor_isolation.swift @@ -0,0 +1,44 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule -emit-module-interface-path %t/Test.swiftinterface -module-name Test -enable-experimental-concurrency %s +// RUN: %FileCheck %s --check-prefix FROMSOURCE --check-prefix CHECK < %t/Test.swiftinterface +// RUN: %target-swift-frontend -emit-module -o /dev/null -merge-modules %t/Test.swiftmodule -disable-objc-attr-requires-foundation-module -emit-module-interface-path %t/TestFromModule.swiftinterface -module-name Test -enable-experimental-concurrency +// RUN: %FileCheck %s --check-prefix FROMMODULE --check-prefix CHECK < %t/TestFromModule.swiftinterface + +// REQUIRES: concurrency +import _Concurrency + +// CHECK: actor public class SomeActor +public actor class SomeActor { + @actorIndependent func maine() { } +} + +// CHECK: @globalActor public struct SomeGlobalActor +@globalActor +public struct SomeGlobalActor { + public static let shared = SomeActor() +} + +// CHECK: @{{(Test.)?}}SomeGlobalActor public protocol P1 +// CHECK-NEXT: @{{(Test.)?}}SomeGlobalActor func method() +@SomeGlobalActor +public protocol P1 { + func method() +} + +// CHECK: class C1 +// CHECK-NEXT: @{{(Test.)?}}SomeGlobalActor public func method() +public class C1: P1 { + public func method() { } +} + +@SomeGlobalActor +public class C2 { } + +// CHECK: @{{(Test.)?}}SomeGlobalActor public class C2 +public class C3: C2 { } + +// CHECK: actor public class SomeSubActor +// CHECK-NEXT: @actorIndependent public func maine() +public actor class SomeSubActor: SomeActor { + override public func maine() { } +}