AST: Move expensive generic signature checks to GenericSignature.cpp

This removes the final dependency on GenericSignatureBuilder.h.
This commit is contained in:
Slava Pestov
2021-10-30 00:28:28 -04:00
parent 25ac1f5471
commit 0eb66222e2
5 changed files with 124 additions and 125 deletions

View File

@@ -1561,6 +1561,8 @@ int swift::compareDependentTypes(Type type1, Type type2) {
return 0;
}
#pragma mark Generic signature verification
void GenericSignature::verify() const {
auto canSig = getCanonicalSignature();
@@ -1738,6 +1740,116 @@ void GenericSignature::verify() const {
}
}
void swift::validateGenericSignature(ASTContext &context,
GenericSignature sig) {
llvm::errs() << "Validating generic signature: ";
sig->print(llvm::errs());
llvm::errs() << "\n";
// Try building a new signature having the same requirements.
SmallVector<GenericTypeParamType *, 2> genericParams;
for (auto *genericParam : sig.getGenericParams())
genericParams.push_back(genericParam);
SmallVector<Requirement, 2> requirements;
for (auto requirement : sig.getRequirements())
requirements.push_back(requirement);
{
PrettyStackTraceGenericSignature debugStack("verifying", sig);
auto newSigWithError = evaluateOrDefault(
context.evaluator,
AbstractGenericSignatureRequest{
nullptr,
genericParams,
requirements},
GenericSignatureWithError());
// If there were any errors, the signature was invalid.
if (newSigWithError.getInt()) {
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_valid,
sig->getAsString());
}
auto newSig = newSigWithError.getPointer();
// The new signature should be equal.
if (!newSig->isEqual(sig)) {
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_equal,
sig->getAsString(), newSig->getAsString());
}
}
// Try removing each requirement in turn.
for (unsigned victimIndex : indices(requirements)) {
PrettyStackTraceGenericSignature debugStack("verifying", sig, victimIndex);
// Add the requirements *except* the victim.
SmallVector<Requirement, 2> newRequirements;
for (unsigned i : indices(requirements)) {
if (i != victimIndex)
newRequirements.push_back(requirements[i]);
}
auto newSigWithError = evaluateOrDefault(
context.evaluator,
AbstractGenericSignatureRequest{
nullptr,
genericParams,
newRequirements},
GenericSignatureWithError());
// If there were any errors, we formed an invalid signature, so
// just continue.
if (newSigWithError.getInt())
continue;
auto newSig = newSigWithError.getPointer();
// If the new signature once again contains the removed requirement, it's
// not redundant.
if (newSig->isEqual(sig))
continue;
// If the removed requirement is satisfied by the new generic signature,
// it is redundant. Complain.
if (newSig->isRequirementSatisfied(requirements[victimIndex])) {
SmallString<32> reqString;
{
llvm::raw_svector_ostream out(reqString);
requirements[victimIndex].print(out, PrintOptions());
}
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_minimal,
reqString, sig->getAsString());
}
}
}
void swift::validateGenericSignaturesInModule(ModuleDecl *module) {
LoadedFile *loadedFile = nullptr;
for (auto fileUnit : module->getFiles()) {
loadedFile = dyn_cast<LoadedFile>(fileUnit);
if (loadedFile) break;
}
if (!loadedFile) return;
// Check all of the (canonical) generic signatures.
SmallVector<GenericSignature, 8> allGenericSignatures;
SmallPtrSet<CanGenericSignature, 4> knownGenericSignatures;
(void)loadedFile->getAllGenericSignatures(allGenericSignatures);
ASTContext &context = module->getASTContext();
for (auto genericSig : allGenericSignatures) {
// Check whether this is the first time we've checked this (canonical)
// signature.
auto canGenericSig = genericSig.getCanonicalSignature();
if (!knownGenericSignatures.insert(canGenericSig).second) continue;
validateGenericSignature(context, canGenericSig);
}
}
GenericSignature
swift::buildGenericSignature(ASTContext &ctx,
GenericSignature baseSignature,