Skip to content

[6.1] ConformanceChecker: Make actor_isolated_witness call out the protocol #78605

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ NOTE(opaque_return_type_declared_here,none,
"opaque return type declared here", ())
NOTE(default_value_declared_here,none,
"default value declared here", ())
NOTE(protocol_requirement_declared_here,none,
"requirement %0 declared here", (const ValueDecl *))

//------------------------------------------------------------------------------
// MARK: Constraint solver diagnostics
Expand Down Expand Up @@ -5643,9 +5645,10 @@ NOTE(shared_state_make_immutable,none,
NOTE(shared_state_nonisolated_unsafe,none,
"disable concurrency-safety checks if accesses are protected by an external synchronization mechanism", (const ValueDecl *))
ERROR(actor_isolated_witness,none,
"%select{|distributed }0%1 %kind2 cannot be used to satisfy %3 protocol "
"requirement",
(bool, ActorIsolation, const ValueDecl *, ActorIsolation))
"%select{|distributed }0%1 %kind2 cannot be used to satisfy %3 "
"requirement from protocol %base4",
(bool, ActorIsolation, const ValueDecl *, ActorIsolation,
const ValueDecl *))
ERROR(actor_cannot_conform_to_global_actor_protocol,none,
"actor %0 cannot conform to global actor isolated protocol %1",
(Type, Type))
Expand Down
21 changes: 14 additions & 7 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3396,10 +3396,12 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,

// Complain that this witness cannot conform to the requirement due to
// actor isolation.
witness->diagnose(diag::actor_isolated_witness,
isDistributed && !isDistributedDecl(witness),
refResult.isolation, witness, requirementIsolation)
.limitBehaviorUntilSwiftVersion(behavior, 6);
witness
->diagnose(diag::actor_isolated_witness,
isDistributed && !isDistributedDecl(witness),
refResult.isolation, witness, requirementIsolation,
Conformance->getProtocol())
.limitBehaviorUntilSwiftVersion(behavior, 6);

// If we need 'distributed' on the witness, add it.
if (missingOptions.contains(MissingFlags::WitnessDistributed)) {
Expand Down Expand Up @@ -3437,8 +3439,12 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
// If there are remaining options, they are missing async/throws on the
// requirement itself. If we have a source location for the requirement,
// provide those in a note.
if (missingOptions && requirement->getLoc().isValid() &&
isa<AbstractFunctionDecl>(requirement)) {

if (requirement->getLoc().isInvalid()) {
return std::nullopt;
}

if (missingOptions && isa<AbstractFunctionDecl>(requirement)) {
int suggestAddingModifiers = 0;
std::string modifiers;
if (missingOptions.contains(MissingFlags::RequirementAsync)) {
Expand Down Expand Up @@ -3484,7 +3490,8 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
diag.fixItInsert(insertLoc, modifiers);
}
} else {
requirement->diagnose(diag::decl_declared_here, requirement);
requirement->diagnose(diag::protocol_requirement_declared_here,
requirement);
}

return std::nullopt;
Expand Down
6 changes: 3 additions & 3 deletions test/Concurrency/actor_isolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,7 @@ protocol SGA_Proto {
// try to override a MA method with inferred isolation from a protocol requirement
class SGA_MA: MA, SGA_Proto {
// expected-error@+2 {{call to global actor 'SomeGlobalActor'-isolated global function 'onions_sga()' in a synchronous main actor-isolated context}}
// expected-warning@+1 {{main actor-isolated instance method 'method()' cannot be used to satisfy global actor 'SomeGlobalActor'-isolated protocol requirement}}
// expected-warning@+1 {{main actor-isolated instance method 'method()' cannot be used to satisfy global actor 'SomeGlobalActor'-isolated requirement from protocol 'SGA_Proto'}}
override func method() { onions_sga() }
// expected-note@-1{{add 'nonisolated' to 'method()' to make this instance method not isolated to the actor}}{{3-3=nonisolated }}
}
Expand Down Expand Up @@ -1612,13 +1612,13 @@ class OverridesNonsiolatedInit: SuperWithNonisolatedInit {
class NonSendable {}

protocol NonisolatedProtocol {
var ns: NonSendable { get } // expected-note {{'ns' declared here}}
var ns: NonSendable { get } // expected-note {{requirement 'ns' declared here}}
}

actor ActorWithNonSendableLet: NonisolatedProtocol {
// expected-note@-1{{add '@preconcurrency' to the 'NonisolatedProtocol' conformance to defer isolation checking to run time}}{{32-32=@preconcurrency }}

// expected-warning@+1 {{actor-isolated property 'ns' cannot be used to satisfy nonisolated protocol requirement; this is an error in the Swift 6 language mode}}
// expected-warning@+1 {{actor-isolated property 'ns' cannot be used to satisfy nonisolated requirement from protocol 'NonisolatedProtocol'; this is an error in the Swift 6 language mode}}
let ns = NonSendable()
}

Expand Down
4 changes: 2 additions & 2 deletions test/Concurrency/actor_isolation_unsafe.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ struct S3_P1: P1 {

struct S4_P1_not_quietly: P1 {
@SomeGlobalActor func onMainActor() { }
// expected-warning @-1 {{global actor 'SomeGlobalActor'-isolated instance method 'onMainActor()' cannot be used to satisfy main actor-isolated protocol requirement}}
// expected-warning @-1 {{global actor 'SomeGlobalActor'-isolated instance method 'onMainActor()' cannot be used to satisfy main actor-isolated requirement from protocol 'P1'}}
}

@SomeGlobalActor
struct S4_P1: P1 {
@SomeGlobalActor func onMainActor() { } // expected-warning{{global actor 'SomeGlobalActor'-isolated instance method 'onMainActor()' cannot be used to satisfy main actor-isolated protocol requirement}}
@SomeGlobalActor func onMainActor() { } // expected-warning{{global actor 'SomeGlobalActor'-isolated instance method 'onMainActor()' cannot be used to satisfy main actor-isolated requirement from protocol 'P1'}}
}

// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
Expand Down
4 changes: 2 additions & 2 deletions test/Concurrency/global_actor_inference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,14 @@ func testNotAllInP1(nap1: NotAllInP1) { // expected-note{{add '@SomeGlobalActor'
// Make sure we don't infer 'nonisolated' for stored properties.
@MainActor
protocol Interface {
nonisolated var baz: Int { get } // expected-note{{'baz' declared here}}
nonisolated var baz: Int { get } // expected-note{{requirement 'baz' declared here}}
}

@MainActor
class Object: Interface {
// expected-note@-1{{add '@preconcurrency' to the 'Interface' conformance to defer isolation checking to run time}}{{15-15=@preconcurrency }}

var baz: Int = 42 // expected-warning{{main actor-isolated property 'baz' cannot be used to satisfy nonisolated protocol requirement}}
var baz: Int = 42 // expected-warning{{main actor-isolated property 'baz' cannot be used to satisfy nonisolated requirement from protocol 'Interface'}}
}


Expand Down
4 changes: 2 additions & 2 deletions test/Concurrency/global_actor_inference_swift6.swift
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ struct S3: InferenceConflict {

extension S3 {
func f() { }
// expected-error@-1{{global actor 'SomeGlobalActor'-isolated instance method 'f()' cannot be used to satisfy main actor-isolated protocol requirement}}
// expected-error@-1{{global actor 'SomeGlobalActor'-isolated instance method 'f()' cannot be used to satisfy main actor-isolated requirement from protocol 'InferMainActorInherited'}}
//expected-note@-2{{add 'nonisolated' to 'f()' to make this instance method not isolated to the actor}}
}

Expand Down Expand Up @@ -208,7 +208,7 @@ class C2: MainActorSuperclass, InferenceConflictWithSuperclass {
func f() {}

func g() {}
// expected-error@-1 {{main actor-isolated instance method 'g()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1 {{main actor-isolated instance method 'g()' cannot be used to satisfy nonisolated requirement from protocol 'InferenceConflictWithSuperclass'}}
// expected-note@-2 {{add 'nonisolated' to 'g()' to make this instance method not isolated to the actor}}
}

Expand Down
14 changes: 7 additions & 7 deletions test/Concurrency/preconcurrency_conformances.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ final class K : @preconcurrency Initializable {
@MainActor
final class MainActorK: Initializable {
// expected-note@-1{{add '@preconcurrency' to the 'Initializable' conformance to defer isolation checking to run time}}{{25-25=@preconcurrency }}
init() { } // expected-warning{{main actor-isolated initializer 'init()' cannot be used to satisfy nonisolated protocol requirement}}
init() { } // expected-warning{{main actor-isolated initializer 'init()' cannot be used to satisfy nonisolated requirement from protocol 'Initializable'}}
// expected-note@-1{{add 'nonisolated' to 'init()' to make this initializer not isolated to the actor}}
}

Expand All @@ -130,7 +130,7 @@ struct GlobalActor {
protocol WithIndividuallyIsolatedRequirements {
@MainActor var a: Int { get set }
@GlobalActor var b: Int { get set }
// expected-note@-1 {{'b' declared here}}
// expected-note@-1 {{requirement 'b' declared here}}

@GlobalActor func test()
// expected-note@-1 {{mark the protocol requirement 'test()' 'async' to allow actor-isolated conformances}}
Expand All @@ -144,21 +144,21 @@ do {
var a: Int = 42

@MainActor var b: Int {
// expected-warning@-1 {{main actor-isolated property 'b' cannot be used to satisfy global actor 'GlobalActor'-isolated protocol requirement}}
// expected-warning@-1 {{main actor-isolated property 'b' cannot be used to satisfy global actor 'GlobalActor'-isolated requirement from protocol 'WithIndividuallyIsolatedRequirements'}}
get { 0 }
set {}
}

@MainActor func test() {
// expected-warning@-1 {{main actor-isolated instance method 'test()' cannot be used to satisfy global actor 'GlobalActor'-isolated protocol requirement}}
// expected-warning@-1 {{main actor-isolated instance method 'test()' cannot be used to satisfy global actor 'GlobalActor'-isolated requirement from protocol 'WithIndividuallyIsolatedRequirements'}}
}
}
}

@MainActor
protocol WithNonIsolated {
var prop: Int { get set }
// expected-note@-1 {{'prop' declared here}}
// expected-note@-1 {{requirement 'prop' declared here}}
nonisolated func test()
// expected-note@-1 {{mark the protocol requirement 'test()' 'async' to allow actor-isolated conformances}}
}
Expand All @@ -168,10 +168,10 @@ do {
// expected-warning@-1 {{@preconcurrency attribute on conformance to 'WithNonIsolated' has no effect}}{{38-54=}}

@GlobalActor var prop: Int = 42
// expected-warning@-1 {{global actor 'GlobalActor'-isolated property 'prop' cannot be used to satisfy main actor-isolated protocol requirement}}
// expected-warning@-1 {{global actor 'GlobalActor'-isolated property 'prop' cannot be used to satisfy main actor-isolated requirement from protocol 'WithNonIsolated'}}

@MainActor func test() {}
// expected-warning@-1 {{main actor-isolated instance method 'test()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-warning@-1 {{main actor-isolated instance method 'test()' cannot be used to satisfy nonisolated requirement from protocol 'WithNonIsolated'}}
}
}

Expand Down
2 changes: 1 addition & 1 deletion test/Concurrency/predates_concurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ extension MainActorPreconcurrency: NotIsolated {
// expected-complete-tns-note@-2{{add '@preconcurrency' to the 'NotIsolated' conformance to defer isolation checking to run time}}{{36-36=@preconcurrency }}

func requirement() {}
// expected-complete-tns-warning@-1 {{main actor-isolated instance method 'requirement()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-complete-tns-warning@-1 {{main actor-isolated instance method 'requirement()' cannot be used to satisfy nonisolated requirement from protocol 'NotIsolated'}}
// expected-complete-tns-note@-2 {{add 'nonisolated' to 'requirement()' to make this instance method not isolated to the actor}}
// expected-complete-tns-note@-3 {{calls to instance method 'requirement()' from outside of its actor context are implicitly asynchronous}}

Expand Down
16 changes: 8 additions & 8 deletions test/Distributed/distributed_protocol_isolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,22 +109,22 @@ distributed actor Nope1_StrictlyLocal: StrictlyLocal {
// expected-note@-1{{add '@preconcurrency' to the 'StrictlyLocal' conformance to defer isolation checking to run time}}

func local() {}
// expected-error@-1{{distributed actor-isolated instance method 'local()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{distributed actor-isolated instance method 'local()' cannot be used to satisfy nonisolated requirement from protocol 'StrictlyLocal'}}
// expected-note@-2{{add 'nonisolated' to 'local()' to make this instance method not isolated to the actor}}
func localThrows() throws {}
// expected-error@-1{{distributed actor-isolated instance method 'localThrows()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{distributed actor-isolated instance method 'localThrows()' cannot be used to satisfy nonisolated requirement from protocol 'StrictlyLocal'}}
// expected-note@-2{{add 'nonisolated' to 'localThrows()' to make this instance method not isolated to the actor}}
func localAsync() async {}
// expected-error@-1{{distributed actor-isolated instance method 'localAsync()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{distributed actor-isolated instance method 'localAsync()' cannot be used to satisfy nonisolated requirement from protocol 'StrictlyLocal'}}
// expected-note@-2{{add 'nonisolated' to 'localAsync()' to make this instance method not isolated to the actor}}
}
distributed actor Nope2_StrictlyLocal: StrictlyLocal {
distributed func local() {}
// expected-error@-1{{actor-isolated distributed instance method 'local()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated distributed instance method 'local()' cannot be used to satisfy nonisolated requirement from protocol 'StrictlyLocal'}}
distributed func localThrows() throws {}
// expected-error@-1{{actor-isolated distributed instance method 'localThrows()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated distributed instance method 'localThrows()' cannot be used to satisfy nonisolated requirement from protocol 'StrictlyLocal'}}
distributed func localAsync() async {}
// expected-error@-1{{actor-isolated distributed instance method 'localAsync()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated distributed instance method 'localAsync()' cannot be used to satisfy nonisolated requirement from protocol 'StrictlyLocal'}}
}
distributed actor OK_StrictlyLocal: StrictlyLocal {
nonisolated func local() {}
Expand Down Expand Up @@ -162,7 +162,7 @@ distributed actor Nope1_AsyncThrowsAll: AsyncThrowsAll {
// expected-note@-1{{add '@preconcurrency' to the 'AsyncThrowsAll' conformance to defer isolation checking to run time}}

func maybe(param: String, int: Int) async throws -> Int { 111 }
// expected-error@-1{{distributed actor-isolated instance method 'maybe(param:int:)' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{distributed actor-isolated instance method 'maybe(param:int:)' cannot be used to satisfy nonisolated requirement from protocol 'AsyncThrowsAll'}}
// expected-note@-2{{add 'nonisolated' to 'maybe(param:int:)' to make this instance method not isolated to the actor}}
// expected-note@-3{{add 'distributed' to 'maybe(param:int:)' to make this instance method satisfy the protocol requirement}}
}
Expand Down Expand Up @@ -209,7 +209,7 @@ distributed actor DA_TerminationWatchingA: TerminationWatchingA {
// expected-note@-1{{add '@preconcurrency' to the 'TerminationWatchingA' conformance to defer isolation checking to run time}}

func terminated(a: String) { }
// expected-error@-1{{distributed actor-isolated instance method 'terminated(a:)' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{distributed actor-isolated instance method 'terminated(a:)' cannot be used to satisfy nonisolated requirement from protocol 'TerminationWatchingA'}}
// expected-note@-2{{add 'nonisolated' to 'terminated(a:)' to make this instance method not isolated to the actor}}
}

Expand Down
20 changes: 10 additions & 10 deletions test/decl/class/actor/conformance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ extension MyActor: AsyncProtocol {
}

protocol SyncProtocol {
var propertyA: Int { get } // expected-note{{'propertyA' declared here}}
var propertyB: Int { get set } // expected-note{{'propertyB' declared here}}
var propertyA: Int { get } // expected-note{{requirement 'propertyA' declared here}}
var propertyB: Int { get set } // expected-note{{requirement 'propertyB' declared here}}

func syncMethodA() // expected-note{{mark the protocol requirement 'syncMethodA()' 'async' to allow actor-isolated conformances}}{{21-21= async}}

Expand All @@ -28,7 +28,7 @@ protocol SyncProtocol {

func syncMethodG() throws -> Void // expected-note{{mark the protocol requirement 'syncMethodG()' 'async' to allow actor-isolated conformances}}{{22-22=async }}

subscript (index: Int) -> String { get } // expected-note{{'subscript(_:)' declared here}}
subscript (index: Int) -> String { get } // expected-note{{requirement 'subscript(_:)' declared here}}

static func staticMethod()
static var staticProperty: Int { get }
Expand All @@ -39,33 +39,33 @@ actor OtherActor: SyncProtocol {
// expected-note@-1{{add '@preconcurrency' to the 'SyncProtocol' conformance to defer isolation checking to run time}}{{19-19=@preconcurrency }}

var propertyB: Int = 17
// expected-error@-1{{actor-isolated property 'propertyB' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated property 'propertyB' cannot be used to satisfy nonisolated requirement from protocol 'SyncProtocol'}}

var propertyA: Int { 17 }
// expected-error@-1{{actor-isolated property 'propertyA' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated property 'propertyA' cannot be used to satisfy nonisolated requirement from protocol 'SyncProtocol'}}

func syncMethodA() { }
// expected-error@-1{{actor-isolated instance method 'syncMethodA()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated instance method 'syncMethodA()' cannot be used to satisfy nonisolated requirement from protocol 'SyncProtocol'}}
// expected-note@-2{{add 'nonisolated' to 'syncMethodA()' to make this instance method not isolated to the actor}}{{3-3=nonisolated }}

// nonisolated methods are okay.
// FIXME: Consider suggesting nonisolated if this didn't match.
nonisolated func syncMethodC() -> Int { 5 }

func syncMethodE() -> Void { }
// expected-error@-1{{actor-isolated instance method 'syncMethodE()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated instance method 'syncMethodE()' cannot be used to satisfy nonisolated requirement from protocol 'SyncProtocol'}}
// expected-note@-2{{add 'nonisolated' to 'syncMethodE()' to make this instance method not isolated to the actor}}{{3-3=nonisolated }}

func syncMethodF(param: String) -> Int { 5 }
// expected-error@-1{{actor-isolated instance method 'syncMethodF(param:)' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated instance method 'syncMethodF(param:)' cannot be used to satisfy nonisolated requirement from protocol 'SyncProtocol'}}
// expected-note@-2{{add 'nonisolated' to 'syncMethodF(param:)' to make this instance method not isolated to the actor}}{{3-3=nonisolated }}

func syncMethodG() { }
// expected-error@-1{{actor-isolated instance method 'syncMethodG()' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated instance method 'syncMethodG()' cannot be used to satisfy nonisolated requirement from protocol 'SyncProtocol'}}
// expected-note@-2{{add 'nonisolated' to 'syncMethodG()' to make this instance method not isolated to the actor}}{{3-3=nonisolated }}

subscript (index: Int) -> String { "\(index)" }
// expected-error@-1{{actor-isolated subscript 'subscript(_:)' cannot be used to satisfy nonisolated protocol requirement}}
// expected-error@-1{{actor-isolated subscript 'subscript(_:)' cannot be used to satisfy nonisolated requirement from protocol 'SyncProtocol'}}
// expected-note@-2{{add 'nonisolated' to 'subscript(_:)' to make this subscript not isolated to the actor}}{{3-3=nonisolated }}

// Static methods and properties are okay.
Expand Down
Loading