Add feature for rethrows protocols and use it in module interface generation

This commit is contained in:
Doug Gregor
2021-02-22 16:18:47 -08:00
parent 267838db44
commit f21c60928c
3 changed files with 62 additions and 0 deletions

View File

@@ -39,5 +39,6 @@ LANGUAGE_FEATURE(AsyncAwait, 296, "async/await", true)
LANGUAGE_FEATURE(MarkerProtocol, 0, "@_marker protocol", true) LANGUAGE_FEATURE(MarkerProtocol, 0, "@_marker protocol", true)
LANGUAGE_FEATURE(Actors, 0, "actors", langOpts.EnableExperimentalConcurrency) LANGUAGE_FEATURE(Actors, 0, "actors", langOpts.EnableExperimentalConcurrency)
LANGUAGE_FEATURE(ConcurrentFunctions, 0, "@concurrent functions", true) LANGUAGE_FEATURE(ConcurrentFunctions, 0, "@concurrent functions", true)
LANGUAGE_FEATURE(RethrowsProtocol, 0, "@rethrows protocol", true)
#undef LANGUAGE_FEATURE #undef LANGUAGE_FEATURE

View File

@@ -2511,6 +2511,57 @@ static bool usesFeatureConcurrentFunctions(Decl *decl) {
return false; return false;
} }
static bool usesFeatureRethrowsProtocol(
Decl *decl, SmallPtrSet<Decl *, 16> &checked) {
// Make sure we don't recurse.
if (!checked.insert(decl).second)
return false;
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
if (proto->getAttrs().hasAttribute<AtRethrowsAttr>())
return true;
}
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
if (auto proto = ext->getSelfProtocolDecl())
if (usesFeatureRethrowsProtocol(proto, checked))
return true;
}
if (auto genericSig = decl->getInnermostDeclContext()
->getGenericSignatureOfContext()) {
for (const auto &req : genericSig->getRequirements()) {
if (req.getKind() == RequirementKind::Conformance &&
usesFeatureRethrowsProtocol(
req.getSecondType()->getAs<ProtocolType>()->getDecl(), checked))
return true;
}
}
if (auto value = dyn_cast<ValueDecl>(decl)) {
if (Type type = value->getInterfaceType()) {
bool hasRethrowsProtocol = type.findIf([&](Type type) {
if (auto nominal = type->getAnyNominal()) {
if (usesFeatureRethrowsProtocol(nominal, checked))
return true;
}
return false;
});
if (hasRethrowsProtocol)
return true;
}
}
return false;
}
static bool usesFeatureRethrowsProtocol(Decl *decl) {
SmallPtrSet<Decl *, 16> checked;
return usesFeatureRethrowsProtocol(decl, checked);
}
/// Determine the set of "new" features used on a given declaration. /// Determine the set of "new" features used on a given declaration.
/// ///
/// Note: right now, all features we check for are "new". At some point, we'll /// Note: right now, all features we check for are "new". At some point, we'll

View File

@@ -67,6 +67,16 @@ public class OldSchool: MP {
public func takeClass() async { } public func takeClass() async { }
} }
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
// CHECK-NEXT: @rethrows public protocol RP
@rethrows public protocol RP {
func f() throws
}
// CHECK: #if compiler(>=5.3) && $RethrowsProtocol
// CHECK-NEXT: public func acceptsRP
public func acceptsRP<T: RP>(_: T) { }
// CHECK-NOT: #if compiler(>=5.3) && $MarkerProtocol // CHECK-NOT: #if compiler(>=5.3) && $MarkerProtocol
// CHECK: extension Array : FeatureTest.MP where Element : FeatureTest.MP { // CHECK: extension Array : FeatureTest.MP where Element : FeatureTest.MP {
extension Array: FeatureTest.MP where Element : FeatureTest.MP { } extension Array: FeatureTest.MP where Element : FeatureTest.MP { }