Skip to content

Commit 6aea5b2

Browse files
committed
[NCGenerics] fix existential conformances
I was not expanding default requirements in AbstractGenericSignatureRequest. Also fixes printing of composition types.
1 parent 7c8092d commit 6aea5b2

File tree

6 files changed

+78
-20
lines changed

6 files changed

+78
-20
lines changed

include/swift/AST/Types.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5790,8 +5790,6 @@ class ProtocolCompositionType final : public TypeBase,
57905790
private llvm::TrailingObjects<ProtocolCompositionType, Type> {
57915791
friend TrailingObjects;
57925792

5793-
// TODO(kavon): this could probably be folded into the existing Bits field
5794-
// or we could just store the InverseType's in the Members array.
57955793
InvertibleProtocolSet Inverses;
57965794

57975795
public:

lib/AST/ASTDumper.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4340,6 +4340,14 @@ namespace {
43404340

43414341
printFlag(T->hasExplicitAnyObject(), "any_object");
43424342

4343+
for (auto ip : T->getInverses()) {
4344+
switch (ip) {
4345+
case InvertibleProtocolKind::Copyable:
4346+
printFlag("inverse_copyable");
4347+
break;
4348+
}
4349+
}
4350+
43434351
for (auto proto : T->getMembers()) {
43444352
printRec(proto);
43454353
}

lib/AST/ASTPrinter.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7192,17 +7192,29 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
71927192
}
71937193

71947194
void visitProtocolCompositionType(ProtocolCompositionType *T) {
7195-
if (T->getMembers().empty()) {
7196-
if (T->hasExplicitAnyObject())
7197-
Printer << "AnyObject";
7198-
else
7199-
Printer.printKeyword("Any", Options);
7200-
} else {
7201-
interleave(T->getMembers(), [&](Type Ty) { visit(Ty); },
7202-
[&] { Printer << " & "; });
7203-
if (T->hasExplicitAnyObject())
7204-
Printer << " & AnyObject";
7205-
}
7195+
interleave(T->getMembers(), [&](Type Ty) { visit(Ty); },
7196+
[&] { Printer << " & "; });
7197+
7198+
bool printed = !T->getMembers().empty();
7199+
auto printSpecial = [&](llvm::StringRef str, bool tilde=false) {
7200+
if (printed)
7201+
Printer << " & ";
7202+
7203+
if (tilde)
7204+
Printer << "~";
7205+
7206+
Printer << str;
7207+
printed = true;
7208+
};
7209+
7210+
if (T->hasExplicitAnyObject())
7211+
printSpecial("AnyObject");
7212+
7213+
for (auto ip : T->getInverses())
7214+
printSpecial(getProtocolName(getKnownProtocolKind(ip)), true);
7215+
7216+
if (!printed)
7217+
Printer.printKeyword("Any", Options);
72067218
}
72077219

72087220
void visitParameterizedProtocolType(ParameterizedProtocolType *T) {

lib/AST/Module.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,15 +1591,26 @@ ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
15911591
if (!protocol->existentialConformsToSelf())
15921592
return ProtocolConformanceRef::forInvalid();
15931593

1594-
// All existentials are Copyable.
1595-
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
1596-
return ProtocolConformanceRef(
1597-
ctx.getBuiltinConformance(type, protocol,
1598-
BuiltinConformanceKind::Synthesized));
1599-
}
1600-
16011594
auto layout = type->getExistentialLayout();
16021595

1596+
// Handle conformance to invertible protocols.
1597+
if (auto known = protocol->getKnownProtocolKind()) {
1598+
if (auto ip = getInvertibleProtocolKind(*known)) {
1599+
switch (*ip) {
1600+
case InvertibleProtocolKind::Copyable: {
1601+
// It doesn't conform if there was a ~Copyable.
1602+
if (layout.hasInverseCopyable)
1603+
return ProtocolConformanceRef::forInvalid();
1604+
1605+
// Otherwise, it conforms concretely.
1606+
return ProtocolConformanceRef(
1607+
ctx.getBuiltinConformance(type, protocol,
1608+
BuiltinConformanceKind::Synthesized));
1609+
}
1610+
}
1611+
}
1612+
}
1613+
16031614
// Due to an IRGen limitation, witness tables cannot be passed from an
16041615
// existential to an archetype parameter, so for now we restrict this to
16051616
// @objc protocols and marker protocols.

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,13 @@ AbstractGenericSignatureRequest::evaluate(
658658
requirements.push_back({req, SourceLoc(), /*wasInferred=*/false});
659659
}
660660

661+
/// Next, we need to expand default requirements for the added parameters.
662+
SmallVector<Type, 2> localGPs;
663+
for (auto *gtpt : addedParameters)
664+
localGPs.push_back(gtpt);
665+
666+
expandDefaultRequirements(ctx, localGPs, requirements, errors);
667+
661668
auto &rewriteCtx = ctx.getRewriteContext();
662669

663670
if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {

test/Generics/inverse_copyable_generics.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,25 @@ extension EnumExtendo: ~Copyable {} // expected-error {{cannot apply inverse '~C
177177

178178
extension NeedsCopyable where Self: ~Copyable {}
179179
// expected-error@-1 {{cannot add inverse constraint 'Self: ~Copyable' on generic parameter 'Self' defined in outer scope}}
180+
181+
protocol NoCopyP: ~Copyable {}
182+
183+
func needsCopyable<T>(_ t: T) {} // expected-note 2{{generic parameter 'T' has an implicit Copyable requirement}}
184+
func noCopyable(_ t: borrowing some ~Copyable) {}
185+
func noCopyableAndP(_ t: borrowing some NoCopyP & ~Copyable) {}
186+
187+
func openingExistentials(_ a: borrowing any NoCopyP & ~Copyable,
188+
_ b: any NoCopyP,
189+
_ nc: borrowing any ~Copyable) {
190+
needsCopyable(a) // expected-error {{noncopyable type 'any NoCopyP & ~Copyable' cannot be substituted for copyable generic parameter 'T' in 'needsCopyable'}}
191+
noCopyable(a)
192+
noCopyableAndP(a)
193+
194+
needsCopyable(b)
195+
noCopyable(b)
196+
noCopyableAndP(b)
197+
198+
needsCopyable(nc) // expected-error {{noncopyable type 'any ~Copyable' cannot be substituted for copyable generic parameter 'T' in 'needsCopyable'}}
199+
noCopyable(nc)
200+
noCopyableAndP(nc) // expected-error {{global function 'noCopyableAndP' requires that 'some NoCopyP & ~Copyable' conform to 'NoCopyP'}}
201+
}

0 commit comments

Comments
 (0)