Hello compiler experts,
A long time ago, there existed a DerivedFileUnit
class for storing synthesized module-level declarations. However, it was removed in this commit by @Douglas_Gregor in 2016:
[Cleanup] Eliminate DerivedFileUnit.
The only client of DerivedFileUnit was synthesized global '=='
operators for Equatable conformances, which has since been removed.
Now, differentiation in Swift is in need of something like DerivedFileUnit
: the differentiation SIL transform synthesizes auxiliary struct/enum data structures and needs to add them somewhere.
So far, we've been using a hack to find an appropriate SourceFile
for adding these structs/enums:
// In lib/SILOptimizer/Mandatory/Differentiation.cpp:
/// Retrieves the file unit that contains implicit declarations in the
/// current Swift module. If it does not exist, create one.
///
// FIXME: Currently it defaults to the file containing `origFn`, if it can be
// determined. Otherwise, it defaults to any file unit in the module. To
// handle this more properly, we should make a DerivedFileUnit class to
// contain all synthesized implicit type declarations.
SourceFile &getDeclarationFileUnit() {
if (original->hasLocation())
if (auto *declContext = original->getLocation().getAsDeclContext())
if (auto *parentSourceFile = declContext->getParentSourceFile())
return *parentSourceFile;
for (auto *file : original->getModule().getSwiftModule()->getFiles())
if (auto *src = dyn_cast<SourceFile>(file))
return *src;
llvm_unreachable("No files?");
}
But this logic recently resulted in a AST serialization crash:
// In lib/Serialization/Serialization.cpp:
bool Serializer::isDeclXRef(const Decl *D) const {
const DeclContext *topLevel = D->getDeclContext()->getModuleScopeContext();
llvm::errs() << "Serializer::isDeclXRef\n";
D->dump();
llvm::errs() << "TOP LEVEL\n";
topLevel->dumpContext();
llvm::errs() << "\n";
if (auto *decl = topLevel->getAsDecl())
decl->dump();
if (topLevel->getParentModule() != M)
return true;
if (!SF || topLevel == SF)
return false;
// Special-case for SIL generic parameter decls, which don't have a real
// DeclContext.
if (!isa<FileUnit>(topLevel)) {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// This assertion failure triggers. We need another special case to
// handle structs/enums synthesized during the differentiation SIL
// transform.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
assert(isa<GenericTypeParamDecl>(D) && "unexpected decl kind");
return false;
}
return true;
}
Assertion failed: (isa<GenericTypeParamDecl>(D) && "unexpected decl kind"), function isDeclXRef, file /Users/danielzheng/swift-tf/swift/lib/Serialization/Serialization.cpp, line 2043.
What's the most robust fix for this issue? (In which FileUnit
should structs/enums synthesized during SILOptimizer transform be added?)
My guess is reviving DerivedFileUnit
may be a good solution. TF-623 tracks this issue.