Skip to content

Commit bd2064a

Browse files
authored
Merge pull request #35839 from DougGregor/backward-compatible-module-interfaces
2 parents eddd874 + 643ce71 commit bd2064a

File tree

9 files changed

+397
-11
lines changed

9 files changed

+397
-11
lines changed

Diff for: include/swift/AST/ASTPrinter.h

+4
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@ void getInheritedForPrinting(const Decl *decl, const PrintOptions &options,
355355
llvm::SmallVectorImpl<TypeLoc> &Results);
356356

357357
StringRef getAccessorKindString(AccessorKind value);
358+
359+
bool printCompatibilityFeatureChecksPre(ASTPrinter &printer, Decl *decl);
360+
void printCompatibilityFeatureChecksPost(ASTPrinter &printer);
361+
358362
} // namespace swift
359363

360364
#endif // LLVM_SWIFT_AST_ASTPRINTER_H

Diff for: include/swift/AST/PrintOptions.h

+4
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ struct PrintOptions {
460460
/// Whether to print inheritance lists for types.
461461
bool PrintInherited = true;
462462

463+
/// Whether to print feature checks for compatibility with older Swift
464+
/// compilers that might parse the result.
465+
bool PrintCompatibilityFeatureChecks = false;
466+
463467
/// \see ShouldQualifyNestedDeclarations
464468
enum class QualifyNestedDeclarations {
465469
Never,

Diff for: include/swift/Basic/Feature.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===--- Feature.h - Helpers related to Swift features ----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_BASIC_FEATURES_H
14+
#define SWIFT_BASIC_FEATURES_H
15+
16+
#include "llvm/ADT/StringRef.h"
17+
18+
namespace swift {
19+
20+
class LangOptions;
21+
22+
/// Enumeration describing all of the named features.
23+
enum class Feature {
24+
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
25+
FeatureName,
26+
#include "swift/Basic/Features.def"
27+
};
28+
29+
/// Determine the in-source name of the given feature.
30+
llvm::StringRef getFeatureName(Feature feature);
31+
32+
}
33+
34+
#endif // SWIFT_BASIC_FEATURES_H

Diff for: include/swift/Basic/Features.def

+5-4
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
// features.
1515
//
1616
//
17-
// FEATURE(FeatureName, SENumber, Description, Option)
17+
// LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
1818
//
19-
// The FEATURE macro describes each named feature that is introduced in
20-
// Swift. It allows Swift code to check for a particular feature with
21-
// "#if $FeatureName" in source code.
19+
// The LANGUAGE_FEATURE macro describes each named feature that is
20+
// introduced in Swift. It allows Swift code to check for a particular
21+
// feature with "#if $FeatureName" in source code.
2222
//
2323
// FeatureName: The name given to this feature to be used in source code,
2424
// e.g., AsyncAwait.
@@ -36,6 +36,7 @@
3636

3737
LANGUAGE_FEATURE(StaticAssert, 0, "#assert", langOpts.EnableExperimentalStaticAssert)
3838
LANGUAGE_FEATURE(AsyncAwait, 296, "async/await", true)
39+
LANGUAGE_FEATURE(MarkerProtocol, 0, "@_marker protocol", true)
3940
LANGUAGE_FEATURE(Actors, 0, "actors", langOpts.EnableExperimentalConcurrency)
4041

4142
#undef LANGUAGE_FEATURE

Diff for: lib/AST/ASTPrinter.cpp

+221-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/ClangModuleLoader.h"
2323
#include "swift/AST/Comment.h"
2424
#include "swift/AST/Decl.h"
25+
#include "swift/AST/ExistentialLayout.h"
2526
#include "swift/AST/Expr.h"
2627
#include "swift/AST/FileUnit.h"
2728
#include "swift/AST/GenericSignature.h"
@@ -36,6 +37,7 @@
3637
#include "swift/AST/TypeWalker.h"
3738
#include "swift/AST/Types.h"
3839
#include "swift/Basic/Defer.h"
40+
#include "swift/Basic/Feature.h"
3941
#include "swift/Basic/PrimitiveParsing.h"
4042
#include "swift/Basic/QuotedString.h"
4143
#include "swift/Basic/STLExtras.h"
@@ -137,6 +139,9 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
137139
// We should print __consuming, __owned, etc for the module interface file.
138140
result.SkipUnderscoredKeywords = false;
139141

142+
// We should provide backward-compatible Swift interfaces when we can.
143+
result.PrintCompatibilityFeatureChecks = true;
144+
140145
result.FunctionBody = [](const ValueDecl *decl, ASTPrinter &printer) {
141146
auto AFD = dyn_cast<AbstractFunctionDecl>(decl);
142147
if (!AFD)
@@ -955,10 +960,17 @@ class PrintAST : public ASTVisitor<PrintAST> {
955960
}
956961
}
957962

963+
958964
Printer.callPrintDeclPre(D, Options.BracketOptions);
959965

966+
bool haveFeatureChecks = Options.PrintCompatibilityFeatureChecks &&
967+
printCompatibilityFeatureChecksPre(Printer, D);
968+
960969
ASTVisitor::visit(D);
961970

971+
if (haveFeatureChecks)
972+
printCompatibilityFeatureChecksPost(Printer);
973+
962974
if (Synthesize) {
963975
Printer.setSynthesizedTarget({});
964976
Printer.printSynthesizedExtensionPost(cast<ExtensionDecl>(D),
@@ -2255,6 +2267,11 @@ static void printExtendedTypeName(Type ExtendedType, ASTPrinter &Printer,
22552267

22562268
void PrintAST::printSynthesizedExtension(Type ExtendedType,
22572269
ExtensionDecl *ExtDecl) {
2270+
// Print compatibility features checks first, if we need them.
2271+
bool haveFeatureChecks = Options.PrintCompatibilityFeatureChecks &&
2272+
Options.BracketOptions.shouldOpenExtension(ExtDecl) &&
2273+
Options.BracketOptions.shouldCloseExtension(ExtDecl) &&
2274+
printCompatibilityFeatureChecksPre(Printer, ExtDecl);
22582275

22592276
auto printRequirementsFrom = [&](ExtensionDecl *ED, bool &IsFirst) {
22602277
auto Sig = ED->getGenericSignature();
@@ -2297,7 +2314,6 @@ void PrintAST::printSynthesizedExtension(Type ExtendedType,
22972314
return true;
22982315
};
22992316

2300-
23012317
if (Options.BracketOptions.shouldOpenExtension(ExtDecl)) {
23022318
printDocumentationComment(ExtDecl);
23032319
printAttributes(ExtDecl);
@@ -2330,6 +2346,9 @@ void PrintAST::printSynthesizedExtension(Type ExtendedType,
23302346
Options.BracketOptions.shouldOpenExtension(ExtDecl),
23312347
Options.BracketOptions.shouldCloseExtension(ExtDecl));
23322348
}
2349+
2350+
if (haveFeatureChecks)
2351+
printCompatibilityFeatureChecksPost(Printer);
23332352
}
23342353

23352354
void PrintAST::printExtension(ExtensionDecl *decl) {
@@ -2373,6 +2392,194 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
23732392
}
23742393
}
23752394

2395+
/// Functions to determine which features a particular declaration uses. The
2396+
/// usesFeatureNNN functions correspond to the features in Features.def.
2397+
2398+
static bool usesFeatureStaticAssert(Decl *decl) {
2399+
return false;
2400+
}
2401+
2402+
static bool usesFeatureAsyncAwait(Decl *decl) {
2403+
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
2404+
if (func->hasAsync())
2405+
return true;
2406+
}
2407+
2408+
// Check for async functions in the types of declarations.
2409+
if (auto value = dyn_cast<ValueDecl>(decl)) {
2410+
if (Type type = value->getInterfaceType()) {
2411+
bool hasAsync = type.findIf([](Type type) {
2412+
if (auto fnType = type->getAs<AnyFunctionType>()) {
2413+
if (fnType->isAsync())
2414+
return true;
2415+
}
2416+
2417+
return false;
2418+
});
2419+
2420+
if (hasAsync)
2421+
return true;
2422+
}
2423+
}
2424+
2425+
return false;
2426+
}
2427+
2428+
static bool usesFeatureMarkerProtocol(Decl *decl) {
2429+
// Check an inheritance clause for a marker protocol.
2430+
auto checkInherited = [&](ArrayRef<TypeLoc> inherited) -> bool {
2431+
for (const auto &inheritedEntry : inherited) {
2432+
if (auto inheritedType = inheritedEntry.getType()) {
2433+
if (inheritedType->isExistentialType()) {
2434+
auto layout = inheritedType->getExistentialLayout();
2435+
for (ProtocolType *protoTy : layout.getProtocols()) {
2436+
if (protoTy->getDecl()->isMarkerProtocol())
2437+
return true;
2438+
}
2439+
}
2440+
}
2441+
}
2442+
2443+
return false;
2444+
};
2445+
2446+
// Check generic requirements for a marker protocol.
2447+
auto checkRequirements = [&](ArrayRef<Requirement> requirements) -> bool {
2448+
for (const auto &req: requirements) {
2449+
if (req.getKind() == RequirementKind::Conformance &&
2450+
req.getSecondType()->castTo<ProtocolType>()->getDecl()
2451+
->isMarkerProtocol())
2452+
return true;
2453+
}
2454+
2455+
return false;
2456+
};
2457+
2458+
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
2459+
if (proto->isMarkerProtocol())
2460+
return true;
2461+
2462+
if (checkInherited(proto->getInherited()))
2463+
return true;
2464+
2465+
if (checkRequirements(proto->getRequirementSignature()))
2466+
return true;
2467+
}
2468+
2469+
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
2470+
if (checkRequirements(ext->getGenericRequirements()))
2471+
return true;
2472+
2473+
if (checkInherited(ext->getInherited()))
2474+
return true;
2475+
}
2476+
2477+
return false;
2478+
}
2479+
2480+
static bool usesFeatureActors(Decl *decl) {
2481+
if (auto classDecl = dyn_cast<ClassDecl>(decl)) {
2482+
if (classDecl->isActor())
2483+
return true;
2484+
}
2485+
2486+
if (auto ext = dyn_cast<ExtensionDecl>(decl)) {
2487+
if (auto classDecl = ext->getSelfClassDecl())
2488+
if (classDecl->isActor())
2489+
return true;
2490+
}
2491+
2492+
// Check for actors in the types of declarations.
2493+
if (auto value = dyn_cast<ValueDecl>(decl)) {
2494+
if (Type type = value->getInterfaceType()) {
2495+
bool hasActor = type.findIf([](Type type) {
2496+
if (auto classDecl = type->getClassOrBoundGenericClass()) {
2497+
if (classDecl->isActor())
2498+
return true;
2499+
}
2500+
2501+
return false;
2502+
});
2503+
2504+
if (hasActor)
2505+
return true;
2506+
}
2507+
}
2508+
2509+
return false;
2510+
}
2511+
2512+
/// Determine the set of "new" features used on a given declaration.
2513+
///
2514+
/// Note: right now, all features we check for are "new". At some point, we'll
2515+
/// want a baseline version.
2516+
static std::vector<Feature> getFeaturesUsed(Decl *decl) {
2517+
std::vector<Feature> features;
2518+
2519+
// Go through each of the features, checking whether the declaration uses that
2520+
// feature. This also ensures that the resulting set is in sorted order.
2521+
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
2522+
if (usesFeature##FeatureName(decl)) \
2523+
features.push_back(Feature::FeatureName);
2524+
#include "swift/Basic/Features.def"
2525+
2526+
return features;
2527+
}
2528+
2529+
/// Get the set of features that are uniquely used by this declaration, and are
2530+
/// not part of the enclosing context.
2531+
static std::vector<Feature> getUniqueFeaturesUsed(Decl *decl) {
2532+
auto features = getFeaturesUsed(decl);
2533+
if (features.empty())
2534+
return features;
2535+
2536+
auto enclosingDecl = decl->getDeclContext()->getAsDecl();
2537+
if (!enclosingDecl)
2538+
return features;
2539+
2540+
if (!isa<NominalTypeDecl>(enclosingDecl) &&
2541+
!isa<ExtensionDecl>(enclosingDecl))
2542+
return features;
2543+
2544+
auto enclosingFeatures = getFeaturesUsed(enclosingDecl);
2545+
if (enclosingFeatures.empty())
2546+
return features;
2547+
2548+
// Remove any features from the enclosing context from this set of features so
2549+
// that we are left with a unique set.
2550+
std::vector<Feature> uniqueFeatures;
2551+
std::set_difference(
2552+
features.begin(), features.end(),
2553+
enclosingFeatures.begin(), enclosingFeatures.end(),
2554+
std::back_inserter(uniqueFeatures));
2555+
return uniqueFeatures;
2556+
}
2557+
2558+
2559+
bool swift::printCompatibilityFeatureChecksPre(
2560+
ASTPrinter &printer, Decl *decl) {
2561+
auto features = getUniqueFeaturesUsed(decl);
2562+
if (features.empty())
2563+
return false;
2564+
2565+
printer.printNewline();
2566+
printer << "#if compiler(>=5.3) && ";
2567+
llvm::interleave(features.begin(), features.end(),
2568+
[&](Feature feature) {
2569+
printer << "$" << getFeatureName(feature);
2570+
},
2571+
[&] { printer << " && "; });
2572+
printer.printNewline();
2573+
2574+
return true;
2575+
}
2576+
2577+
void swift::printCompatibilityFeatureChecksPost(ASTPrinter &printer) {
2578+
printer.printNewline();
2579+
printer << "#endif\n";
2580+
}
2581+
2582+
23762583
void PrintAST::visitExtensionDecl(ExtensionDecl *decl) {
23772584
if (Options.TransformContext &&
23782585
Options.TransformContext->isPrintingSynthesizedExtension()) {
@@ -5232,11 +5439,21 @@ swift::getInheritedForPrinting(const Decl *decl, const PrintOptions &options,
52325439
// Collect explicit inherited types.
52335440
for (auto TL: inherited) {
52345441
if (auto ty = TL.getType()) {
5235-
bool foundUnprintable = ty.findIf([&options](Type subTy) {
5442+
bool foundUnprintable = ty.findIf([&](Type subTy) {
52365443
if (auto aliasTy = dyn_cast<TypeAliasType>(subTy.getPointer()))
52375444
return !options.shouldPrint(aliasTy->getDecl());
5238-
if (auto NTD = subTy->getAnyNominal())
5239-
return !options.shouldPrint(NTD);
5445+
if (auto NTD = subTy->getAnyNominal()) {
5446+
if (!options.shouldPrint(NTD))
5447+
return true;
5448+
5449+
if (auto PD = dyn_cast<ProtocolDecl>(NTD)) {
5450+
// Marker protocols are unprintable on concrete types, but they're
5451+
// okay on extension declarations and protocols.
5452+
if (PD->isMarkerProtocol() && !isa<ExtensionDecl>(decl) &&
5453+
!isa<ProtocolDecl>(decl))
5454+
return true;
5455+
}
5456+
}
52405457
return false;
52415458
});
52425459
if (foundUnprintable)

Diff for: lib/Basic/LangOptions.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "swift/Basic/LangOptions.h"
19+
#include "swift/Basic/Feature.h"
1920
#include "swift/Basic/Platform.h"
2021
#include "swift/Basic/Range.h"
2122
#include "swift/Config.h"
@@ -375,3 +376,11 @@ std::pair<bool, bool> LangOptions::setTarget(llvm::Triple triple) {
375376

376377
return { false, false };
377378
}
379+
380+
llvm::StringRef swift::getFeatureName(Feature feature) {
381+
switch (feature) {
382+
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
383+
case Feature::FeatureName: return #FeatureName;
384+
#include "swift/Basic/Features.def"
385+
}
386+
}

0 commit comments

Comments
 (0)