From 90d8816dee7c8feacfcbb08080885aaacc307804 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 25 Aug 2021 21:22:29 +0900 Subject: [PATCH 1/6] [Distributed] Move property synthesis to DerivedConformanceDistributedActor --- lib/Sema/CodeSynthesisDistributedActor.cpp | 91 +----------------- .../DerivedConformanceDistributedActor.cpp | 95 +++++++++++++++++++ lib/Sema/DerivedConformances.cpp | 8 ++ lib/Sema/TypeCheckDeclPrimary.cpp | 5 + lib/Sema/TypeCheckDistributed.cpp | 8 +- lib/Sema/TypeCheckProtocol.cpp | 1 + .../Distributed/distributed_actor_basic.swift | 32 +++++++ ...distributed_actor_default_deinit_sil.swift | 2 +- 8 files changed, 147 insertions(+), 95 deletions(-) diff --git a/lib/Sema/CodeSynthesisDistributedActor.cpp b/lib/Sema/CodeSynthesisDistributedActor.cpp index 1a8bf1c86fff4..ad5dccdbe221c 100644 --- a/lib/Sema/CodeSynthesisDistributedActor.cpp +++ b/lib/Sema/CodeSynthesisDistributedActor.cpp @@ -93,95 +93,6 @@ static void addFactoryResolveFunction(ClassDecl *decl) { decl->addMember(factoryDecl); } -/******************************************************************************/ -/******************************** PROPERTIES **********************************/ -/******************************************************************************/ - -// TODO: deduplicate with 'declareDerivedProperty' from DerivedConformance... -std::pair -createStoredProperty(ClassDecl *classDecl, ASTContext &ctx, - VarDecl::Introducer introducer, Identifier name, - Type propertyInterfaceType, Type propertyContextType, - bool isStatic, bool isFinal) { - auto parentDC = classDecl; - - VarDecl *propDecl = new (ctx) - VarDecl(/*IsStatic*/ isStatic, introducer, - SourceLoc(), name, parentDC); - propDecl->setImplicit(); - propDecl->setSynthesized(); - propDecl->copyFormalAccessFrom(classDecl, /*sourceIsParentContext*/ true); - propDecl->setInterfaceType(propertyInterfaceType); - - Pattern *propPat = NamedPattern::createImplicit(ctx, propDecl); - propPat->setType(propertyContextType); - - propPat = TypedPattern::createImplicit(ctx, propPat, propertyContextType); - propPat->setType(propertyContextType); - - auto *pbDecl = PatternBindingDecl::createImplicit( - ctx, StaticSpellingKind::None, propPat, /*InitExpr*/ nullptr, - parentDC); - return {propDecl, pbDecl}; -} - -/// Adds the following, fairly special, properties to each distributed actor: -/// - actorTransport -/// - id -// TODO(distributed): move this synthesis to DerivedConformance style -static void addImplicitDistributedActorStoredProperties(ClassDecl *decl) { - assert(decl->isDistributedActor()); - - auto &C = decl->getASTContext(); - - // ``` - // @_distributedActorIndependent - // let id: AnyActorIdentity - // ``` - { - auto propertyType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType(); - - VarDecl *propDecl; - PatternBindingDecl *pbDecl; - std::tie(propDecl, pbDecl) = createStoredProperty( - decl, C, - VarDecl::Introducer::Let, C.Id_id, - propertyType, propertyType, - /*isStatic=*/false, /*isFinal=*/true); - - // mark as @_distributedActorIndependent, allowing access to it from everywhere - propDecl->getAttrs().add( - new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true)); - - decl->addMember(propDecl); - decl->addMember(pbDecl); - } - - // ``` - // @_distributedActorIndependent - // let actorTransport: ActorTransport - // ``` - // (no need for @actorIndependent because it is an immutable let) - { - auto propertyType = C.getActorTransportDecl()->getDeclaredInterfaceType(); - - VarDecl *propDecl; - PatternBindingDecl *pbDecl; - std::tie(propDecl, pbDecl) = createStoredProperty( - decl, C, - VarDecl::Introducer::Let, C.Id_actorTransport, - propertyType, propertyType, - /*isStatic=*/false, /*isFinal=*/true); - - // mark as @_distributedActorIndependent, allowing access to it from everywhere - propDecl->getAttrs().add( - new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true)); - - decl->addMember(propDecl); - decl->addMember(pbDecl); - } -} - /******************************************************************************/ /*************************** _REMOTE_ FUNCTIONS *******************************/ /******************************************************************************/ @@ -355,6 +266,6 @@ void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) { return; addFactoryResolveFunction(decl); - addImplicitDistributedActorStoredProperties(decl); +// addImplicitDistributedActorStoredProperties(decl); addImplicitRemoteActorFunctions(decl); } diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index 322e9f7dc392e..3ab15a040c79a 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -30,6 +30,101 @@ bool DerivedConformance::canDeriveDistributedActor( } // ==== ------------------------------------------------------------------------ +// TODO: deduplicate with 'declareDerivedProperty' from DerivedConformance... +std::pair +createStoredProperty(ClassDecl *classDecl, ASTContext &ctx, + VarDecl::Introducer introducer, Identifier name, + Type propertyInterfaceType, Type propertyContextType, + bool isStatic, bool isFinal) { + auto parentDC = classDecl; + + VarDecl *propDecl = new (ctx) + VarDecl(/*IsStatic*/ isStatic, introducer, + SourceLoc(), name, parentDC); + propDecl->setImplicit(); + propDecl->setSynthesized(); + propDecl->copyFormalAccessFrom(classDecl, /*sourceIsParentContext*/ true); + propDecl->setInterfaceType(propertyInterfaceType); + + Pattern *propPat = NamedPattern::createImplicit(ctx, propDecl); + propPat->setType(propertyContextType); + + propPat = TypedPattern::createImplicit(ctx, propPat, propertyContextType); + propPat->setType(propertyContextType); + + auto *pbDecl = PatternBindingDecl::createImplicit( + ctx, StaticSpellingKind::None, propPat, /*InitExpr*/ nullptr, + parentDC); + return {propDecl, pbDecl}; +} + +static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { + assert(derived.Nominal->isDistributedActor()); + auto decl = dyn_cast(derived.Nominal); + auto &C = derived.Context; + + // ``` + // @_distributedActorIndependent + // let id: AnyActorIdentity + // ``` + auto propertyType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType(); + + VarDecl *propDecl; + PatternBindingDecl *pbDecl; + std::tie(propDecl, pbDecl) = createStoredProperty( + decl, C, + VarDecl::Introducer::Let, C.Id_id, + propertyType, propertyType, + /*isStatic=*/false, /*isFinal=*/true); + + // mark as @_distributedActorIndependent, allowing access to it from everywhere + propDecl->getAttrs().add( + new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true)); + + derived.addMembersToConformanceContext({ propDecl, pbDecl }); + return propDecl; +} + +static ValueDecl *deriveDistributedActor_actorTransport( + DerivedConformance &derived) { + assert(derived.Nominal->isDistributedActor()); + auto decl = dyn_cast(derived.Nominal); + auto &C = derived.Context; + + // ``` + // @_distributedActorIndependent + // let actorTransport: ActorTransport + // ``` + // (no need for @actorIndependent because it is an immutable let) + auto propertyType = C.getActorTransportDecl()->getDeclaredInterfaceType(); + + VarDecl *propDecl; + PatternBindingDecl *pbDecl; + std::tie(propDecl, pbDecl) = createStoredProperty( + decl, C, + VarDecl::Introducer::Let, C.Id_actorTransport, + propertyType, propertyType, + /*isStatic=*/false, /*isFinal=*/true); + + // mark as @_distributedActorIndependent, allowing access to it from everywhere + propDecl->getAttrs().add( + new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true)); + + derived.addMembersToConformanceContext({ propDecl, pbDecl }); + return propDecl; +} + + +// ==== ------------------------------------------------------------------------ + ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { + if (auto var = dyn_cast(requirement)) { + if (var->getName() == Context.Id_id) + return deriveDistributedActor_id(*this); + + if (var->getName() == Context.Id_actorTransport) + return deriveDistributedActor_actorTransport(*this); + } + return nullptr; } diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index e29faecdee540..996a839d973a1 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -312,6 +312,14 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, if (name.isSimpleName(ctx.Id_unownedExecutor)) return getRequirement(KnownProtocolKind::Actor); + // DistributedActor.id + if(name.isSimpleName(ctx.Id_id)) + return getRequirement(KnownProtocolKind::DistributedActor); + + // DistributedActor.actorTransport + if(name.isSimpleName(ctx.Id_actorTransport)) + return getRequirement(KnownProtocolKind::DistributedActor); + return nullptr; } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 35b646516e46b..1f4c1b4eba1b4 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2930,6 +2930,11 @@ class DeclChecker : public DeclVisitor { TypeChecker::checkDeclAttributes(ED); + if (nominal->isDistributedActor()) { + auto decl = dyn_cast(nominal); + TypeChecker::checkDistributedActor(decl); + } + for (Decl *Member : ED->getMembers()) visit(Member); diff --git a/lib/Sema/TypeCheckDistributed.cpp b/lib/Sema/TypeCheckDistributed.cpp index 3fecfa10ee2f4..4fdaec54cd4e1 100644 --- a/lib/Sema/TypeCheckDistributed.cpp +++ b/lib/Sema/TypeCheckDistributed.cpp @@ -154,9 +154,11 @@ void swift::checkDistributedActorProperties(const ClassDecl *decl) { for (auto member : decl->getMembers()) { if (auto prop = dyn_cast(member)) { + if (prop->isSynthesized()) + continue; + auto id = prop->getName(); - if (id == C.Id_actorTransport || - id == C.Id_id) { + if (id == C.Id_actorTransport || id == C.Id_id) { prop->diagnose(diag::distributed_actor_user_defined_special_property, id); } @@ -235,7 +237,5 @@ void TypeChecker::checkDistributedActor(ClassDecl *decl) { // --- Synthesize properties // TODO: those could technically move to DerivedConformance style swift::addImplicitDistributedActorMembersToClass(decl); - - // ==== Functions } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 67c8b7181255d..c1f5edc63491f 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -6412,6 +6412,7 @@ ValueDecl *TypeChecker::deriveProtocolRequirement(DeclContext *DC, return derived.deriveDifferentiable(Requirement); case KnownDerivableProtocolKind::DistributedActor: + fprintf(stderr, "[%s:%d] (%s) DERIVE DistributedActor \n", __FILE__, __LINE__, __FUNCTION__); return derived.deriveDistributedActor(Requirement); case KnownDerivableProtocolKind::OptionSet: diff --git a/test/Distributed/distributed_actor_basic.swift b/test/Distributed/distributed_actor_basic.swift index 309f08e3b9ee3..772a1a8d3cb1e 100644 --- a/test/Distributed/distributed_actor_basic.swift +++ b/test/Distributed/distributed_actor_basic.swift @@ -6,4 +6,36 @@ import _Distributed @available(SwiftStdlib 5.5, *) distributed actor DA { +} + +@available(SwiftStdlib 5.5, *) +distributed actor First { + distributed func one(second: Second) async throws { + try await second.two(first: self, second: second) + } +} + +@available(SwiftStdlib 5.5, *) +distributed actor Second { + distributed func two(first: First, second: Second) async { + try! await first.one(second: self) + } +} + +// ==== ------------------------------------------------------------------------ + +@available(SwiftStdlib 5.5, *) +extension First { + @_dynamicReplacement (for :_remote_one(second:)) + nonisolated func _impl_one(second: Second) async throws { + fatalError() + } +} + +@available(SwiftStdlib 5.5, *) +extension Second { + @_dynamicReplacement (for :_remote_two(first:second:)) + nonisolated func _impl_two(first: First, second: Second) async throws { + fatalError() + } } \ No newline at end of file diff --git a/test/SIL/Distributed/distributed_actor_default_deinit_sil.swift b/test/SIL/Distributed/distributed_actor_default_deinit_sil.swift index 69b84c8ef69fa..0c41e263c5ad5 100644 --- a/test/SIL/Distributed/distributed_actor_default_deinit_sil.swift +++ b/test/SIL/Distributed/distributed_actor_default_deinit_sil.swift @@ -36,8 +36,8 @@ distributed actor SimpleEmptyDistributedActor { // Finish up the destroying... // CHECK: bb3: -// CHECK: destroy_addr [[ID_ADDR]] : $*AnyActorIdentity // CHECK: destroy_addr [[TRANSPORT_ADDR]] : $*ActorTransport +// CHECK: destroy_addr [[ID_ADDR]] : $*AnyActorIdentity // CHECK: [[_:%[0-9]+]] = builtin "destroyDefaultActor"(%0 : $SimpleEmptyDistributedActor) : $() // CHECK: [[SELF:%[0-9]+]] = unchecked_ref_cast %0 : $SimpleEmptyDistributedActor to $Builtin.NativeObject // CHECK: return [[SELF]] : $Builtin.NativeObject From e408fa9722d0a330ea877b68dfb41e90cb6678d1 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 26 Aug 2021 00:32:47 +0900 Subject: [PATCH 2/6] [Distributed] unlock distributed_actor_deinit test again --- lib/Sema/CodeSynthesisDistributedActor.cpp | 1 - lib/Sema/TypeCheckProtocol.cpp | 1 - .../Runtime/distributed_actor_deinit.swift | 24 +++- .../distributed_actor_default_init_sil.swift | 49 +++++---- .../distributed_actor_remote_deinit_sil.swift | 104 +++++++----------- ...buted_actor_remote_deinit_sil_normal.swift | 31 ++++++ ...ibuted_actor_user_transport_init_sil.swift | 98 ++++++++++------- 7 files changed, 170 insertions(+), 138 deletions(-) create mode 100644 test/SIL/Distributed/distributed_actor_remote_deinit_sil_normal.swift diff --git a/lib/Sema/CodeSynthesisDistributedActor.cpp b/lib/Sema/CodeSynthesisDistributedActor.cpp index ad5dccdbe221c..d813ab24d68ca 100644 --- a/lib/Sema/CodeSynthesisDistributedActor.cpp +++ b/lib/Sema/CodeSynthesisDistributedActor.cpp @@ -266,6 +266,5 @@ void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) { return; addFactoryResolveFunction(decl); -// addImplicitDistributedActorStoredProperties(decl); addImplicitRemoteActorFunctions(decl); } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index c1f5edc63491f..67c8b7181255d 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -6412,7 +6412,6 @@ ValueDecl *TypeChecker::deriveProtocolRequirement(DeclContext *DC, return derived.deriveDifferentiable(Requirement); case KnownDerivableProtocolKind::DistributedActor: - fprintf(stderr, "[%s:%d] (%s) DERIVE DistributedActor \n", __FILE__, __LINE__, __FUNCTION__); return derived.deriveDistributedActor(Requirement); case KnownDerivableProtocolKind::OptionSet: diff --git a/test/Distributed/Runtime/distributed_actor_deinit.swift b/test/Distributed/Runtime/distributed_actor_deinit.swift index 07a4830fb50f2..14f3b9d373f20 100644 --- a/test/Distributed/Runtime/distributed_actor_deinit.swift +++ b/test/Distributed/Runtime/distributed_actor_deinit.swift @@ -7,24 +7,33 @@ // UNSUPPORTED: use_os_stdlib // UNSUPPORTED: back_deployment_runtime -// REQUIRES: rdar78290608 - import _Distributed @available(SwiftStdlib 5.5, *) -actor A {} + actor A {} @available(SwiftStdlib 5.5, *) distributed actor DA { + init(transport: ActorTransport) { + defer { transport.actorReady(self) } + } } @available(SwiftStdlib 5.5, *) distributed actor DA_userDefined { + init(transport: ActorTransport) { + defer { transport.actorReady(self) } + } + deinit {} } @available(SwiftStdlib 5.5, *) distributed actor DA_userDefined2 { + init(transport: ActorTransport) { + defer { transport.actorReady(self) } + } + deinit { print("Deinitializing \(self.id)") return @@ -36,6 +45,10 @@ distributed actor DA_state { var name = "Hello" var age = 42 + init(transport: ActorTransport) { + defer { transport.actorReady(self) } + } + deinit { print("Deinitializing \(self.id)") return @@ -59,7 +72,7 @@ struct FakeTransport: ActorTransport { fatalError("not implemented \(#function)") } - func resolve(_ identity: Act.ID, as actorType: Act.Type) throws -> Act? + func resolve(_ identity: AnyActorIdentity, as actorType: Act.Type) throws -> Act? where Act: DistributedActor { print("resolve type:\(actorType), address:\(identity)") return nil @@ -121,9 +134,10 @@ func test() { // a remote actor should not resign it's address, it was never "assigned" it print("before") - _ = try! DA_userDefined2(resolve: .init(address), using: transport) + _ = try! DA_userDefined2.resolve(.init(address), using: transport) print("done") // CHECK: before + // CHECK-NEXT: resolve type:DA_userDefined2, address:AnyActorIdentity(ActorAddress(address: "xxx")) // CHECK-NEXT: Deinitializing // CHECK-NEXT: done } diff --git a/test/SIL/Distributed/distributed_actor_default_init_sil.swift b/test/SIL/Distributed/distributed_actor_default_init_sil.swift index 4a4471195d2cc..76e4fb90654b6 100644 --- a/test/SIL/Distributed/distributed_actor_default_init_sil.swift +++ b/test/SIL/Distributed/distributed_actor_default_init_sil.swift @@ -6,28 +6,31 @@ import _Distributed distributed actor SimpleEmptyDistributedActor { } -// Check the default (synthesized) constructor: // CHECK: // SimpleEmptyDistributedActor.init(transport:) -// sil hidden [available 12.0] @$s34distributed_actor_default_init_sil27SimpleEmptyDistributedActorC9transportAC01_H00I9Transport_p_tcfc : $@convention(method) (@in ActorTransport, @owned SimpleEmptyDistributedActor) -> @owned SimpleEmptyDistributedActor { -// CHECK: [[TRANSPORT:%[0-9]+]] "transport" -// CHECK: [[SELF:%[0-9]+]] "self" -// CHECK: bb0([[TRANSPORT]] : $*ActorTransport, [[SELF]] : $SimpleEmptyDistributedActor): -// debug_value_addr [[TRANSPORT]] : $*ActorTransport, let, name "transport", argno 1 -// debug_value [[SELF]] : $SimpleEmptyDistributedActor, let, name "self", argno 2 -// CHECK: [[DEFAULT_ACTOR_INIT:%[0-9]+]] = builtin "initializeDefaultActor"([[SELF]] : $SimpleEmptyDistributedActor) : $() -// CHECK: [[OPEN_TRANSPORT_EXISTENTIAL:%[0-9]+]] = open_existential_addr immutable_access [[TRANSPORT]] : $*ActorTransport to $*@opened({{.*}}) ActorTransport -// CHECK: [[SELF_METATYPE:%[0-9]+]] = metatype $@thick SimpleEmptyDistributedActor.Type -// CHECK: [[ASSIGN_WITNESS_METHOD:%[0-9]+]] = witness_method $@opened({{.*}}) ActorTransport, #ActorTransport.assignIdentity : (Self) -> (Act.Type) -> AnyActorIdentity, [[OPEN_TRANSPORT_EXISTENTIAL]] : $*@opened({{.*}}) ActorTransport : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity -// CHECK: [[IDENTITY_STACK_TMP:%[0-9]+]] = alloc_stack $AnyActorIdentity -// CHECK: [[IDENTITY_RETURNED:%[0-9]+]] = apply [[ASSIGN_WITNESS_METHOD]]<@opened({{.*}}) ActorTransport, SimpleEmptyDistributedActor>([[IDENTITY_STACK_TMP]], [[SELF_METATYPE]], [[OPEN_TRANSPORT_EXISTENTIAL]]) : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity -// CHECK: [[IDENTITY_PROPERTY:%[0-9]+]] = ref_element_addr [[SELF]] : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.id -// Store the identity -// CHECK: copy_addr [take] [[IDENTITY_STACK_TMP]] to [initialization] [[IDENTITY_PROPERTY]] : $*AnyActorIdentity -// CHECK: [[TRANSPORT_PROPERTY:%[0-9]+]] = ref_element_addr [[SELF]] : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.actorTransport +// CHECK: sil hidden{{.*}} @$s34distributed_actor_default_init_sil27SimpleEmptyDistributedActorC9transportAC01_H00I9Transport_p_tcfc : $@convention(method) (@in ActorTransport, @owned SimpleEmptyDistributedActor) -> @owned SimpleEmptyDistributedActor { +// CHECK: // %0 "transport" // users: %15, %7, %6, %2 +// CHECK: // %1 "self" // users: %5, %12, %4, %16, %3 +// CHECK: bb0(%0 : $*ActorTransport, %1 : $SimpleEmptyDistributedActor): +// CHECK: debug_value_addr %0 : $*ActorTransport, let, name "transport", argno 1, implicit // id: %2 +// CHECK: debug_value %1 : $SimpleEmptyDistributedActor, let, name "self", argno 2, implicit // id: %3 +// CHECK: %4 = builtin "initializeDefaultActor"(%1 : $SimpleEmptyDistributedActor) : $() + // Store the transport -// CHECK: copy_addr [[TRANSPORT]] to [initialization] [[TRANSPORT_PROPERTY]] : $*ActorTransport -// CHECK: dealloc_stack [[IDENTITY_STACK_TMP]] : $*AnyActorIdentity -// CHECK: destroy_addr [[TRANSPORT]] : $*ActorTransport -// // While in AST the return was "return null" after SILGen we properly return the self -// CHECK: return [[SELF]] : $SimpleEmptyDistributedActor -// } // end sil function '$s34distributed_actor_default_init_sil27SimpleEmptyDistributedActorC9transportAC01_H00I9Transport_p_tcfc' +// CHECK: %5 = ref_element_addr %1 : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.actorTransport // user: %6 +// CHECK: copy_addr %0 to [initialization] %5 : $*ActorTransport // id: %6 + +// Assign an identity +// CHECK: %7 = open_existential_addr immutable_access %0 : $*ActorTransport to $*@opened("{{.*}}") ActorTransport // users: %11, %11, %9 +// CHECK: %8 = metatype $@thick SimpleEmptyDistributedActor.Type // user: %11 +// CHECK: %9 = witness_method $@opened("{{.*}}") ActorTransport, #ActorTransport.assignIdentity : (Self) -> (Act.Type) -> AnyActorIdentity, %7 : $*@opened("{{.*}}") ActorTransport : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity // type-defs: %7; user: %11 +// CHECK: %10 = alloc_stack $AnyActorIdentity // users: %14, %13, %11 +// CHECK: %11 = apply %9<@opened("{{.*}}") ActorTransport, SimpleEmptyDistributedActor>(%10, %8, %7) : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity // type-defs: %7 + +// Store the identity +// CHECK: %12 = ref_element_addr %1 : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.id // user: %13 +// CHECK: copy_addr [take] %10 to [initialization] %12 : $*AnyActorIdentity // id: %13 + +// CHECK: dealloc_stack %10 : $*AnyActorIdentity // id: %14 +// CHECK: destroy_addr %0 : $*ActorTransport // id: %15 +// CHECK: return %1 : $SimpleEmptyDistributedActor // id: %16 +// CHECK: } // end sil function '$s34distributed_actor_default_init_sil27SimpleEmptyDistributedActorC9transportAC01_H00I9Transport_p_tcfc' diff --git a/test/SIL/Distributed/distributed_actor_remote_deinit_sil.swift b/test/SIL/Distributed/distributed_actor_remote_deinit_sil.swift index c4edb534aa585..ef46461dedd1a 100644 --- a/test/SIL/Distributed/distributed_actor_remote_deinit_sil.swift +++ b/test/SIL/Distributed/distributed_actor_remote_deinit_sil.swift @@ -4,15 +4,6 @@ import _Distributed class SomeClass {} -@available(SwiftStdlib 5.5, *) -actor SimpleActor { - let someFieldInLocalActor: SomeClass - init(field: SomeClass) { - self.someFieldInLocalActor = field - } -} - - @available(SwiftStdlib 5.5, *) distributed actor SimpleEmptyDistributedActor { let localOnlyField: SomeClass @@ -25,73 +16,52 @@ distributed actor SimpleEmptyDistributedActor { // ==== ------------------------------------------------------------------------ // ==== Check that a normal local only actor is left unchanged -// CHECK: // SimpleActor.deinit -// CHECK: sil hidden{{.*}} @$s35distributed_actor_remote_deinit_sil11SimpleActorCfd : $@convention(method) (@guaranteed SimpleActor) -> @owned Builtin.NativeObject { -// CHECK: // %0 "self" // users: %6, %5, %2, %1 -// CHECK: bb0(%0 : $SimpleActor): -// CHECK: debug_value %0 : $SimpleActor, let, name "self", argno 1, implicit // id: %1 -// CHECK: %2 = ref_element_addr %0 : $SimpleActor, #SimpleActor.someFieldInLocalActor // user: %3 -// CHECK: %3 = load %2 : $*SomeClass // user: %4 -// CHECK: strong_release %3 : $SomeClass // id: %4 -// CHECK: %5 = builtin "destroyDefaultActor"(%0 : $SimpleActor) : $() -// CHECK: %6 = unchecked_ref_cast %0 : $SimpleActor to $Builtin.NativeObject // user: %7 -// CHECK: return %6 : $Builtin.NativeObject // id: %7 -// CHECK: } // end sil function '$s35distributed_actor_remote_deinit_sil11SimpleActorCfd' - - - - // ==== deinit must have the extra "if remote..." path emitted for the // distributed actor only. That path will not attempt deallocating the // `localOnly...` fields, since they were never initialized and have no storage. // CHECK: // SimpleEmptyDistributedActor.deinit -// sil hidden [available 12.0] @$s35distributed_actor_remote_deinit_sil27SimpleEmptyDistributedActorCfd : $@convention(method) (@guaranteed SimpleEmptyDistributedActor) -> @owned Builtin.NativeObject { +// CHECK: sil hidden{{.*}} @$s35distributed_actor_remote_deinit_sil27SimpleEmptyDistributedActorCfd : $@convention(method) (@guaranteed SimpleEmptyDistributedActor) -> @owned Builtin.NativeObject { // CHECK: // [[SELF:%[0-9]+]] "self" // CHECK: bb0(%0 : $SimpleEmptyDistributedActor): -// CHECK: debug_value [[SELF]] : $SimpleEmptyDistributedActor, let, name "self", argno 1, implicit -// CHECK: [[IDENTITY_ADDR:%[0-9]+]] = ref_element_addr %0 : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.id // users: %13, %24 -// CHECK: [[TRANSPORT_ADDR:%[0-9]+]] = ref_element_addr %0 : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.actorTransport +// CHECK-NEXT: debug_value [[SELF]] : $SimpleEmptyDistributedActor, let, name "self", argno 1, implicit +// CHECK-NEXT: [[IDENTITY_ADDR:%[0-9]+]] = ref_element_addr %0 : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.id +// CHECK-NEXT: [[TRANSPORT_ADDR:%[0-9]+]] = ref_element_addr %0 : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.actorTransport // CHECK: [[SELF_1:%[0-9]+]] = init_existential_ref %0 : $SimpleEmptyDistributedActor : $SimpleEmptyDistributedActor, $AnyObject // CHECK: // function_ref swift_distributed_actor_is_remote // CHECK: [[IS_REMOTE_FN_1:%[0-9]+]] = function_ref @swift_distributed_actor_is_remote : $@convention(thin) (@guaranteed AnyObject) -> Bool // CHECK: [[IS_REMOTE_FN_RES_1:%[0-9]+]] = apply [[IS_REMOTE_FN_1]]([[SELF_1]]) : $@convention(thin) (@guaranteed AnyObject) -> Bool // CHECK: [[IS_REMOTE_BOOL_1:%[0-9]+]] = struct_extract [[IS_REMOTE_FN_RES_1]] : $Bool, #Bool._value -// CHECK: cond_br [[IS_REMOTE_BOOL_1]], [[BB_CONT_1:bb[0-9]+]], [[BB_RESIGN_DIST_IDENTITY:bb[0-9]+]] - -// CHECK: [[BB_CONT_1]]: -// CHECK: br [[BB_CHECK_REMOTE_OR_LOCAL_MEMBER_DEINIT_TYPE:bb[0-9]+]] - -// It was a local actor, so we resign the address: -// CHECK: [[BB_RESIGN_DIST_IDENTITY]]: -// %11 = open_existential_addr immutable_access %4 : $*ActorTransport to $*@opened({{.*}}) ActorTransport // users: %13, %13, %12 -// CHECK: [[RESIGN_FN:%[0-9]+]] = witness_method $@opened({{.*}}) ActorTransport, #ActorTransport.resignIdentity -// CHECK: [[RESIGNED:%[0-9]+]] = apply [[RESIGN_FN]]<@opened({{.*}}) ActorTransport>(%3, %11) : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport> (@in_guaranteed AnyActorIdentity, @in_guaranteed τ_0_0) -> () -// CHECK: br [[BB_CHECK_REMOTE_OR_LOCAL_MEMBER_DEINIT_TYPE]] - -// Check if we must skip destroying local storage because actor was remote -// CHECK: [[BB_CHECK_REMOTE_OR_LOCAL_MEMBER_DEINIT_TYPE]]: -// CHECK: %15 = init_existential_ref %0 : $SimpleEmptyDistributedActor : $SimpleEmptyDistributedActor, $AnyObject -// CHECK: %16 = apply %6(%15) : $@convention(thin) (@guaranteed AnyObject) -> Bool -// CHECK: %17 = struct_extract %16 : $Bool, #Bool._value // user: %18 -// CHECK: cond_br %17, [[BB_CONT_REMOTE_DONT_DESTROY_LOCAL_MEMBERS:bb[0-9]+]], [[BB_CONT_DESTROY_LOCAL_THEN_INDEPENDENT_MEMBERS:bb[0-9]+]] - -// CHECK: [[BB_CONT_REMOTE_DONT_DESTROY_LOCAL_MEMBERS]]: -// CHECK: br [[BB_DESTROY_INDEPENDENT_MEMBERS:bb[0-9]+]] - -// We were a local instance after all, and thus must destroy local properties -// CHECK: [[BB_CONT_DESTROY_LOCAL_THEN_INDEPENDENT_MEMBERS]]: -// CHECK: [[FIELD_ADDR:%[0-9]+]] = ref_element_addr %0 : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.localOnlyField -// CHECK: [[LOAD_FIELD_ADDR:%[0-9]+]] = load [[FIELD_ADDR]] : $*SomeClass -// CHECK: strong_release [[LOAD_FIELD_ADDR]] : $SomeClass -// CHECK: br [[BB_DESTROY_INDEPENDENT_MEMBERS]] - -// Destroy "distributed nonisolated" fields and the actor itself -// CHECK: [[BB_DESTROY_INDEPENDENT_MEMBERS]]: -// CHECK: destroy_addr [[IDENTITY_ADDR]] : $*AnyActorIdentity -// CHECK: destroy_addr [[TRANSPORT_ADDR]] : $*ActorTransport -// CHECK: {{.*}} = builtin "destroyDefaultActor"(%0 : $SimpleEmptyDistributedActor) : $() -// CHECK: dealloc_ref [[SELF]] : $SimpleEmptyDistributedActor -// CHECK: [[EMPTY:%[0-9]+]] = tuple () -// CHECK: return [[EMPTY]] : $() -// } // end sil function '$s35distributed_actor_remote_deinit_sil27SimpleEmptyDistributedActorCfD' \ No newline at end of file +// CHECK: cond_br [[IS_REMOTE_BOOL_1]], bb2, bb1 + +// CHECK: bb1: // Preds: bb0 +// CHECK: %9 = open_existential_addr immutable_access %3 : $*ActorTransport to $*@opened("{{.*}}") ActorTransport // users: %11, %11, %10 +// CHECK: %10 = witness_method $@opened("{{.*}}") ActorTransport, #ActorTransport.resignIdentity : (Self) -> (AnyActorIdentity) -> (), %9 : $*@opened("{{.*}}") ActorTransport : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport> (@in_guaranteed AnyActorIdentity, @in_guaranteed τ_0_0) -> () // type-defs: %9; user: %11 +// CHECK: %11 = apply %10<@opened("{{.*}}") ActorTransport>(%2, %9) : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport> (@in_guaranteed AnyActorIdentity, @in_guaranteed τ_0_0) -> () // type-defs: %9 +// CHECK: br bb3 // id: %12 + +// CHECK: bb2: // Preds: bb0 +// CHECK: br bb3 // id: %13 + +// CHECK: bb3: // Preds: bb1 bb2 +// CHECK: %14 = init_existential_ref %0 : $SimpleEmptyDistributedActor : $SimpleEmptyDistributedActor, $AnyObject // user: %15 +// CHECK: %15 = apply %5(%14) : $@convention(thin) (@guaranteed AnyObject) -> Bool // user: %16 +// CHECK: %16 = struct_extract %15 : $Bool, #Bool._value // user: %17 +// CHECK: cond_br %16, bb4, bb5 // id: %17 + +// CHECK: bb4: // Preds: bb3 +// CHECK: br bb6 // id: %18 + +// CHECK: bb5: // Preds: bb3 +// CHECK: %19 = ref_element_addr %0 : $SimpleEmptyDistributedActor, #SimpleEmptyDistributedActor.localOnlyField // user: %20 +// CHECK: %20 = load %19 : $*SomeClass // user: %21 +// CHECK: strong_release %20 : $SomeClass // id: %21 +// CHECK: br bb6 // id: %22 + +// CHECK: bb6: // Preds: bb5 bb4 +// CHECK: destroy_addr %3 : $*ActorTransport // id: %23 +// CHECK: destroy_addr %2 : $*AnyActorIdentity // id: %24 +// CHECK: %25 = builtin "destroyDefaultActor"(%0 : $SimpleEmptyDistributedActor) : $() +// CHECK: %26 = unchecked_ref_cast %0 : $SimpleEmptyDistributedActor to $Builtin.NativeObject // user: %27 +// CHECK: return %26 : $Builtin.NativeObject // id: %27 +// CHECK: } // end sil function '$s35distributed_actor_remote_deinit_sil27SimpleEmptyDistributedActorCfd' \ No newline at end of file diff --git a/test/SIL/Distributed/distributed_actor_remote_deinit_sil_normal.swift b/test/SIL/Distributed/distributed_actor_remote_deinit_sil_normal.swift new file mode 100644 index 0000000000000..7ace6f2c308eb --- /dev/null +++ b/test/SIL/Distributed/distributed_actor_remote_deinit_sil_normal.swift @@ -0,0 +1,31 @@ +// RUN: %target-swift-frontend -O -primary-file %s -emit-sil -enable-experimental-distributed | %FileCheck %s --dump-input=fail + +import _Distributed + +class SomeClass {} + +@available(SwiftStdlib 5.5, *) +actor SimpleActor { + let someFieldInLocalActor: SomeClass + init(field: SomeClass) { + self.someFieldInLocalActor = field + } +} + + +// ==== ------------------------------------------------------------------------ +// ==== Check that a normal local only actor is left unchanged + +// CHECK: // SimpleActor.deinit +// CHECK: sil hidden{{.*}} @$s42distributed_actor_remote_deinit_sil_normal11SimpleActorCfd : $@convention(method) (@guaranteed SimpleActor) -> @owned Builtin.NativeObject { +// CHECK: // %0 "self" // users: %6, %5, %2, %1 +// CHECK: bb0(%0 : $SimpleActor): +// CHECK: debug_value %0 : $SimpleActor, let, name "self", argno 1, implicit +// CHECK: %2 = ref_element_addr %0 : $SimpleActor, #SimpleActor.someFieldInLocalActor +// CHECK: %3 = load %2 : $*SomeClass // user: %4 +// CHECK: strong_release %3 : $SomeClass // id: %4 +// CHECK: %5 = builtin "destroyDefaultActor"(%0 : $SimpleActor) : $() +// CHECK: %6 = unchecked_ref_cast %0 : $SimpleActor to $Builtin.NativeObject // user: %7 +// CHECK: return %6 : $Builtin.NativeObject // id: %7 +// CHECK: } // end sil function '$s42distributed_actor_remote_deinit_sil_normal11SimpleActorCfd' + diff --git a/test/SIL/Distributed/distributed_actor_user_transport_init_sil.swift b/test/SIL/Distributed/distributed_actor_user_transport_init_sil.swift index eb5f5045e81d3..97144f4535930 100644 --- a/test/SIL/Distributed/distributed_actor_user_transport_init_sil.swift +++ b/test/SIL/Distributed/distributed_actor_user_transport_init_sil.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -O -primary-file %s -emit-sil -enable-experimental-distributed | %FileCheck %s +// RUN: %target-swift-frontend -O -primary-file %s -emit-sil -enable-experimental-distributed | %FileCheck %s --dump-input=fail import _Distributed @@ -9,49 +9,65 @@ distributed actor SimpleUserDefinedInitDistributedActor { } // CHECK: // SimpleUserDefinedInitDistributedActor.init(kappa:other:) -// CHECK: [[TRANSPORT:%[0-9]+]] "transport" -// CHECK: [[OTHER:%[0-9]+]] "other" -// CHECK: [[SELF:%[0-9]+]] "self" -// CHECK: bb0([[TRANSPORT]] : $*ActorTransport, [[OTHER]] : $Int, [[SELF]] : $SimpleUserDefinedInitDistributedActor): -// CHECK: [[DEFAULT_ACTOR_INIT:%[0-9]+]] = builtin "initializeDefaultActor"([[SELF]] : $SimpleUserDefinedInitDistributedActor) : $() -// CHECK: [[OPEN_TRANSPORT_EXISTENTIAL:%[0-9]+]] = open_existential_addr immutable_access [[TRANSPORT]] : $*ActorTransport to $*@opened({{.*}}) ActorTransport -// CHECK: [[SELF_METATYPE:%[0-9]+]] = metatype $@thick SimpleUserDefinedInitDistributedActor.Type -// CHECK: [[ASSIGN_WITNESS_METHOD:%[0-9]+]] = witness_method $@opened({{.*}}) ActorTransport, #ActorTransport.assignIdentity -// CHECK: [[IDENTITY_STACK_TMP:%[0-9]+]] = alloc_stack $AnyActorIdentity -// CHECK: [[IDENTITY_RETURNED:%[0-9]+]] = apply [[ASSIGN_WITNESS_METHOD]]<@opened({{.*}}) ActorTransport, SimpleUserDefinedInitDistributedActor>([[IDENTITY_STACK_TMP]], [[SELF_METATYPE]], [[OPEN_TRANSPORT_EXISTENTIAL]]) : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity -// CHECK: [[IDENTITY_PROPERTY:%[0-9]+]] = ref_element_addr [[SELF]] : $SimpleUserDefinedInitDistributedActor, #SimpleUserDefinedInitDistributedActor.id -// Store the identity -// CHECK: copy_addr [take] [[IDENTITY_STACK_TMP]] to [initialization] [[IDENTITY_PROPERTY]] : $*AnyActorIdentity -// CHECK: [[TRANSPORT_PROPERTY:%[0-9]+]] = ref_element_addr [[SELF]] : $SimpleUserDefinedInitDistributedActor, #SimpleUserDefinedInitDistributedActor.actorTransport +// CHECK: sil hidden{{.*}} @$s41distributed_actor_user_transport_init_sil37SimpleUserDefinedInitDistributedActorC5kappa5otherAC01_K00L9Transport_p_Sitcfc : $@convention(method) (@in ActorTransport, Int, @owned SimpleUserDefinedInitDistributedActor) -> @owned SimpleUserDefinedInitDistributedActor { +// CHECK: // %0 "transport" // users: %17, %9, %8, %3 +// CHECK: // %1 "other" // user: %4 +// CHECK: // %2 "self" // users: %7, %14, %6, %18, %5 +// CHECK: bb0(%0 : $*ActorTransport, %1 : $Int, %2 : $SimpleUserDefinedInitDistributedActor): +// CHECK: debug_value_addr %0 : $*ActorTransport, let, name "transport", argno 1 // id: %3 +// CHECK: debug_value %1 : $Int, let, name "other", argno 2 // id: %4 +// CHECK: debug_value %2 : $SimpleUserDefinedInitDistributedActor, let, name "self", argno 3, implicit // id: %5 +// CHECK: %6 = builtin "initializeDefaultActor"(%2 : $SimpleUserDefinedInitDistributedActor) : $() + // Store the transport -// CHECK: copy_addr [[TRANSPORT]] to [initialization] [[TRANSPORT_PROPERTY]] : $*ActorTransport -// CHECK: dealloc_stack [[IDENTITY_STACK_TMP]] : $*AnyActorIdentity -// CHECK: destroy_addr [[TRANSPORT]] : $*ActorTransport -// // While in AST the return was "return null" after SILGen we properly return the self -// CHECK: return [[SELF]] : $SimpleUserDefinedInitDistributedActor -// CHECK: } +// CHECK: %7 = ref_element_addr %2 : $SimpleUserDefinedInitDistributedActor, #SimpleUserDefinedInitDistributedActor.actorTransport // user: %8 +// CHECK: copy_addr %0 to [initialization] %7 : $*ActorTransport // id: %8 + +// Assign the identity +// CHECK: %9 = open_existential_addr immutable_access %0 : $*ActorTransport to $*@opened("{{.*}}") ActorTransport // users: %13, %13, %11 +// CHECK: %10 = metatype $@thick SimpleUserDefinedInitDistributedActor.Type // user: %13 +// CHECK: %11 = witness_method $@opened("{{.*}}") ActorTransport, #ActorTransport.assignIdentity : (Self) -> (Act.Type) -> AnyActorIdentity, %9 : $*@opened("{{.*}}") ActorTransport : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity // type-defs: %9; user: %13 +// CHECK: %12 = alloc_stack $AnyActorIdentity // users: %16, %15, %13 +// CHECK: %13 = apply %11<@opened("{{.*}}") ActorTransport, SimpleUserDefinedInitDistributedActor>(%12, %10, %9) : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity // type-defs: %9 + +// Store the identity +// CHECK: %14 = ref_element_addr %2 : $SimpleUserDefinedInitDistributedActor, #SimpleUserDefinedInitDistributedActor.id // user: %15 +// CHECK: copy_addr [take] %12 to [initialization] %14 : $*AnyActorIdentity // id: %15 +// CHECK: dealloc_stack %12 : $*AnyActorIdentity // id: %16 +// CHECK: destroy_addr %0 : $*ActorTransport // id: %17 +// CHECK: return %2 : $SimpleUserDefinedInitDistributedActor // id: %18 +// CHECK: } // end sil function '$s41distributed_actor_user_transport_init_sil37SimpleUserDefinedInitDistributedActorC5kappa5otherAC01_K00L9Transport_p_Sitcfc' + // Even if the transport is in another position, we still locate it by the type // CHECK: // SimpleUserDefinedInitDistributedActor.init(other:theTransport:) -// CHECK: [[OTHER:%[0-9]+]] "other" -// CHECK: [[TRANSPORT:%[0-9]+]] "theTransport" -// CHECK: [[SELF:%[0-9]+]] "self" -// CHECK: bb0([[OTHER]] : $Int, [[TRANSPORT]] : $*ActorTransport, [[SELF]] : $SimpleUserDefinedInitDistributedActor): -// CHECK: [[DEFAULT_ACTOR_INIT:%[0-9]+]] = builtin "initializeDefaultActor"([[SELF]] : $SimpleUserDefinedInitDistributedActor) : $() -// CHECK: [[OPEN_TRANSPORT_EXISTENTIAL:%[0-9]+]] = open_existential_addr immutable_access [[TRANSPORT]] : $*ActorTransport to $*@opened({{.*}}) ActorTransport -// CHECK: [[SELF_METATYPE:%[0-9]+]] = metatype $@thick SimpleUserDefinedInitDistributedActor.Type -// CHECK: [[ASSIGN_WITNESS_METHOD:%[0-9]+]] = witness_method $@opened({{.*}}) ActorTransport, #ActorTransport.assignIdentity -// CHECK: [[IDENTITY_STACK_TMP:%[0-9]+]] = alloc_stack $AnyActorIdentity -// CHECK: [[IDENTITY_RETURNED:%[0-9]+]] = apply [[ASSIGN_WITNESS_METHOD]]<@opened({{.*}}) ActorTransport, SimpleUserDefinedInitDistributedActor>([[IDENTITY_STACK_TMP]], [[SELF_METATYPE]], [[OPEN_TRANSPORT_EXISTENTIAL]]) : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity -// CHECK: [[IDENTITY_PROPERTY:%[0-9]+]] = ref_element_addr [[SELF]] : $SimpleUserDefinedInitDistributedActor, #SimpleUserDefinedInitDistributedActor.id -// Store the identity -// CHECK: copy_addr [take] [[IDENTITY_STACK_TMP]] to [initialization] [[IDENTITY_PROPERTY]] : $*AnyActorIdentity -// CHECK: [[TRANSPORT_PROPERTY:%[0-9]+]] = ref_element_addr [[SELF]] : $SimpleUserDefinedInitDistributedActor, #SimpleUserDefinedInitDistributedActor.actorTransport +// CHECK: sil hidden{{.*}} @$s41distributed_actor_user_transport_init_sil37SimpleUserDefinedInitDistributedActorC5other12theTransportACSi_01_K00lO0_ptcfc : $@convention(method) (Int, @in ActorTransport, @owned SimpleUserDefinedInitDistributedActor) -> @owned SimpleUserDefinedInitDistributedActor { +// CHECK: // %0 "other" // user: %3 +// CHECK: // %1 "theTransport" // users: %17, %9, %8, %4 +// CHECK: // %2 "self" // users: %7, %14, %6, %18, %5 +// CHECK: bb0(%0 : $Int, %1 : $*ActorTransport, %2 : $SimpleUserDefinedInitDistributedActor): +// CHECK: debug_value %0 : $Int, let, name "other", argno 1 // id: %3 +// CHECK: debug_value_addr %1 : $*ActorTransport, let, name "theTransport", argno 2 // id: %4 +// CHECK: debug_value %2 : $SimpleUserDefinedInitDistributedActor, let, name "self", argno 3, implicit // id: %5 +// CHECK: %6 = builtin "initializeDefaultActor"(%2 : $SimpleUserDefinedInitDistributedActor) : $() + // Store the transport -// CHECK: copy_addr [[TRANSPORT]] to [initialization] [[TRANSPORT_PROPERTY]] : $*ActorTransport -// CHECK: dealloc_stack [[IDENTITY_STACK_TMP]] : $*AnyActorIdentity -// CHECK: destroy_addr [[TRANSPORT]] : $*ActorTransport -// // While in AST the return was "return null" after SILGen we properly return the self -// CHECK: return [[SELF]] : $SimpleUserDefinedInitDistributedActor -// CHECK: } +// CHECK: %7 = ref_element_addr %2 : $SimpleUserDefinedInitDistributedActor, #SimpleUserDefinedInitDistributedActor.actorTransport // user: %8 +// CHECK: copy_addr %1 to [initialization] %7 : $*ActorTransport // id: %8 + +// Assign an identity +// CHECK: %9 = open_existential_addr immutable_access %1 : $*ActorTransport to $*@opened("{{.*}}") ActorTransport // users: %13, %13, %11 +// CHECK: %10 = metatype $@thick SimpleUserDefinedInitDistributedActor.Type // user: %13 +// CHECK: %11 = witness_method $@opened("{{.*}}") ActorTransport, #ActorTransport.assignIdentity : (Self) -> (Act.Type) -> AnyActorIdentity, %9 : $*@opened("{{.*}}") ActorTransport : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity // type-defs: %9; user: %13 +// CHECK: %12 = alloc_stack $AnyActorIdentity // users: %16, %15, %13 +// CHECK: %13 = apply %11<@opened("{{.*}}") ActorTransport, SimpleUserDefinedInitDistributedActor>(%12, %10, %9) : $@convention(witness_method: ActorTransport) <τ_0_0 where τ_0_0 : ActorTransport><τ_1_0 where τ_1_0 : DistributedActor> (@thick τ_1_0.Type, @in_guaranteed τ_0_0) -> @out AnyActorIdentity // type-defs: %9 + +// Store the identity +// CHECK: %14 = ref_element_addr %2 : $SimpleUserDefinedInitDistributedActor, #SimpleUserDefinedInitDistributedActor.id // user: %15 +// CHECK: copy_addr [take] %12 to [initialization] %14 : $*AnyActorIdentity // id: %15 +// CHECK: dealloc_stack %12 : $*AnyActorIdentity // id: %16 +// CHECK: destroy_addr %1 : $*ActorTransport // id: %17 +// While in AST the return was "return null" after SILGen we properly return the self +// CHECK: return %2 : $SimpleUserDefinedInitDistributedActor // id: %18 +// CHECK: } // end sil function '$s41distributed_actor_user_transport_init_sil37SimpleUserDefinedInitDistributedActorC5other12theTransportACSi_01_K00lO0_ptcfc' From fa1b4b2feca8d1831031f9a93d8273c2dec52006 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 26 Aug 2021 07:43:37 +0900 Subject: [PATCH 3/6] fix test: decl/protocol/special/DistributedActor.swift --- test/decl/protocol/special/DistributedActor.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/decl/protocol/special/DistributedActor.swift b/test/decl/protocol/special/DistributedActor.swift index e56be3935d9d1..3db8b1582e111 100644 --- a/test/decl/protocol/special/DistributedActor.swift +++ b/test/decl/protocol/special/DistributedActor.swift @@ -28,16 +28,15 @@ distributed actor D3 { @available(SwiftStdlib 5.5, *) distributed actor D4 { // expected-error@-1{{actor 'D4' has no initializers}} - // expected-error@-2{{type 'D4' does not conform to protocol 'DistributedActor'}} let actorTransport: String - // expected-error@-1{{invalid redeclaration of synthesized property 'actorTransport'}} + // expected-error@-1{{invalid redeclaration of synthesized implementation for protocol requirement 'actorTransport'}} // expected-error@-2{{property 'actorTransport' cannot be defined explicitly, as it conflicts with distributed actor synthesized stored property}} // expected-note@-3{{stored property 'actorTransport' without initial value prevents synthesized initializers}} let id: AnyActorIdentity - // expected-error@-1{{invalid redeclaration of synthesized property 'id'}} + // expected-error@-1{{actor-isolated property 'id' cannot be used to satisfy a protocol requirement}} // expected-error@-2{{property 'id' cannot be defined explicitly, as it conflicts with distributed actor synthesized stored property}} - // expected-note@-3{{stored property 'id' without initial value prevents synthesized initializers}} - // expected-note@-4{{candidate exactly matches}} + // expected-error@-3{{actor-isolated property 'id' cannot be used to satisfy a protocol requirement}} + // expected-note@-4{{stored property 'id' without initial value prevents synthesized initializers}} } // ==== Tests ------------------------------------------------------------------ From a1ae362aa41a3cd81a6ca0f7edb8b99ecd461237 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 26 Aug 2021 07:46:49 +0900 Subject: [PATCH 4/6] [Distributed] remove duplicated code --- lib/Sema/DerivedConformanceDistributedActor.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index 3ab15a040c79a..e98814b4e1035 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -60,7 +60,6 @@ createStoredProperty(ClassDecl *classDecl, ASTContext &ctx, static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { assert(derived.Nominal->isDistributedActor()); - auto decl = dyn_cast(derived.Nominal); auto &C = derived.Context; // ``` @@ -71,9 +70,8 @@ static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { VarDecl *propDecl; PatternBindingDecl *pbDecl; - std::tie(propDecl, pbDecl) = createStoredProperty( - decl, C, - VarDecl::Introducer::Let, C.Id_id, + std::tie(propDecl, pbDecl) = derived.declareDerivedProperty( + C.Id_id, propertyType, propertyType, /*isStatic=*/false, /*isFinal=*/true); @@ -88,7 +86,6 @@ static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { static ValueDecl *deriveDistributedActor_actorTransport( DerivedConformance &derived) { assert(derived.Nominal->isDistributedActor()); - auto decl = dyn_cast(derived.Nominal); auto &C = derived.Context; // ``` @@ -100,9 +97,8 @@ static ValueDecl *deriveDistributedActor_actorTransport( VarDecl *propDecl; PatternBindingDecl *pbDecl; - std::tie(propDecl, pbDecl) = createStoredProperty( - decl, C, - VarDecl::Introducer::Let, C.Id_actorTransport, + std::tie(propDecl, pbDecl) = derived.declareDerivedProperty( + C.Id_actorTransport, propertyType, propertyType, /*isStatic=*/false, /*isFinal=*/true); From 1669fb42788a262a72ea47bb6ca0cf4d10b24cd1 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 26 Aug 2021 08:22:22 +0900 Subject: [PATCH 5/6] introducer --- lib/Sema/DerivedConformanceDistributedActor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index e98814b4e1035..92d5bd0dffbc7 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -75,6 +75,8 @@ static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { propertyType, propertyType, /*isStatic=*/false, /*isFinal=*/true); + propDecl->setIntroducer(VarDecl::Introducer::Let); + // mark as @_distributedActorIndependent, allowing access to it from everywhere propDecl->getAttrs().add( new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true)); @@ -102,6 +104,8 @@ static ValueDecl *deriveDistributedActor_actorTransport( propertyType, propertyType, /*isStatic=*/false, /*isFinal=*/true); + propDecl->setIntroducer(VarDecl::Introducer::Let); + // mark as @_distributedActorIndependent, allowing access to it from everywhere propDecl->getAttrs().add( new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true)); From c868bdd9f15ac71e6b6d60e0f2a03daea1cb2793 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 26 Aug 2021 19:44:14 +0900 Subject: [PATCH 6/6] [Distributed] resolve synthesis via DerivedConformanceDistributedActor <3 --- lib/Sema/CodeSynthesisDistributedActor.cpp | 64 ----------- .../DerivedConformanceDistributedActor.cpp | 102 +++++++++++++----- lib/Sema/DerivedConformances.cpp | 11 ++ lib/Sema/TypeCheckDistributed.cpp | 3 + .../public/Distributed/DistributedActor.swift | 3 +- .../Runtime/distributed_actor_deinit.swift | 2 - 6 files changed, 90 insertions(+), 95 deletions(-) diff --git a/lib/Sema/CodeSynthesisDistributedActor.cpp b/lib/Sema/CodeSynthesisDistributedActor.cpp index d813ab24d68ca..71bcb6b10e11f 100644 --- a/lib/Sema/CodeSynthesisDistributedActor.cpp +++ b/lib/Sema/CodeSynthesisDistributedActor.cpp @@ -30,69 +30,6 @@ #include "DerivedConformances.h" using namespace swift; -/******************************************************************************/ -/******************************* RESOLVE FUNCTION *****************************/ -/******************************************************************************/ - -/// Synthesizes the -/// -/// \verbatim -/// static resolve(_ address: ActorAddress, -/// using transport: ActorTransport) throws -> Self { -/// -/// } -/// \endverbatim -/// -/// factory function in the AST, with an empty body. Its body is -/// expected to be filled-in during SILGen. -// TODO(distributed): move this synthesis to DerivedConformance style -static void addFactoryResolveFunction(ClassDecl *decl) { - assert(decl->isDistributedActor()); - auto &C = decl->getASTContext(); - - auto mkParam = [&](Identifier argName, Identifier paramName, Type ty) -> ParamDecl* { - auto *param = new (C) ParamDecl(SourceLoc(), - SourceLoc(), argName, - SourceLoc(), paramName, decl); - param->setImplicit(); - param->setSpecifier(ParamSpecifier::Default); - param->setInterfaceType(ty); - return param; - }; - - auto addressType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType(); - auto transportType = C.getActorTransportDecl()->getDeclaredInterfaceType(); - - // (_ identity: AnyActorIdentity, using transport: ActorTransport) - auto *params = ParameterList::create( - C, - /*LParenLoc=*/SourceLoc(), - /*params=*/{ mkParam(Identifier(), C.Id_identity, addressType), - mkParam(C.Id_using, C.Id_transport, transportType) - }, - /*RParenLoc=*/SourceLoc() - ); - - // Func name: resolve(_:using:) - DeclName name(C, C.Id_resolve, params); - - // Expected type: (Self) -> (AnyActorIdentity, ActorTransport) throws -> (Self) - auto *factoryDecl = - FuncDecl::createImplicit(C, StaticSpellingKind::KeywordStatic, - name, SourceLoc(), - /*async=*/false, - /*throws=*/true, - /*genericParams=*/nullptr, - params, - /*returnType*/decl->getDeclaredInterfaceType(), - decl); - - factoryDecl->setDistributedActorFactory(); // TODO(distributed): should we mark this specifically as the resolve factory? - factoryDecl->copyFormalAccessFrom(decl, /*sourceIsParentContext=*/true); - - decl->addMember(factoryDecl); -} - /******************************************************************************/ /*************************** _REMOTE_ FUNCTIONS *******************************/ /******************************************************************************/ @@ -265,6 +202,5 @@ void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) { if (!swift::ensureDistributedModuleLoaded(decl)) return; - addFactoryResolveFunction(decl); addImplicitRemoteActorFunctions(decl); } diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index 92d5bd0dffbc7..3ebfb1dcc071b 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -28,36 +28,78 @@ bool DerivedConformance::canDeriveDistributedActor( auto classDecl = dyn_cast(nominal); return classDecl && classDecl->isDistributedActor() && dc == nominal; } + // ==== ------------------------------------------------------------------------ -// TODO: deduplicate with 'declareDerivedProperty' from DerivedConformance... -std::pair -createStoredProperty(ClassDecl *classDecl, ASTContext &ctx, - VarDecl::Introducer introducer, Identifier name, - Type propertyInterfaceType, Type propertyContextType, - bool isStatic, bool isFinal) { - auto parentDC = classDecl; - - VarDecl *propDecl = new (ctx) - VarDecl(/*IsStatic*/ isStatic, introducer, - SourceLoc(), name, parentDC); - propDecl->setImplicit(); - propDecl->setSynthesized(); - propDecl->copyFormalAccessFrom(classDecl, /*sourceIsParentContext*/ true); - propDecl->setInterfaceType(propertyInterfaceType); - - Pattern *propPat = NamedPattern::createImplicit(ctx, propDecl); - propPat->setType(propertyContextType); - - propPat = TypedPattern::createImplicit(ctx, propPat, propertyContextType); - propPat->setType(propertyContextType); - - auto *pbDecl = PatternBindingDecl::createImplicit( - ctx, StaticSpellingKind::None, propPat, /*InitExpr*/ nullptr, - parentDC); - return {propDecl, pbDecl}; +/******************************************************************************/ +/******************************* RESOLVE FUNCTION *****************************/ +/******************************************************************************/ + +/// Synthesizes the +/// +/// \verbatim +/// static resolve(_ address: ActorAddress, +/// using transport: ActorTransport) throws -> Self { +/// +/// } +/// \endverbatim +/// +/// factory function in the AST, with an empty body. Its body is +/// expected to be filled-in during SILGen. +// TODO(distributed): move this synthesis to DerivedConformance style +static FuncDecl *deriveDistributedActor_resolve(DerivedConformance &derived) { + auto decl = dyn_cast(derived.Nominal); + assert(decl->isDistributedActor()); + auto &C = decl->getASTContext(); + + auto mkParam = [&](Identifier argName, Identifier paramName, Type ty) -> ParamDecl* { + auto *param = new (C) ParamDecl(SourceLoc(), + SourceLoc(), argName, + SourceLoc(), paramName, decl); + param->setImplicit(); + param->setSpecifier(ParamSpecifier::Default); + param->setInterfaceType(ty); + return param; + }; + + auto addressType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType(); + auto transportType = C.getActorTransportDecl()->getDeclaredInterfaceType(); + + // (_ identity: AnyActorIdentity, using transport: ActorTransport) + auto *params = ParameterList::create( + C, + /*LParenLoc=*/SourceLoc(), + /*params=*/{ mkParam(Identifier(), C.Id_identity, addressType), + mkParam(C.Id_using, C.Id_transport, transportType) + }, + /*RParenLoc=*/SourceLoc() + ); + + // Func name: resolve(_:using:) + DeclName name(C, C.Id_resolve, params); + + // Expected type: (Self) -> (AnyActorIdentity, ActorTransport) throws -> (Self) + auto *factoryDecl = + FuncDecl::createImplicit(C, StaticSpellingKind::KeywordStatic, + name, SourceLoc(), + /*async=*/false, + /*throws=*/true, + /*genericParams=*/nullptr, + params, + /*returnType*/decl->getDeclaredInterfaceType(), + decl); + + factoryDecl->setDistributedActorFactory(); // TODO(distributed): should we mark this specifically as the resolve factory? + factoryDecl->copyFormalAccessFrom(decl, /*sourceIsParentContext=*/true); + + derived.addMembersToConformanceContext({factoryDecl}); + return factoryDecl; } +/******************************************************************************/ +/******************************* PROPERTIES ***********************************/ +/******************************************************************************/ + static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { assert(derived.Nominal->isDistributedActor()); auto &C = derived.Context; @@ -114,7 +156,6 @@ static ValueDecl *deriveDistributedActor_actorTransport( return propDecl; } - // ==== ------------------------------------------------------------------------ ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { @@ -126,5 +167,12 @@ ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { return deriveDistributedActor_actorTransport(*this); } + if (auto func = dyn_cast(requirement)) { + // just a simple name check is enough here, + // if we are invoked here we know for sure it is for the "right" function + if (func->getName().getBaseName() == Context.Id_resolve) + return deriveDistributedActor_resolve(*this); + } + return nullptr; } diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index 996a839d973a1..19d80d9b9181b 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -359,6 +359,17 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, return getRequirement(KnownProtocolKind::Hashable); } + // static DistributedActor.resolve(_:using:) + if (name.isCompoundName() && name.getBaseName() == ctx.Id_resolve && + func->isStatic()) { + auto argumentNames = name.getArgumentNames(); + if (argumentNames.size() == 2 && + argumentNames[0] == Identifier() && + argumentNames[1] == ctx.Id_using) { + return getRequirement(KnownProtocolKind::DistributedActor); + } + } + return nullptr; } diff --git a/lib/Sema/TypeCheckDistributed.cpp b/lib/Sema/TypeCheckDistributed.cpp index 4fdaec54cd4e1..fead2c7807833 100644 --- a/lib/Sema/TypeCheckDistributed.cpp +++ b/lib/Sema/TypeCheckDistributed.cpp @@ -215,6 +215,9 @@ void swift::checkDistributedActorConstructor(const ClassDecl *decl, ConstructorD // ==== ------------------------------------------------------------------------ void TypeChecker::checkDistributedActor(ClassDecl *decl) { + if (!decl) + return; + // ==== Ensure the _Distributed module is available, // without it there's no reason to check the decl in more detail anyway. if (!swift::ensureDistributedModuleLoaded(decl)) diff --git a/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index e9e771cfed801..da2d7404b484c 100644 --- a/stdlib/public/Distributed/DistributedActor.swift +++ b/stdlib/public/Distributed/DistributedActor.swift @@ -34,8 +34,7 @@ public protocol AnyActor: Sendable, AnyObject {} /// distributed actor. @available(SwiftStdlib 5.5, *) public protocol DistributedActor: - AnyActor, - Identifiable, Hashable, Codable { + AnyActor, Identifiable, Hashable, Codable { /// Resolves the passed in `identity` against the `transport`, returning /// either a local or remote actor reference. /// diff --git a/test/Distributed/Runtime/distributed_actor_deinit.swift b/test/Distributed/Runtime/distributed_actor_deinit.swift index 14f3b9d373f20..863c4322b7b3a 100644 --- a/test/Distributed/Runtime/distributed_actor_deinit.swift +++ b/test/Distributed/Runtime/distributed_actor_deinit.swift @@ -135,11 +135,9 @@ func test() { // a remote actor should not resign it's address, it was never "assigned" it print("before") _ = try! DA_userDefined2.resolve(.init(address), using: transport) - print("done") // CHECK: before // CHECK-NEXT: resolve type:DA_userDefined2, address:AnyActorIdentity(ActorAddress(address: "xxx")) // CHECK-NEXT: Deinitializing - // CHECK-NEXT: done } @available(SwiftStdlib 5.5, *)