mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Prohibit isolated conformances for checked casts to potentially-SendableMetatype types
This removes the IsolatedConformances feature gate from SILGen for dynamic casts, such that all dynamic casts that will not work with isolated conformances are marked as such. Isolated conformances can still only come into a program when part of it enables the feature flag.
This commit is contained in:
@@ -308,16 +308,17 @@ namespace {
|
||||
if (!TargetType->isAnyExistentialType())
|
||||
return CastingIsolatedConformances::Allow;
|
||||
|
||||
// Only do this if isolated conformances are enabled.
|
||||
ASTContext &ctx = TargetType->getASTContext();
|
||||
if (!ctx.LangOpts.hasFeature(Feature::IsolatedConformances))
|
||||
return CastingIsolatedConformances::Allow;
|
||||
|
||||
auto proto = ctx.getProtocol(KnownProtocolKind::SendableMetatype);
|
||||
|
||||
// If there is a conformance to SendableMetatype, then this existential
|
||||
// can leave the current isolation domain. Prohibit isolated conformances.
|
||||
if (proto && lookupConformance(TargetType, proto, /*allowMissing=*/false))
|
||||
ASTContext &ctx = TargetType->getASTContext();
|
||||
Type checkType;
|
||||
if (auto existentialMetatype = TargetType->getAs<ExistentialMetatypeType>())
|
||||
checkType = existentialMetatype->getInstanceType();
|
||||
else
|
||||
checkType = TargetType;
|
||||
|
||||
auto proto = ctx.getProtocol(KnownProtocolKind::SendableMetatype);
|
||||
if (proto && lookupConformance(checkType, proto, /*allowMissing=*/false))
|
||||
return CastingIsolatedConformances::Prohibit;
|
||||
|
||||
return CastingIsolatedConformances::Allow;
|
||||
|
||||
53
test/Concurrency/isolated_conformance_inference.swift
Normal file
53
test/Concurrency/isolated_conformance_inference.swift
Normal file
@@ -0,0 +1,53 @@
|
||||
// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature IsolatedConformances -enable-experimental-feature InferIsolatedConformances %s
|
||||
|
||||
// REQUIRES: swift_feature_IsolatedConformances
|
||||
// REQUIRES: swift_feature_InferIsolatedConformances
|
||||
// REQUIRES: concurrency
|
||||
|
||||
protocol P {
|
||||
func f()
|
||||
}
|
||||
|
||||
@SomeGlobalActor
|
||||
protocol Q {
|
||||
func g()
|
||||
}
|
||||
|
||||
@globalActor
|
||||
actor SomeGlobalActor {
|
||||
static let shared = SomeGlobalActor()
|
||||
}
|
||||
|
||||
@SomeGlobalActor
|
||||
protocol R {
|
||||
func h()
|
||||
}
|
||||
|
||||
@SomeGlobalActor
|
||||
class CExplicit: P {
|
||||
func f() { } // okay! conformance above is isolated
|
||||
}
|
||||
|
||||
// If the protocol itself is isolated, don't do anything.
|
||||
extension CExplicit: Q {
|
||||
func g() { }
|
||||
}
|
||||
|
||||
// expected-error@+3{{conformance of 'CNonIsolated' to protocol 'P' crosses into global actor 'SomeGlobalActor'-isolated code and can cause data races}}
|
||||
// expected-note@+2{{turn data races into runtime errors with '@preconcurrency'}}
|
||||
// expected-note@+1{{isolate this conformance to the global actor 'SomeGlobalActor' with '@SomeGlobalActor'}}{{33-33=@SomeGlobalActor }}
|
||||
nonisolated class CNonIsolated: P {
|
||||
@SomeGlobalActor func f() { } // expected-note{{global actor 'SomeGlobalActor'-isolated instance method 'f()' cannot satisfy nonisolated requirement}}
|
||||
}
|
||||
|
||||
func acceptSendablePMeta<T: Sendable & P>(_: T.Type) { }
|
||||
func acceptSendableQMeta<T: Sendable & Q>(_: T.Type) { }
|
||||
|
||||
nonisolated func testConformancesFromNonisolated() {
|
||||
let _: any P = CExplicit() // expected-error{{global actor 'SomeGlobalActor'-isolated conformance of 'CExplicit' to 'P' cannot be used in nonisolated context}}
|
||||
|
||||
let _: any P = CNonIsolated()
|
||||
|
||||
// Okay, these are nonisolated conformances.
|
||||
let _: any Q = CExplicit()
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -Xllvm -sil-print-types -emit-silgen -enable-experimental-feature IsolatedConformances -verify %s | %FileCheck %s
|
||||
|
||||
// REQUIRES: swift_feature_IsolatedConformances
|
||||
// REQUIRES: concurrency
|
||||
// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -Xllvm -sil-print-types -emit-silgen -verify %s | %FileCheck %s
|
||||
|
||||
protocol P { }
|
||||
|
||||
|
||||
@@ -296,17 +296,17 @@ func downcasts(
|
||||
let _ = baseAndP as! Derived
|
||||
|
||||
// CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $any Base<Int> & P
|
||||
// CHECK-NEXT: checked_cast_br any Base<Int> & P in [[COPIED]] : $any Base<Int> & P to any Derived & R
|
||||
// CHECK-NEXT: checked_cast_br [prohibit_isolated_conformances] any Base<Int> & P in [[COPIED]] : $any Base<Int> & P to any Derived & R
|
||||
let _ = baseAndP as? (Derived & R)
|
||||
|
||||
// CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $any Base<Int> & P
|
||||
// CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $any Base<Int> & P to any Derived & R
|
||||
// CHECK-NEXT: unconditional_checked_cast [prohibit_isolated_conformances] [[COPIED]] : $any Base<Int> & P to any Derived & R
|
||||
let _ = baseAndP as! (Derived & R)
|
||||
|
||||
// CHECK: checked_cast_br Derived.Type in %3 : $@thick Derived.Type to any (Derived & R).Type
|
||||
// CHECK: checked_cast_br [prohibit_isolated_conformances] Derived.Type in %3 : $@thick Derived.Type to any (Derived & R).Type
|
||||
let _ = derivedType as? (Derived & R).Type
|
||||
|
||||
// CHECK: unconditional_checked_cast %3 : $@thick Derived.Type to any (Derived & R).Type
|
||||
// CHECK: unconditional_checked_cast [prohibit_isolated_conformances] %3 : $@thick Derived.Type to any (Derived & R).Type
|
||||
let _ = derivedType as! (Derived & R).Type
|
||||
|
||||
// CHECK: checked_cast_br any (Base<Int> & P).Type in %2 : $@thick any (Base<Int> & P).Type to Derived.Type
|
||||
@@ -315,10 +315,10 @@ func downcasts(
|
||||
// CHECK: unconditional_checked_cast %2 : $@thick any (Base<Int> & P).Type to Derived.Type
|
||||
let _ = baseAndPType as! Derived.Type
|
||||
|
||||
// CHECK: checked_cast_br any (Base<Int> & P).Type in %2 : $@thick any (Base<Int> & P).Type to any (Derived & R).Type
|
||||
// CHECK: checked_cast_br [prohibit_isolated_conformances] any (Base<Int> & P).Type in %2 : $@thick any (Base<Int> & P).Type to any (Derived & R).Type
|
||||
let _ = baseAndPType as? (Derived & R).Type
|
||||
|
||||
// CHECK: unconditional_checked_cast %2 : $@thick any (Base<Int> & P).Type to any (Derived & R).Type
|
||||
// CHECK: unconditional_checked_cast [prohibit_isolated_conformances] %2 : $@thick any (Base<Int> & P).Type to any (Derived & R).Type
|
||||
let _ = baseAndPType as! (Derived & R).Type
|
||||
|
||||
// CHECK: return
|
||||
@@ -378,33 +378,33 @@ func archetypeDowncasts<S,
|
||||
// CHECK: [[COPY:%.*]] = alloc_stack $S
|
||||
// CHECK-NEXT: copy_addr %0 to [init] [[COPY]] : $*S
|
||||
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $any Base<T> & P
|
||||
// CHECK-NEXT: checked_cast_addr_br take_always S in [[COPY]] : $*S to any Base<T> & P in [[RESULT]] : $*any Base<T> & P
|
||||
// CHECK-NEXT: checked_cast_addr_br [prohibit_isolated_conformances] take_always S in [[COPY]] : $*S to any Base<T> & P in [[RESULT]] : $*any Base<T> & P
|
||||
let _ = s as? (Base<T> & P)
|
||||
|
||||
// CHECK: [[COPY:%.*]] = alloc_stack $S
|
||||
// CHECK-NEXT: copy_addr [[ARG0]] to [init] [[COPY]] : $*S
|
||||
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $any Base<T> & P
|
||||
// CHECK-NEXT: unconditional_checked_cast_addr S in [[COPY]] : $*S to any Base<T> & P in [[RESULT]] : $*any Base<T> & P
|
||||
// CHECK-NEXT: unconditional_checked_cast_addr [prohibit_isolated_conformances] S in [[COPY]] : $*S to any Base<T> & P in [[RESULT]] : $*any Base<T> & P
|
||||
let _ = s as! (Base<T> & P)
|
||||
|
||||
// CHECK: [[COPY:%.*]] = alloc_stack $S
|
||||
// CHECK-NEXT: copy_addr [[ARG0]] to [init] [[COPY]] : $*S
|
||||
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $any Base<Int> & P
|
||||
// CHECK-NEXT: checked_cast_addr_br take_always S in [[COPY]] : $*S to any Base<Int> & P in [[RESULT]] : $*any Base<Int> & P
|
||||
// CHECK-NEXT: checked_cast_addr_br [prohibit_isolated_conformances] take_always S in [[COPY]] : $*S to any Base<Int> & P in [[RESULT]] : $*any Base<Int> & P
|
||||
let _ = s as? (Base<Int> & P)
|
||||
|
||||
// CHECK: [[COPY:%.*]] = alloc_stack $S
|
||||
// CHECK-NEXT: copy_addr [[ARG0]] to [init] [[COPY]] : $*S
|
||||
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $any Base<Int> & P
|
||||
// CHECK-NEXT: unconditional_checked_cast_addr S in [[COPY]] : $*S to any Base<Int> & P in [[RESULT]] : $*any Base<Int> & P
|
||||
// CHECK-NEXT: unconditional_checked_cast_addr [prohibit_isolated_conformances] S in [[COPY]] : $*S to any Base<Int> & P in [[RESULT]] : $*any Base<Int> & P
|
||||
let _ = s as! (Base<Int> & P)
|
||||
|
||||
// CHECK: [[COPIED:%.*]] = copy_value [[ARG5]] : $BaseTAndP
|
||||
// CHECK-NEXT: checked_cast_br BaseTAndP in [[COPIED]] : $BaseTAndP to any Derived & R
|
||||
// CHECK-NEXT: checked_cast_br [prohibit_isolated_conformances] BaseTAndP in [[COPIED]] : $BaseTAndP to any Derived & R
|
||||
let _ = baseTAndP_archetype as? (Derived & R)
|
||||
|
||||
// CHECK: [[COPIED:%.*]] = copy_value [[ARG5]] : $BaseTAndP
|
||||
// CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $BaseTAndP to any Derived & R
|
||||
// CHECK-NEXT: unconditional_checked_cast [prohibit_isolated_conformances] [[COPIED]] : $BaseTAndP to any Derived & R
|
||||
let _ = baseTAndP_archetype as! (Derived & R)
|
||||
|
||||
// CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $any Base<T> & P
|
||||
@@ -447,11 +447,11 @@ func archetypeDowncasts<S,
|
||||
let _ = baseTAndP_concrete as! BaseTAndP
|
||||
|
||||
// CHECK: [[COPIED:%.*]] = copy_value [[ARG6]] : $BaseIntAndP
|
||||
// CHECK-NEXT: checked_cast_br BaseIntAndP in [[COPIED]] : $BaseIntAndP to any Derived & R
|
||||
// CHECK-NEXT: checked_cast_br [prohibit_isolated_conformances] BaseIntAndP in [[COPIED]] : $BaseIntAndP to any Derived & R
|
||||
let _ = baseIntAndP_archetype as? (Derived & R)
|
||||
|
||||
// CHECK: [[COPIED:%.*]] = copy_value [[ARG6]] : $BaseIntAndP
|
||||
// CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $BaseIntAndP to any Derived & R
|
||||
// CHECK-NEXT: unconditional_checked_cast [prohibit_isolated_conformances] [[COPIED]] : $BaseIntAndP to any Derived & R
|
||||
let _ = baseIntAndP_archetype as! (Derived & R)
|
||||
|
||||
// CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $any Base<Int> & P
|
||||
|
||||
Reference in New Issue
Block a user