Skip to content

Commit fb968ca

Browse files
authored
Merge pull request swiftlang#36415 from DougGregor/module-interface-more-ifs
[Module interfaces] More aggressively #if-out declarations.
2 parents 2aae121 + c18ef1a commit fb968ca

File tree

3 files changed

+128
-29
lines changed

3 files changed

+128
-29
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,16 +2446,53 @@ static bool usesFeatureAsyncAwait(Decl *decl) {
24462446
}
24472447

24482448
static bool usesFeatureMarkerProtocol(Decl *decl) {
2449+
// Check an inheritance clause for a marker protocol.
2450+
auto checkInherited = [&](ArrayRef<TypeLoc> inherited) -> bool {
2451+
for (const auto &inheritedEntry : inherited) {
2452+
if (auto inheritedType = inheritedEntry.getType()) {
2453+
if (inheritedType->isExistentialType()) {
2454+
auto layout = inheritedType->getExistentialLayout();
2455+
for (ProtocolType *protoTy : layout.getProtocols()) {
2456+
if (protoTy->getDecl()->isMarkerProtocol())
2457+
return true;
2458+
}
2459+
}
2460+
}
2461+
}
2462+
2463+
return false;
2464+
};
2465+
2466+
// Check generic requirements for a marker protocol.
2467+
auto checkRequirements = [&](ArrayRef<Requirement> requirements) -> bool {
2468+
for (const auto &req: requirements) {
2469+
if (req.getKind() == RequirementKind::Conformance &&
2470+
req.getSecondType()->castTo<ProtocolType>()->getDecl()
2471+
->isMarkerProtocol())
2472+
return true;
2473+
}
2474+
2475+
return false;
2476+
};
2477+
24492478
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
24502479
if (proto->isMarkerProtocol())
24512480
return true;
2481+
2482+
if (checkInherited(proto->getInherited()))
2483+
return true;
2484+
2485+
if (checkRequirements(proto->getRequirementSignature()))
2486+
return true;
24522487
}
24532488

24542489
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
2455-
if (auto proto = ext->getSelfProtocolDecl())
2456-
if (proto->isMarkerProtocol())
2457-
return true;
2458-
}
2490+
if (checkRequirements(ext->getGenericRequirements()))
2491+
return true;
2492+
2493+
if (checkInherited(ext->getInherited()))
2494+
return true;
2495+
}
24592496

24602497
return false;
24612498
}
@@ -2524,15 +2561,40 @@ static bool usesFeatureRethrowsProtocol(
25242561
if (!checked.insert(decl).second)
25252562
return false;
25262563

2564+
// Check an inheritance clause for a marker protocol.
2565+
auto checkInherited = [&](ArrayRef<TypeLoc> inherited) -> bool {
2566+
for (const auto &inheritedEntry : inherited) {
2567+
if (auto inheritedType = inheritedEntry.getType()) {
2568+
if (inheritedType->isExistentialType()) {
2569+
auto layout = inheritedType->getExistentialLayout();
2570+
for (ProtocolType *protoTy : layout.getProtocols()) {
2571+
if (usesFeatureRethrowsProtocol(protoTy->getDecl(), checked))
2572+
return true;
2573+
}
2574+
}
2575+
}
2576+
}
2577+
2578+
return false;
2579+
};
2580+
2581+
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
2582+
if (checkInherited(nominal->getInherited()))
2583+
return true;
2584+
}
2585+
25272586
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
25282587
if (proto->getAttrs().hasAttribute<AtRethrowsAttr>())
25292588
return true;
25302589
}
25312590

25322591
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
2533-
if (auto proto = ext->getSelfProtocolDecl())
2534-
if (usesFeatureRethrowsProtocol(proto, checked))
2592+
if (auto nominal = ext->getSelfNominalTypeDecl())
2593+
if (usesFeatureRethrowsProtocol(nominal, checked))
25352594
return true;
2595+
2596+
if (checkInherited(ext->getInherited()))
2597+
return true;
25362598
}
25372599

25382600
if (auto genericSig = decl->getInnermostDeclContext()
@@ -2635,15 +2697,30 @@ static std::vector<Feature> getUniqueFeaturesUsed(Decl *decl) {
26352697
if (features.empty())
26362698
return features;
26372699

2638-
Decl *enclosingDecl;
2639-
if (auto accessor = dyn_cast<AccessorDecl>(decl))
2640-
enclosingDecl = accessor->getStorage();
2641-
else
2642-
enclosingDecl = decl->getDeclContext()->getAsDecl();
2643-
if (!enclosingDecl)
2644-
return features;
2700+
// Gather the features used by all enclosing declarations.
2701+
Decl *enclosingDecl = decl;
2702+
std::vector<Feature> enclosingFeatures;
2703+
while (true) {
2704+
// Find the next outermost enclosing declaration.
2705+
if (auto accessor = dyn_cast<AccessorDecl>(enclosingDecl))
2706+
enclosingDecl = accessor->getStorage();
2707+
else
2708+
enclosingDecl = enclosingDecl->getDeclContext()->getAsDecl();
2709+
if (!enclosingDecl)
2710+
break;
2711+
2712+
auto outerEnclosingFeatures = getFeaturesUsed(enclosingDecl);
2713+
if (outerEnclosingFeatures.empty())
2714+
continue;
2715+
2716+
auto currentEnclosingFeatures = std::move(enclosingFeatures);
2717+
enclosingFeatures.clear();
2718+
std::merge(outerEnclosingFeatures.begin(), outerEnclosingFeatures.end(),
2719+
currentEnclosingFeatures.begin(), currentEnclosingFeatures.end(),
2720+
std::back_inserter(enclosingFeatures));
2721+
}
26452722

2646-
auto enclosingFeatures = getFeaturesUsed(enclosingDecl);
2723+
// If there were no enclosing features, we're done.
26472724
if (enclosingFeatures.empty())
26482725
return features;
26492726

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,11 +550,11 @@ class InheritedProtocolCollector {
550550
if (!handledProtocols.insert(inherited).second)
551551
return TypeWalker::Action::SkipChildren;
552552

553-
// If 'nominal' is an 'actor class', we do not synthesize its
554-
// conformance to the Actor protocol through a dummy extension.
553+
// If 'nominal' is an actor, we do not synthesize its conformance
554+
// to the Actor protocol through a dummy extension.
555555
// There is a special restriction on the Actor protocol in that
556-
// it is only valid to conform to Actor on an 'actor class' decl,
557-
// not extensions of that 'actor class'.
556+
// it is only valid to conform to Actor on an 'actor' decl,
557+
// not extensions of that 'actor'.
558558
if (actorClass &&
559559
inherited->isSpecificProtocol(KnownProtocolKind::Actor))
560560
return TypeWalker::Action::SkipChildren;

test/ModuleInterface/features.swift

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
// compilers to skip over the uses of newer features.
1111

1212
// CHECK: #if compiler(>=5.3) && $Actors
13-
// CHECK-NEXT: actor {{.*}} MyActor
13+
// CHECK-NEXT: public actor MyActor
1414
// CHECK: }
1515
// CHECK-NEXT: #endif
16-
public actor class MyActor {
16+
public actor MyActor {
1717
}
1818

1919
// CHECK: #if compiler(>=5.3) && $Actors
@@ -47,10 +47,10 @@ public func globalAsync() async { }
4747
// CHECK-NEXT: #endif
4848
@_marker public protocol MP2: MP { }
4949

50-
// CHECK-NOT: #if compiler(>=5.3) && $MarkerProtocol
51-
// CHECK: public protocol MP3 : FeatureTest.MP {
50+
// CHECK: #if compiler(>=5.3) && $MarkerProtocol
51+
// CHECK-NEXT: public protocol MP3 : AnyObject, FeatureTest.MP {
5252
// CHECK-NEXT: }
53-
public protocol MP3: MP { }
53+
public protocol MP3: AnyObject, MP { }
5454

5555
// CHECK: #if compiler(>=5.3) && $MarkerProtocol
5656
// CHECK-NEXT: extension MP2 {
@@ -67,10 +67,18 @@ public class OldSchool: MP {
6767
public func takeClass() async { }
6868
}
6969

70+
// CHECK: class OldSchool2 {
71+
public class OldSchool2: MP {
72+
// CHECK: #if compiler(>=5.3) && $AsyncAwait
73+
// CHECK-NEXT: takeClass()
74+
// CHECK-NEXT: #endif
75+
public func takeClass() async { }
76+
}
77+
7078
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
7179
// CHECK-NEXT: @rethrows public protocol RP
7280
@rethrows public protocol RP {
73-
func f() throws
81+
func f() throws -> Bool
7482
}
7583

7684
// CHECK: public struct UsesRP {
@@ -84,17 +92,31 @@ public struct UsesRP {
8492
}
8593
}
8694

95+
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
96+
// CHECK-NEXT: public struct IsRP
97+
public struct IsRP: RP {
98+
// CHECK-NEXT: public func f()
99+
public func f() -> Bool { }
100+
101+
// CHECK-NOT: $RethrowsProtocol
102+
// CHECK-NEXT: public var isF:
103+
// CHECK-NEXT: get
104+
public var isF: Bool {
105+
f()
106+
}
107+
}
108+
87109
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
88110
// CHECK-NEXT: public func acceptsRP
89111
public func acceptsRP<T: RP>(_: T) { }
90112

91-
// CHECK-NOT: #if compiler(>=5.3) && $MarkerProtocol
92-
// CHECK: extension Array : FeatureTest.MP where Element : FeatureTest.MP {
113+
// CHECK: #if compiler(>=5.3) && $MarkerProtocol
114+
// CHECK-NEXT: extension Array : FeatureTest.MP where Element : FeatureTest.MP {
93115
extension Array: FeatureTest.MP where Element : FeatureTest.MP { }
94-
// CHECK-NEXT: }
116+
// CHECK: }
95117

96-
// CHECK-NOT: #if compiler(>=5.3) && $MarkerProtocol
97-
// CHECK: extension OldSchool : Swift.UnsafeConcurrentValue {
118+
// CHECK: #if compiler(>=5.3) && $MarkerProtocol
119+
// CHECK-NEXT: extension OldSchool : Swift.UnsafeConcurrentValue {
98120
extension OldSchool: UnsafeConcurrentValue { }
99121
// CHECK-NEXT: }
100122

0 commit comments

Comments
 (0)