Skip to content

Commit bc7eb59

Browse files
author
David Ungar
authored
Merge pull request #36099 from CodaFi/extensionality
Register Dependency Arcs for Extension Members
2 parents 2589d25 + a99d07a commit bc7eb59

23 files changed

+299
-49
lines changed

include/swift/AST/AbstractSourceFileDepGraphFactory.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,11 @@ class AbstractSourceFileDepGraphFactory {
7373
for (const auto &declOrPair : contentsVec) {
7474
auto fp =
7575
AbstractSourceFileDepGraphFactory::getFingerprintIfAny(declOrPair);
76-
addADefinedDecl(
77-
DependencyKey::createForProvidedEntityInterface<kind>(declOrPair),
78-
fp);
76+
auto key = DependencyKey::Builder{kind, DeclAspect::interface}
77+
.withContext(declOrPair)
78+
.withName(declOrPair)
79+
.build();
80+
addADefinedDecl(key, fp);
7981
}
8082
}
8183

include/swift/AST/DependencyCollector.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
namespace swift {
2525

26-
class NominalTypeDecl;
26+
class DeclContext;
2727

2828
namespace evaluator {
2929

@@ -50,31 +50,31 @@ struct DependencyCollector {
5050
Dynamic,
5151
} kind;
5252

53-
NominalTypeDecl *subject;
53+
DeclContext *subject;
5454
DeclBaseName name;
5555

5656
private:
57-
Reference(Kind kind, NominalTypeDecl *subject, DeclBaseName name)
57+
Reference(Kind kind, DeclContext *subject, DeclBaseName name)
5858
: kind(kind), subject(subject), name(name) {}
5959

6060
public:
6161
static Reference empty() {
62-
return {Kind::Empty, llvm::DenseMapInfo<NominalTypeDecl *>::getEmptyKey(),
62+
return {Kind::Empty, llvm::DenseMapInfo<DeclContext *>::getEmptyKey(),
6363
llvm::DenseMapInfo<DeclBaseName>::getEmptyKey()};
6464
}
6565

6666
static Reference tombstone() {
6767
return {Kind::Tombstone,
68-
llvm::DenseMapInfo<NominalTypeDecl *>::getTombstoneKey(),
68+
llvm::DenseMapInfo<DeclContext *>::getTombstoneKey(),
6969
llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey()};
7070
}
7171

7272
public:
73-
static Reference usedMember(NominalTypeDecl *subject, DeclBaseName name) {
73+
static Reference usedMember(DeclContext *subject, DeclBaseName name) {
7474
return {Kind::UsedMember, subject, name};
7575
}
7676

77-
static Reference potentialMember(NominalTypeDecl *subject) {
77+
static Reference potentialMember(DeclContext *subject) {
7878
return {Kind::PotentialMember, subject, DeclBaseName()};
7979
}
8080

@@ -119,7 +119,7 @@ struct DependencyCollector {
119119
/// up front. A used member dependency causes the file to be rebuilt if the
120120
/// definition of that member changes in any way - via
121121
/// deletion, addition, or mutation of a member with that same name.
122-
void addUsedMember(NominalTypeDecl *subject, DeclBaseName name);
122+
void addUsedMember(DeclContext *subject, DeclBaseName name);
123123
/// Registers a reference from the current dependency scope to a
124124
/// "potential member" of the given \p subject type.
125125
///
@@ -133,7 +133,7 @@ struct DependencyCollector {
133133
///
134134
/// These dependencies are most appropriate for protocol conformances,
135135
/// superclass constraints, and other requirements involving entire types.
136-
void addPotentialMember(NominalTypeDecl *subject);
136+
void addPotentialMember(DeclContext *subject);
137137
/// Registers a reference from the current dependency scope to a given
138138
/// top-level \p name.
139139
///

include/swift/AST/FineGrainedDependencies.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -426,14 +426,14 @@ class DependencyKey {
426426
private:
427427
const NodeKind kind;
428428
const DeclAspect aspect;
429-
const NominalTypeDecl *context;
429+
const DeclContext *context;
430430
StringRef name;
431431

432432
private:
433433
// A private copy constructor so our clients are forced to use the
434434
// move-only builder interface.
435435
explicit Builder(NodeKind kind, DeclAspect aspect,
436-
const NominalTypeDecl *context, StringRef name)
436+
const DeclContext *context, StringRef name)
437437
: kind(kind), aspect(aspect), context(context), name(name) {}
438438

439439
public:
@@ -535,11 +535,6 @@ class DependencyKey {
535535
}
536536
bool isInterface() const { return getAspect() == DeclAspect::interface; }
537537

538-
/// Create just the interface half of the keys for a provided Decl or Decl
539-
/// pair
540-
template <NodeKind kind, typename Entity>
541-
static DependencyKey createForProvidedEntityInterface(Entity);
542-
543538
DependencyKey correspondingImplementation() const {
544539
return withAspect(DeclAspect::implementation);
545540
}

lib/AST/Evaluator.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//
1616
//===----------------------------------------------------------------------===//
1717
#include "swift/AST/Evaluator.h"
18+
#include "swift/AST/DeclContext.h"
1819
#include "swift/AST/DiagnosticEngine.h"
1920
#include "swift/Basic/LangOptions.h"
2021
#include "swift/Basic/Range.h"
@@ -112,13 +113,14 @@ evaluator::DependencyCollector::~DependencyCollector() {
112113
#endif
113114
}
114115

115-
void evaluator::DependencyCollector::addUsedMember(NominalTypeDecl *subject,
116+
void evaluator::DependencyCollector::addUsedMember(DeclContext *subject,
116117
DeclBaseName name) {
118+
assert(subject->isTypeContext());
117119
return parent.recordDependency(Reference::usedMember(subject, name));
118120
}
119121

120-
void evaluator::DependencyCollector::addPotentialMember(
121-
NominalTypeDecl *subject) {
122+
void evaluator::DependencyCollector::addPotentialMember(DeclContext *subject) {
123+
assert(subject->isTypeContext());
122124
return parent.recordDependency(Reference::potentialMember(subject));
123125
}
124126

lib/AST/FrontendSourceFileDepGraphFactory.cpp

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,28 +56,29 @@ using namespace fine_grained_dependencies;
5656
// MARK: Helpers for key construction that must be in frontend
5757
//==============================================================================
5858

59-
static std::string mangleTypeAsContext(const NominalTypeDecl *NTD) {
59+
static std::string identifierForContext(const DeclContext *DC) {
60+
if (!DC) return "";
61+
6062
Mangle::ASTMangler Mangler;
61-
return !NTD ? "" : Mangler.mangleTypeAsContextUSR(NTD);
63+
if (const auto *context = dyn_cast<NominalTypeDecl>(DC)) {
64+
return Mangler.mangleTypeAsContextUSR(context);
65+
}
66+
67+
const auto *ext = cast<ExtensionDecl>(DC);
68+
auto fp = ext->getBodyFingerprint().getValueOr(Fingerprint::ZERO());
69+
auto typeStr = Mangler.mangleTypeAsContextUSR(ext->getExtendedNominal());
70+
return (typeStr + "@" + fp.getRawValue()).str();
6271
}
6372

6473
//==============================================================================
6574
// MARK: DependencyKey::Builder
6675
//==============================================================================
6776

68-
template <NodeKind kindArg, typename Entity>
69-
DependencyKey DependencyKey::createForProvidedEntityInterface(Entity entity) {
70-
return DependencyKey::Builder{kindArg, DeclAspect::interface}
71-
.withContext(entity)
72-
.withName(entity)
73-
.build();
74-
}
75-
7677
DependencyKey DependencyKey::Builder::build() && {
7778
return DependencyKey{
7879
kind,
7980
aspect,
80-
context ? mangleTypeAsContext(context) : "",
81+
identifierForContext(context),
8182
name.str()
8283
};
8384
}
@@ -92,24 +93,29 @@ DependencyKey::Builder DependencyKey::Builder::fromReference(
9293
case Kind::Tombstone:
9394
llvm_unreachable("Cannot enumerate dead reference!");
9495
case Kind::PotentialMember:
95-
return Builder{kind, aspect}.withContext(ref.subject);
96+
return Builder{kind, aspect}.withContext(ref.subject->getAsDecl());
9697
case Kind::TopLevel:
9798
case Kind::Dynamic:
9899
return Builder{kind, aspect, nullptr, ref.name.userFacingName()};
99100
case Kind::UsedMember:
100101
return Builder{kind, aspect, nullptr, ref.name.userFacingName()}
101-
.withContext(ref.subject);
102+
.withContext(ref.subject->getAsDecl());
102103
}
103104
}
104105

105106
DependencyKey::Builder DependencyKey::Builder::withContext(const Decl *D) && {
106107
switch (kind) {
107108
case NodeKind::nominal:
108109
case NodeKind::potentialMember:
109-
case NodeKind::member:
110+
case NodeKind::member: {
110111
/// nominal and potential member dependencies are created from a Decl and
111112
/// use the context field.
112-
return Builder{kind, aspect, cast<NominalTypeDecl>(D), name};
113+
const DeclContext *context = dyn_cast<NominalTypeDecl>(D);
114+
if (!context) {
115+
context = cast<ExtensionDecl>(D);
116+
}
117+
return Builder{kind, aspect, context, name};
118+
}
113119
case NodeKind::topLevel:
114120
case NodeKind::dynamicLookup:
115121
case NodeKind::externalDepend:
@@ -411,6 +417,7 @@ void FrontendSourceFileDepGraphFactory::addAllDefinedDecls() {
411417
addAllDefinedDeclsOfAGivenType<NodeKind::topLevel>(declFinder.topNominals);
412418
addAllDefinedDeclsOfAGivenType<NodeKind::topLevel>(declFinder.topValues);
413419
addAllDefinedDeclsOfAGivenType<NodeKind::nominal>(declFinder.allNominals);
420+
addAllDefinedDeclsOfAGivenType<NodeKind::nominal>(declFinder.extensions);
414421
addAllDefinedDeclsOfAGivenType<NodeKind::potentialMember>(
415422
declFinder.potentialMemberHolders);
416423
addAllDefinedDeclsOfAGivenType<NodeKind::member>(
@@ -463,16 +470,28 @@ class UsedDeclEnumerator {
463470
void enumerateNominalUses(UseEnumerator enumerator) {
464471
auto &Ctx = SF->getASTContext();
465472
Ctx.evaluator.enumerateReferencesInFile(SF, [&](const auto &ref) {
466-
const NominalTypeDecl *subject = ref.subject;
473+
const DeclContext *subject = ref.subject;
467474
if (!subject) {
468475
return;
469476
}
470477

471-
auto key =
478+
auto nominalKey =
472479
DependencyKey::Builder(NodeKind::nominal, DeclAspect::interface)
473-
.withContext(subject)
480+
.withContext(subject->getSelfNominalTypeDecl())
474481
.build();
475-
enumerateUse(key, enumerator);
482+
enumerateUse(nominalKey, enumerator);
483+
484+
auto declKey =
485+
DependencyKey::Builder(NodeKind::nominal, DeclAspect::interface)
486+
.withContext(subject->getAsDecl())
487+
.build();
488+
489+
// If the subject of this dependency is not the nominal type itself,
490+
// record another arc for the extension this member came from.
491+
if (nominalKey != declKey) {
492+
assert(isa<ExtensionDecl>(subject));
493+
enumerateUse(declKey, enumerator);
494+
}
476495
});
477496
}
478497

@@ -579,6 +598,7 @@ void ModuleDepGraphFactory::addAllDefinedDecls() {
579598
addAllDefinedDeclsOfAGivenType<NodeKind::topLevel>(declFinder.topNominals);
580599
addAllDefinedDeclsOfAGivenType<NodeKind::topLevel>(declFinder.topValues);
581600
addAllDefinedDeclsOfAGivenType<NodeKind::nominal>(declFinder.allNominals);
601+
addAllDefinedDeclsOfAGivenType<NodeKind::nominal>(declFinder.extensions);
582602
addAllDefinedDeclsOfAGivenType<NodeKind::potentialMember>(
583603
declFinder.potentialMemberHolders);
584604
addAllDefinedDeclsOfAGivenType<NodeKind::member>(

lib/AST/NameLookupRequests.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,13 @@ void DirectLookupRequest::writeDependencySink(
305305
evaluator::DependencyCollector &tracker,
306306
const TinyPtrVector<ValueDecl *> &result) const {
307307
auto &desc = std::get<0>(getStorage());
308+
// Add used members from the perspective of
309+
// 1) The decl context they are found in
310+
// 2) The decl context of the request
311+
// This gets us a dependency not just on `Foo.bar` but on `extension Foo.bar`.
312+
for (const auto *member : result) {
313+
tracker.addUsedMember(member->getDeclContext(), desc.Name.getBaseName());
314+
}
308315
tracker.addUsedMember(desc.DC, desc.Name.getBaseName());
309316
}
310317

lib/Frontend/DependencyVerifier.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ struct Obligation {
188188
}
189189
static bool isEqual(const Obligation::Key &LHS,
190190
const Obligation::Key &RHS) {
191-
return LHS.Name == RHS.Name && LHS.Kind == RHS.Kind;
191+
return LHS.Name.equals(RHS.Name) && LHS.Kind == RHS.Kind;
192192
}
193193
};
194194
};
@@ -395,12 +395,12 @@ bool DependencyVerifier::constructObligations(const SourceFile *SF,
395395
llvm_unreachable("Cannot enumerate dead dependency!");
396396

397397
case NodeKind::PotentialMember: {
398-
auto key = copyQualifiedTypeName(Ctx, reference.subject);
398+
auto key = copyQualifiedTypeName(Ctx, reference.subject->getSelfNominalTypeDecl());
399399
Obligations.insert({Obligation::Key::forPotentialMember(key),
400400
{"", Expectation::Kind::PotentialMember}});
401401
} break;
402402
case NodeKind::UsedMember: {
403-
auto demContext = copyQualifiedTypeName(Ctx, reference.subject);
403+
auto demContext = copyQualifiedTypeName(Ctx, reference.subject->getSelfNominalTypeDecl());
404404
auto name = reference.name.userFacingName();
405405
auto key = Ctx.AllocateCopy((demContext + "." + name).str());
406406
Obligations.insert(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public struct S {
2+
private
3+
static func foo(_ i: Int) {print("1: other:2 commented out")}
4+
}
5+
extension S {
6+
// private // commented out to ensure we see a change to the fingerprint
7+
static func foo2(_ i: Int) {print("2: other:6 commented out")}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public struct S {
2+
private // commenting out this line works
3+
static func foo(_ i: Int) {print("1: other:2 commented out")}
4+
}
5+
extension S {
6+
private // commenting out this line fails
7+
static func foo2(_ i: Int) {print("2: other:6 commented out")}
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
extension S {
2+
static func foo<I: SignedInteger>(_ si: I) {
3+
print("1: other:2 not commented out")
4+
}
5+
static func foo2<I: SignedInteger>(_ si: I) {
6+
print("2: other:6 not commented out")
7+
}
8+
}
9+
10+
S.foo(3)
11+
S.foo2(3)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"main.swift": {
3+
"object": "./main.o",
4+
"swift-dependencies": "./main.swiftdeps"
5+
},
6+
"definesS.swift": {
7+
"object": "./definesS.o",
8+
"swift-dependencies": "./definesS.swiftdeps"
9+
},
10+
"": {
11+
"swift-dependencies": "./main~buildrecord.swiftdeps"
12+
}
13+
}
14+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
public protocol P {
2+
func foo()
3+
}
4+
5+
public protocol Q: P {
6+
func bar()
7+
}
8+
9+
public struct S {}
10+
11+
extension S: P {
12+
public func foo() {}
13+
}
14+
15+
extension S: Q {
16+
public func bar() {}
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
public protocol P {
2+
func foo()
3+
}
4+
5+
public protocol Q: P {
6+
func bar()
7+
}
8+
9+
public struct S {}
10+
11+
extension S: P {
12+
public func foo() {}
13+
public func bar() {}
14+
}
15+
16+
extension S: Q {
17+
18+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extension S {
2+
public func foo(_ parameter: Int = 42) {}
3+
public func bar(_ parameter: Int = 42) {}
4+
}
5+
6+
S().foo()
7+
S().bar()

0 commit comments

Comments
 (0)