Skip to content

Commit 7b1f41b

Browse files
authored
Merge pull request #72362 from DougGregor/suppressible-noncopyable-generics
Make NoncopyableGenerics a suppressible feature
2 parents 71bee24 + 164ae68 commit 7b1f41b

File tree

6 files changed

+175
-31
lines changed

6 files changed

+175
-31
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ struct PrintOptions {
382382
/// Suppress 'isolated' and '#isolation' on isolated parameters with optional type.
383383
bool SuppressOptionalIsolatedParams = false;
384384

385+
/// Suppress Noncopyable generics.
386+
bool SuppressNoncopyableGenerics = false;
387+
385388
/// List of attribute kinds that should not be printed.
386389
std::vector<AnyAttrKind> ExcludeAttrList = {
387390
DeclAttrKind::Transparent, DeclAttrKind::Effects,

include/swift/Basic/Features.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ EXPERIMENTAL_FEATURE(RawLayout, true)
299299
EXPERIMENTAL_FEATURE(Embedded, true)
300300

301301
/// Enables noncopyable generics
302-
EXPERIMENTAL_FEATURE(NoncopyableGenerics, true)
302+
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(NoncopyableGenerics, true)
303303

304304
/// Allow destructuring stored `let` bindings in structs.
305305
EXPERIMENTAL_FEATURE(StructLetDestructuring, true)

lib/AST/ASTPrinter.cpp

Lines changed: 91 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,22 @@ class PrintAST : public ASTVisitor<PrintAST> {
966966
IncludeOuterInverses = 64,
967967
};
968968

969+
/// The default generic signature flags for printing requirements.
970+
unsigned defaultGenericRequirementFlags() const {
971+
return defaultGenericRequirementFlags(Options);
972+
}
973+
974+
/// The default generic signature flags for printing requirements.
975+
static unsigned
976+
defaultGenericRequirementFlags(const PrintOptions &options) {
977+
unsigned flags = PrintRequirements;
978+
979+
if (!options.SuppressNoncopyableGenerics)
980+
flags |= PrintInverseRequirements;
981+
982+
return flags;
983+
}
984+
969985
void printInheritedFromRequirementSignature(ProtocolDecl *proto,
970986
TypeDecl *attachingTo);
971987
void printWhereClauseFromRequirementSignature(ProtocolDecl *proto,
@@ -1617,7 +1633,8 @@ void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto,
16171633
// inheritance clause, because they do not gain any default requirements.
16181634
// HACK: also exclude Sendable from getting inverses printed.
16191635
if (!proto->getInvertibleProtocolKind()
1620-
&& !proto->isSpecificProtocol(KnownProtocolKind::Sendable))
1636+
&& !proto->isSpecificProtocol(KnownProtocolKind::Sendable) &&
1637+
!Options.SuppressNoncopyableGenerics)
16211638
flags |= PrintInverseRequirements;
16221639

16231640
printRequirementSignature(
@@ -1628,7 +1645,7 @@ void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto,
16281645

16291646
void PrintAST::printWhereClauseFromRequirementSignature(ProtocolDecl *proto,
16301647
TypeDecl *attachingTo) {
1631-
unsigned flags = PrintRequirements | PrintInverseRequirements;
1648+
unsigned flags = defaultGenericRequirementFlags();
16321649
if (isa<AssociatedTypeDecl>(attachingTo))
16331650
flags |= SwapSelfAndDependentMemberType;
16341651
printRequirementSignature(proto, proto->getRequirementSignature(), flags,
@@ -1670,6 +1687,21 @@ void PrintAST::printGenericSignature(GenericSignature genericSig,
16701687
[&](const Requirement &) { return true; });
16711688
}
16721689

1690+
// Erase any requirements involving invertible protocols.
1691+
static void eraseInvertibleProtocolConformances(
1692+
SmallVectorImpl<Requirement> &requirements) {
1693+
llvm::erase_if(requirements, [&](Requirement req) {
1694+
if (req.getKind() == RequirementKind::Conformance) {
1695+
if (auto protoType = req.getSecondType()->getAs<ProtocolType>()) {
1696+
auto proto = protoType->getDecl();
1697+
return proto->getInvertibleProtocolKind().has_value();
1698+
}
1699+
}
1700+
1701+
return false;
1702+
});
1703+
}
1704+
16731705
void PrintAST::printGenericSignature(
16741706
GenericSignature genericSig,
16751707
unsigned flags,
@@ -1683,6 +1715,9 @@ void PrintAST::printGenericSignature(
16831715
} else {
16841716
requirements.append(genericSig.getRequirements().begin(),
16851717
genericSig.getRequirements().end());
1718+
1719+
if (Options.SuppressNoncopyableGenerics)
1720+
eraseInvertibleProtocolConformances(requirements);
16861721
}
16871722

16881723
// Unless `IncludeOuterInverses` is enabled, limit inverses to the
@@ -1976,6 +2011,9 @@ void PrintAST::printRequirementSignature(ProtocolDecl *owner,
19762011
} else {
19772012
requirements.append(sig.getRequirements().begin(),
19782013
sig.getRequirements().end());
2014+
2015+
if (Options.SuppressNoncopyableGenerics)
2016+
eraseInvertibleProtocolConformances(requirements);
19792017
}
19802018

19812019
if (attachingTo) {
@@ -2724,7 +2762,7 @@ void PrintAST::printDeclGenericRequirements(GenericContext *decl) {
27242762
if (parentSig && parentSig->isEqual(genericSig))
27252763
return;
27262764

2727-
unsigned flags = PrintRequirements | PrintInverseRequirements;
2765+
unsigned flags = defaultGenericRequirementFlags();
27282766

27292767
// In many cases, inverses should not be printed for outer generic parameters.
27302768
// Exceptions to that include extensions, as it's valid to write an inverse
@@ -2892,14 +2930,15 @@ void PrintAST::printSynthesizedExtensionImpl(Type ExtendedType,
28922930
SmallVector<InverseRequirement, 2> inverses;
28932931
auto Sig = ED->getGenericSignature();
28942932
Sig->getRequirementsWithInverses(requirements, inverses);
2895-
printSingleDepthOfGenericSignature(Sig.getGenericParams(),
2896-
requirements,
2897-
inverses,
2898-
IsFirst,
2899-
PrintRequirements | PrintInverseRequirements,
2900-
[](const Requirement &Req){
2901-
return true;
2902-
});
2933+
printSingleDepthOfGenericSignature(
2934+
Sig.getGenericParams(),
2935+
requirements,
2936+
inverses,
2937+
IsFirst,
2938+
PrintAST::defaultGenericRequirementFlags(Options),
2939+
[](const Requirement &Req){
2940+
return true;
2941+
});
29032942
};
29042943

29052944
auto printCombinedRequirementsIfNeeded = [&]() -> bool {
@@ -2995,8 +3034,7 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
29953034
assert(baseGenericSig &&
29963035
"an extension can't be generic if the base type isn't");
29973036
printGenericSignature(genericSig,
2998-
PrintRequirements
2999-
| PrintInverseRequirements
3037+
defaultGenericRequirementFlags()
30003038
| IncludeOuterInverses,
30013039
[baseGenericSig](const Requirement &req) -> bool {
30023040
// Only include constraints that are not satisfied by the base type.
@@ -3099,6 +3137,14 @@ static void suppressingFeatureAssociatedTypeImplements(PrintOptions &options,
30993137
options.ExcludeAttrList.resize(originalExcludeAttrCount);
31003138
}
31013139

3140+
static void suppressingFeatureNoncopyableGenerics(
3141+
PrintOptions &options,
3142+
llvm::function_ref<void()> action) {
3143+
llvm::SaveAndRestore<bool> scope(
3144+
options.SuppressNoncopyableGenerics, true);
3145+
action();
3146+
}
3147+
31023148
/// Suppress the printing of a particular feature.
31033149
static void suppressingFeature(PrintOptions &options, Feature feature,
31043150
llvm::function_ref<void()> action) {
@@ -6609,8 +6655,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
66096655
printFunctionExtInfo(T);
66106656
printGenericSignature(T->getGenericSignature(),
66116657
PrintAST::PrintParams |
6612-
PrintAST::PrintRequirements |
6613-
PrintAST::PrintInverseRequirements);
6658+
PrintAST::defaultGenericRequirementFlags(Options));
66146659
Printer << " ";
66156660

66166661
visitAnyFunctionTypeParams(T->getParams(), /*printLabels*/true);
@@ -6696,8 +6741,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
66966741
if (GenericSignature sig = T->getInvocationGenericSignature()) {
66976742
printGenericSignature(sig,
66986743
PrintAST::PrintParams |
6699-
PrintAST::PrintRequirements |
6700-
PrintAST::PrintInverseRequirements);
6744+
PrintAST::defaultGenericRequirementFlags(Options));
67016745
Printer << " ";
67026746
}
67036747

@@ -6833,12 +6877,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
68336877

68346878
// Capture list used here to ensure we don't print anything using `this`
68356879
// printer, but only the sub-Printer.
6836-
[&sub, T]{
6880+
[&sub, T, options=Options]{
68376881
if (auto sig = T->getLayout()->getGenericSignature()) {
68386882
sub.printGenericSignature(sig,
68396883
PrintAST::PrintParams |
6840-
PrintAST::PrintRequirements |
6841-
PrintAST::PrintInverseRequirements);
6884+
PrintAST::defaultGenericRequirementFlags(options));
68426885
sub.Printer << " ";
68436886
}
68446887
sub.Printer << "{";
@@ -7394,8 +7437,8 @@ void GenericSignature::print(ASTPrinter &Printer,
73947437
}
73957438

73967439
auto flags = PrintAST::PrintParams | PrintAST::PrintRequirements;
7397-
if (Opts.PrintInverseRequirements)
7398-
flags |= PrintAST::PrintInverseRequirements;
7440+
if (Opts.PrintInverseRequirements && !Opts.SuppressNoncopyableGenerics)
7441+
flags |= PrintAST::PrintInverseRequirements;
73997442
PrintAST(Printer, Opts).printGenericSignature(*this, flags);
74007443
}
74017444

@@ -7410,8 +7453,8 @@ void RequirementSignature::print(ProtocolDecl *owner,
74107453
ASTPrinter &Printer,
74117454
const PrintOptions &Opts) const {
74127455
auto flags = PrintAST::PrintParams | PrintAST::PrintRequirements;
7413-
if (Opts.PrintInverseRequirements)
7414-
flags |= PrintAST::PrintInverseRequirements;
7456+
if (Opts.PrintInverseRequirements && !Opts.SuppressNoncopyableGenerics)
7457+
flags |= PrintAST::PrintInverseRequirements;
74157458
PrintAST(Printer, Opts).printRequirementSignature(owner, *this, flags, nullptr);
74167459
}
74177460

@@ -7615,10 +7658,10 @@ void ProtocolConformance::printName(llvm::raw_ostream &os,
76157658
StreamPrinter sPrinter(os);
76167659
TypePrinter typePrinter(sPrinter, PO);
76177660
typePrinter
7618-
.printGenericSignature(genericSig,
7619-
PrintAST::PrintParams |
7620-
PrintAST::PrintRequirements |
7621-
PrintAST::PrintInverseRequirements);
7661+
.printGenericSignature(
7662+
genericSig,
7663+
PrintAST::PrintParams |
7664+
PrintAST::defaultGenericRequirementFlags(PO));
76227665
os << ' ';
76237666
}
76247667
}
@@ -7787,6 +7830,26 @@ swift::getInheritedForPrinting(
77877830
});
77887831
if (foundUnprintable)
77897832
continue;
7833+
7834+
// Suppress Copyable and ~Copyable.
7835+
if (options.SuppressNoncopyableGenerics) {
7836+
if (auto pct = ty->getAs<ProtocolCompositionType>()) {
7837+
auto inverses = pct->getInverses();
7838+
if (inverses.contains(InvertibleProtocolKind::Copyable)) {
7839+
inverses.remove(InvertibleProtocolKind::Copyable);
7840+
ty = ProtocolCompositionType::get(decl->getASTContext(),
7841+
pct->getMembers(),
7842+
inverses,
7843+
pct->hasExplicitAnyObject());
7844+
if (ty->isAny())
7845+
continue;
7846+
}
7847+
}
7848+
7849+
if (auto protoTy = ty->getAs<ProtocolType>())
7850+
if (protoTy->getDecl()->isSpecificProtocol(KnownProtocolKind::Copyable))
7851+
continue;
7852+
}
77907853
}
77917854

77927855
Results.push_back(inherited.getEntry(i));

lib/AST/FeatureSet.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,16 @@ static bool usesFeatureNoncopyableGenerics(Decl *decl) {
514514
return true;
515515
}
516516

517+
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
518+
auto reqSig = proto->getRequirementSignature();
519+
520+
SmallVector<Requirement, 2> reqs;
521+
SmallVector<InverseRequirement, 2> inverses;
522+
reqSig.getRequirementsWithInverses(proto, reqs, inverses);
523+
if (!inverses.empty())
524+
return true;
525+
}
526+
517527
if (isa<AbstractFunctionDecl>(valueDecl) ||
518528
isa<AbstractStorageDecl>(valueDecl)) {
519529
if (valueDecl->getInterfaceType().findIf([&](Type type) -> bool {
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name Test -enable-experimental-feature NoncopyableGenerics
3+
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name Test
4+
// RUN: %FileCheck %s < %t.swiftinterface
5+
6+
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
7+
// CHECK: public protocol P : ~Copyable {
8+
// CHECK: associatedtype A : ~Copyable
9+
// CHECK: }
10+
// CHECK: #else
11+
// CHECK: public protocol P {
12+
// CHECK: associatedtype A
13+
// CHECK: }
14+
// CHECK: #endif
15+
public protocol P: ~Copyable {
16+
associatedtype A: ~Copyable
17+
}
18+
19+
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
20+
// CHECK: public struct X<T> : ~Copyable where T : ~Copyable {
21+
// CHECK: }
22+
// CHECK: #else
23+
// CHECK: public struct X<T> {
24+
// CHECK: }
25+
// CHECK: #endif
26+
public struct X<T: ~Copyable>: ~Copyable { }
27+
28+
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
29+
// CHECK: extension Test.X : Swift.Copyable {
30+
// CHECK-NEXT: func f()
31+
// CHECK: }
32+
// CHECK: #else
33+
// CHECK: extension Test.X {
34+
// CHECK-NEXT: func f()
35+
// CHECK: }
36+
extension X: Copyable {
37+
public func f() { }
38+
}
39+
40+
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
41+
// CHECK: extension Test.X where T : ~Copyable {
42+
// CHECK: public func g(other: borrowing T)
43+
// CHECK: }
44+
// CHECK: #else
45+
// CHECK: extension Test.X {
46+
// CHECK: public func g(other: borrowing T)
47+
// CHECK: }
48+
// CHECK: #endif
49+
extension X where T: ~Copyable {
50+
public func g(other: borrowing T) { }
51+
}
52+
53+
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
54+
// CHECK: public enum Y<T> : ~Copyable where T : ~Copyable {
55+
// CHECK: case none
56+
// CHECK: case some(T)
57+
// CHECK: }
58+
// CHECK: #else
59+
// CHECK: public enum Y<T> {
60+
// CHECK: case none
61+
// CHECK: case some(T)
62+
// CHECK: }
63+
public enum Y<T: ~Copyable>: ~Copyable {
64+
case none
65+
case some(T)
66+
}
67+
68+
extension Y: Copyable where T: Copyable { }

test/ModuleInterface/noncopyable_generics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,12 @@ import NoncopyableGenerics_Misc
8686
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
8787
// CHECK-MISC-NEXT: extension NoncopyableGenerics_Misc.Hello : Swift.Escapable where T : ~Copyable {
8888
// CHECK-MISC-NEXT: }
89-
// CHECK-MISC-NEXT: #endif
89+
// CHECK-MISC: #endif
9090

9191
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
9292
// CHECK-MISC-NEXT: extension NoncopyableGenerics_Misc.Hello : Swift.Copyable where T : ~Escapable {
9393
// CHECK-MISC-NEXT: }
94-
// CHECK-MISC-NEXT: #endif
94+
// CHECK-MISC: #endif
9595

9696
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
9797
// CHECK-MISC-NEXT: public protocol TestAssocTypes {

0 commit comments

Comments
 (0)