Skip to content

Commit 4295625

Browse files
committed
AST: Fix regression with reference-dependencies-members test
When the call to checkGenericArguments() was removed from ConformanceChecker::checkConformance(), we stopped recording a dependency on the extended nominal type when checking an extension that adds a protocol conformance to the type. Fix this in a hacky way by recording an explicit dependency in the same place where we used to call checkGenericArguments(). Surely this is not the best place for it though, so this should be revisited since I'm pretty sure the old behavior was an accident.
1 parent c4fab13 commit 4295625

File tree

2 files changed

+41
-30
lines changed

2 files changed

+41
-30
lines changed

include/swift/AST/Module.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ class SourceFile final : public FileUnit {
948948
SourceLoc diagLoc = {});
949949
/// @}
950950

951-
ReferencedNameTracker *getReferencedNameTracker() {
951+
ReferencedNameTracker *getReferencedNameTracker() const {
952952
return ReferencedNames;
953953
}
954954
void setReferencedNameTracker(ReferencedNameTracker *Tracker) {

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3700,6 +3700,35 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) {
37003700
}
37013701
}
37023702

3703+
static void recordConformanceDependency(DeclContext *DC,
3704+
NominalTypeDecl *Adoptee,
3705+
ProtocolConformance *Conformance,
3706+
bool InExpression) {
3707+
if (!Conformance)
3708+
return;
3709+
3710+
auto *topLevelContext = DC->getModuleScopeContext();
3711+
auto *SF = dyn_cast<SourceFile>(topLevelContext);
3712+
if (!SF)
3713+
return;
3714+
3715+
auto *tracker = SF->getReferencedNameTracker();
3716+
if (!tracker)
3717+
return;
3718+
3719+
if (SF->getParentModule() !=
3720+
Conformance->getDeclContext()->getParentModule())
3721+
return;
3722+
3723+
auto &Context = DC->getASTContext();
3724+
3725+
// FIXME: 'deinit' is being used as a dummy identifier here. Really we
3726+
// don't care about /any/ of the type's members, only that it conforms to
3727+
// the protocol.
3728+
tracker->addUsedMember({Adoptee, Context.Id_deinit},
3729+
DC->isCascadingContextForLookup(InExpression));
3730+
}
3731+
37033732
#pragma mark Protocol conformance checking
37043733
void ConformanceChecker::checkConformance() {
37053734
assert(!Conformance->isComplete() && "Conformance is already complete");
@@ -3715,6 +3744,12 @@ void ConformanceChecker::checkConformance() {
37153744
// Resolve all of the type witnesses.
37163745
resolveTypeWitnesses();
37173746

3747+
// Ensure the conforming type is used.
3748+
//
3749+
// FIXME: This feels like the wrong place for this, but if we don't put
3750+
// it here, extensions don't end up depending on the extended type.
3751+
recordConformanceDependency(DC, Adoptee->getAnyNominal(), Conformance, false);
3752+
37183753
// If we complain about any associated types, there is no point in continuing.
37193754
// FIXME: Not really true. We could check witnesses that don't involve the
37203755
// failed associated types.
@@ -4156,38 +4191,14 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto,
41564191
SourceLoc ComplainLoc) {
41574192
bool InExpression = options.contains(ConformanceCheckFlags::InExpression);
41584193

4159-
const DeclContext *topLevelContext = DC->getModuleScopeContext();
41604194
auto recordDependency = [=](ProtocolConformance *conformance = nullptr) {
4161-
if (options.contains(ConformanceCheckFlags::SuppressDependencyTracking))
4162-
return;
4163-
4164-
// Record that we depend on the type's conformance.
4165-
auto *constSF = dyn_cast<SourceFile>(topLevelContext);
4166-
if (!constSF)
4167-
return;
4168-
auto *SF = const_cast<SourceFile *>(constSF);
4169-
4170-
auto *tracker = SF->getReferencedNameTracker();
4171-
if (!tracker)
4172-
return;
4173-
4174-
// We only care about intra-module dependencies.
4175-
if (conformance)
4176-
if (SF->getParentModule() !=
4177-
conformance->getDeclContext()->getParentModule())
4178-
return;
4179-
4180-
if (auto nominal = T->getAnyNominal()) {
4181-
// FIXME: 'deinit' is being used as a dummy identifier here. Really we
4182-
// don't care about /any/ of the type's members, only that it conforms to
4183-
// the protocol.
4184-
tracker->addUsedMember({nominal, Context.Id_deinit},
4185-
DC->isCascadingContextForLookup(InExpression));
4186-
}
4195+
if (!options.contains(ConformanceCheckFlags::SuppressDependencyTracking))
4196+
if (auto nominal = T->getAnyNominal())
4197+
recordConformanceDependency(DC, nominal, conformance, InExpression);
41874198
};
41884199

41894200
// Look up conformance in the module.
4190-
Module *M = topLevelContext->getParentModule();
4201+
Module *M = DC->getParentModule();
41914202
auto lookupResult = M->lookupConformance(T, Proto, this);
41924203
if (!lookupResult) {
41934204
if (ComplainLoc.isValid())
@@ -4206,7 +4217,7 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto,
42064217
} else {
42074218
if (Conformance)
42084219
*Conformance = nullptr;
4209-
recordDependency(nullptr);
4220+
recordDependency();
42104221
}
42114222

42124223
// If we're using this conformance, note that.

0 commit comments

Comments
 (0)