Skip to content

Commit 8614620

Browse files
authored
Merge pull request swiftlang#12805 from DougGregor/validate-stdlib-generic-signatures
2 parents d99c72a + 5d5e612 commit 8614620

File tree

10 files changed

+135
-1
lines changed

10 files changed

+135
-1
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,16 @@ class GenericSignatureBuilder {
802802
/// Determine whether the two given types are in the same equivalence class.
803803
bool areInSameEquivalenceClass(Type type1, Type type2);
804804

805+
/// Verify the correctness of the given generic signature.
806+
///
807+
/// This routine will test that the given generic signature is both minimal
808+
/// and canonical, emitting errors if it is not.
809+
static void verifyGenericSignature(ASTContext &context,
810+
GenericSignature *sig);
811+
812+
/// Verify all of the generic sigantures in the given module.
813+
static void verifyGenericSignaturesInModule(ModuleDecl *module);
814+
805815
/// \brief Dump all of the requirements, both specified and inferred.
806816
LLVM_ATTRIBUTE_DEPRECATED(
807817
void dump(),

include/swift/AST/Module.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,15 @@ class LoadedFile : public FileUnit {
11731173

11741174
virtual bool isSystemModule() const { return false; }
11751175

1176+
/// Retrieve the set of generic signatures stored within this module.
1177+
///
1178+
/// \returns \c true if this module file supports retrieving all of the
1179+
/// generic signatures, \c false otherwise.
1180+
virtual bool getAllGenericSignatures(
1181+
SmallVectorImpl<GenericSignature*> &genericSignatures) {
1182+
return false;
1183+
}
1184+
11761185
static bool classof(const FileUnit *file) {
11771186
return file->getKind() == FileUnitKind::SerializedAST ||
11781187
file->getKind() == FileUnitKind::ClangModule;

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ class FrontendOptions {
296296
/// too complex.
297297
unsigned SolverExpressionTimeThreshold = 0;
298298

299+
/// The module for which we should verify all of the generic signatures.
300+
std::string VerifyGenericSignaturesInModule;
301+
299302
enum ActionType {
300303
NoneAction, ///< No specific action
301304
Parse, ///< Parse only

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ def verify_apply_fixes : Flag<["-"], "verify-apply-fixes">,
7676
HelpText<"Like -verify, but updates the original source file">;
7777
def verify_ignore_unknown: Flag<["-"], "verify-ignore-unknown">,
7878
HelpText<"Allow diagnostics for '<unknown>' location in verify mode">;
79+
def verify_generic_signatures : Separate<["-"], "verify-generic-signatures">,
80+
MetaVarName<"<module-name>">,
81+
HelpText<"Verify the generic signatures in the given module">;
7982

8083
def show_diagnostics_after_fatal : Flag<["-"], "show-diagnostics-after-fatal">,
8184
HelpText<"Keep emitting subsequent diagnostics after a fatal error">;

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ class SerializedASTFile final : public LoadedFile {
195195

196196
virtual const clang::Module *getUnderlyingClangModule() const override;
197197

198+
virtual bool getAllGenericSignatures(
199+
SmallVectorImpl<GenericSignature*> &genericSignatures)
200+
override;
201+
198202
static bool classof(const FileUnit *file) {
199203
return file->getKind() == FileUnitKind::SerializedAST;
200204
}

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/LazyResolver.h"
2626
#include "swift/AST/Module.h"
2727
#include "swift/AST/ParameterList.h"
28+
#include "swift/AST/PrettyStackTrace.h"
2829
#include "swift/AST/ProtocolConformance.h"
2930
#include "swift/AST/TypeMatcher.h"
3031
#include "swift/AST/TypeRepr.h"
@@ -6364,7 +6365,7 @@ GenericSignature *GenericSignatureBuilder::computeGenericSignature(
63646365
// over-minimizing.
63656366
if (allowBuilderToMove && !Impl->HadAnyError &&
63666367
!Impl->HadAnyRedundantConstraints) {
6367-
// Register this generic signature builer as the canonical builder for the
6368+
// Register this generic signature builder as the canonical builder for the
63686369
// given signature.
63696370
Context.registerGenericSignatureBuilder(sig, std::move(*this));
63706371
}
@@ -6402,3 +6403,77 @@ GenericSignature *GenericSignatureBuilder::computeRequirementSignature(
64026403
/*allowBuilderToMove=*/false);
64036404
}
64046405

6406+
#pragma mark Generic signature verification
6407+
6408+
void GenericSignatureBuilder::verifyGenericSignature(ASTContext &context,
6409+
GenericSignature *sig) {
6410+
llvm::errs() << "Validating generic signature: ";
6411+
sig->print(llvm::errs());
6412+
llvm::errs() << "\n";
6413+
6414+
// Try removing each requirement in turn.
6415+
auto genericParams = sig->getGenericParams();
6416+
auto requirements = sig->getRequirements();
6417+
for (unsigned victimIndex : indices(requirements)) {
6418+
PrettyStackTraceGenericSignature debugStack("verifying", sig, victimIndex);
6419+
6420+
// Form a new generic signature builder.
6421+
GenericSignatureBuilder builder(context);
6422+
6423+
// Add the generic parameters.
6424+
for (auto gp : genericParams)
6425+
builder.addGenericParameter(gp);
6426+
6427+
// Add the requirements *except* the victim.
6428+
auto source = FloatingRequirementSource::forAbstract();
6429+
for (unsigned i : indices(requirements)) {
6430+
if (i != victimIndex)
6431+
builder.addRequirement(requirements[i], source, nullptr);
6432+
}
6433+
6434+
// Finalize the generic signature. If there were any errors, we formed
6435+
// an invalid signature, so just continue.
6436+
if (builder.Impl->HadAnyError) continue;
6437+
6438+
// Form a generic signature from the result.
6439+
auto newSig =
6440+
std::move(builder).computeGenericSignature(
6441+
SourceLoc(),
6442+
/*allowConcreteGenericParams=*/true,
6443+
/*allowBuilderToMove=*/true);
6444+
6445+
// Check whether the removed requirement
6446+
assert(!newSig->isRequirementSatisfied(requirements[victimIndex]) &&
6447+
"Generic signature is not minimal");
6448+
6449+
// Canonicalize the signature to check that it is canonical.
6450+
(void)newSig->getCanonicalSignature();
6451+
}
6452+
}
6453+
6454+
void GenericSignatureBuilder::verifyGenericSignaturesInModule(
6455+
ModuleDecl *module) {
6456+
LoadedFile *loadedFile = nullptr;
6457+
for (auto fileUnit : module->getFiles()) {
6458+
loadedFile = dyn_cast<LoadedFile>(fileUnit);
6459+
if (loadedFile) break;
6460+
}
6461+
6462+
if (!loadedFile) return;
6463+
6464+
// Check all of the (canonical) generic signatures.
6465+
SmallVector<GenericSignature *, 8> allGenericSignatures;
6466+
SmallPtrSet<CanGenericSignature, 4> knownGenericSignatures;
6467+
(void)loadedFile->getAllGenericSignatures(allGenericSignatures);
6468+
ASTContext &context = module->getASTContext();
6469+
for (auto genericSig : allGenericSignatures) {
6470+
// Check whether this is the first time we've checked this (canonical)
6471+
// signature.
6472+
auto canGenericSig = genericSig->getCanonicalSignature();
6473+
if (!knownGenericSignatures.insert(canGenericSig).second) continue;
6474+
6475+
verifyGenericSignature(context, canGenericSig);
6476+
}
6477+
}
6478+
6479+

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
229229

230230
Opts.ParseStdlib |= Args.hasArg(OPT_parse_stdlib);
231231

232+
if (const Arg *A = Args.getLastArg(OPT_verify_generic_signatures)) {
233+
Opts.VerifyGenericSignaturesInModule = A->getValue();
234+
}
235+
232236
// Determine what the user has asked the frontend to do.
233237
FrontendOptions::ActionType &Action = Opts.RequestedAction;
234238
if (const Arg *A = Args.getLastArg(OPT_modes_Group)) {

lib/FrontendTool/FrontendTool.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/AST/ASTScope.h"
3131
#include "swift/AST/DiagnosticsFrontend.h"
3232
#include "swift/AST/DiagnosticsSema.h"
33+
#include "swift/AST/GenericSignatureBuilder.h"
3334
#include "swift/AST/IRGenOptions.h"
3435
#include "swift/AST/ASTMangler.h"
3536
#include "swift/AST/LegacyASTTransformer.h"
@@ -630,6 +631,14 @@ static bool performCompile(CompilerInstance &Instance,
630631

631632
ASTContext &Context = Instance.getASTContext();
632633

634+
635+
auto verifyGenericSignaturesInModule =
636+
Invocation.getFrontendOptions().VerifyGenericSignaturesInModule;
637+
if (!verifyGenericSignaturesInModule.empty()) {
638+
if (auto module = Context.getModuleByName(verifyGenericSignaturesInModule))
639+
GenericSignatureBuilder::verifyGenericSignaturesInModule(module);
640+
}
641+
633642
if (Invocation.getMigratorOptions().shouldRunMigrator()) {
634643
migrator::updateCodeAndEmitRemap(&Instance, Invocation);
635644
}

lib/Serialization/ModuleFile.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,17 @@ bool SerializedASTFile::hasEntryPoint() const {
21752175
return File.Bits.HasEntryPoint;
21762176
}
21772177

2178+
bool SerializedASTFile::getAllGenericSignatures(
2179+
SmallVectorImpl<GenericSignature*> &genericSignatures) {
2180+
genericSignatures.clear();
2181+
for (unsigned index : indices(File.GenericSignatures)) {
2182+
if (auto genericSig = File.getGenericSignature(index + 1))
2183+
genericSignatures.push_back(genericSig);
2184+
}
2185+
2186+
return true;
2187+
}
2188+
21782189
ClassDecl *SerializedASTFile::getMainClass() const {
21792190
assert(hasEntryPoint());
21802191
return cast_or_null<ClassDecl>(File.getDecl(File.Bits.EntryPointDeclID));
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Verifies that all of the generic signatures in the standard library are
2+
// minimal and canonical.
3+
4+
// RUN: %target-typecheck-verify-swift -typecheck %s -verify-generic-signatures Swift
5+
6+
// expected-no-diagnostics

0 commit comments

Comments
 (0)