Skip to content

Commit c7c9d80

Browse files
committed
[NCGenerics] fix Combine issue
The solution is to add the unconditional conformances when building the conformance lookup table for each nominal, instead of waiting until conformance lookup infers it. At the moment, because the stdlib isn't being built with Copyable conformances injected into it, we still end up needing to infer Copyable conformances for nominals like `Int` from the stdlib when trying to test the feature, since it loads those nominals, but they lack conformance. That should go away once we do enable NoncopyableGenerics for the stdlib by default, and we'll be left with only inferring the conditional conformance in TypeCheckInvertible.
1 parent 58480c3 commit c7c9d80

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

lib/AST/ProtocolConformance.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/FileUnit.h"
2424
#include "swift/AST/GenericEnvironment.h"
2525
#include "swift/AST/InFlightSubstitution.h"
26+
#include "swift/AST/InverseMarking.h"
2627
#include "swift/AST/LazyResolver.h"
2728
#include "swift/AST/Module.h"
2829
#include "swift/AST/PackConformance.h"
@@ -1091,6 +1092,16 @@ void NominalTypeDecl::prepareConformanceTable() const {
10911092
}
10921093
};
10931094

1095+
// Synthesize the unconditional conformances to invertible protocols.
1096+
// For conditional ones, see findSynthesizedConformances .
1097+
if (haveNoncopyableGenerics) {
1098+
for (auto ip : InvertibleProtocolSet::full()) {
1099+
auto invertible = getMarking(ip);
1100+
if (!invertible.getInverse() || bool(invertible.getPositive()))
1101+
addSynthesized(ctx.getProtocol(getKnownProtocolKind(ip)));
1102+
}
1103+
}
1104+
10941105
// Add protocols for any synthesized protocol attributes.
10951106
for (auto attr : getAttrs().getAttributes<SynthesizedProtocolAttr>()) {
10961107
addSynthesized(attr->getProtocol());
@@ -1263,9 +1274,12 @@ static SmallVector<ProtocolConformance *, 2> findSynthesizedConformances(
12631274
if (!isa<ProtocolDecl>(nominal)) {
12641275
trySynthesize(KnownProtocolKind::Sendable);
12651276

1266-
if (nominal->getASTContext().LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
1267-
trySynthesize(KnownProtocolKind::Copyable);
1268-
trySynthesize(KnownProtocolKind::Escapable);
1277+
// Triggers synthesis of a possibly conditional conformance.
1278+
// For the unconditional ones, see NominalTypeDecl::prepareConformanceTable
1279+
if (nominal->getASTContext().LangOpts.hasFeature(
1280+
Feature::NoncopyableGenerics)) {
1281+
for (auto ip : InvertibleProtocolSet::full())
1282+
trySynthesize(getKnownProtocolKind(ip));
12691283
}
12701284

12711285
if (nominal->getASTContext().LangOpts.hasFeature(

lib/Sema/TypeCheckInvertible.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,14 @@ ProtocolConformance *deriveConformanceForInvertible(Evaluator &evaluator,
464464
return generateConditionalConformance();
465465

466466
case InverseMarking::Kind::None:
467+
// All types already start with conformances to the invertible protocols in
468+
// this case, within `NominalTypeDecl::prepareConformanceTable`.
469+
//
470+
// I'm currently unsure what happens when rebuilding a module from its
471+
// interface, so this might not be unreachable code just yet.
472+
if (SWIFT_ENABLE_EXPERIMENTAL_NONCOPYABLE_GENERICS)
473+
llvm_unreachable("when can this actually happen??");
474+
467475
// If there's no inverse, we infer a positive IP conformance.
468476
return generateConformance(nominal);
469477
}

test/Generics/inverse_generics.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,10 @@ func checkOwnership<T: HasMember>(_ t: T,
415415
_ o: T.Member.NCBuddy.NCBuddy
416416
// expected-error@-1 {{parameter of noncopyable type 'T.Member.NCBuddy.NCBuddy' must specify ownership}} // expected-note@-1 3{{add}}
417417
) {}
418+
419+
// Covers an issue when building Combine from its interface.
420+
public struct Record<Output> {
421+
public init(recording: Record<Output>) {}
422+
}
423+
protocol P {}
424+
extension Record : Decodable where Output : P {}

0 commit comments

Comments
 (0)