From e032f33cfb92962f30700990b958939135ee64e4 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 7 Jul 2025 15:48:46 -0700 Subject: [PATCH 1/2] [Concurrency] Prevent use of `nonisolated(nonsending)` and `@concurrent` on `@_inheritActorContext` parameters `@_inheritActorContext` is a form of isolation which precludes direct use of inference of `nonisolated(nonsending)` and `@concurrent` just like other isolation attributes/modifiers would i.e. `isolated` or `@isolated(any)`. --- include/swift/AST/DiagnosticsSema.def | 8 ++++ lib/Sema/TypeCheckAttr.cpp | 3 ++ lib/Sema/TypeCheckDecl.cpp | 3 ++ lib/Sema/TypeCheckType.cpp | 37 +++++++++++++------ lib/Sema/TypeCheckType.h | 3 ++ .../attr_execution/attr_execution.swift | 13 +++++++ .../attr_execution/migration_mode.swift | 6 +++ .../nonisolated_nonsending_by_default.swift | 5 +++ test/Parse/execution_behavior_attrs.swift | 7 ++++ 9 files changed, 73 insertions(+), 12 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2fb3d000e0f3f..8b1d48772d6af 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8702,6 +8702,14 @@ ERROR(inherit_actor_context_only_on_async_or_isolation_erased_params,none, "asynchronous function types", (DeclAttribute)) +ERROR(inherit_actor_context_with_concurrent,none, + "'@_inheritActorContext' attribute cannot be used together with %0", + (const TypeAttribute *)) + +ERROR(inherit_actor_context_with_nonisolated_nonsending,none, + "'@_inheritActorContext' attribute cannot be used together with %0", + (TypeRepr *)) + //===----------------------------------------------------------------------===// // MARK: @concurrent and nonisolated(nonsending) attributes //===----------------------------------------------------------------------===// diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 48f3242d61b79..8d475ec630ea6 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -7871,6 +7871,9 @@ void AttributeChecker::visitInheritActorContextAttr( return; auto paramTy = P->getInterfaceType(); + if (paramTy->hasError()) + return; + auto *funcTy = paramTy->lookThroughAllOptionalTypes()->getAs(); if (!funcTy) { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 2540469873b4f..aff024004c3f1 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2337,6 +2337,9 @@ static Type validateParameterType(ParamDecl *decl) { if (dc->isInSpecializeExtensionContext()) options |= TypeResolutionFlags::AllowUsableFromInline; + if (decl->getAttrs().hasAttribute()) + options |= TypeResolutionFlags::InheritsActorContext; + Type Ty; auto *nestedRepr = decl->getTypeRepr(); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 1fc7ccd5e1d97..a9f4d968a92f0 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4219,6 +4219,11 @@ NeverNullType TypeResolver::resolveASTFunctionType( attr->getAttrName()); } + if (options.contains(TypeResolutionFlags::InheritsActorContext)) { + diagnoseInvalid(repr, attr->getAttrLoc(), + diag::inherit_actor_context_with_concurrent, attr); + } + switch (isolation.getKind()) { case FunctionTypeIsolation::Kind::NonIsolated: break; @@ -4265,18 +4270,20 @@ NeverNullType TypeResolver::resolveASTFunctionType( if (!repr->isInvalid()) isolation = FunctionTypeIsolation::forNonIsolated(); } else if (!getWithoutClaiming(attrs)) { - // Infer async function type as `nonisolated(nonsending)` if there is - // no `@concurrent` or `nonisolated(nonsending)` attribute and isolation - // is nonisolated. - if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) && - repr->isAsync() && isolation.isNonIsolated()) { - isolation = FunctionTypeIsolation::forNonIsolatedCaller(); - } else if (ctx.LangOpts - .getFeatureState(Feature::NonisolatedNonsendingByDefault) - .isEnabledForMigration()) { - // Diagnose only in the interface stage, which is run once. - if (inStage(TypeResolutionStage::Interface)) { - warnAboutNewNonisolatedAsyncExecutionBehavior(ctx, repr, isolation); + if (!options.contains(TypeResolutionFlags::InheritsActorContext)) { + // Infer async function type as `nonisolated(nonsending)` if there is + // no `@concurrent` or `nonisolated(nonsending)` attribute and isolation + // is nonisolated. + if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) && + repr->isAsync() && isolation.isNonIsolated()) { + isolation = FunctionTypeIsolation::forNonIsolatedCaller(); + } else if (ctx.LangOpts + .getFeatureState(Feature::NonisolatedNonsendingByDefault) + .isEnabledForMigration()) { + // Diagnose only in the interface stage, which is run once. + if (inStage(TypeResolutionStage::Interface)) { + warnAboutNewNonisolatedAsyncExecutionBehavior(ctx, repr, isolation); + } } } } @@ -5326,6 +5333,12 @@ TypeResolver::resolveCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *repr, return ErrorType::get(getASTContext()); } + if (options.contains(TypeResolutionFlags::InheritsActorContext)) { + diagnoseInvalid(repr, repr->getLoc(), + diag::inherit_actor_context_with_nonisolated_nonsending, + repr); + } + if (!fnType->isAsync()) { diagnoseInvalid(repr, repr->getStartLoc(), diag::nonisolated_nonsending_only_on_async, repr); diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index ecf18d2f05e00..9e622246bde17 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -87,6 +87,9 @@ enum class TypeResolutionFlags : uint16_t { /// Whether the immediate context has an @escaping attribute. DirectEscaping = 1 << 14, + + /// We are in a `@_inheritActorContext` parameter declaration. + InheritsActorContext = 1 << 15, }; /// Type resolution contexts that require special handling. diff --git a/test/Concurrency/attr_execution/attr_execution.swift b/test/Concurrency/attr_execution/attr_execution.swift index 93702c1c8aacb..0c409a760534e 100644 --- a/test/Concurrency/attr_execution/attr_execution.swift +++ b/test/Concurrency/attr_execution/attr_execution.swift @@ -80,3 +80,16 @@ func testClosure() { takesClosure { } } + +// CHECK-LABEL: // testInheritsActor(fn:) +// CHECK: Isolation: global_actor. type: MainActor +// CHECK: sil hidden [ossa] @$s14attr_execution17testInheritsActor2fnyyyYaYbXE_tYaF : $@convention(thin) @async (@guaranteed @noescape @Sendable @async @callee_guaranteed () -> ()) -> () +// CHECK: bb0([[FN:%.*]] : @guaranteed $@noescape @Sendable @async @callee_guaranteed () -> ()): +// CHECK: [[FN_COPY:%.*]] = copy_value [[FN]] +// CHECK: [[BORROWED_FN_COPY:%.*]] = begin_borrow [[FN_COPY]] +// CHECK: apply [[BORROWED_FN_COPY]]() : $@noescape @Sendable @async @callee_guaranteed () -> () +// CHECK: } // end sil function '$s14attr_execution17testInheritsActor2fnyyyYaYbXE_tYaF' +@MainActor +func testInheritsActor(@_inheritActorContext(always) fn: @Sendable () async -> Void) async { + await fn() +} diff --git a/test/Concurrency/attr_execution/migration_mode.swift b/test/Concurrency/attr_execution/migration_mode.swift index 08929d2186651..25d08906ac06e 100644 --- a/test/Concurrency/attr_execution/migration_mode.swift +++ b/test/Concurrency/attr_execution/migration_mode.swift @@ -393,3 +393,9 @@ do { } } } + +// @_inheritActorContext prevents `nonisolated(nonsending)` inference. +do { + func testInherit1(@_inheritActorContext _: @Sendable () async -> Void) {} + func testInherit2(@_inheritActorContext(always) _: (@Sendable () async -> Void)?) {} +} diff --git a/test/Concurrency/attr_execution/nonisolated_nonsending_by_default.swift b/test/Concurrency/attr_execution/nonisolated_nonsending_by_default.swift index 6c240ec88f364..2a94b64d30819 100644 --- a/test/Concurrency/attr_execution/nonisolated_nonsending_by_default.swift +++ b/test/Concurrency/attr_execution/nonisolated_nonsending_by_default.swift @@ -8,3 +8,8 @@ func testCasts() { // expected-error@-1 {{cannot convert value of type '(nonisolated(nonsending) () async -> ()).Type' to type '(() async -> ()).Type' in coercion}} _ = defaultedType as (nonisolated(nonsending) () async -> ()).Type // Ok } + +func test(@_inheritActorContext fn: @Sendable () async -> Void) { + let _: Int = fn + // expected-error@-1 {{cannot convert value of type '@Sendable () async -> Void' to specified type 'Int'}} +} diff --git a/test/Parse/execution_behavior_attrs.swift b/test/Parse/execution_behavior_attrs.swift index 6f0a1035ff6c0..2ad748d1f289d 100644 --- a/test/Parse/execution_behavior_attrs.swift +++ b/test/Parse/execution_behavior_attrs.swift @@ -84,3 +84,10 @@ do { nonisolated(0) // expected-warning {{result of call to 'nonisolated' is unused}} print("hello") } + +do { + func testActorInheriting1(@_inheritActorContext _: @concurrent @Sendable () async -> Void) {} + // expected-error@-1 {{'@_inheritActorContext' attribute cannot be used together with '@concurrent'}} + func testActorInheriting2(@_inheritActorContext _: nonisolated(nonsending) @Sendable () async -> Void) {} + // expected-error@-1 {{'@_inheritActorContext' attribute cannot be used together with 'nonisolated(nonsending)'}} +} From 648bb8fe3027a57e5ebd743c749744472f21b7b2 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 3 Jul 2025 16:39:31 -0700 Subject: [PATCH 2/2] [concurrency] Perform some fixes so that transfernonsendable_closureliterals_isolationinference.swift now passes. The reason why this failed is that concurrently to @xedin landing 79af04ccc41faa717cfa3666e492f396993fcad1, I enabled NonisolatedNonsendingByDefault on a bunch of other tests. That change broke the test and so we needed to fix it. This commit fixes a few issues that were exposed: 1. We do not propagate nonisolated(nonsending) into a closure if its inferred context isolation is global actor isolated or if the closure captures an isolated parameter. We previously just always inferred nonisolated(nonsending). Unfortunately since we do not yet have capture information in CSApply, this required us to put the isolation change into TypeCheckConcurrency.cpp and basically have function conversions of the form: ``` (function_conversion_expr type="nonisolated(nonsending) () async -> Void" (closure_expr type="() async -> ()" isolated_to_caller_isolation)) ``` Notice how we have a function conversion to nonisolated(nonsending) from a closure expr that has an isolation that is isolated_to_caller. 2. With this in hand, we found that this pattern caused us to first thunk a nonisolated(nonsending) function to an @concurrent function and then thunk that back to nonisolated(nonsending), causing the final function to always be concurrent. I put into SILGen a peephole that recognizes this pattern and emits the correct code. 3. With that in hand, we found that we were emitting nonisolated(nonsending) parameters for inheritActorContext functions. This was then fixed by @xedin in With all this in hand, closure literal isolation and all of the other RBI tests with nonisolated(nonsending) enabled pass. rdar://154969621 --- lib/SILGen/SILGenExpr.cpp | 64 +++++++++++++++++++ lib/Sema/CSApply.cpp | 17 ----- lib/Sema/TypeCheckConcurrency.cpp | 29 ++++++++- .../attr_execution/attr_execution.swift | 6 +- .../attr_execution/conversions_silgen.swift | 6 +- ...e_closureliterals_isolationinference.swift | 6 +- 6 files changed, 99 insertions(+), 29 deletions(-) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 148cf3514c80f..0dcda6d0fbf7f 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -497,6 +497,10 @@ namespace { RValue emitFunctionCvtFromExecutionCallerToGlobalActor(FunctionConversionExpr *E, SGFContext C); + + RValue emitFunctionCvtForNonisolatedNonsendingClosureExpr( + FunctionConversionExpr *E, SGFContext C); + RValue visitActorIsolationErasureExpr(ActorIsolationErasureExpr *E, SGFContext C); RValue visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E, @@ -2031,6 +2035,44 @@ RValueEmitter::emitFunctionCvtToExecutionCaller(FunctionConversionExpr *e, return RValue(SGF, e, destType, result); } +RValue RValueEmitter::emitFunctionCvtForNonisolatedNonsendingClosureExpr( + FunctionConversionExpr *E, SGFContext C) { + // The specific AST pattern for this looks as follows: + // + // (function_conversion_expr type="nonisolated(nonsending) () async -> Void" + // (closure_expr type="() async -> ()" isolated_to_caller_isolation)) + CanAnyFunctionType destType = + cast(E->getType()->getCanonicalType()); + auto subExpr = E->getSubExpr()->getSemanticsProvidingExpr(); + + // If we do not have a closure or if that closure is not caller isolation + // inheriting, bail. + auto *closureExpr = dyn_cast(subExpr); + if (!closureExpr || + !closureExpr->getActorIsolation().isCallerIsolationInheriting()) + return RValue(); + + // Then grab our closure type... make sure it is non isolated and then make + // sure it is the same as our destType but with nonisolated. + CanAnyFunctionType closureType = + cast(closureExpr->getType()->getCanonicalType()); + if (!closureType->getIsolation().isNonIsolated() || + closureType != + destType->withIsolation(FunctionTypeIsolation::forNonIsolated()) + ->getCanonicalType()) + return RValue(); + + // NOTE: This is a partial inline of getClosureTypeInfo. We do this so we have + // more control and make this change less viral in the compiler for 6.2. + auto newExtInfo = closureType->getExtInfo().withIsolation( + FunctionTypeIsolation::forNonIsolatedCaller()); + closureType = closureType.withExtInfo(newExtInfo); + auto info = SGF.getFunctionTypeInfo(closureType); + + auto closure = emitClosureReference(closureExpr, info); + return RValue(SGF, closureExpr, destType, closure); +} + RValue RValueEmitter::emitFunctionCvtFromExecutionCallerToGlobalActor( FunctionConversionExpr *e, SGFContext C) { // We are pattern matching a conversion sequence like the following: @@ -2142,6 +2184,28 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e, // TODO: Move this up when we can emit closures directly with C calling // convention. auto subExpr = e->getSubExpr()->getSemanticsProvidingExpr(); + + // Before we go any further into emitting the convert function expr, see if + // our SubExpr is a ClosureExpr with the exact same type as our + // FunctionConversionExpr except with the FunctionConversionExpr adding + // nonisolated(nonsending). Then see if the ClosureExpr itself (even though it + // is not nonisolated(nonsending) typed is considered to have + // nonisolated(nonsending) isolation. In such a case, emit the closure + // directly. We are going to handle it especially in closure emission to work + // around the missing information in the type. + // + // DISCUSSION: We need to do this here since in the Expression TypeChecker we + // do not have access to capture information when we would normally want to + // mark the closure type as being nonisolated(nonsending). As a result, we + // cannot know if the nonisolated(nonsending) should be overridden by for + // example an actor that is captured by the closure. So to work around this in + // Sema, we still mark the ClosureExpr as having the appropriate isolation + // even though its type does not have it... and then we work around this here + // and also in getClosureTypeInfo. + if (destType->getIsolation().isNonIsolatedCaller()) + if (auto rv = emitFunctionCvtForNonisolatedNonsendingClosureExpr(e, C)) + return rv; + // Look through `as` type ascriptions that don't induce bridging too. while (auto subCoerce = dyn_cast(subExpr)) { // Coercions that introduce bridging aren't simple type ascriptions. diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 077785c16b62a..a6d86969ff3f7 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7849,23 +7849,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, } } - // If we have a ClosureExpr, then we can safely propagate the - // 'nonisolated(nonsending)' isolation if it's not explicitly - // marked as `@concurrent`. - if (toEI.getIsolation().isNonIsolatedCaller() && - (fromEI.getIsolation().isNonIsolated() && - !isClosureMarkedAsConcurrent(expr))) { - auto newFromFuncType = fromFunc->withIsolation( - FunctionTypeIsolation::forNonIsolatedCaller()); - if (applyTypeToClosureExpr(cs, expr, newFromFuncType)) { - fromFunc = newFromFuncType->castTo(); - // Propagating 'nonisolated(nonsending)' might have satisfied the entire - // conversion. If so, we're done, otherwise keep converting. - if (fromFunc->isEqual(toType)) - return expr; - } - } - if (ctx.LangOpts.isDynamicActorIsolationCheckingEnabled()) { // Passing a synchronous global actor-isolated function value and // parameter that expects a synchronous non-isolated function type could diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index af6f0f4d9d7ba..028cd7f7ac262 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4964,8 +4964,33 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation( closure->getParent(), getClosureActorIsolation); preconcurrency |= parentIsolation.preconcurrency(); - return computeClosureIsolationFromParent(closure, parentIsolation, - checkIsolatedCapture); + auto normalIsolation = computeClosureIsolationFromParent( + closure, parentIsolation, checkIsolatedCapture); + + // The solver has to be conservative and produce a conversion to + // `nonisolated(nonsending)` because at solution application time + // we don't yet know whether there are any captures which would + // make closure isolated. + // + // At this point we know that closure is not explicitly annotated with + // global actor, nonisolated/@concurrent attributes and doesn't have + // isolated parameters. If our closure is nonisolated and we have a + // conversion to nonisolated(nonsending), then we should respect that. + if (auto *explicitClosure = dyn_cast(closure); + !normalIsolation.isGlobalActor()) { + if (auto *fce = + dyn_cast_or_null(Parent.getAsExpr())) { + auto expectedIsolation = + fce->getType()->castTo()->getIsolation(); + if (expectedIsolation.isNonIsolatedCaller()) { + auto captureInfo = explicitClosure->getCaptureInfo(); + if (!captureInfo.getIsolatedParamCapture()) + return ActorIsolation::forCallerIsolationInheriting(); + } + } + } + + return normalIsolation; }(); // Apply computed preconcurrency. diff --git a/test/Concurrency/attr_execution/attr_execution.swift b/test/Concurrency/attr_execution/attr_execution.swift index 0c409a760534e..bc848de3c3889 100644 --- a/test/Concurrency/attr_execution/attr_execution.swift +++ b/test/Concurrency/attr_execution/attr_execution.swift @@ -18,7 +18,7 @@ func callerTest() async {} struct Test { // CHECK-LABEL: // closure #1 in variable initialization expression of Test.x // CHECK: // Isolation: caller_isolation_inheriting - // CHECK: sil private [ossa] @$s14attr_execution4TestV1xyyYaYCcvpfiyyYaYCcfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () + // CHECK: sil private [ossa] @$s14attr_execution4TestV1xyyYaYCcvpfiyyYacfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () var x: () async -> Void = {} // CHECK-LABEL: // Test.test() @@ -67,7 +67,7 @@ func takesClosure(fn: () async -> Void) { } // CHECK-LABEL: sil hidden [ossa] @$s14attr_execution11testClosureyyF : $@convention(thin) () -> () -// CHECK: [[CLOSURE:%.*]] = function_ref @$s14attr_execution11testClosureyyFyyYaYCXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () +// CHECK: [[CLOSURE:%.*]] = function_ref @$s14attr_execution11testClosureyyFyyYaXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () // CHECK: [[THUNKED_CLOSURE:%.*]] = thin_to_thick_function %0 to $@noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () // CHECK: [[TAKES_CLOSURE:%.*]] = function_ref @$s14attr_execution12takesClosure2fnyyyYaYCXE_tF : $@convention(thin) (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () // CHECK: apply [[TAKES_CLOSURE]]([[THUNKED_CLOSURE]]) @@ -75,7 +75,7 @@ func takesClosure(fn: () async -> Void) { // CHECK-LABEL: // closure #1 in testClosure() // CHECK: // Isolation: caller_isolation_inheriting -// CHECK: sil private [ossa] @$s14attr_execution11testClosureyyFyyYaYCXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () +// CHECK: sil private [ossa] @$s14attr_execution11testClosureyyFyyYaXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () func testClosure() { takesClosure { } diff --git a/test/Concurrency/attr_execution/conversions_silgen.swift b/test/Concurrency/attr_execution/conversions_silgen.swift index 7b97a59fc57e5..2271c686ed172 100644 --- a/test/Concurrency/attr_execution/conversions_silgen.swift +++ b/test/Concurrency/attr_execution/conversions_silgen.swift @@ -421,7 +421,7 @@ func conversionsFromSyncToAsync(_ x: @escaping @Sendable (NonSendableKlass) -> V } func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) async -> Void) { - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaYCcfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYacfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional): // CHECK: hop_to_executor [[EXECUTOR]] let _: nonisolated(nonsending) () async -> Void = { @@ -430,7 +430,7 @@ func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) asy func testParam(_: nonisolated(nonsending) () async throws -> Void) {} - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaYCXEfU0_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> @error any Error + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaXEfU0_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional): // CHECK: hop_to_executor [[EXECUTOR]] testParam { 42 } @@ -440,7 +440,7 @@ func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) asy // CHECK: hop_to_executor [[GENERIC_EXECUTOR]] testParam { @concurrent in 42 } - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFySiYaYCcfU2_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, Int) -> () + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFySiYacfU2_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, Int) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional, %1 : $Int): // CHECK: hop_to_executor [[EXECUTOR]] fn = { _ in } diff --git a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift index 150c8c16ad680..fb3669656dfd4 100644 --- a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift +++ b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift @@ -1,14 +1,12 @@ -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - 2>/dev/null | %FileCheck %s // RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -verify-additional-prefix ni- -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - -enable-upcoming-feature NonisolatedNonsendingByDefault | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - -enable-upcoming-feature NonisolatedNonsendingByDefault 2>/dev/null | %FileCheck %s // RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault -verify-additional-prefix ni-ns- // REQUIRES: concurrency // REQUIRES: asserts // REQUIRES: swift_feature_NonisolatedNonsendingByDefault -// REQUIRES: rdar154969621 - // This test validates the behavior of transfernonsendable around // closure literals