From 42745667b34345d563981aa3a257055d85d64f77 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 2 Feb 2023 14:04:01 -0800 Subject: [PATCH 1/8] windows: convert swift-crypto to static linking We should be able to use static linking here without negatively impacting code size. --- utils/build-windows-toolchain.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/build-windows-toolchain.bat b/utils/build-windows-toolchain.bat index cd99dc49f53a7..1ac13db9a7241 100644 --- a/utils/build-windows-toolchain.bat +++ b/utils/build-windows-toolchain.bat @@ -508,6 +508,7 @@ cmake --build %BuildRoot%\11 --target install || (exit /b) cmake ^ -B %BuildRoot%\12 ^ + -D BUILD_SHARED_LIBS=NO ^ -D CMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE% ^ -D CMAKE_C_COMPILER=cl ^ -D CMAKE_C_FLAGS="/GS- /Oy /Gw /Gy" ^ From 2e92b4992ae7be0ab443ef4a7fb85e8d69bc41be Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 14 Feb 2023 16:30:39 -0800 Subject: [PATCH 2/8] [CSBindings] Solver result builder transformed closures as soon as all contextual information becomes available We determine that based on four criteria: - Builder type doesn't have any unresolved generic parameters; - Contextual type associated with the closure doesn't have any unresolved type variables (which means that all possible contextual information is provided to the body); - All of the references to declarations from outer scope are resolved (i.e. a variable declaration from a parent closure); - The contextual result type is either fully resolved or opaque type. If all the criteria a met the conjunction that represents a closure is going to be picked and solved as the next solver step. Resolves: rdar://104645543 (cherry picked from commit f27369d93a323d4fdabd70c91dee0df9139910bf) (cherry picked from commit a815de7586f770ee2d8cbbd0bc3bbfe894f4a311) (cherry picked from commit 38f8be15441ca2f18174cd5dcfbe5cb06d003aab) (cherry picked from commit 5bb9d75e119fa8597842902a4c2a814daeade374) (cherry picked from commit fda75304183bb66f3aad53cad57794b5749578c0) (cherry picked from commit b84d70bb5a16ccddbb0ecac68f47f8bd1386a1fa) --- include/swift/Sema/ConstraintSystem.h | 10 ++- lib/Sema/BuilderTransform.cpp | 3 + lib/Sema/CSBindings.cpp | 55 ++++++++++++ lib/Sema/CSSimplify.cpp | 2 +- lib/Sema/TypeCheckConstraints.cpp | 16 ++++ ...result_builder_conjunction_selection.swift | 83 +++++++++++++++++++ 6 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 test/Constraints/result_builder_conjunction_selection.swift diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 1aa66ac894bea..91d6166748daf 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -486,6 +486,9 @@ class TypeVariableType::Implementation { /// expression. bool isCodeCompletionToken() const; + /// Determine whether this type variable represents an opened opaque type. + bool isOpaqueType() const; + /// Retrieve the representative of the equivalence class to which this /// type variable belongs. /// @@ -977,6 +980,11 @@ struct AppliedBuilderTransform { /// converted. Opaque types should be unopened. Type bodyResultType; + /// If transform is applied to a closure, this type represents + /// contextual type the closure is converted type (e.g. a parameter + /// type or or pattern type). + Type contextualType; + /// The version of the original body with result builder applied /// as AST transformation. NullablePtr transformedBody; @@ -5662,7 +5670,7 @@ class ConstraintSystem { Optional matchResultBuilder(AnyFunctionRef fn, Type builderType, Type bodyResultType, ConstraintKind bodyResultConstraintKind, - ConstraintLocatorBuilder locator); + Type contextualType, ConstraintLocatorBuilder locator); /// Matches a wrapped or projected value parameter type to its backing /// property wrapper type by applying the property wrapper. diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index a71d6e807fe3c..1ed04b2894d8b 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -2311,6 +2311,7 @@ Optional TypeChecker::applyResultBuilderBodyTransform( if (auto result = cs.matchResultBuilder( func, builderType, resultContextType, resultConstraintKind, + /*contextualType=*/Type(), cs.getConstraintLocator(func->getBody()))) { if (result->isFailure()) return nullptr; @@ -2398,6 +2399,7 @@ Optional ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType, Type bodyResultType, ConstraintKind bodyResultConstraintKind, + Type contextualType, ConstraintLocatorBuilder locator) { builderType = simplifyType(builderType); auto builder = builderType->getAnyNominal(); @@ -2522,6 +2524,7 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType, transformInfo.builderType = builderType; transformInfo.bodyResultType = bodyResultType; + transformInfo.contextualType = contextualType; transformInfo.transformedBody = transformedBody->second; // Record the transformation. diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index c6e66bcacb2d9..ba7bccfc1fc57 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -1071,6 +1071,61 @@ bool BindingSet::favoredOverConjunction(Constraint *conjunction) const { if (forClosureResult() || forGenericParameter()) return false; } + + auto *locator = conjunction->getLocator(); + if (locator->directlyAt()) { + auto *closure = castToExpr(locator->getAnchor()); + + if (auto transform = CS.getAppliedResultBuilderTransform(closure)) { + // Conjunctions that represent closures with result builder transformed + // bodies could be attempted right after their resolution if they meet + // all of the following criteria: + // + // - Builder type doesn't have any unresolved generic parameters; + // - Closure doesn't have any parameters; + // - The contextual result type is either concrete or opaque type. + auto contextualType = transform->contextualType; + if (!(contextualType && contextualType->is())) + return true; + + auto *contextualFnType = + CS.simplifyType(contextualType)->castTo(); + { + auto resultType = contextualFnType->getResult(); + if (resultType->hasTypeVariable()) { + auto *typeVar = resultType->getAs(); + // If contextual result type is represented by an opaque type, + // it's a strong indication that body is self-contained, otherwise + // closure might rely on external types flowing into the body for + // disambiguation of `build{Partial}Block` or `buildFinalResult` + // calls. + if (!(typeVar && typeVar->getImpl().isOpaqueType())) + return true; + } + } + + // If some of the closure parameters are unresolved, the conjunction + // has to be delayed to give them a chance to be inferred. + if (llvm::any_of(contextualFnType->getParams(), [](const auto ¶m) { + return param.getPlainType()->hasTypeVariable(); + })) + return true; + + // Check whether conjunction has any unresolved type variables + // besides the variable that represents the closure. + // + // Conjunction could refer to declarations from outer context + // (i.e. a variable declared in the outer closure) or generic + // parameters of the builder type), if any of such references + // are not yet inferred the conjunction has to be delayed. + auto *closureType = CS.getType(closure)->castTo(); + return llvm::any_of( + conjunction->getTypeVariables(), [&](TypeVariableType *typeVar) { + return !(typeVar == closureType || CS.getFixedType(typeVar)); + }); + } + } + return true; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 89b0c3c51bef2..bf240b7638548 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -10964,7 +10964,7 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar, if (resultBuilderType) { if (auto result = matchResultBuilder( closure, resultBuilderType, closureType->getResult(), - ConstraintKind::Conversion, locator)) { + ConstraintKind::Conversion, contextualType, locator)) { return result->isSuccess(); } } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 1beebb42af304..1d021f484c03a 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -154,6 +154,22 @@ bool TypeVariableType::Implementation::isCodeCompletionToken() const { return locator && locator->directlyAt(); } +bool TypeVariableType::Implementation::isOpaqueType() const { + if (!locator) + return false; + + auto GP = locator->getLastElementAs(); + if (!GP) + return false; + + if (auto *GPT = GP->getType()->getAs()) { + auto *decl = GPT->getDecl(); + return decl && decl->isOpaqueType(); + } + + return false; +} + void *operator new(size_t bytes, ConstraintSystem& cs, size_t alignment) { return cs.getAllocator().Allocate(bytes, alignment); diff --git a/test/Constraints/result_builder_conjunction_selection.swift b/test/Constraints/result_builder_conjunction_selection.swift new file mode 100644 index 0000000000000..8b94c59315930 --- /dev/null +++ b/test/Constraints/result_builder_conjunction_selection.swift @@ -0,0 +1,83 @@ +// RUN: %target-typecheck-verify-swift -debug-constraints -disable-availability-checking 2>%t.err +// RUN: %FileCheck %s < %t.err + +protocol P { + associatedtype Output +} + +struct S : P { + init(_: Output) {} +} + +@resultBuilder +struct Builder { + static func buildExpression(_ e: T) -> T { e } + + static func buildBlock(_ t1: T1) -> some P { + return S(t1) + } + + static func buildBlock(_ t1: T1, _ t2: T2) -> some P<(T1, T2)> { + return S((t1, t2)) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) -> some P<(T1, T2, T3)> { + return S((t1, t2, t3)) + } + + static func buildOptional(_ value: T?) -> T? { return value } +} + +do { + func test(_: T, @Builder _: () -> some P) {} + + // CHECK: ---Initial constraints for the given expression--- + // CHECK: (integer_literal_expr type='[[LITERAL_VAR:\$T[0-9]+]]' {{.*}} + // CHECK: (attempting type variable [[CLOSURE:\$T[0-9]+]] := () -> {{.*}} + // CHECK-NOT: (attempting type variable [[LITERAL_VAR]] := {{.*}} + // CHECK: (attempting conjunction element pattern binding element @ 0 + // CHECK: (applying conjunction result to outer context + // CHECK: (attempting type variable [[LITERAL_VAR]] := Int + test(42) { + 1 + "" + } +} + +do { + func test(_: T, @Builder _: (T) -> some P) {} + + // CHECK: ---Initial constraints for the given expression--- + // CHECK: (integer_literal_expr type='[[LITERAL_VAR:\$T[0-9]+]]' {{.*}} + // CHECK: (attempting type variable [[LITERAL_VAR]] := Int + // CHECK: (attempting conjunction element pattern binding element @ 0 + test(42) { v in + v + "" + } +} + +do { + func test(@Builder _: (Bool) -> some P, transform: (T?) -> U) {} + + // CHECK: ---Initial constraints for the given expression--- + // CHECK: (attempting type variable {{.*}} := () -> {{.*}} + // CHECK: (attempting conjunction element pattern binding element @ 0 : + // CHECK-NEXT: (pattern_named 'x') + // CHECK: (attempting conjunction element syntactic element + // CHECK-NEXT: (call_expr {{.*}} + // CHECK: (attempting type variable {{.*}} := (Bool) -> {{.*}} + // CHECK: (attempting conjunction element pattern binding element @ 0 + // CHECK: (pattern_named implicit '$__builder{{.*}}') + // CHECK: (applying conjunction result to outer context + // CHECK: (attempting type variable {{.*}} := (Int?) -> {{.*}} + // CHECK: (attempting disjunction choice {{.*}} bound to decl {{.*}}.Int.init(_:) + let _ = { + let x = 42 + test { cond in + x + } transform: { v in + Int(v ?? 0) + } + } +} From fd749888eb0006ec5959cdb09d6e0bb44b1dd8e4 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Mon, 20 Feb 2023 20:05:08 +0900 Subject: [PATCH 3/8] [Distributed] correct take semantics for synthesized ID assignments cleanup: no need to dump input always --- lib/SILGen/SILGenDistributed.cpp | 30 +++--- ...distributed_actor_default_init_sil_8.swift | 102 ++++++++++++++++++ .../SIL/distributed_actor_resolve_sil.swift | 33 ++++++ ...stributed_actor_accessor_section_elf.swift | 2 +- 4 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 test/Distributed/SIL/distributed_actor_default_init_sil_8.swift create mode 100644 test/Distributed/SIL/distributed_actor_resolve_sil.swift diff --git a/lib/SILGen/SILGenDistributed.cpp b/lib/SILGen/SILGenDistributed.cpp index 12d66cd0016f4..99cfbedf2fa0b 100644 --- a/lib/SILGen/SILGenDistributed.cpp +++ b/lib/SILGen/SILGenDistributed.cpp @@ -54,18 +54,19 @@ static SILValue emitActorPropertyReference( /// \param value the value to use when initializing the property. static void initializeProperty(SILGenFunction &SGF, SILLocation loc, SILValue actorSelf, - VarDecl* prop, SILValue value) { + VarDecl* prop, SILValue value, + IsTake_t isTake) { Type formalType = SGF.F.mapTypeIntoContext(prop->getInterfaceType()); SILType loweredType = SGF.getLoweredType(formalType); auto fieldAddr = emitActorPropertyReference(SGF, loc, actorSelf, prop); if (loweredType.isAddressOnly(SGF.F)) { - SGF.B.createCopyAddr(loc, value, fieldAddr, IsNotTake, IsInitialization); + SGF.B.createCopyAddr(loc, value, fieldAddr, isTake, IsInitialization); } else { if (value->getType().isAddress()) { SGF.emitSemanticLoadInto(loc, value, SGF.F.getTypeLowering(value->getType()), - fieldAddr, SGF.getTypeLowering(loweredType), IsTake, IsInitialization); + fieldAddr, SGF.getTypeLowering(loweredType), isTake, IsInitialization); } else { value = SGF.B.emitCopyValueOperation(loc, value); SGF.B.emitStoreValueOperation( @@ -152,10 +153,10 @@ static SILArgument *findFirstDistributedActorSystemArg(SILFunction &F) { /// For the initialization of a local distributed actor instance, emits code to /// initialize the instance's stored property corresponding to the system. static void emitActorSystemInit(SILGenFunction &SGF, - ConstructorDecl *ctor, - SILLocation loc, - ManagedValue actorSelf, - SILValue systemValue) { + ConstructorDecl *ctor, + SILLocation loc, + ManagedValue actorSelf, + SILValue systemValue) { assert(ctor->isImplicit() && "unexpected explicit dist actor init"); assert(ctor->isDesignatedInit()); @@ -166,9 +167,8 @@ static void emitActorSystemInit(SILGenFunction &SGF, // exactly one ActorSystem-conforming argument to the constructor, // so we grab the first one from the params. VarDecl *var = classDecl->getDistributedActorSystemProperty(); - assert(var); - - initializeProperty(SGF, loc, actorSelf.getValue(), var, systemValue); + + initializeProperty(SGF, loc, actorSelf.getValue(), var, systemValue, IsNotTake); } /// Emits the distributed actor's identity (`id`) initialization. @@ -209,7 +209,7 @@ void SILGenFunction::emitDistActorIdentityInit(ConstructorDecl *ctor, { temp, selfMetatypeValue }); // --- initialize the property. - initializeProperty(*this, loc, borrowedSelfArg, var, temp); + initializeProperty(*this, loc, borrowedSelfArg, var, temp, IsTake); } // TODO(distributed): rename to DistributedActorID @@ -443,14 +443,16 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) { // TODO(distrib loc.markAutoGenerated(); auto *dc = fd->getDeclContext(); auto classDecl = dc->getSelfClassDecl(); - + initializeProperty(*this, loc, remote, classDecl->getDistributedActorIDProperty(), - idArg); + idArg, + IsNotTake); initializeProperty(*this, loc, remote, classDecl->getDistributedActorSystemProperty(), - actorSystemArg); + actorSystemArg, + IsNotTake); // ==== Branch to return the fully initialized remote instance B.createBranch(loc, returnBB, {remote}); diff --git a/test/Distributed/SIL/distributed_actor_default_init_sil_8.swift b/test/Distributed/SIL/distributed_actor_default_init_sil_8.swift new file mode 100644 index 0000000000000..b44aff8db3844 --- /dev/null +++ b/test/Distributed/SIL/distributed_actor_default_init_sil_8.swift @@ -0,0 +1,102 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -module-name default_deinit -primary-file %s -emit-sil -verify -disable-availability-checking -I %t | %FileCheck %s --enable-var-scope --dump-input=fail +// REQUIRES: concurrency +// REQUIRES: distributed + +/// The convention in this test is that the Swift declaration comes before its FileCheck lines. + +import Distributed +import FakeDistributedActorSystems + +/// This actor system is a class, therefore SIL is slightly different +typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem + +// ==== ---------------------------------------------------------------------------------------------------------------- + +class SomeClass {} + +enum Err : Error { + case blah +} + +func getSomeClass() throws -> SomeClass { throw Err.blah } +func getSystem() throws -> FakeRoundtripActorSystem { throw Err.blah } + +distributed actor MyDistActor { + var someField: SomeClass + + init() throws { + do { + actorSystem = try getSystem() + } catch { + actorSystem = FakeRoundtripActorSystem() + } + someField = try getSomeClass() + } + +// CHECK: sil hidden @$s14default_deinit11MyDistActorCACyKcfc : $@convention(method) (@owned MyDistActor) -> (@owned MyDistActor, @error any Error) { +// CHECK: bb0([[SELF:%[0-9]+]] : $MyDistActor): +// CHECK: builtin "initializeDefaultActor"([[SELF]] : $MyDistActor) +// CHECK: try_apply {{%[0-9]+}}() : $@convention(thin) () -> (@owned FakeRoundtripActorSystem, @error any Error), normal [[SYSTEM_SUCCESS_BB:bb[0-9]+]], error [[SYSTEM_ERROR_BB:bb[0-9]+]] + +// CHECK: [[SYSTEM_SUCCESS_BB]]([[SYSTEM_VAL:%[0-9]+]] : $FakeRoundtripActorSystem): + // *** save system *** +// CHECK: [[TP_FIELD1:%[0-9]+]] = ref_element_addr [[SELF]] : $MyDistActor, #MyDistActor.actorSystem +// CHECK: store [[SYSTEM_VAL]] to [[TP_FIELD1]] : $*FakeRoundtripActorSystem + // *** obtain an identity *** +// CHECK: [[TP_FIELD2:%[0-9]+]] = ref_element_addr [[SELF]] : $MyDistActor, #MyDistActor.actorSystem +// CHECK: [[RELOADED_SYS1:%[0-9]+]] = load [[TP_FIELD2]] : $*FakeRoundtripActorSystem +// CHECK: [[SELF_METATYPE:%[0-9]+]] = metatype $@thick MyDistActor.Type +// CHECK: strong_retain [[RELOADED_SYS1]] : $FakeRoundtripActorSystem +// CHECK: [[ASSIGN_ID_FN:%[0-9]+]] = function_ref @$s27FakeDistributedActorSystems0a9RoundtripC6SystemC8assignIDyAA0C7AddressVxm0B00bC0RzlF +// CHECK: [[ID:%[0-9]+]] = apply [[ASSIGN_ID_FN]]([[SELF_METATYPE]], [[RELOADED_SYS1]]) +// CHECK: strong_release [[RELOADED_SYS1]] : $FakeRoundtripActorSystem + // *** save identity *** +// CHECK: [[ID_FIELD:%[0-9]+]] = ref_element_addr [[SELF]] : $MyDistActor, #MyDistActor.id +// CHECK: store [[ID]] to [[ID_FIELD]] : $*ActorAddress +// CHECK-NOT: apply +// CHECK: br [[JOIN_PT:bb[0-9]+]] + +// CHECK: [[JOIN_PT]]: +// CHECK: try_apply {{.*}}() : $@convention(thin) () -> (@owned SomeClass, @error any Error), normal [[CLASS_SUCCESS_BB:bb[0-9]+]], error [[CLASS_ERROR_BB:bb[0-9]+]] + +// CHECK: [[CLASS_SUCCESS_BB]]{{.*}}: +// CHECK: store {{.*}} to {{.*}} : $*SomeClass + // *** invoke actorReady *** +// CHECK: [[TP_FIELD3:%[0-9]+]] = ref_element_addr [[SELF]] : $MyDistActor, #MyDistActor.actorSystem +// CHECK: [[RELOADED_SYS2:%[0-9]+]] = load [[TP_FIELD3]] : $*FakeRoundtripActorSystem +// CHECK: [[READY_FN:%[0-9]+]] = function_ref @$s27FakeDistributedActorSystems0a9RoundtripC6SystemC10actorReadyyyx0B00bC0RzAA0C7AddressV2IDRtzlF +// CHECK: = apply [[READY_FN]]([[SELF]], [[RELOADED_SYS2]]) +// CHECK: return [[SELF]] : $MyDistActor + +// CHECK: [[SYSTEM_ERROR_BB]]([[ERROR_ARG:%[0-9]+]] : $any Error): +// CHECK: strong_retain [[ERROR_ARG]] : $any Error +// CHECK: function_ref @$s27FakeDistributedActorSystems0a9RoundtripC6SystemCACycfC +// CHECK: store {{.*}} to {{.*}} : $*FakeRoundtripActorSystem +// CHECK: store {{.*}} to {{.*}} : $*ActorAddress +// CHECK: br [[JOIN_PT]] + +// CHECK: [[CLASS_ERROR_BB]]{{.*}}: + // ** deinit the id ** +// CHECK: [[REF_ID_D:%[0-9]+]] = ref_element_addr [[SELF]] : $MyDistActor, #MyDistActor.id +// CHECK: [[ID_D:%[0-9]+]] = begin_access [deinit] [static] [[REF_ID_D]] : $*ActorAddress +// CHECK: [[REF_SYS_D:%[0-9]+]] = ref_element_addr [[SELF]] : $MyDistActor, #MyDistActor.actorSystem +// CHECK: [[ID:%[0-9]+]] = load [[ID_D]] : $*ActorAddress +// CHECK: [[SYS:%[0-9]+]] = load [[REF_SYS_D]] : $*FakeRoundtripActorSystem +// CHECK: [[RESIGN_FN:%[0-9]+]] = function_ref @$s27FakeDistributedActorSystems0a9RoundtripC6SystemC8resignIDyyAA0C7AddressVF +// CHECK: = apply [[RESIGN_FN]]([[ID]], [[SYS]]) : $@convention(method) (@guaranteed ActorAddress, @guaranteed FakeRoundtripActorSystem) -> () +// CHECK: destroy_addr [[ID_D]] : $*ActorAddress +// CHECK: end_access [[ID_D]] : $*ActorAddress + // ** deinit the system ** +// CHECK: [[REF_SYS_D2:%[0-9]+]] = ref_element_addr [[SELF]] : $MyDistActor, #MyDistActor.actorSystem +// CHECK: [[SYSTEM_ACC:%[0-9]+]] = begin_access [deinit] [static] [[REF_SYS_D2]] : $*FakeRoundtripActorSystem +// CHECK: destroy_addr [[SYSTEM_ACC]] : $*FakeRoundtripActorSystem +// CHECK: end_access [[SYSTEM_ACC]] : $*FakeRoundtripActorSystem +// CHECK: builtin "destroyDefaultActor"([[SELF]] : $MyDistActor) : $() +// CHECK: dealloc_partial_ref [[SELF]] +// CHECK: throw + + +} + diff --git a/test/Distributed/SIL/distributed_actor_resolve_sil.swift b/test/Distributed/SIL/distributed_actor_resolve_sil.swift new file mode 100644 index 0000000000000..5c0629a14bbe8 --- /dev/null +++ b/test/Distributed/SIL/distributed_actor_resolve_sil.swift @@ -0,0 +1,33 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -module-name default_deinit -primary-file %s -emit-sil -verify -disable-availability-checking -I %t | %FileCheck %s --enable-var-scope --dump-input=fail +// REQUIRES: concurrency +// REQUIRES: distributed + +/// The convention in this test is that the Swift declaration comes before its FileCheck lines. + +import Distributed +import FakeDistributedActorSystems + +typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem + +// ==== ---------------------------------------------------------------------------------------------------------------- + +distributed actor MyDistActor { + +// protocol witness for DistributedActorSystem.resolve(id:as:) in conformance FakeRoundtripActorSystem +// CHECK: sil hidden @$s14default_deinit11MyDistActorC7resolve2id5usingAC015FakeDistributedE7Systems0E7AddressV_AG0i9RoundtripE6SystemCtKFZ +// CHECK: bb0([[ACTOR_ID_ARG:%[0-9]+]] : $ActorAddress, [[SYSTEM_ARG:%[0-9]+]] : $FakeRoundtripActorSystem, [[TYPE_ARG:%[0-9]+]] : $@thick MyDistActor.Type): +// CHECK: [[SYS_RESOLVE_RESULT:%[0-9]+]] = function_ref @$s27FakeDistributedActorSystems0a9RoundtripC6SystemC7resolve2id2asxSgAA0C7AddressV_xmtK0B00bC0RzlF + +// CHECK: // makeProxyBB +// CHECK: [[ACTOR_INSTANCE:%[0-9]+]] = builtin "initializeDistributedRemoteActor"(%7 : $@thick MyDistActor.Type) : $MyDistActor +// CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [[ACTOR_INSTANCE]] : $MyDistActor, #MyDistActor.id +// CHECK: retain_value [[ACTOR_ID_ARG]] : $ActorAddress +// CHECK: store [[ACTOR_ID_ARG]] to [[ID_PROPERTY]] : $*ActorAddress +// CHECK: [[SYSTEM_PROPERTY:%[0-9]+]] = ref_element_addr [[ACTOR_INSTANCE]] : $MyDistActor, #MyDistActor.actorSystem +// CHECK: strong_retain [[SYSTEM_ARG]] : $FakeRoundtripActorSystem +// CHECK: store [[SYSTEM_ARG]] to [[SYSTEM_PROPERTY]] : $*FakeRoundtripActorSystem +// CHECK: br bb5([[ACTOR_INSTANCE]] : $MyDistActor) +} + diff --git a/test/Distributed/distributed_actor_accessor_section_elf.swift b/test/Distributed/distributed_actor_accessor_section_elf.swift index f968852aa4b8c..47a624b2cde62 100644 --- a/test/Distributed/distributed_actor_accessor_section_elf.swift +++ b/test/Distributed/distributed_actor_accessor_section_elf.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift -// RUN: %target-swift-frontend -emit-irgen -module-name distributed_actor_accessors -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s --dump-input=always +// RUN: %target-swift-frontend -emit-irgen -module-name distributed_actor_accessors -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s // UNSUPPORTED: back_deploy_concurrency // REQUIRES: concurrency From 5e99d9c02cf11e9c4b892c3764e6ba88f347302d Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 19 Apr 2022 22:58:38 -0700 Subject: [PATCH 4/8] Use `-strict-concurrency=minimal` as the default for Swift 5.x mode. Emulate the behavior of Swift 5.5/5.6 by default, using `-strict-concurrency=minimal`. --- include/swift/Basic/LangOptions.h | 2 +- lib/Frontend/CompilerInvocation.cpp | 4 ++-- test/Concurrency/strict_concurrency_minimal.swift | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 8b400f2dbe398..807522708899b 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -331,7 +331,7 @@ namespace swift { bool UseMalloc = false; /// Specifies how strict concurrency checking will be. - StrictConcurrency StrictConcurrencyLevel = StrictConcurrency::Targeted; + StrictConcurrency StrictConcurrencyLevel = StrictConcurrency::Minimal; /// Enable experimental concurrency model. bool EnableExperimentalConcurrency = false; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index e07c122e1b7f4..0a57134a41037 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -788,8 +788,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, } else if (Args.hasArg(OPT_warn_concurrency)) { Opts.StrictConcurrencyLevel = StrictConcurrency::Complete; } else { - // Default to "limited" checking in Swift 5.x. - Opts.StrictConcurrencyLevel = StrictConcurrency::Targeted; + // Default to minimal checking in Swift 5.x. + Opts.StrictConcurrencyLevel = StrictConcurrency::Minimal; } Opts.WarnImplicitOverrides = diff --git a/test/Concurrency/strict_concurrency_minimal.swift b/test/Concurrency/strict_concurrency_minimal.swift index 093b7d6d8f13e..ba261108aeb44 100644 --- a/test/Concurrency/strict_concurrency_minimal.swift +++ b/test/Concurrency/strict_concurrency_minimal.swift @@ -1,4 +1,5 @@ // RUN: %target-typecheck-verify-swift -strict-concurrency=minimal +// RUN: %target-typecheck-verify-swift // REQUIRES: concurrency class C1 { } From 51bcd7d82a1d5aaea7faa4ad1558e743d51ff7d6 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 21 Feb 2023 13:11:42 +0900 Subject: [PATCH 5/8] [Distributed] better test for SIL lifetime with AddressOnly types --- .../Inputs/FakeDistributedActorSystems.swift | 104 +++++++++++++++++- ...buted_id_system_ownership_verify_sil.swift | 52 +++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 test/Distributed/SIL/distributed_id_system_ownership_verify_sil.swift diff --git a/test/Distributed/Inputs/FakeDistributedActorSystems.swift b/test/Distributed/Inputs/FakeDistributedActorSystems.swift index 8ee09b9a1bae9..4d38e7f59e067 100644 --- a/test/Distributed/Inputs/FakeDistributedActorSystems.swift +++ b/test/Distributed/Inputs/FakeDistributedActorSystems.swift @@ -34,6 +34,36 @@ public struct ActorAddress: Hashable, Sendable, Codable { } } +/// This type is same as ActorAddress however for purposes of SIL tests we make it not-loadable. +/// +/// By adding the `Any` we don't know the full size of the struct making the type in SIL `$*ActorAddress` +/// when we try to store or pass it around, which triggers `isAddressOnly` guarded paths which we need to test. +public struct NotLoadableActorAddress: Hashable, Sendable, Codable { + public let address: String + public let any: Sendable = "" // DO NOT REMOVE, this makes this struct address-only which is crucial for testing. + + public init(parse address: String) { + self.address = address + } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + self.address = try container.decode(String.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(self.address) + } + + public func hash(into hasher: inout Swift.Hasher) { + } + + public static func ==(lhs: NotLoadableActorAddress, rhs: NotLoadableActorAddress) -> Bool { + lhs.address == rhs.address + } +} + // ==== Noop Transport --------------------------------------------------------- @available(SwiftStdlib 5.7, *) @@ -109,9 +139,81 @@ public struct FakeActorSystem: DistributedActorSystem, CustomStringConvertible { } } +@available(SwiftStdlib 5.7, *) +public struct FakeNotLoadableAddressActorSystem: DistributedActorSystem, CustomStringConvertible { + public typealias ActorID = NotLoadableActorAddress + public typealias InvocationDecoder = FakeInvocationDecoder + public typealias InvocationEncoder = FakeInvocationEncoder + public typealias SerializationRequirement = Codable + public typealias ResultHandler = FakeRoundtripResultHandler + + // just so that the struct does not become "trivial" + let someValue: String = "" + let someValue2: String = "" + let someValue3: String = "" + let someValue4: String = "" + + public init() { + print("Initialized new FakeActorSystem") + } + + public func resolve(id: ActorID, as actorType: Act.Type) throws -> Act? + where Act: DistributedActor, + Act.ID == ActorID { + nil + } + + public func assignID(_ actorType: Act.Type) -> ActorID + where Act: DistributedActor, + Act.ID == ActorID { + NotLoadableActorAddress(parse: "xxx") + } + + public func actorReady(_ actor: Act) + where Act: DistributedActor, + Act.ID == ActorID { + } + + public func resignID(_ id: ActorID) { + } + + public func makeInvocationEncoder() -> InvocationEncoder { + .init() + } + + public func remoteCall( + on actor: Act, + target: RemoteCallTarget, + invocation invocationEncoder: inout InvocationEncoder, + throwing: Err.Type, + returning: Res.Type + ) async throws -> Res + where Act: DistributedActor, + Act.ID == ActorID, + Err: Error, + Res: SerializationRequirement { + throw ExecuteDistributedTargetError(message: "\(#function) not implemented.") + } + + public func remoteCallVoid( + on actor: Act, + target: RemoteCallTarget, + invocation invocationEncoder: inout InvocationEncoder, + throwing: Err.Type + ) async throws + where Act: DistributedActor, + Act.ID == ActorID, + Err: Error { + throw ExecuteDistributedTargetError(message: "\(#function) not implemented.") + } + + public nonisolated var description: Swift.String { + "\(Self.self)()" + } +} + // ==== Fake Roundtrip Transport ----------------------------------------------- -// TODO(distributed): not thread safe... @available(SwiftStdlib 5.7, *) public final class FakeRoundtripActorSystem: DistributedActorSystem, @unchecked Sendable { public typealias ActorID = ActorAddress diff --git a/test/Distributed/SIL/distributed_id_system_ownership_verify_sil.swift b/test/Distributed/SIL/distributed_id_system_ownership_verify_sil.swift new file mode 100644 index 0000000000000..cde33e15464e0 --- /dev/null +++ b/test/Distributed/SIL/distributed_id_system_ownership_verify_sil.swift @@ -0,0 +1,52 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -verify -emit-sil -module-name main -disable-availability-checking -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift | %FileCheck %s + +// REQUIRES: concurrency +// REQUIRES: distributed + +// rdar://76038845 +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime + +// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 +// UNSUPPORTED: OS=windows-msvc + +import Distributed +import FakeDistributedActorSystems + +/// This type uses a non loadable (size not known at compile time) ID which forces the actor's init SILGen +/// to make use of the isAddressOnly handling of the ID assignments. +/// +/// This test covers rdar://104583893 / https://github.com/apple/swift/issues/62898 +/// And used to fail with: +/// SIL memory lifetime failure in @$s18DistributedCluster0B16EventStreamActorC11actorSystemAcA0bG0C_tcfc: memory is initialized, but shouldn't be +typealias DefaultDistributedActorSystem = FakeNotLoadableAddressActorSystem + +distributed actor Greeter { + + init(actorSystem: ActorSystem) { + self.actorSystem = actorSystem + } + + distributed func echo(name: String) -> String { + return "Echo: \(name)" + } +} + +// CHECK: sil hidden @$s4main7GreeterC7resolve2id5usingAcA23NotLoadableActorAddressV_AA04FakefgiH6SystemVtKFZ : $@convention(method) (@in_guaranteed NotLoadableActorAddress, @guaranteed FakeNotLoadableAddressActorSystem, @thick Greeter.Type) -> (@owned Greeter, @error any Error) { +// CHECK: bb0([[ADDRESS_ARG:%[0-9]+]] : $*NotLoadableActorAddress, [[SYSTEM_ARG:%[0-9]+]] : $FakeNotLoadableAddressActorSystem, [[TYPE_ARG:%[0-9]+]] : $@thick Greeter.Type): +// CHECK: [[TYPE:%[0-9]+]] = metatype $@thick Greeter.Type + +// CHECK: // makeProxyBB +// CHECK: [[INSTANCE:%[0-9]+]] = builtin "initializeDistributedRemoteActor"([[TYPE]] : $@thick Greeter.Type) : $Greeter +// CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [[INSTANCE]] : $Greeter, #Greeter.id +// Note specifically that we don't [take] in the below copy_addr: +// CHECK: copy_addr [[ADDRESS_ARG]] to [init] [[ID_PROPERTY]] : $*NotLoadableActorAddress + +func test() async throws { + let system = DefaultDistributedActorSystem() + + let local = Greeter(actorSystem: system) + _ = try await local.echo(name: "Caplin") +} From 4b2f803eb1d5c57a4c66d2fc500b15721d7107da Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Sat, 18 Feb 2023 00:34:27 -0800 Subject: [PATCH 6/8] [BuilderTransform] Rework missing `buildWithAvailability` detection Since all of the branches of an `if` statement are joined together and hence produce the same type, that type should be used to check whether `buildWithAvailability` is required but missing regardless of availability condition kind. Resolves: https://github.com/apple/swift/issues/63764 (cherry picked from commit c4ea02c2d74583277d50b084d61397185f598335) --- lib/Sema/CSSyntacticElement.cpp | 28 ++++--------------- .../result_builder_availability.swift | 7 +++-- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/lib/Sema/CSSyntacticElement.cpp b/lib/Sema/CSSyntacticElement.cpp index adcabea5a4a2e..ec4981a7bc398 100644 --- a/lib/Sema/CSSyntacticElement.cpp +++ b/lib/Sema/CSSyntacticElement.cpp @@ -1891,7 +1891,7 @@ class ResultBuilderRewriter : public SyntacticElementSolutionApplication { NullablePtr transformIf(IfStmt *ifStmt, TypeJoinExpr *join, unsigned index) { // FIXME: Turn this into a condition once warning is an error. - (void)diagnoseMissingBuildWithAvailability(ifStmt); + (void)diagnoseMissingBuildWithAvailability(ifStmt, join); auto *joinVar = join->getVar(); @@ -1993,7 +1993,8 @@ class ResultBuilderRewriter : public SyntacticElementSolutionApplication { /// have had the chance to adopt buildLimitedAvailability(), we'll upgrade /// this warning to an error. LLVM_NODISCARD - bool diagnoseMissingBuildWithAvailability(IfStmt *ifStmt) { + bool diagnoseMissingBuildWithAvailability(IfStmt *ifStmt, + TypeJoinExpr *join) { auto findAvailabilityCondition = [](StmtCondition stmtCond) -> const StmtConditionElement * { for (const auto &cond : stmtCond) { @@ -2017,27 +2018,10 @@ class ResultBuilderRewriter : public SyntacticElementSolutionApplication { return false; SourceLoc loc = availabilityCond->getStartLoc(); - Type bodyType; - if (availabilityCond->getAvailability()->isUnavailability()) { - BraceStmt *elseBody = nullptr; - // For #unavailable, we need to check the "else". - if (auto *innerIf = getAsStmt(ifStmt->getElseStmt())) { - elseBody = castToStmt(innerIf->getThenStmt()); - } else { - elseBody = castToStmt(ifStmt->getElseStmt()); - } - - Type elseBodyType = - solution.simplifyType(solution.getType(elseBody->getLastElement())); - bodyType = elseBodyType; - } else { - auto *thenBody = castToStmt(ifStmt->getThenStmt()); - Type thenBodyType = - solution.simplifyType(solution.getType(thenBody->getLastElement())); - bodyType = thenBodyType; - } - auto builderType = solution.simplifyType(Transform.builderType); + // Since all of the branches of `if` statement have to join into the same + // type we can just use the type of the join variable here. + Type bodyType = solution.getResolvedType(join->getVar()); return bodyType.findIf([&](Type type) { auto nominal = type->getAnyNominal(); diff --git a/test/Constraints/result_builder_availability.swift b/test/Constraints/result_builder_availability.swift index 0ed6c9ddb40d9..e992d0aa37bd3 100644 --- a/test/Constraints/result_builder_availability.swift +++ b/test/Constraints/result_builder_availability.swift @@ -103,8 +103,6 @@ tuplify(true) { cond in globalFuncAvailableOn10_52() } else if false { globalFuncAvailableOn10_52() - } else { - globalFuncAvailableOn10_52() } } } @@ -166,6 +164,11 @@ tuplifyWithAvailabilityErasure(true) { cond in } else { globalFuncAvailableOn10_52() } + + // https://github.com/apple/swift/issues/63764 + if #unavailable(OSX 10.52) { + cond // Ok + } } // rdar://97533700 – Make sure we can prefer an unavailable buildPartialBlock if From a08421eef71f6391cec3b9b803106b33d97f92bc Mon Sep 17 00:00:00 2001 From: Kyungwoo Lee Date: Tue, 21 Feb 2023 20:52:20 -0800 Subject: [PATCH 7/8] Fix Test in Release Build This fixes `ninja check-swift-validation` in the Release+Distribution build as the block name is set under `#ifndef NDEBUG`. --- test/Distributed/SIL/distributed_actor_resolve_sil.swift | 1 - .../SIL/distributed_id_system_ownership_verify_sil.swift | 1 - 2 files changed, 2 deletions(-) diff --git a/test/Distributed/SIL/distributed_actor_resolve_sil.swift b/test/Distributed/SIL/distributed_actor_resolve_sil.swift index 5c0629a14bbe8..e739b6a80a75c 100644 --- a/test/Distributed/SIL/distributed_actor_resolve_sil.swift +++ b/test/Distributed/SIL/distributed_actor_resolve_sil.swift @@ -20,7 +20,6 @@ distributed actor MyDistActor { // CHECK: bb0([[ACTOR_ID_ARG:%[0-9]+]] : $ActorAddress, [[SYSTEM_ARG:%[0-9]+]] : $FakeRoundtripActorSystem, [[TYPE_ARG:%[0-9]+]] : $@thick MyDistActor.Type): // CHECK: [[SYS_RESOLVE_RESULT:%[0-9]+]] = function_ref @$s27FakeDistributedActorSystems0a9RoundtripC6SystemC7resolve2id2asxSgAA0C7AddressV_xmtK0B00bC0RzlF -// CHECK: // makeProxyBB // CHECK: [[ACTOR_INSTANCE:%[0-9]+]] = builtin "initializeDistributedRemoteActor"(%7 : $@thick MyDistActor.Type) : $MyDistActor // CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [[ACTOR_INSTANCE]] : $MyDistActor, #MyDistActor.id // CHECK: retain_value [[ACTOR_ID_ARG]] : $ActorAddress diff --git a/test/Distributed/SIL/distributed_id_system_ownership_verify_sil.swift b/test/Distributed/SIL/distributed_id_system_ownership_verify_sil.swift index cde33e15464e0..2698772c3c9a1 100644 --- a/test/Distributed/SIL/distributed_id_system_ownership_verify_sil.swift +++ b/test/Distributed/SIL/distributed_id_system_ownership_verify_sil.swift @@ -38,7 +38,6 @@ distributed actor Greeter { // CHECK: bb0([[ADDRESS_ARG:%[0-9]+]] : $*NotLoadableActorAddress, [[SYSTEM_ARG:%[0-9]+]] : $FakeNotLoadableAddressActorSystem, [[TYPE_ARG:%[0-9]+]] : $@thick Greeter.Type): // CHECK: [[TYPE:%[0-9]+]] = metatype $@thick Greeter.Type -// CHECK: // makeProxyBB // CHECK: [[INSTANCE:%[0-9]+]] = builtin "initializeDistributedRemoteActor"([[TYPE]] : $@thick Greeter.Type) : $Greeter // CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [[INSTANCE]] : $Greeter, #Greeter.id // Note specifically that we don't [take] in the below copy_addr: From 038a9ea8bcd9ffde070eace90e55755753037cae Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 22 Feb 2023 08:36:25 +0000 Subject: [PATCH 8/8] Don't use tsd_private.h in compatibility libraries for ARM64_32. Apparently this issue also affects ARM64_32. rdar://105768086 --- include/swift/Threading/Impl/Darwin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/Threading/Impl/Darwin.h b/include/swift/Threading/Impl/Darwin.h index 1946aad36aad2..69e6352595ca7 100644 --- a/include/swift/Threading/Impl/Darwin.h +++ b/include/swift/Threading/Impl/Darwin.h @@ -186,7 +186,7 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { // On Darwin, we want to use the reserved keys #define SWIFT_THREADING_USE_RESERVED_TLS_KEYS 1 -#if !(SWIFT_THREADING_IS_COMPATIBILITY_LIBRARY && __ARM_ARCH_7K__) && __has_include() +#if !(SWIFT_THREADING_IS_COMPATIBILITY_LIBRARY && (__ARM_ARCH_7K__ || __ARM64_ARCH_8_32__)) && __has_include() } // namespace threading_impl } // namespace swift