Skip to content

Commit 8c69814

Browse files
committed
Define Dependency Sinks
Convert most of the name lookup requests and a few other ancillary typechecking requests into dependency sinks. Some requests are also combined sinks and sources in order to emulate the current scheme, which performs scope changes based on lookup flags. This is generally undesirable, since it means those requests cannot immediately be generalized to a purely context-based scheme because they depend on some client-provided entropy source. In particular, the few callers that are providing the "known private" name lookup flag need to be converted to perform lookups in the appropriate private context. Clients that are passing "no known dependency" are currently considered universally incorrect and are outside the scope of the compatibility guarantees. This means that request-based dependency tracking registers strictly more edges than manual dependency tracking. It also means that once we fixup the clients that are passing "known private", we can completely remove these name lookup flags. Finally, some tests had to change to accomodate the new scheme. Currently, we go out of our way to register a dependency edge for extensions that declare protocol conformances. However, we were also asserting in at least one test that extensions without protocol conformances weren't registering dependency edges. This is blatantly incorrect and has been undone now that the request-based scheme is automatically registering this edge.
1 parent 9b4e014 commit 8c69814

15 files changed

+498
-53
lines changed

docs/RequestEvaluator.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ The request-evaluator contains a cache of any requests that have already been ev
5252

5353
Until then, the request-evaluator lives in a compiler that has mutable ASTs, and will for the foreseeable future. To cope with this, requests can opt for "separate" caching of their results, implementing a simple protocol to query their own cache (`getCachedResult`) and set the value for the cache (`cacheResult`). For now, these functions can directly modify state in the AST, allowing the requests to be mixed with direct mutation of the state. For each request, the intent is to make all state access go through the evaluator, but getting there can be an incremental process.
5454

55+
## Incremental Dependency Tracking
56+
Request evaluation naturally captures the dependency structure of any given invocation of the compiler frontend. In fact, it captures it so well that the request graph trace generated by a select kind of lookup request can be used to completely recover the information relevant to the Swift compiler's incremental compilation subsystem. For these select *dependency-relevant* requests, we can further subdivide them into so-called *dependency sources* and *dependency sinks*. A dependency source is any (usually high-level) request that introduces a new context under which dependencies can be registered. Currently, these are the requests that operate that the level of individual source files. A dependency sink is any (usually lower-level) request that executes as a sub-computation of a dependency source. Any names that are dependency-relevant, such as the result of a lookup in a particular context, are then registered against trackers in the active dependency source (file). Using this, the evaluator pushes and pops sources and sinks automatically as request evaluation proceeds, and sink requests pair automatically to source requests to write out dependency information.
57+
58+
To define a request as a dependency source, it must implement an accessor for the new active scope (`readDependencySource`). To define a request as a dependency sink, it must implement a function that writes the result of evaluating the request into the current active source (`writeDependencySink`).
59+
5560
## Open Projects
5661

5762
The request-evaluator is relatively new to the Swift compiler, having been introduced in mid-2018. There are a number of improvements that can be made to the evaluator itself and how it is used in the compiler:

include/swift/AST/Evaluator.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -464,18 +464,29 @@ class Evaluator {
464464
}
465465

466466
private:
467+
// Report the result of evaluating a request that is not a dependency sink -
468+
// which is to say do nothing.
467469
template <typename Request,
468470
typename std::enable_if<!Request::isDependencySink>::type * = nullptr>
469471
void reportEvaluatedResult(const Request &r,
470-
const typename Request::OutputType &o) const {}
472+
const typename Request::OutputType &o) {}
471473

474+
// Report the result of evaluating a request that is a dependency sink.
472475
template <typename Request,
473476
typename std::enable_if<Request::isDependencySink>::type * = nullptr>
474477
void reportEvaluatedResult(const Request &r,
475478
const typename Request::OutputType &o) {
476479
r.writeDependencySink(*this, o);
477480
}
478481

482+
/// If there is an active dependency source, returns its
483+
/// \c ReferencedNameTracker. Else, returns \c nullptr.
484+
ReferencedNameTracker *getActiveDependencyTracker() const {
485+
if (auto *source = getActiveDependencySource())
486+
return source->getRequestBasedReferencedNameTracker();
487+
return nullptr;
488+
}
489+
479490
public:
480491
/// Returns \c true if the scope of the current active source cascades.
481492
///
@@ -496,20 +507,14 @@ class Evaluator {
496507

497508
/// Returns the active dependency's source file, or \c nullptr if no
498509
/// dependency source is active.
510+
///
511+
/// If there is no active scope, the result always cascades.
499512
SourceFile *getActiveDependencySource() const {
500513
if (dependencySources.empty())
501514
return nullptr;
502515
return dependencySources.back().getPointer();
503516
}
504517

505-
/// If there is an active dependency source, returns its
506-
/// \c ReferencedNameTracker. Else, returns \c nullptr.
507-
ReferencedNameTracker *getActiveDependencyTracker() const {
508-
if (auto *source = getActiveDependencySource())
509-
return source->getRequestBasedReferencedNameTracker();
510-
return nullptr;
511-
}
512-
513518
public:
514519
/// Print the dependencies of the given request as a tree.
515520
///

include/swift/AST/EvaluatorDependencies.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ inline DependencyScope getScopeForAccessLevel(AccessLevel l) {
7373
}
7474
}
7575

76-
// A \c DependencySource is a currently defined to be a parent source file and
76+
// A \c DependencySource is currently defined to be a parent source file and
7777
// an associated dependency scope.
7878
//
7979
// The \c SourceFile instance is an artifact of the current dependency system,

include/swift/AST/NameLookupRequests.h

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818

1919
#include "swift/AST/SimpleRequest.h"
2020
#include "swift/AST/ASTTypeIDs.h"
21+
#include "swift/AST/EvaluatorDependencies.h"
2122
#include "swift/AST/FileUnit.h"
2223
#include "swift/AST/Identifier.h"
24+
#include "swift/AST/NameLookup.h"
2325
#include "swift/Basic/Statistic.h"
2426
#include "llvm/ADT/Hashing.h"
2527
#include "llvm/ADT/TinyPtrVector.h"
@@ -164,9 +166,10 @@ class SuperclassDeclRequest :
164166
};
165167

166168
class InheritedProtocolsRequest
167-
: public SimpleRequest<InheritedProtocolsRequest,
168-
ArrayRef<ProtocolDecl *>(ProtocolDecl *),
169-
CacheKind::SeparatelyCached> {
169+
: public SimpleRequest<
170+
InheritedProtocolsRequest, ArrayRef<ProtocolDecl *>(ProtocolDecl *),
171+
CacheKind::SeparatelyCached | CacheKind::DependencySink |
172+
CacheKind::DependencySource> {
170173
public:
171174
using SimpleRequest::SimpleRequest;
172175

@@ -178,10 +181,16 @@ class InheritedProtocolsRequest
178181
evaluate(Evaluator &evaluator, ProtocolDecl *PD) const;
179182

180183
public:
181-
// Caching.
184+
// Caching
182185
bool isCached() const { return true; }
183186
Optional<ArrayRef<ProtocolDecl *>> getCachedResult() const;
184-
void cacheResult(ArrayRef<ProtocolDecl *> decls) const;
187+
void cacheResult(ArrayRef<ProtocolDecl *> value) const;
188+
189+
public:
190+
// Incremental dependencies
191+
evaluator::DependencySource readDependencySource(Evaluator &e) const;
192+
void writeDependencySink(Evaluator &evaluator,
193+
ArrayRef<ProtocolDecl *> result) const;
185194
};
186195

187196
/// Requests whether or not this class has designated initializers that are
@@ -208,10 +217,10 @@ class HasMissingDesignatedInitializersRequest :
208217
};
209218

210219
/// Request the nominal declaration extended by a given extension declaration.
211-
class ExtendedNominalRequest :
212-
public SimpleRequest<ExtendedNominalRequest,
213-
NominalTypeDecl *(ExtensionDecl *),
214-
CacheKind::SeparatelyCached> {
220+
class ExtendedNominalRequest
221+
: public SimpleRequest<
222+
ExtendedNominalRequest, NominalTypeDecl *(ExtensionDecl *),
223+
CacheKind::SeparatelyCached | CacheKind::DependencySink> {
215224
public:
216225
using SimpleRequest::SimpleRequest;
217226

@@ -227,6 +236,11 @@ class ExtendedNominalRequest :
227236
bool isCached() const { return true; }
228237
Optional<NominalTypeDecl *> getCachedResult() const;
229238
void cacheResult(NominalTypeDecl *value) const;
239+
240+
public:
241+
// Incremental dependencies
242+
void writeDependencySink(Evaluator &evaluator,
243+
NominalTypeDecl *result) const;
230244
};
231245

232246
struct SelfBounds {
@@ -292,10 +306,10 @@ class CustomAttrNominalRequest :
292306
};
293307

294308
/// Finds or synthesizes a destructor for the given class.
295-
class GetDestructorRequest :
296-
public SimpleRequest<GetDestructorRequest,
297-
DestructorDecl *(ClassDecl *),
298-
CacheKind::SeparatelyCached> {
309+
class GetDestructorRequest
310+
: public SimpleRequest<GetDestructorRequest, DestructorDecl *(ClassDecl *),
311+
CacheKind::SeparatelyCached |
312+
CacheKind::DependencySource> {
299313
public:
300314
using SimpleRequest::SimpleRequest;
301315

@@ -311,6 +325,10 @@ class GetDestructorRequest :
311325
bool isCached() const { return true; }
312326
Optional<DestructorDecl *> getCachedResult() const;
313327
void cacheResult(DestructorDecl *value) const;
328+
329+
public:
330+
// Incremental dependencies.
331+
evaluator::DependencySource readDependencySource(Evaluator &) const;
314332
};
315333

316334
class GenericParamListRequest :
@@ -399,7 +417,8 @@ SourceLoc extractNearestSourceLoc(const UnqualifiedLookupDescriptor &desc);
399417
class UnqualifiedLookupRequest
400418
: public SimpleRequest<UnqualifiedLookupRequest,
401419
LookupResult(UnqualifiedLookupDescriptor),
402-
CacheKind::Uncached> {
420+
CacheKind::Uncached | CacheKind::DependencySource |
421+
CacheKind::DependencySink> {
403422
public:
404423
using SimpleRequest::SimpleRequest;
405424

@@ -409,6 +428,11 @@ class UnqualifiedLookupRequest
409428
// Evaluation.
410429
LookupResult evaluate(Evaluator &evaluator,
411430
UnqualifiedLookupDescriptor desc) const;
431+
432+
public:
433+
// Incremental dependencies
434+
evaluator::DependencySource readDependencySource(Evaluator &) const;
435+
void writeDependencySink(Evaluator &eval, LookupResult res) const;
412436
};
413437

414438
using QualifiedLookupResult = SmallVector<ValueDecl *, 4>;
@@ -438,7 +462,7 @@ class AnyObjectLookupRequest
438462
: public SimpleRequest<AnyObjectLookupRequest,
439463
QualifiedLookupResult(const DeclContext *,
440464
DeclNameRef, NLOptions),
441-
CacheKind::Uncached> {
465+
CacheKind::Uncached | CacheKind::DependencySink> {
442466
public:
443467
using SimpleRequest::SimpleRequest;
444468

@@ -449,14 +473,18 @@ class AnyObjectLookupRequest
449473
const DeclContext *dc,
450474
DeclNameRef name,
451475
NLOptions options) const;
476+
477+
public:
478+
// Incremental dependencies
479+
void writeDependencySink(Evaluator &eval, QualifiedLookupResult l) const;
452480
};
453481

454482
class ModuleQualifiedLookupRequest
455483
: public SimpleRequest<ModuleQualifiedLookupRequest,
456484
QualifiedLookupResult(const DeclContext *,
457485
ModuleDecl *, DeclNameRef,
458486
NLOptions),
459-
CacheKind::Uncached> {
487+
CacheKind::Uncached | CacheKind::DependencySource | CacheKind::DependencySink> {
460488
public:
461489
using SimpleRequest::SimpleRequest;
462490

@@ -468,14 +496,20 @@ class ModuleQualifiedLookupRequest
468496
const DeclContext *DC,
469497
ModuleDecl *mod, DeclNameRef name,
470498
NLOptions opts) const;
499+
500+
public:
501+
// Incremental dependencies
502+
evaluator::DependencySource readDependencySource(Evaluator &) const;
503+
void writeDependencySink(Evaluator &eval,
504+
QualifiedLookupResult lookupResult) const;
471505
};
472506

473507
class QualifiedLookupRequest
474508
: public SimpleRequest<QualifiedLookupRequest,
475509
QualifiedLookupResult(const DeclContext *,
476510
SmallVector<NominalTypeDecl *, 4>,
477511
DeclNameRef, NLOptions),
478-
CacheKind::Uncached> {
512+
CacheKind::Uncached | CacheKind::DependencySource> {
479513
public:
480514
using SimpleRequest::SimpleRequest;
481515

@@ -488,6 +522,10 @@ class QualifiedLookupRequest
488522
SmallVector<NominalTypeDecl *, 4> decls,
489523
DeclNameRef name,
490524
NLOptions opts) const;
525+
526+
public:
527+
// Incremental dependencies.
528+
evaluator::DependencySource readDependencySource(Evaluator &) const;
491529
};
492530

493531
/// The input type for a direct lookup request.
@@ -526,7 +564,7 @@ SourceLoc extractNearestSourceLoc(const DirectLookupDescriptor &desc);
526564
class DirectLookupRequest
527565
: public SimpleRequest<DirectLookupRequest,
528566
TinyPtrVector<ValueDecl *>(DirectLookupDescriptor),
529-
CacheKind::Uncached> {
567+
CacheKind::Uncached|CacheKind::DependencySink> {
530568
public:
531569
using SimpleRequest::SimpleRequest;
532570

@@ -536,6 +574,11 @@ class DirectLookupRequest
536574
// Evaluation.
537575
TinyPtrVector<ValueDecl *>
538576
evaluate(Evaluator &evaluator, DirectLookupDescriptor desc) const;
577+
578+
public:
579+
// Incremental dependencies
580+
void writeDependencySink(Evaluator &evaluator,
581+
TinyPtrVector<ValueDecl *> result) const;
539582
};
540583

541584
class OperatorLookupDescriptor final {
@@ -598,23 +641,29 @@ template <typename OperatorType>
598641
class LookupOperatorRequest
599642
: public SimpleRequest<LookupOperatorRequest<OperatorType>,
600643
OperatorType *(OperatorLookupDescriptor),
601-
CacheKind::Cached> {
644+
CacheKind::Cached|CacheKind::DependencySink> {
602645
using SimpleRequest<LookupOperatorRequest<OperatorType>,
603646
OperatorType *(OperatorLookupDescriptor),
604-
CacheKind::Cached>::SimpleRequest;
647+
CacheKind::Cached |
648+
CacheKind::DependencySink>::SimpleRequest;
605649

606650
private:
607651
friend SimpleRequest<LookupOperatorRequest<OperatorType>,
608652
OperatorType *(OperatorLookupDescriptor),
609-
CacheKind::Cached>;
653+
CacheKind::Cached|CacheKind::DependencySink>;
610654

611655
// Evaluation.
612-
OperatorType *
613-
evaluate(Evaluator &evaluator, OperatorLookupDescriptor desc) const;
656+
OperatorType *evaluate(Evaluator &evaluator,
657+
OperatorLookupDescriptor desc) const;
614658

615659
public:
616660
// Cached.
617661
bool isCached() const { return true; }
662+
663+
public:
664+
// Incremental dependencies
665+
void writeDependencySink(Evaluator &evaluator,
666+
OperatorType *o) const;
618667
};
619668

620669
using LookupPrefixOperatorRequest = LookupOperatorRequest<PrefixOperatorDecl>;
@@ -690,7 +739,7 @@ SourceLoc extractNearestSourceLoc(const LookupConformanceDescriptor &desc);
690739
class LookupConformanceInModuleRequest
691740
: public SimpleRequest<LookupConformanceInModuleRequest,
692741
ProtocolConformanceRef(LookupConformanceDescriptor),
693-
CacheKind::Uncached> {
742+
CacheKind::Uncached|CacheKind::DependencySink> {
694743
public:
695744
using SimpleRequest::SimpleRequest;
696745

@@ -700,6 +749,11 @@ class LookupConformanceInModuleRequest
700749
// Evaluation.
701750
ProtocolConformanceRef evaluate(
702751
Evaluator &evaluator, LookupConformanceDescriptor desc) const;
752+
753+
public:
754+
// Incremental dependencies
755+
void writeDependencySink(Evaluator &evaluator,
756+
ProtocolConformanceRef result) const;
703757
};
704758

705759
#define SWIFT_TYPEID_ZONE NameLookup

include/swift/AST/SimpleRequest.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,6 @@ class SimpleRequest<Derived, Output(Inputs...), Caching> {
270270
public:
271271
constexpr static bool isDependencySource = detail::isDependencySource(Caching);
272272
constexpr static bool isDependencySink = detail::isDependencySink(Caching);
273-
constexpr static bool reportsDependencyReads = isDependencySource || isDependencySink;
274273

275274
using OutputType = Output;
276275

0 commit comments

Comments
 (0)