Skip to content

Use "resilient conformance" logic for deciding protocol dependencies involving Sendable #76707

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
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
19 changes: 14 additions & 5 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -959,8 +959,13 @@ namespace {

/// Return true if the witness table requires runtime instantiation to
/// handle resiliently-added requirements with default implementations.
///
/// If disableOptimizations is true, skip optimizations that treat
/// formally-resilient conformances as non-resilient.
bool IRGenModule::isResilientConformance(
const NormalProtocolConformance *conformance) {
const NormalProtocolConformance *conformance,
bool disableOptimizations
) {
// If the protocol is not resilient, the conformance is not resilient
// either.
bool shouldTreatProtocolNonResilient =
Expand Down Expand Up @@ -992,16 +997,18 @@ bool IRGenModule::isResilientConformance(
// This is an optimization -- a conformance of a non-generic type cannot
// resiliently become dependent.
if (!conformance->getDeclContext()->isGenericContext() &&
conformanceModule == conformance->getProtocol()->getParentModule())
conformanceModule == conformance->getProtocol()->getParentModule() &&
!disableOptimizations)
return false;

// We have a resilient conformance.
return true;
}

bool IRGenModule::isResilientConformance(const RootProtocolConformance *root) {
bool IRGenModule::isResilientConformance(const RootProtocolConformance *root,
bool disableOptimizations) {
if (auto normal = dyn_cast<NormalProtocolConformance>(root))
return isResilientConformance(normal);
return isResilientConformance(normal, disableOptimizations);
// Self-conformances never require this.
return false;
}
Expand Down Expand Up @@ -1185,7 +1192,9 @@ bool IRGenModule::isDependentConformance(
const RootProtocolConformance *conformance) {
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> visited;
return ::isDependentConformance(
*this, conformance, conformance->getProtocol()->isResilient(), visited);
*this, conformance,
isResilientConformance(conformance, /*disableOptimizations=*/true),
visited);
}

static llvm::Value *
Expand Down
6 changes: 4 additions & 2 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1119,8 +1119,10 @@ class IRGenModule {

TypeExpansionContext getMaximalTypeExpansionContext() const;

bool isResilientConformance(const NormalProtocolConformance *conformance);
bool isResilientConformance(const RootProtocolConformance *root);
bool isResilientConformance(const NormalProtocolConformance *conformance,
bool disableOptimizations = false);
bool isResilientConformance(const RootProtocolConformance *root,
bool disableOptimizations = false);
bool isDependentConformance(const RootProtocolConformance *conformance);

Alignment getCappedAlignment(Alignment alignment);
Expand Down
26 changes: 26 additions & 0 deletions test/IRGen/protocol_resilience_sendable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,37 @@
// RUN: %target-swift-frontend -I %t -emit-ir %s -target %target-cpu-apple-macos14.0 | %FileCheck %s -DINT=i%target-ptrsize -check-prefix=CHECK-USAGE -check-prefix=CHECK-USAGE-BEFORE
// RUN: %target-swift-frontend -I %t -emit-ir %s -target %target-cpu-apple-macos15.0 | %FileCheck %s -DINT=i%target-ptrsize -check-prefix=CHECK-USAGE -check-prefix=CHECK-USAGE-AFTER

// RUN: %target-swift-frontend -I %t -emit-ir %s -target %target-cpu-apple-macos14.0 -enable-library-evolution | %FileCheck %s -DINT=i%target-ptrsize -check-prefix=CHECK-USAGE -check-prefix=CHECK-USAGE-BEFORE
// RUN: %target-swift-frontend -I %t -emit-ir %s -target %target-cpu-apple-macos15.0 -enable-library-evolution | %FileCheck %s -DINT=i%target-ptrsize -check-prefix=CHECK-USAGE -check-prefix=CHECK-USAGE-AFTER

// REQUIRES: OS=macosx

import resilient_protocol
import non_resilient_protocol

// CHECK-USAGE: @"$s28protocol_resilience_sendable9LocalTypeVAA0D11SubProtocolAAWP" = hidden constant [3 x ptr] [
// CHECK-USAGE-SAME: ptr @"$s28protocol_resilience_sendable9LocalTypeVAA0D11SubProtocolAAMc",
// CHECK-USAGE-SAME: ptr @"$s28protocol_resilience_sendable9LocalTypeVAA0D8ProtocolAAWP",
// CHECK-USAGE-SAME: ptr @"$s28protocol_resilience_sendable9LocalTypeVAA0D11SubProtocolA2aDP9subMethodyyFTW"
public protocol LocalProtocol: Sendable {
func method()
}

protocol LocalSubProtocol: Sendable, LocalProtocol {
func subMethod()
}

struct LocalType: Sendable, LocalSubProtocol {
func method() { }
func subMethod() { }
}

func acceptLocalProtocol<T: LocalProtocol>(_: T.Type) { }
func testLocalType() {
acceptLocalProtocol(LocalType.self)
}


func acceptResilientSendableBase<T: ResilientSendableBase>(_: T.Type) { }

// CHECK-USAGE: define{{.*}}swiftcc void @"$s28protocol_resilience_sendable25passResilientSendableBaseyyF"()
Expand Down