mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Forming an isolated conformance to a SendableMetatype-inherting protocol opens up a soundness hole any time the conformance is used. Reword the recently-introduced diagnostic for this case and promote it to an error (except when it's preconcurrency). Fixes rdar://154808002.
256 lines
10 KiB
Swift
256 lines
10 KiB
Swift
// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s
|
|
|
|
// REQUIRES: concurrency
|
|
|
|
protocol P {
|
|
func f()
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Definition of isolated conformances
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// expected-warning@+4{{conformance of 'CWithNonIsolated' to protocol 'P' crosses into main actor-isolated code and can cause data races}}
|
|
// expected-note@+3{{mark all declarations used in the conformance 'nonisolated'}}
|
|
// expected-note@+2{{isolate this conformance to the main actor with '@MainActor'}}{{25-25=@MainActor }}
|
|
@MainActor
|
|
class CWithNonIsolated: P {
|
|
// expected-note@-1{{turn data races into runtime errors with '@preconcurrency'}}{{25-25=@preconcurrency }}
|
|
func f() { } // expected-note{{main actor-isolated instance method 'f()' cannot satisfy nonisolated requirement}}
|
|
}
|
|
|
|
// Make sure we correctly apply the conformance attribute for more complex
|
|
// inheritance entries.
|
|
do {
|
|
protocol EmptyP {}
|
|
struct Nested {
|
|
protocol P { func f() }
|
|
protocol Q { func f() }
|
|
}
|
|
do {
|
|
// expected-warning@+4 {{conformance of 'S' to protocol 'P' crosses into main actor-isolated code and can cause data races}}
|
|
// expected-note@+3 {{mark all declarations used in the conformance 'nonisolated'}}
|
|
// expected-note@+2 {{isolate this conformance to the main actor with '@MainActor'}}{{26-26=@MainActor }}
|
|
// expected-note@+1 {{turn data races into runtime errors with '@preconcurrency'}}{{26-26=@preconcurrency }}
|
|
@MainActor struct S: Nested.P {
|
|
func f() {} // expected-note {{main actor-isolated instance method 'f()' cannot satisfy nonisolated requirement}}
|
|
}
|
|
}
|
|
do {
|
|
// Attribute inserted *before* '@unsafe'.
|
|
@MainActor struct S: @unsafe Nested.P {
|
|
// expected-warning@-1 {{conformance of 'S' to protocol 'P' crosses into main actor-isolated code and can cause data races}}
|
|
// expected-note@-2 {{mark all declarations used in the conformance 'nonisolated'}}
|
|
// expected-note@-3 {{isolate this conformance to the main actor with '@MainActor'}}{{26-26=@MainActor }}
|
|
// expected-note@-4 {{turn data races into runtime errors with '@preconcurrency'}}{{26-26=@preconcurrency }}
|
|
func f() {} // expected-note {{main actor-isolated instance method 'f()' cannot satisfy nonisolated requirement}}
|
|
}
|
|
}
|
|
do {
|
|
// expected-warning@+5 {{conformance of 'S' to protocol 'Q' crosses into main actor-isolated code and can cause data races}}
|
|
// expected-warning@+4 {{conformance of 'S' to protocol 'P' crosses into main actor-isolated code and can cause data races}}
|
|
// expected-note@+3 2 {{mark all declarations used in the conformance 'nonisolated'}}
|
|
// expected-note@+2 2 {{isolate this conformance to the main actor with '@MainActor'}}{{26-26=@MainActor }}
|
|
// expected-note@+1 2 {{turn data races into runtime errors with '@preconcurrency'}}{{26-26=@preconcurrency }}
|
|
@MainActor struct S: Nested.P & Nested.Q {
|
|
func f() {} // expected-note 2 {{main actor-isolated instance method 'f()' cannot satisfy nonisolated requirement}}
|
|
}
|
|
}
|
|
do {
|
|
// FIXME: We shouldn't be applying nonisolated to both protocols.
|
|
// expected-warning@+4 {{conformance of 'S' to protocol 'P' crosses into main actor-isolated code and can cause data races}}
|
|
// expected-note@+3 {{mark all declarations used in the conformance 'nonisolated'}}
|
|
// expected-note@+2 {{isolate this conformance to the main actor with '@MainActor'}}{{26-26=@MainActor }}
|
|
// expected-note@+1 {{turn data races into runtime errors with '@preconcurrency'}}{{26-26=@preconcurrency }}
|
|
@MainActor struct S: Nested.P & EmptyP {
|
|
func f() {} // expected-note {{main actor-isolated instance method 'f()' cannot satisfy nonisolated requirement}}
|
|
}
|
|
}
|
|
}
|
|
|
|
actor SomeActor { }
|
|
|
|
// Isolated conformances need a global-actor-constrained type.
|
|
class CNonIsolated: @MainActor P {
|
|
func f() { }
|
|
}
|
|
|
|
extension SomeActor: @MainActor P {
|
|
@MainActor func f() { }
|
|
}
|
|
|
|
@globalActor
|
|
struct SomeGlobalActor {
|
|
static let shared = SomeActor()
|
|
}
|
|
|
|
// Isolation of the conformance can be different from that of the enclosing
|
|
// type, so long as the witnesses match up.
|
|
@MainActor
|
|
class CMismatchedIsolation: @SomeGlobalActor P {
|
|
@SomeGlobalActor func f() { }
|
|
}
|
|
|
|
@MainActor
|
|
class C: @MainActor P {
|
|
func f() { } // okay
|
|
}
|
|
|
|
// Associated conformances with isolation
|
|
|
|
protocol Q {
|
|
associatedtype A: P
|
|
}
|
|
|
|
// expected-warning@+2{{conformance of 'SMissingIsolation' to protocol 'Q' crosses into main actor-isolated code and can cause data races}}
|
|
@MainActor
|
|
struct SMissingIsolation: Q {
|
|
// expected-note@-1{{conformance depends on main actor-isolated conformance of 'C' to protocol 'P'}}
|
|
// expected-note@-2{{isolate this conformance to the main actor with '@MainActor'}}
|
|
typealias A = C
|
|
}
|
|
|
|
struct PWrapper<T: P>: P {
|
|
func f() { }
|
|
}
|
|
|
|
// expected-warning@+2{{conformance of 'SMissingIsolationViaWrapper' to protocol 'Q' crosses into main actor-isolated code and can cause data races}}
|
|
@MainActor
|
|
struct SMissingIsolationViaWrapper: Q {
|
|
// expected-note@-1{{conformance depends on main actor-isolated conformance of 'C' to protocol 'P'}}
|
|
// expected-note@-2{{isolate this conformance to the main actor with '@MainActor'}}{{37-37=@MainActor }}
|
|
typealias A = PWrapper<C>
|
|
}
|
|
|
|
@SomeGlobalActor
|
|
class C2: @SomeGlobalActor P {
|
|
func f() { }
|
|
}
|
|
|
|
@MainActor
|
|
struct S: @MainActor Q {
|
|
typealias A = C
|
|
}
|
|
|
|
// expected-warning@+3{{conformance of 'SMismatchedActors' to protocol 'Q' crosses into global actor 'SomeGlobalActor'-isolated code and can cause data races}}
|
|
// expected-note@+2{{conformance depends on global actor 'SomeGlobalActor'-isolated conformance of 'C2' to protocol 'P'}}
|
|
@MainActor
|
|
struct SMismatchedActors: @MainActor Q {
|
|
typealias A = C2
|
|
}
|
|
|
|
protocol PSendable: P, Sendable { }
|
|
|
|
// expected-error@+2{{type 'PSendableS' does not conform to protocol 'PSendable'}}
|
|
// expected-error@+1{{main actor-isolated conformance of 'PSendableS' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter 'Self'}}
|
|
struct PSendableS: @MainActor PSendable { // expected-note{{requirement specified as 'Self' : 'P' [with Self = PSendableS]}}
|
|
func f() { }
|
|
}
|
|
|
|
protocol R: SendableMetatype {
|
|
func f()
|
|
}
|
|
|
|
// expected-error@+1{{cannot form main actor-isolated conformance of 'RSendableSMainActor' to SendableMetatype-inheriting protocol 'R'}}
|
|
@MainActor struct RSendableSMainActor: @MainActor R {
|
|
func f() { }
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Use checking of isolated conformances.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// expected-note@+1{{requirement specified as 'T' : 'P' [with T = C]}}
|
|
struct PSendableWrapper<T: P & Sendable>: P {
|
|
func f() { }
|
|
}
|
|
|
|
// expected-note@+1{{requirement specified as 'T' : 'P' [with T = C]}}
|
|
struct PSendableMetaWrapper<T: P & SendableMetatype>: P {
|
|
func f() { }
|
|
}
|
|
|
|
@MainActor
|
|
func testIsolationConformancesInTypes() {
|
|
typealias A1 = PWrapper<C>
|
|
typealias A2 = PSendableWrapper<C> // expected-error{{isolated conformance of 'C' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter 'T'}}
|
|
typealias A3 = PSendableMetaWrapper<C> // expected-error{{isolated conformance of 'C' to 'P' cannot satisfy conformance requirement for a 'SendableMetatype' type parameter 'T'}}
|
|
}
|
|
|
|
func acceptP<T: P>(_: T) { }
|
|
|
|
func acceptSendableP<T: Sendable & P>(_: T) { }
|
|
// expected-note@-1{{'acceptSendableP' declared here}}
|
|
|
|
func acceptSendableMetaP<T: SendableMetatype & P>(_: T) { }
|
|
// expected-note@-1 3{{'acceptSendableMetaP' declared here}}
|
|
|
|
@MainActor
|
|
func testIsolationConformancesInCall(c: C) {
|
|
acceptP(c) // okay
|
|
|
|
acceptSendableP(c) // expected-error{{main actor-isolated conformance of 'C' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter}}
|
|
acceptSendableMetaP(c) // expected-error{{isolated conformance of 'C' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter}}
|
|
}
|
|
|
|
@MainActor
|
|
func testIsolatedConformancesOfActor(a: SomeActor) {
|
|
acceptP(a)
|
|
acceptSendableMetaP(a) // expected-error{{main actor-isolated conformance of 'SomeActor' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter}}
|
|
}
|
|
|
|
@SomeGlobalActor
|
|
func testIsolatedConformancesOfOtherGlobalActor(c: CMismatchedIsolation) {
|
|
acceptP(c)
|
|
acceptSendableMetaP(c) // expected-error{{global actor 'SomeGlobalActor'-isolated conformance of 'CMismatchedIsolation' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter}}
|
|
}
|
|
|
|
func testIsolationConformancesFromOutside(c: C) {
|
|
acceptP(c) // expected-warning{{main actor-isolated conformance of 'C' to 'P' cannot be used in nonisolated context}}
|
|
let _: any P = c // expected-warning{{main actor-isolated conformance of 'C' to 'P' cannot be used in nonisolated context}}
|
|
let _ = PWrapper<C>() // expected-warning{{main actor-isolated conformance of 'C' to 'P' cannot be used in nonisolated context}}
|
|
}
|
|
|
|
protocol HasAssociatedType {
|
|
associatedtype A
|
|
}
|
|
|
|
func acceptHasAssocWithP<T: HasAssociatedType>(_: T) where T.A: P { }
|
|
|
|
func acceptSendableHasAssocWithP<T: Sendable & HasAssociatedType>(_: T) where T.A: P { }
|
|
// expected-note@-1{{'acceptSendableHasAssocWithP' declared here}}
|
|
|
|
|
|
struct HoldsC: HasAssociatedType {
|
|
typealias A = C
|
|
}
|
|
|
|
extension HasAssociatedType {
|
|
static func acceptAliased<T: P>(_: T.Type) where A == T { }
|
|
}
|
|
|
|
extension HasAssociatedType where Self: Sendable {
|
|
static func acceptSendableAliased<T: P>(_: T.Type) where A == T { }
|
|
}
|
|
|
|
func testIsolatedConformancesOnAssociatedTypes(hc: HoldsC, c: C) {
|
|
acceptHasAssocWithP(hc)
|
|
acceptSendableHasAssocWithP(hc) // expected-error{{main actor-isolated conformance of 'C' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter }}
|
|
|
|
HoldsC.acceptAliased(C.self) // okay
|
|
|
|
// FIXME: the following should produce an error, because the isolated
|
|
// conformance of C: P can cross isolation boundaries via the Sendable Self's
|
|
// associated type.
|
|
HoldsC.acceptSendableAliased(C.self)
|
|
}
|
|
|
|
|
|
struct MyHashable: @MainActor Hashable {
|
|
var counter = 0
|
|
}
|
|
|
|
@concurrent func testMyHashableSet() async {
|
|
let _: Set<MyHashable> = [] // expected-warning{{main actor-isolated conformance of 'MyHashable' to 'Hashable' cannot be used in nonisolated context}}
|
|
}
|