Introduce Name Binding as a Frontend Action

Introduces the -name-bind frontend action that is intended as an intermediary between the parse-only actions and a full typechecking pass.  In this phase, module imports will be validated and resolved, making it possible to emit full make-style dependencies files among other things.

Note that all information available to a parse-only pass is available to name binding, but because it does not continue-on to typecheck input files, full semantic information is not.
This commit is contained in:
Robert Widmann
2018-06-29 15:49:54 -07:00
parent c440b0ba5a
commit cb1e9dd821
8 changed files with 89 additions and 29 deletions

View File

@@ -425,7 +425,21 @@ shouldImplicityImportSwiftOnoneSupportModule(CompilerInvocation &Invocation) {
return Invocation.getFrontendOptions().isCreatingSIL();
}
void CompilerInstance::performParseAndNameBindingOnly() {
performSemaUpTo(SourceFile::NameBound);
}
void CompilerInstance::performSema() {
performSemaUpTo(SourceFile::TypeChecked);
}
void CompilerInstance::performSemaUpTo(SourceFile::ASTStage_t LimitStage) {
// FIXME: A lot of the logic in `performParseOnly` is a stripped-down version
// of the logic in `performSemaUpTo`. We should try to unify them over time.
if (LimitStage <= SourceFile::Parsed) {
return performParseOnly();
}
FrontendStatsTracer tracer(Context->Stats, "perform-sema");
Context->LoadedModules[MainModule->getName()] = getMainModule();
@@ -457,9 +471,10 @@ void CompilerInstance::performSema() {
if (MainBufferID != NO_SUCH_BUFFER)
addMainFileToModule(implicitImports);
parseAndCheckTypes(implicitImports);
parseAndCheckTypesUpTo(implicitImports, LimitStage);
}
CompilerInstance::ImplicitImports::ImplicitImports(CompilerInstance &compiler) {
kind = compiler.Invocation.getImplicitModuleImportKind();
@@ -575,8 +590,8 @@ void CompilerInstance::addMainFileToModule(
addAdditionalInitialImportsTo(MainFile, implicitImports);
}
void CompilerInstance::parseAndCheckTypes(
const ImplicitImports &implicitImports) {
void CompilerInstance::parseAndCheckTypesUpTo(
const ImplicitImports &implicitImports, SourceFile::ASTStage_t limitStage) {
FrontendStatsTracer tracer(Context->Stats, "parse-and-check-types");
// Delayed parsing callback for the primary file, or all files
// in non-WMO mode.
@@ -611,8 +626,8 @@ void CompilerInstance::parseAndCheckTypes(
// In addition, the main file has parsing and type-checking
// interwined.
if (MainBufferID != NO_SUCH_BUFFER) {
parseAndTypeCheckMainFile(PersistentState, PrimaryDelayedCB.get(),
TypeCheckOptions);
parseAndTypeCheckMainFileUpTo(limitStage, PersistentState,
PrimaryDelayedCB.get(), TypeCheckOptions);
}
assert(llvm::all_of(MainModule->getFiles(), [](const FileUnit *File) -> bool {
@@ -623,6 +638,11 @@ void CompilerInstance::parseAndCheckTypes(
}) && "some files have not yet had their imports resolved");
MainModule->setHasResolvedImports();
// If the limiting AST stage is name binding, we're done.
if (limitStage <= SourceFile::NameBound) {
return;
}
const auto &options = Invocation.getFrontendOptions();
forEachFileToTypeCheck([&](SourceFile &SF) {
performTypeChecking(SF, PersistentState.getTopLevelContext(),
@@ -720,7 +740,8 @@ bool CompilerInstance::parsePartialModulesAndLibraryFiles(
return hadLoadError;
}
void CompilerInstance::parseAndTypeCheckMainFile(
void CompilerInstance::parseAndTypeCheckMainFileUpTo(
SourceFile::ASTStage_t LimitStage,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *DelayedParseCB,
OptionSet<TypeCheckingFlags> TypeCheckOptions) {
@@ -747,15 +768,27 @@ void CompilerInstance::parseAndTypeCheckMainFile(
parseIntoSourceFile(MainFile, MainFile.getBufferID().getValue(), &Done,
TheSILModule ? &SILContext : nullptr, &PersistentState,
DelayedParseCB);
if (mainIsPrimary) {
const auto &options = Invocation.getFrontendOptions();
performTypeChecking(MainFile, PersistentState.getTopLevelContext(),
TypeCheckOptions, CurTUElem,
options.WarnLongFunctionBodies,
options.WarnLongExpressionTypeChecking,
options.SolverExpressionTimeThreshold,
options.SwitchCheckingInvocationThreshold);
switch (LimitStage) {
case SourceFile::Parsing:
case SourceFile::Parsed:
llvm_unreachable("invalid limit stage");
case SourceFile::NameBound:
performNameBinding(MainFile, CurTUElem);
break;
case SourceFile::TypeChecked:
const auto &options = Invocation.getFrontendOptions();
performTypeChecking(MainFile, PersistentState.getTopLevelContext(),
TypeCheckOptions, CurTUElem,
options.WarnLongFunctionBodies,
options.WarnLongExpressionTypeChecking,
options.SolverExpressionTimeThreshold,
options.SwitchCheckingInvocationThreshold);
break;
}
}
CurTUElem = MainFile.Decls.size();
} while (!Done);