Skip to content
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

[Sema] Emit dynamic actor isolation checks for derived protocol witnesses #78650

Merged
merged 3 commits into from
Jan 15, 2025
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
10 changes: 10 additions & 0 deletions lib/Sema/CodeSynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "TypeCheckObjC.h"
#include "TypeCheckType.h"
#include "TypeChecker.h"
#include "DerivedConformances.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/AvailabilityInference.h"
Expand Down Expand Up @@ -1728,6 +1729,15 @@ bool swift::hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal) {
});
}

bool swift::addNonIsolatedToSynthesized(DerivedConformance &derived,
ValueDecl *value) {
if (auto *conformance = derived.Conformance) {
if (conformance && conformance->isPreconcurrency())
return false;
}
return addNonIsolatedToSynthesized(derived.Nominal, value);
}

bool swift::addNonIsolatedToSynthesized(NominalTypeDecl *nominal,
ValueDecl *value) {
if (!getActorIsolation(nominal).isActorIsolated())
Expand Down
6 changes: 6 additions & 0 deletions lib/Sema/CodeSynthesis.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class ParamDecl;
class Type;
class ValueDecl;
class VarDecl;
class DerivedConformance;

enum class SelfAccessorKind {
/// We're building a derived accessor on top of whatever this
Expand Down Expand Up @@ -85,6 +86,11 @@ ValueDecl *getProtocolRequirement(ProtocolDecl *protocol, Identifier name);
// with an initial value.
bool hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal);

/// Add 'nonisolated' to the synthesized declaration for a derived
/// conformance when needed. Returns true if an attribute was added.
bool addNonIsolatedToSynthesized(DerivedConformance &conformance,
ValueDecl *value);

/// Add 'nonisolated' to the synthesized declaration when needed. Returns true
/// if an attribute was added.
bool addNonIsolatedToSynthesized(NominalTypeDecl *nominal, ValueDecl *value);
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/DerivedConformanceCodable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,7 @@ static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) {
encodeDecl->getAttrs().add(attr);
}

addNonIsolatedToSynthesized(derived.Nominal, encodeDecl);
addNonIsolatedToSynthesized(derived, encodeDecl);

encodeDecl->copyFormalAccessFrom(derived.Nominal,
/*sourceIsParentContext*/ true);
Expand Down Expand Up @@ -1906,7 +1906,7 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) {
initDecl->getAttrs().add(reqAttr);
}

addNonIsolatedToSynthesized(derived.Nominal, initDecl);
addNonIsolatedToSynthesized(derived, initDecl);

initDecl->copyFormalAccessFrom(derived.Nominal,
/*sourceIsParentContext*/ true);
Expand Down
6 changes: 3 additions & 3 deletions lib/Sema/DerivedConformanceEquatableHashable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ deriveEquatable_eq(
return nullptr;
}

addNonIsolatedToSynthesized(derived.Nominal, eqDecl);
addNonIsolatedToSynthesized(derived, eqDecl);

eqDecl->setBodySynthesizer(bodySynthesizer);

Expand Down Expand Up @@ -553,7 +553,7 @@ deriveHashable_hashInto(
/*sourceIsParentContext=*/true);

// The derived hash(into:) for an actor must be non-isolated.
if (!addNonIsolatedToSynthesized(derived.Nominal, hashDecl) &&
if (!addNonIsolatedToSynthesized(derived, hashDecl) &&
derived.Nominal->isActor())
hashDecl->getAttrs().add(
new (C) NonisolatedAttr(/*unsafe*/ false, /*implicit*/ true));
Expand Down Expand Up @@ -913,7 +913,7 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) {
hashValueDecl->setAccessors(SourceLoc(), {getterDecl}, SourceLoc());

// The derived hashValue of an actor must be nonisolated.
if (!addNonIsolatedToSynthesized(derived.Nominal, hashValueDecl) &&
if (!addNonIsolatedToSynthesized(derived, hashValueDecl) &&
derived.Nominal->isActor())
hashValueDecl->getAttrs().add(
new (C) NonisolatedAttr(/*unsafe*/ false, /*implicit*/ true));
Expand Down
112 changes: 112 additions & 0 deletions test/SILGen/preconcurrency_conformances.swift
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,71 @@ struct PreconcurrencyAppliesToParentToo : @preconcurrency Child {
// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF
// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]])

@available(*, unavailable)
extension NotSendable: Sendable {}

struct NotSendable: Equatable, Hashable {
}

@MainActor
struct TestDerivedEquatable : @preconcurrency Equatable {
var x: NotSendable
}

// protocol witness for static Equatable.== infix(_:_:) in conformance TestDerivedEquatable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances20TestDerivedEquatableVSQAASQ2eeoiySbx_xtFZTW
// CHECK: [[MAIN_ACTOR:%.*]] = begin_borrow {{.*}} : $MainActor
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF
// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]])

@MainActor
struct TestDerivedHashable : @preconcurrency Hashable {
var x: NotSendable
}

// protocol witness for Hashable.hashValue.getter in conformance TestDerivedHashable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances19TestDerivedHashableVSHAASH9hashValueSivgTW
// CHECK: [[MAIN_ACTOR:%.*]] = begin_borrow {{.*}} : $MainActor
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF
// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]])

// protocol witness for Hashable.hash(into:) in conformance TestDerivedHashable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances19TestDerivedHashableVSHAASH4hash4intoys6HasherVz_tFTW
// CHECK: [[MAIN_ACTOR:%.*]] = begin_borrow {{.*}} : $MainActor
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF
// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]])

// protocol witness for static Equatable.== infix(_:_:) in conformance TestDerivedHashable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances19TestDerivedHashableVSQAASQ2eeoiySbx_xtFZTW
// CHECK: [[MAIN_ACTOR:%.*]] = begin_borrow {{.*}} : $MainActor
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF
// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]])

extension NotSendable : Codable {}

@MainActor
struct TestDerivedCodable : @preconcurrency Codable {
var x: NotSendable
}

// protocol witness for Decodable.init(from:) in conformance TestDerivedCodable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances18TestDerivedCodableVSeAASe4fromxs7Decoder_p_tKcfCTW
// CHECK: [[MAIN_ACTOR:%.*]] = begin_borrow {{.*}} : $MainActor
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF
// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]])

// protocol witness for Encodable.encode(to:) in conformance TestDerivedCodable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances18TestDerivedCodableVSEAASE6encode2toys7Encoder_p_tKFTW
// CHECK: [[MAIN_ACTOR:%.*]] = begin_borrow {{.*}} : $MainActor
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF
// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]])

//--- checks_disabled.swift
protocol P {
associatedtype T
Expand Down Expand Up @@ -498,3 +563,50 @@ struct PreconcurrencyAppliesToParentToo : @preconcurrency Child {
// protocol witness for Parent.a() in conformance PreconcurrencyAppliesToParentToo
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances32PreconcurrencyAppliesToParentTooVAA0F0A2aDP1ayyFTW : $@convention(witness_method: Parent) (@in_guaranteed PreconcurrencyAppliesToParentToo) -> ()
// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF

@available(*, unavailable)
extension NotSendable: Sendable {}

struct NotSendable: Equatable, Hashable {
}

@MainActor
struct TestDerivedEquatable : @preconcurrency Equatable {
var x: NotSendable
}

// protocol witness for static Equatable.== infix(_:_:) in conformance TestDerivedEquatable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances20TestDerivedEquatableVSQAASQ2eeoiySbx_xtFZTW
// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF

@MainActor
struct TestDerivedHashable : @preconcurrency Hashable {
var x: NotSendable
}

// protocol witness for Hashable.hashValue.getter in conformance TestDerivedHashable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances19TestDerivedHashableVSHAASH9hashValueSivgTW
// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF

// protocol witness for Hashable.hash(into:) in conformance TestDerivedHashable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances19TestDerivedHashableVSHAASH4hash4intoys6HasherVz_tFTW
// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF

// protocol witness for static Equatable.== infix(_:_:) in conformance TestDerivedHashable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances19TestDerivedHashableVSQAASQ2eeoiySbx_xtFZTW
// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF

extension NotSendable : Codable {}

@MainActor
struct TestDerivedCodable : @preconcurrency Codable {
var x: NotSendable
}

// protocol witness for Decodable.init(from:) in conformance TestDerivedCodable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances18TestDerivedCodableVSeAASe4fromxs7Decoder_p_tKcfCTW
// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF

// protocol witness for Encodable.encode(to:) in conformance TestDerivedCodable
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances18TestDerivedCodableVSEAASE6encode2toys7Encoder_p_tKFTW
// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF