Skip to content

Commit cb1e9dd

Browse files
committed
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.
1 parent c440b0b commit cb1e9dd

File tree

8 files changed

+89
-29
lines changed

8 files changed

+89
-29
lines changed

include/swift/Frontend/Frontend.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -539,10 +539,14 @@ class CompilerInstance {
539539

540540
/// Parses the input file but does no type-checking or module imports.
541541
/// Note that this only supports parsing an invocation with a single file.
542-
///
543-
///
544542
void performParseOnly(bool EvaluateConditionals = false);
545543

544+
/// Parses and performs name binding on all input files.
545+
///
546+
/// Like a parse-only invocation, a single file is required. Unlike a
547+
/// parse-only invocation, module imports will be processed.
548+
void performParseAndNameBindingOnly();
549+
546550
private:
547551
SourceFile *
548552
createSourceFileForMainModule(SourceFileKind FileKind,
@@ -581,7 +585,9 @@ class CompilerInstance {
581585

582586
void addMainFileToModule(const ImplicitImports &implicitImports);
583587

584-
void parseAndCheckTypes(const ImplicitImports &implicitImports);
588+
void performSemaUpTo(SourceFile::ASTStage_t LimitStage);
589+
void parseAndCheckTypesUpTo(const ImplicitImports &implicitImports,
590+
SourceFile::ASTStage_t LimitStage);
585591

586592
void parseLibraryFile(unsigned BufferID,
587593
const ImplicitImports &implicitImports,
@@ -600,9 +606,10 @@ class CompilerInstance {
600606

601607
void forEachFileToTypeCheck(llvm::function_ref<void(SourceFile &)> fn);
602608

603-
void parseAndTypeCheckMainFile(PersistentParserState &PersistentState,
604-
DelayedParsingCallbacks *DelayedParseCB,
605-
OptionSet<TypeCheckingFlags> TypeCheckOptions);
609+
void parseAndTypeCheckMainFileUpTo(SourceFile::ASTStage_t LimitStage,
610+
PersistentParserState &PersistentState,
611+
DelayedParsingCallbacks *DelayedParseCB,
612+
OptionSet<TypeCheckingFlags> TypeCheckOptions);
606613

607614
void finishTypeChecking(OptionSet<TypeCheckingFlags> TypeCheckOptions);
608615

include/swift/Frontend/FrontendOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class FrontendOptions {
105105
enum class ActionType {
106106
NoneAction, ///< No specific action
107107
Parse, ///< Parse only
108+
NameBind, ///< Parse and perform name-binding only
108109
Typecheck, ///< Parse and type-check only
109110
DumpParse, ///< Parse only and dump AST
110111
DumpInterfaceHash, ///< Parse and dump the interface token hash.

include/swift/Option/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,9 @@ def fixit_all : Flag<["-"], "fixit-all">,
637637
def parse: Flag<["-"], "parse">,
638638
HelpText<"Parse input file(s)">, ModeOpt,
639639
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
640+
def namebind : Flag<["-"], "name-bind">,
641+
HelpText<"Parse and perform name binding on input file(s)">, ModeOpt,
642+
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
640643
def typecheck : Flag<["-"], "typecheck">,
641644
HelpText<"Parse and type-check input file(s)">, ModeOpt,
642645
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>;

lib/Driver/Driver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,7 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
13701370
OI.LinkAction = LinkKind::None;
13711371
break;
13721372
case options::OPT_parse:
1373+
case options::OPT_namebind:
13731374
case options::OPT_typecheck:
13741375
case options::OPT_dump_parse:
13751376
case options::OPT_dump_ast:

lib/Frontend/Frontend.cpp

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,21 @@ shouldImplicityImportSwiftOnoneSupportModule(CompilerInvocation &Invocation) {
425425
return Invocation.getFrontendOptions().isCreatingSIL();
426426
}
427427

428+
void CompilerInstance::performParseAndNameBindingOnly() {
429+
performSemaUpTo(SourceFile::NameBound);
430+
}
431+
428432
void CompilerInstance::performSema() {
433+
performSemaUpTo(SourceFile::TypeChecked);
434+
}
435+
436+
void CompilerInstance::performSemaUpTo(SourceFile::ASTStage_t LimitStage) {
437+
// FIXME: A lot of the logic in `performParseOnly` is a stripped-down version
438+
// of the logic in `performSemaUpTo`. We should try to unify them over time.
439+
if (LimitStage <= SourceFile::Parsed) {
440+
return performParseOnly();
441+
}
442+
429443
FrontendStatsTracer tracer(Context->Stats, "perform-sema");
430444
Context->LoadedModules[MainModule->getName()] = getMainModule();
431445

@@ -457,9 +471,10 @@ void CompilerInstance::performSema() {
457471
if (MainBufferID != NO_SUCH_BUFFER)
458472
addMainFileToModule(implicitImports);
459473

460-
parseAndCheckTypes(implicitImports);
474+
parseAndCheckTypesUpTo(implicitImports, LimitStage);
461475
}
462476

477+
463478
CompilerInstance::ImplicitImports::ImplicitImports(CompilerInstance &compiler) {
464479
kind = compiler.Invocation.getImplicitModuleImportKind();
465480

@@ -575,8 +590,8 @@ void CompilerInstance::addMainFileToModule(
575590
addAdditionalInitialImportsTo(MainFile, implicitImports);
576591
}
577592

578-
void CompilerInstance::parseAndCheckTypes(
579-
const ImplicitImports &implicitImports) {
593+
void CompilerInstance::parseAndCheckTypesUpTo(
594+
const ImplicitImports &implicitImports, SourceFile::ASTStage_t limitStage) {
580595
FrontendStatsTracer tracer(Context->Stats, "parse-and-check-types");
581596
// Delayed parsing callback for the primary file, or all files
582597
// in non-WMO mode.
@@ -611,8 +626,8 @@ void CompilerInstance::parseAndCheckTypes(
611626
// In addition, the main file has parsing and type-checking
612627
// interwined.
613628
if (MainBufferID != NO_SUCH_BUFFER) {
614-
parseAndTypeCheckMainFile(PersistentState, PrimaryDelayedCB.get(),
615-
TypeCheckOptions);
629+
parseAndTypeCheckMainFileUpTo(limitStage, PersistentState,
630+
PrimaryDelayedCB.get(), TypeCheckOptions);
616631
}
617632

618633
assert(llvm::all_of(MainModule->getFiles(), [](const FileUnit *File) -> bool {
@@ -623,6 +638,11 @@ void CompilerInstance::parseAndCheckTypes(
623638
}) && "some files have not yet had their imports resolved");
624639
MainModule->setHasResolvedImports();
625640

641+
// If the limiting AST stage is name binding, we're done.
642+
if (limitStage <= SourceFile::NameBound) {
643+
return;
644+
}
645+
626646
const auto &options = Invocation.getFrontendOptions();
627647
forEachFileToTypeCheck([&](SourceFile &SF) {
628648
performTypeChecking(SF, PersistentState.getTopLevelContext(),
@@ -720,7 +740,8 @@ bool CompilerInstance::parsePartialModulesAndLibraryFiles(
720740
return hadLoadError;
721741
}
722742

723-
void CompilerInstance::parseAndTypeCheckMainFile(
743+
void CompilerInstance::parseAndTypeCheckMainFileUpTo(
744+
SourceFile::ASTStage_t LimitStage,
724745
PersistentParserState &PersistentState,
725746
DelayedParsingCallbacks *DelayedParseCB,
726747
OptionSet<TypeCheckingFlags> TypeCheckOptions) {
@@ -747,15 +768,27 @@ void CompilerInstance::parseAndTypeCheckMainFile(
747768
parseIntoSourceFile(MainFile, MainFile.getBufferID().getValue(), &Done,
748769
TheSILModule ? &SILContext : nullptr, &PersistentState,
749770
DelayedParseCB);
771+
750772
if (mainIsPrimary) {
751-
const auto &options = Invocation.getFrontendOptions();
752-
performTypeChecking(MainFile, PersistentState.getTopLevelContext(),
753-
TypeCheckOptions, CurTUElem,
754-
options.WarnLongFunctionBodies,
755-
options.WarnLongExpressionTypeChecking,
756-
options.SolverExpressionTimeThreshold,
757-
options.SwitchCheckingInvocationThreshold);
773+
switch (LimitStage) {
774+
case SourceFile::Parsing:
775+
case SourceFile::Parsed:
776+
llvm_unreachable("invalid limit stage");
777+
case SourceFile::NameBound:
778+
performNameBinding(MainFile, CurTUElem);
779+
break;
780+
case SourceFile::TypeChecked:
781+
const auto &options = Invocation.getFrontendOptions();
782+
performTypeChecking(MainFile, PersistentState.getTopLevelContext(),
783+
TypeCheckOptions, CurTUElem,
784+
options.WarnLongFunctionBodies,
785+
options.WarnLongExpressionTypeChecking,
786+
options.SolverExpressionTimeThreshold,
787+
options.SwitchCheckingInvocationThreshold);
788+
break;
789+
}
758790
}
791+
759792
CurTUElem = MainFile.Decls.size();
760793
} while (!Done);
761794

lib/Frontend/FrontendOptions.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) {
3131
switch (action) {
3232
case ActionType::NoneAction:
3333
case ActionType::Parse:
34+
case ActionType::NameBind:
3435
case ActionType::Typecheck:
3536
case ActionType::DumpParse:
3637
case ActionType::DumpAST:
@@ -65,6 +66,7 @@ bool FrontendOptions::isActionImmediate(ActionType action) {
6566
switch (action) {
6667
case ActionType::NoneAction:
6768
case ActionType::Parse:
69+
case ActionType::NameBind:
6870
case ActionType::Typecheck:
6971
case ActionType::DumpParse:
7072
case ActionType::DumpAST:
@@ -134,6 +136,7 @@ FrontendOptions::suffixForPrincipalOutputFileForAction(ActionType action) {
134136
return StringRef();
135137

136138
case ActionType::Parse:
139+
case ActionType::NameBind:
137140
case ActionType::Typecheck:
138141
case ActionType::DumpParse:
139142
case ActionType::DumpInterfaceHash:
@@ -195,6 +198,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) {
195198
case ActionType::Immediate:
196199
case ActionType::REPL:
197200
return false;
201+
case ActionType::NameBind:
198202
case ActionType::Typecheck:
199203
case ActionType::MergeModules:
200204
case ActionType::EmitModuleOnly:
@@ -216,6 +220,7 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) {
216220
switch (action) {
217221
case ActionType::NoneAction:
218222
case ActionType::Parse:
223+
case ActionType::NameBind:
219224
case ActionType::DumpParse:
220225
case ActionType::DumpInterfaceHash:
221226
case ActionType::DumpAST:
@@ -258,6 +263,7 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) {
258263
case ActionType::REPL:
259264
return false;
260265
case ActionType::Parse:
266+
case ActionType::NameBind:
261267
case ActionType::Typecheck:
262268
case ActionType::MergeModules:
263269
case ActionType::EmitModuleOnly:
@@ -288,6 +294,7 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) {
288294
case ActionType::Immediate:
289295
case ActionType::REPL:
290296
return false;
297+
case ActionType::NameBind:
291298
case ActionType::Typecheck:
292299
case ActionType::MergeModules:
293300
case ActionType::EmitModuleOnly:
@@ -309,6 +316,7 @@ bool FrontendOptions::canActionEmitModule(ActionType action) {
309316
switch (action) {
310317
case ActionType::NoneAction:
311318
case ActionType::Parse:
319+
case ActionType::NameBind:
312320
case ActionType::Typecheck:
313321
case ActionType::DumpParse:
314322
case ActionType::DumpInterfaceHash:
@@ -343,6 +351,7 @@ bool FrontendOptions::canActionEmitModuleDoc(ActionType action) {
343351
bool FrontendOptions::doesActionProduceOutput(ActionType action) {
344352
switch (action) {
345353
case ActionType::Parse:
354+
case ActionType::NameBind:
346355
case ActionType::Typecheck:
347356
case ActionType::DumpParse:
348357
case ActionType::DumpAST:
@@ -388,6 +397,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) {
388397
return false;
389398

390399
case ActionType::Parse:
400+
case ActionType::NameBind:
391401
case ActionType::Typecheck:
392402
case ActionType::DumpParse:
393403
case ActionType::DumpInterfaceHash:

lib/FrontendTool/FrontendTool.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -895,11 +895,14 @@ static bool performCompile(CompilerInstance &Instance,
895895
if (Invocation.getInputKind() == InputFileKind::IFK_LLVM_IR)
896896
return compileLLVMIR(Invocation, Instance, Stats);
897897

898-
if (FrontendOptions::shouldActionOnlyParse(Action))
898+
if (FrontendOptions::shouldActionOnlyParse(Action)) {
899899
Instance.performParseOnly(/*EvaluateConditionals*/
900900
Action == FrontendOptions::ActionType::EmitImportedModules);
901-
else
901+
} else if (Action == FrontendOptions::ActionType::NameBind) {
902+
Instance.performParseAndNameBindingOnly();
903+
} else {
902904
Instance.performSema();
905+
}
903906

904907
SWIFT_DEFER {
905908
// Emit request-evaluator graph via GraphViz, if requested.
@@ -912,8 +915,15 @@ static bool performCompile(CompilerInstance &Instance,
912915
}
913916
};
914917

918+
ASTContext &Context = Instance.getASTContext();
915919
if (Action == FrontendOptions::ActionType::Parse)
916-
return Instance.getASTContext().hadError();
920+
return Context.hadError();
921+
922+
(void)emitMakeDependenciesIfNeeded(Context.Diags,
923+
Instance.getDependencyTracker(), opts);
924+
925+
if (Action == FrontendOptions::ActionType::NameBind)
926+
return Context.hadError();
917927

918928
if (observer)
919929
observer->performedSemanticAnalysis(Instance);
@@ -929,8 +939,6 @@ static bool performCompile(CompilerInstance &Instance,
929939
debugFailWithCrash();
930940
}
931941

932-
ASTContext &Context = Instance.getASTContext();
933-
934942
verifyGenericSignaturesIfNeeded(Invocation, Context);
935943

936944
(void)migrator::updateCodeAndEmitRemapIfNeeded(&Instance, Invocation);
@@ -948,9 +956,6 @@ static bool performCompile(CompilerInstance &Instance,
948956
if (opts.PrintClangStats && Context.getClangModuleLoader())
949957
Context.getClangModuleLoader()->printStatistics();
950958

951-
(void)emitMakeDependenciesIfNeeded(Context.Diags,
952-
Instance.getDependencyTracker(), opts);
953-
954959
emitReferenceDependenciesForAllPrimaryInputsIfNeeded(Invocation, Instance);
955960

956961
(void)emitLoadedModuleTraceForAllPrimariesIfNeeded(

test/Frontend/dependencies.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// RUN: %empty-directory(%t)
44

5-
// RUN: %target-swift-frontend -emit-dependencies-path - -typecheck %S/../Inputs/empty\ file.swift | %FileCheck -check-prefix=CHECK-BASIC %s
5+
// RUN: %target-swift-frontend -emit-dependencies-path - -name-bind %S/../Inputs/empty\ file.swift | %FileCheck -check-prefix=CHECK-BASIC %s
66
// RUN: %target-swift-frontend -emit-reference-dependencies-path - -typecheck -primary-file %S/../Inputs/empty\ file.swift | %FileCheck -check-prefix=CHECK-BASIC-YAML %s
77

88
// RUN: %target-swift-frontend -emit-dependencies-path %t.d -emit-reference-dependencies-path %t.swiftdeps -typecheck -primary-file %S/../Inputs/empty\ file.swift
@@ -38,7 +38,7 @@
3838
// CHECK-MULTIPLE-OUTPUTS: Swift.swiftmodule
3939
// CHECK-MULTIPLE-OUTPUTS-NOT: :
4040

41-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -import-objc-header %S/Inputs/dependencies/extra-header.h -emit-dependencies-path - -typecheck %s | %FileCheck -check-prefix=CHECK-IMPORT %s
41+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -import-objc-header %S/Inputs/dependencies/extra-header.h -emit-dependencies-path - -name-bind %s | %FileCheck -check-prefix=CHECK-IMPORT %s
4242
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -import-objc-header %S/Inputs/dependencies/extra-header.h -emit-reference-dependencies-path - -typecheck -primary-file %s | %FileCheck -check-prefix=CHECK-IMPORT-YAML %s
4343

4444
// CHECK-IMPORT-LABEL: - :

0 commit comments

Comments
 (0)