Skip to content

Commit ad00350

Browse files
authored
Merge pull request #31568 from CodaFi/this-is-a-private-party
Initial Infrastructure for "Private Intransitive" Dependencies
2 parents 75623f9 + b06211e commit ad00350

29 files changed

+1179
-38
lines changed

include/swift/AST/Evaluator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ class Evaluator {
245245
/// diagnostics through the given diagnostics engine.
246246
Evaluator(DiagnosticEngine &diags,
247247
bool debugDumpCycles,
248-
bool buildDependencyGraph);
248+
bool buildDependencyGraph,
249+
bool enableExperimentalPrivateDeps);
249250

250251
/// Emit GraphViz output visualizing the request graph.
251252
void emitRequestEvaluatorGraphViz(llvm::StringRef graphVizPath);

include/swift/AST/EvaluatorDependencies.h

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,22 @@ struct DependencyCollector {
113113
llvm::SmallVector<evaluator::DependencySource, 8> dependencySources;
114114

115115
public:
116-
DependencyCollector() = default;
116+
enum class Mode {
117+
// Enables the current "status quo" behavior of the dependency collector.
118+
//
119+
// By default, the dependency collector moves to register dependencies in
120+
// the referenced name trackers at the top of the active dependency stack.
121+
StatusQuo,
122+
// Enables an experimental mode to only register private dependencies.
123+
//
124+
// This mode restricts the dependency collector to ignore changes of
125+
// scope. This has practical effect of charging all unqualified lookups to
126+
// the primary file being acted upon instead of to the destination file.
127+
ExperimentalPrivateDependencies,
128+
};
129+
Mode mode;
130+
131+
explicit DependencyCollector(Mode mode) : mode{mode} {};
117132

118133
public:
119134
/// Registers a named reference from the current dependency scope to a member
@@ -206,19 +221,43 @@ struct DependencyCollector {
206221
};
207222

208223
private:
224+
/// Returns the first dependency source registered with the tracker, or
225+
/// \c nullptr if no dependency sources have been registered.
226+
SourceFile *getFirstDependencySourceOrNull() const {
227+
if (dependencySources.empty())
228+
return nullptr;
229+
return dependencySources.front().getPointer();
230+
}
231+
209232
/// If there is an active dependency source, returns its
210233
/// \c ReferencedNameTracker. Else, returns \c nullptr.
211234
ReferencedNameTracker *getActiveDependencyTracker() const {
212-
if (auto *source = getActiveDependencySourceOrNull())
213-
return source->getRequestBasedReferencedNameTracker();
214-
return nullptr;
235+
SourceFile *source = nullptr;
236+
switch (mode) {
237+
case Mode::StatusQuo:
238+
source = getActiveDependencySourceOrNull();
239+
break;
240+
case Mode::ExperimentalPrivateDependencies:
241+
source = getFirstDependencySourceOrNull();
242+
break;
243+
}
244+
245+
if (!source)
246+
return nullptr;
247+
248+
return source->getRequestBasedReferencedNameTracker();
215249
}
216250

217251
/// Returns \c true if the scope of the current active source cascades.
218252
///
219253
/// If there is no active scope, the result always cascades.
220254
bool isActiveSourceCascading() const {
221-
return getActiveSourceScope() == evaluator::DependencyScope::Cascading;
255+
switch (mode) {
256+
case Mode::StatusQuo:
257+
return getActiveSourceScope() == evaluator::DependencyScope::Cascading;
258+
case Mode::ExperimentalPrivateDependencies:
259+
return false;
260+
}
222261
}
223262
};
224263
} // end namespace evaluator

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ namespace swift {
357357
/// conformances.
358358
bool EnableExperimentalAdditiveArithmeticDerivedConformances = false;
359359

360+
/// Whether to enable a more aggressive mode of incremental dependency
361+
/// gathering that never captures cascading edges.
362+
bool EnableExperientalPrivateIntransitiveDependencies = false;
363+
360364
/// Enable verification when every SubstitutionMap is constructed.
361365
bool VerifyAllSubstitutionMaps = false;
362366

include/swift/Option/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,12 @@ def enable_experimental_concise_pound_file : Flag<["-"],
511511
Flags<[FrontendOption]>,
512512
HelpText<"Enable experimental concise '#file' identifier">;
513513

514+
def experimental_private_intransitive_dependencies : Flag<["-"],
515+
"experimental-private-intransitive-dependencies">,
516+
Flags<[FrontendOption, HelpHidden]>,
517+
HelpText<"Enable experimental dependency tracking that never cascades">;
518+
519+
514520
// Diagnostic control options
515521
def suppress_warnings : Flag<["-"], "suppress-warnings">,
516522
Flags<[FrontendOption]>,

lib/AST/ASTContext.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,8 @@ ASTContext::ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts,
552552
SearchPathOpts(SearchPathOpts), SourceMgr(SourceMgr), Diags(Diags),
553553
evaluator(Diags,
554554
langOpts.DebugDumpCycles,
555-
langOpts.BuildRequestDependencyGraph),
555+
langOpts.BuildRequestDependencyGraph,
556+
langOpts.EnableExperientalPrivateIntransitiveDependencies),
556557
TheBuiltinModule(createBuiltinModule(*this)),
557558
StdlibModuleName(getIdentifier(STDLIB_NAME)),
558559
SwiftShimsModuleName(getIdentifier(SWIFT_SHIMS_NAME)),

lib/AST/Evaluator.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,22 @@ void Evaluator::registerRequestFunctions(
6060
requestFunctionsByZone.push_back({zoneID, functions});
6161
}
6262

63-
Evaluator::Evaluator(DiagnosticEngine &diags,
64-
bool debugDumpCycles,
65-
bool buildDependencyGraph)
66-
: diags(diags),
67-
debugDumpCycles(debugDumpCycles),
68-
buildDependencyGraph(buildDependencyGraph) { }
63+
static evaluator::DependencyCollector::Mode
64+
computeDependencyModeFromFlags(bool enableExperimentalPrivateDeps) {
65+
using Mode = evaluator::DependencyCollector::Mode;
66+
if (enableExperimentalPrivateDeps) {
67+
return Mode::ExperimentalPrivateDependencies;
68+
}
69+
return Mode::StatusQuo;
70+
}
71+
72+
Evaluator::Evaluator(DiagnosticEngine &diags, bool debugDumpCycles,
73+
bool buildDependencyGraph,
74+
bool enableExperimentalPrivateDeps)
75+
: diags(diags), debugDumpCycles(debugDumpCycles),
76+
buildDependencyGraph(buildDependencyGraph),
77+
collector{computeDependencyModeFromFlags(enableExperimentalPrivateDeps)} {
78+
}
6979

7080
void Evaluator::emitRequestEvaluatorGraphViz(llvm::StringRef graphVizPath) {
7181
std::error_code error;

lib/Driver/ToolChains.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
250250
options::OPT_enable_experimental_concise_pound_file);
251251
inputArgs.AddLastArg(arguments,
252252
options::OPT_verify_incremental_dependencies);
253-
253+
inputArgs.AddLastArg(arguments,
254+
options::OPT_experimental_private_intransitive_dependencies);
255+
254256
// Pass on any build config options
255257
inputArgs.AddAllArgs(arguments, options::OPT_D);
256258

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
434434
if (Args.hasArg(OPT_enable_experimental_additive_arithmetic_derivation))
435435
Opts.EnableExperimentalAdditiveArithmeticDerivedConformances = true;
436436

437+
if (Args.hasArg(OPT_experimental_private_intransitive_dependencies))
438+
Opts.EnableExperientalPrivateIntransitiveDependencies = true;
439+
437440
Opts.EnableExperimentalForwardModeDifferentiation |=
438441
Args.hasArg(OPT_enable_experimental_forward_mode_differentiation);
439442

lib/FrontendTool/FrontendTool.cpp

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -791,10 +791,9 @@ static bool compileLLVMIR(CompilerInstance &Instance) {
791791
inputsAndOutputs.getFilenameOfFirstInput());
792792

793793
if (!FileBufOrErr) {
794-
Instance.getASTContext().Diags.diagnose(
795-
SourceLoc(), diag::error_open_input_file,
796-
inputsAndOutputs.getFilenameOfFirstInput(),
797-
FileBufOrErr.getError().message());
794+
Instance.getDiags().diagnose(SourceLoc(), diag::error_open_input_file,
795+
inputsAndOutputs.getFilenameOfFirstInput(),
796+
FileBufOrErr.getError().message());
798797
return true;
799798
}
800799
llvm::MemoryBuffer *MainFile = FileBufOrErr.get().get();
@@ -806,9 +805,9 @@ static bool compileLLVMIR(CompilerInstance &Instance) {
806805
if (!Module) {
807806
// TODO: Translate from the diagnostic info to the SourceManager location
808807
// if available.
809-
Instance.getASTContext().Diags.diagnose(
810-
SourceLoc(), diag::error_parse_input_file,
811-
inputsAndOutputs.getFilenameOfFirstInput(), Err.getMessage());
808+
Instance.getDiags().diagnose(SourceLoc(), diag::error_parse_input_file,
809+
inputsAndOutputs.getFilenameOfFirstInput(),
810+
Err.getMessage());
812811
return true;
813812
}
814813
return performLLVM(Invocation.getIRGenOptions(), Instance.getASTContext(),
@@ -927,7 +926,7 @@ static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded(
927926
if (Invocation.getFrontendOptions()
928927
.InputsAndOutputs.hasReferenceDependenciesPath() &&
929928
Instance.getPrimarySourceFiles().empty()) {
930-
Instance.getASTContext().Diags.diagnose(
929+
Instance.getDiags().diagnose(
931930
SourceLoc(), diag::emit_reference_dependencies_without_primary_file);
932931
return;
933932
}
@@ -936,48 +935,47 @@ static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded(
936935
Invocation.getReferenceDependenciesFilePathForPrimary(
937936
SF->getFilename());
938937
if (!referenceDependenciesFilePath.empty()) {
939-
auto LangOpts = Invocation.getLangOptions();
938+
const auto LangOpts = Invocation.getLangOptions();
940939
(void)fine_grained_dependencies::emitReferenceDependencies(
941-
Instance.getASTContext().Diags, SF,
942-
*Instance.getDependencyTracker(),
940+
Instance.getDiags(), SF, *Instance.getDependencyTracker(),
943941
referenceDependenciesFilePath,
944942
LangOpts.EmitFineGrainedDependencySourcefileDotFiles);
945943
}
946944
}
947945
}
948946
static void
949-
emitSwiftRangesForAllPrimaryInputsIfNeeded(const CompilerInstance &Instance) {
947+
emitSwiftRangesForAllPrimaryInputsIfNeeded(CompilerInstance &Instance) {
950948
const auto &Invocation = Instance.getInvocation();
951949
if (Invocation.getFrontendOptions().InputsAndOutputs.hasSwiftRangesPath() &&
952950
Instance.getPrimarySourceFiles().empty()) {
953-
Instance.getASTContext().Diags.diagnose(
954-
SourceLoc(), diag::emit_swift_ranges_without_primary_file);
951+
Instance.getDiags().diagnose(SourceLoc(),
952+
diag::emit_swift_ranges_without_primary_file);
955953
return;
956954
}
957955
for (auto *SF : Instance.getPrimarySourceFiles()) {
958956
const std::string &swiftRangesFilePath =
959957
Invocation.getSwiftRangesFilePathForPrimary(SF->getFilename());
960958
if (!swiftRangesFilePath.empty()) {
961-
(void)Instance.emitSwiftRanges(Instance.getASTContext().Diags, SF,
959+
(void)Instance.emitSwiftRanges(Instance.getDiags(), SF,
962960
swiftRangesFilePath);
963961
}
964962
}
965963
}
966964
static void emitCompiledSourceForAllPrimaryInputsIfNeeded(
967-
const CompilerInstance &Instance) {
965+
CompilerInstance &Instance) {
968966
const auto &Invocation = Instance.getInvocation();
969967
if (Invocation.getFrontendOptions()
970968
.InputsAndOutputs.hasCompiledSourcePath() &&
971969
Instance.getPrimarySourceFiles().empty()) {
972-
Instance.getASTContext().Diags.diagnose(
970+
Instance.getDiags().diagnose(
973971
SourceLoc(), diag::emit_compiled_source_without_primary_file);
974972
return;
975973
}
976974
for (auto *SF : Instance.getPrimarySourceFiles()) {
977975
const std::string &compiledSourceFilePath =
978976
Invocation.getCompiledSourceFilePathForPrimary(SF->getFilename());
979977
if (!compiledSourceFilePath.empty()) {
980-
(void)Instance.emitCompiledSource(Instance.getASTContext().Diags, SF,
978+
(void)Instance.emitCompiledSource(Instance.getDiags(), SF,
981979
compiledSourceFilePath);
982980
}
983981
}
@@ -1037,9 +1035,8 @@ static bool writeLdAddCFileIfNeeded(CompilerInstance &Instance) {
10371035
std::error_code EC;
10381036
llvm::raw_fd_ostream OS(Path, EC, llvm::sys::fs::F_None);
10391037
if (EC) {
1040-
module->getASTContext().Diags.diagnose(SourceLoc(),
1041-
diag::error_opening_output,
1042-
Path, EC.message());
1038+
Instance.getDiags().diagnose(SourceLoc(), diag::error_opening_output, Path,
1039+
EC.message());
10431040
return true;
10441041
}
10451042
OS << "// Automatically generated C source file from the Swift compiler \n"
@@ -1254,7 +1251,7 @@ static bool performCompile(CompilerInstance &Instance,
12541251
scanDependencies(Instance);
12551252
}
12561253

1257-
(void)emitMakeDependenciesIfNeeded(Context.Diags,
1254+
(void)emitMakeDependenciesIfNeeded(Instance.getDiags(),
12581255
Instance.getDependencyTracker(), opts);
12591256

12601257
if (Action == FrontendOptions::ActionType::ResolveImports ||
@@ -2187,6 +2184,14 @@ int swift::performFrontend(ArrayRef<const char *> Args,
21872184
Invocation.getFrontendOptions().DumpAPIPath);
21882185
}
21892186

2187+
// If we're asked to enable private intransitive dependencies, we need to
2188+
// write over the dependency files we just emitted because we need to
2189+
// get the dependencies written post-Sema down on disk.
2190+
// FIXME: Evaluate the impact turning this on universally has.
2191+
if (Invocation.getLangOptions().EnableExperientalPrivateIntransitiveDependencies) {
2192+
emitReferenceDependenciesForAllPrimaryInputsIfNeeded(*Instance);
2193+
}
2194+
21902195
// Verify reference dependencies of the current compilation job *before*
21912196
// verifying diagnostics so that the former can be tested via the latter.
21922197
if (Invocation.getFrontendOptions().EnableIncrementalDependencyVerifier) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
protocol IntMaker {}
2+
extension IntMaker {
3+
func make() -> Int { return 0 }
4+
}
5+
6+
protocol DoubleMaker {}
7+
extension DoubleMaker {
8+
func make() -> Double { return 0 }
9+
}
10+
11+
12+
#if OLD
13+
typealias InterestingType = Int
14+
typealias InterestingProto = IntMaker
15+
16+
#elseif NEW
17+
typealias InterestingType = Double
18+
typealias InterestingProto = DoubleMaker
19+
20+
#else
21+
typealias InterestingType = ErrorMustSetOLDOrNew
22+
23+
#endif
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// REQUIRES: shell
2+
// Also uses awk:
3+
// XFAIL OS=windows
4+
5+
// RUN: %target-swift-frontend -emit-silgen -primary-file %s %S/Inputs/InterestingType.swift -DOLD -emit-reference-dependencies-path %t.swiftdeps -module-name main -experimental-private-intransitive-dependencies | %FileCheck %s -check-prefix=CHECK-OLD
6+
// RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh <%t.swiftdeps >%t-processed.swiftdeps
7+
// RUN: %FileCheck -check-prefix=CHECK-DEPS %s < %t-processed.swiftdeps
8+
9+
// RUN: %target-swift-frontend -emit-silgen -primary-file %s %S/Inputs/InterestingType.swift -DNEW -emit-reference-dependencies-path %t.swiftdeps -module-name main -experimental-private-intransitive-dependencies | %FileCheck %s -check-prefix=CHECK-NEW
10+
// RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh <%t.swiftdeps >%t-processed.swiftdeps
11+
// RUN: %FileCheck -check-prefix=CHECK-DEPS %s < %t-processed.swiftdeps
12+
13+
private func testParamType(_: InterestingType) {}
14+
15+
// CHECK-OLD: sil_global hidden @$s4main1x{{[^ ]+}} : ${{(@[a-zA-Z_]+ )?}}(Int) -> ()
16+
// CHECK-NEW: sil_global hidden @$s4main1x{{[^ ]+}} : ${{(@[a-zA-Z_]+ )?}}(Double) -> ()
17+
internal var x = testParamType
18+
19+
// CHECK-DEPS: topLevel interface '' InterestingType false
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// REQUIRES: shell
2+
// Also uses awk:
3+
// XFAIL OS=windows
4+
5+
// RUN: %target-swift-frontend -emit-silgen -primary-file %s %S/Inputs/InterestingType.swift -DOLD -emit-reference-dependencies-path %t.swiftdeps -module-name main -experimental-private-intransitive-dependencies | %FileCheck %s -check-prefix=CHECK-OLD
6+
// RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh <%t.swiftdeps >%t-processed.swiftdeps
7+
// RUN: %FileCheck -check-prefix=CHECK-DEPS %s < %t-processed.swiftdeps
8+
9+
// RUN: %target-swift-frontend -emit-silgen -primary-file %s %S/Inputs/InterestingType.swift -DNEW -emit-reference-dependencies-path %t.swiftdeps -module-name main -experimental-private-intransitive-dependencies | %FileCheck %s -check-prefix=CHECK-NEW
10+
// RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh <%t.swiftdeps >%t-processed.swiftdeps
11+
// RUN: %FileCheck -check-prefix=CHECK-DEPS %s < %t-processed.swiftdeps
12+
13+
private func testReturnType() -> InterestingType { fatalError() }
14+
15+
// CHECK-OLD: sil_global @$s4main1x{{[^ ]+}} : $Int
16+
// CHECK-NEW: sil_global @$s4main1x{{[^ ]+}} : $Double
17+
public var x = testReturnType() + 0
18+
19+
// CHECK-DEPS: topLevel interface '' InterestingType false
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// REQUIRES: shell
2+
// Also uses awk:
3+
// XFAIL OS=windows
4+
5+
// RUN: %target-swift-frontend -emit-silgen -primary-file %s %S/Inputs/InterestingType.swift -DOLD -emit-reference-dependencies-path %t.swiftdeps -module-name main -experimental-private-intransitive-dependencies | %FileCheck %s -check-prefix=CHECK-OLD
6+
// RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh <%t.swiftdeps >%t-processed.swiftdeps
7+
// RUN: %FileCheck -check-prefix=CHECK-DEPS %s < %t-processed.swiftdeps
8+
9+
// RUN: %target-swift-frontend -emit-silgen -primary-file %s %S/Inputs/InterestingType.swift -DNEW -emit-reference-dependencies-path %t.swiftdeps -module-name main -experimental-private-intransitive-dependencies | %FileCheck %s -check-prefix=CHECK-NEW
10+
// RUN: %S/../../Inputs/process_fine_grained_swiftdeps.sh <%t.swiftdeps >%t-processed.swiftdeps
11+
// RUN: %FileCheck -check-prefix=CHECK-DEPS %s < %t-processed.swiftdeps
12+
13+
private struct Test {}
14+
extension Test : InterestingProto {}
15+
16+
// CHECK-OLD: sil_global @$s4main1x{{[^ ]+}} : $Int
17+
// CHECK-NEW: sil_global @$s4main1x{{[^ ]+}} : $Double
18+
public var x = Test().make() + 0
19+
20+
// CHECK-DEPS-DAG: topLevel interface '' InterestingProto false
21+
22+
// CHECK-DEPS-DAG: member interface 4main{{8IntMaker|11DoubleMaker}}P make false
23+
24+
// CHECK-DEPS-DAG: nominal interface 4main{{8IntMaker|11DoubleMaker}}P '' false

0 commit comments

Comments
 (0)