Skip to content

Commit 2756377

Browse files
committed
[Type checker] Separate more functionality from the TypeChecker instance.
Use the usual bag of tricks to eliminating dependence on the TypeChecker instance: static functions, LazyResolver callbacks, and emitting diagnostics on decls/ASTContext.
1 parent 05b1035 commit 2756377

10 files changed

+181
-165
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -980,10 +980,11 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
980980
// Unqualified reference to a type.
981981
if (auto typeDecl = dyn_cast<TypeDecl>(value)) {
982982
// Resolve the reference to this type declaration in our current context.
983-
auto type = TC.resolveTypeInContext(typeDecl, nullptr,
984-
TypeResolution::forContextual(useDC),
985-
TypeResolverContext::InExpression,
986-
/*isSpecialized=*/false);
983+
auto type = TypeChecker::resolveTypeInContext(
984+
typeDecl, nullptr,
985+
TypeResolution::forContextual(useDC),
986+
TypeResolverContext::InExpression,
987+
/*isSpecialized=*/false);
987988

988989
// Open the type.
989990
type = openUnboundGenericType(type, locator);

lib/Sema/DerivedConformanceEquatableHashable.cpp

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,23 @@ using namespace swift;
3737
/// \p theEnum The enum whose elements and associated values should be checked.
3838
/// \p protocol The protocol being requested.
3939
/// \return True if all associated values of all elements of the enum conform.
40-
static bool allAssociatedValuesConformToProtocol(TypeChecker &tc,
41-
DeclContext *DC,
40+
static bool allAssociatedValuesConformToProtocol(DeclContext *DC,
4241
EnumDecl *theEnum,
4342
ProtocolDecl *protocol) {
43+
auto lazyResolver = DC->getASTContext().getLazyResolver();
4444
for (auto elt : theEnum->getAllElements()) {
4545
if (!elt->hasInterfaceType())
46-
tc.validateDecl(elt);
46+
lazyResolver->resolveDeclSignature(elt);
4747

4848
auto PL = elt->getParameterList();
4949
if (!PL)
5050
continue;
5151

5252
for (auto param : *PL) {
5353
auto type = param->getType()->mapTypeOutOfContext();
54-
if (!tc.conformsToProtocol(DC->mapTypeIntoContext(type), protocol, DC,
55-
ConformanceCheckFlags::Used)) {
54+
if (!TypeChecker::conformsToProtocol(DC->mapTypeIntoContext(type),
55+
protocol, DC,
56+
ConformanceCheckFlags::Used)) {
5657
return false;
5758
}
5859
}
@@ -65,41 +66,42 @@ static bool allAssociatedValuesConformToProtocol(TypeChecker &tc,
6566
/// \p theStruct The struct whose stored properties should be checked.
6667
/// \p protocol The protocol being requested.
6768
/// \return True if all stored properties of the struct conform.
68-
static bool allStoredPropertiesConformToProtocol(TypeChecker &tc,
69-
DeclContext *DC,
69+
static bool allStoredPropertiesConformToProtocol(DeclContext *DC,
7070
StructDecl *theStruct,
7171
ProtocolDecl *protocol) {
72+
auto lazyResolver = DC->getASTContext().getLazyResolver();
7273
auto storedProperties =
7374
theStruct->getStoredProperties(/*skipInaccessible=*/true);
7475
for (auto propertyDecl : storedProperties) {
7576
if (!propertyDecl->hasType())
76-
tc.validateDecl(propertyDecl);
77+
lazyResolver->resolveDeclSignature(propertyDecl);
7778
if (!propertyDecl->hasType())
7879
return false;
7980

8081
auto type = propertyDecl->getType()->mapTypeOutOfContext();
81-
if (!tc.conformsToProtocol(DC->mapTypeIntoContext(type), protocol, DC,
82-
ConformanceCheckFlags::Used)) {
82+
if (!TypeChecker::conformsToProtocol(DC->mapTypeIntoContext(type),
83+
protocol, DC,
84+
ConformanceCheckFlags::Used)) {
8385
return false;
8486
}
8587
}
8688
return true;
8789
}
8890

8991
/// Common preconditions for Equatable and Hashable.
90-
static bool canDeriveConformance(TypeChecker &tc, DeclContext *DC,
92+
static bool canDeriveConformance(DeclContext *DC,
9193
NominalTypeDecl *target,
9294
ProtocolDecl *protocol) {
9395
// The type must be an enum or a struct.
9496
if (auto enumDecl = dyn_cast<EnumDecl>(target)) {
9597
// The cases must not have associated values, or all associated values must
9698
// conform to the protocol.
97-
return allAssociatedValuesConformToProtocol(tc, DC, enumDecl, protocol);
99+
return allAssociatedValuesConformToProtocol(DC, enumDecl, protocol);
98100
}
99101

100102
if (auto structDecl = dyn_cast<StructDecl>(target)) {
101103
// All stored properties of the struct must conform to the protocol.
102-
return allStoredPropertiesConformToProtocol(tc, DC, structDecl, protocol);
104+
return allStoredPropertiesConformToProtocol(DC, structDecl, protocol);
103105
}
104106

105107
return false;
@@ -675,12 +677,12 @@ deriveEquatable_eq(DerivedConformance &derived,
675677
return eqDecl;
676678
}
677679

678-
bool DerivedConformance::canDeriveEquatable(TypeChecker &tc, DeclContext *DC,
680+
bool DerivedConformance::canDeriveEquatable(DeclContext *DC,
679681
NominalTypeDecl *type) {
680682
ASTContext &ctx = DC->getASTContext();
681683
auto equatableProto = ctx.getProtocol(KnownProtocolKind::Equatable);
682684
if (!equatableProto) return false;
683-
return canDeriveConformance(tc, DC, type, equatableProto);
685+
return canDeriveConformance(DC, type, equatableProto);
684686
}
685687

686688
ValueDecl *DerivedConformance::deriveEquatable(ValueDecl *requirement) {
@@ -1187,7 +1189,7 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) {
11871189
// Refuse to synthesize Hashable if type isn't a struct or enum, or if it
11881190
// has non-Hashable stored properties/associated values.
11891191
auto hashableProto = C.getProtocol(KnownProtocolKind::Hashable);
1190-
if (!canDeriveConformance(TC, getConformanceContext(), Nominal,
1192+
if (!canDeriveConformance(getConformanceContext(), Nominal,
11911193
hashableProto)) {
11921194
TC.diagnose(ConformanceDecl->getLoc(), diag::type_does_not_conform,
11931195
Nominal->getDeclaredType(),

lib/Sema/DerivedConformances.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ Type DerivedConformance::getProtocolType() const {
4747
return Protocol->getDeclaredType();
4848
}
4949

50-
bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC,
51-
DeclContext *DC,
50+
bool DerivedConformance::derivesProtocolConformance(DeclContext *DC,
5251
NominalTypeDecl *Nominal,
5352
ProtocolDecl *Protocol) {
5453
// Only known protocols can be derived.
@@ -73,7 +72,7 @@ bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC,
7372
// Enums without associated values can implicitly derive Equatable
7473
// conformance.
7574
case KnownProtocolKind::Equatable:
76-
return canDeriveEquatable(TC, DC, Nominal);
75+
return canDeriveEquatable(DC, Nominal);
7776

7877
// "Simple" enums without availability attributes can explicitly derive
7978
// a CaseIterable conformance.
@@ -129,7 +128,7 @@ bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC,
129128
if (auto structDecl = dyn_cast<StructDecl>(Nominal)) {
130129
switch (*knownProtocol) {
131130
case KnownProtocolKind::Equatable:
132-
return canDeriveEquatable(TC, DC, Nominal);
131+
return canDeriveEquatable(DC, Nominal);
133132
default:
134133
return false;
135134
}
@@ -158,8 +157,7 @@ ValueDecl *DerivedConformance::getDerivableRequirement(TypeChecker &tc,
158157
ConformanceCheckFlags::SkipConditionalRequirements)) {
159158
auto DC = conformance->getConcrete()->getDeclContext();
160159
// Check whether this nominal type derives conformances to the protocol.
161-
if (!DerivedConformance::derivesProtocolConformance(tc, DC, nominal,
162-
proto))
160+
if (!DerivedConformance::derivesProtocolConformance(DC, nominal, proto))
163161
return nullptr;
164162
}
165163

lib/Sema/DerivedConformances.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,14 @@ class DerivedConformance {
5858
/// declarations for requirements of the protocol that are not satisfied by
5959
/// the type's explicit members.
6060
///
61-
/// \param tc The type checker.
62-
///
6361
/// \param nominal The nominal type for which we are determining whether to
6462
/// derive a witness.
6563
///
6664
/// \param protocol The protocol whose requirements are being derived.
6765
///
6866
/// \return True if the type can implicitly derive a conformance for the
6967
/// given protocol.
70-
static bool derivesProtocolConformance(TypeChecker &tc, DeclContext *DC,
68+
static bool derivesProtocolConformance(DeclContext *DC,
7169
NominalTypeDecl *nominal,
7270
ProtocolDecl *protocol);
7371

@@ -120,8 +118,7 @@ class DerivedConformance {
120118
/// associated values, and for structs with all-Equatable stored properties.
121119
///
122120
/// \returns True if the requirement can be derived.
123-
static bool canDeriveEquatable(TypeChecker &tc, DeclContext *DC,
124-
NominalTypeDecl *type);
121+
static bool canDeriveEquatable(DeclContext *DC, NominalTypeDecl *type);
125122

126123
/// Derive an Equatable requirement for a type.
127124
///

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,14 +1068,17 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
10681068
}
10691069
break;
10701070

1071-
case RequirementKind::Superclass:
1071+
case RequirementKind::Superclass: {
10721072
// Superclass requirements.
1073-
if (!isSubclassOf(firstType, secondType, dc)) {
1073+
// FIXME: Don't use the type checker instance here?
1074+
TypeChecker &tc = static_cast<TypeChecker &>(*ctx.getLazyResolver());
1075+
if (!tc.isSubclassOf(firstType, secondType, dc)) {
10741076
diagnostic = diag::type_does_not_inherit;
10751077
diagnosticNote = diag::type_does_not_inherit_or_conform_requirement;
10761078
requirementFailure = true;
10771079
}
10781080
break;
1081+
}
10791082

10801083
case RequirementKind::SameType:
10811084
if (!firstType->isEqual(secondType)) {

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
447447
if (options.contains(NameLookupFlags::IgnoreAccessControl))
448448
subOptions |= NL_IgnoreAccessControl;
449449

450-
if (!dc->lookupQualified(type, name, subOptions, this, decls))
450+
if (!dc->lookupQualified(type, name, subOptions, nullptr, decls))
451451
return result;
452452

453453
// Look through the declarations, keeping only the unique type declarations.
@@ -457,9 +457,11 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
457457
auto *typeDecl = cast<TypeDecl>(decl);
458458

459459
// FIXME: This should happen before we attempt shadowing checks.
460-
validateDecl(typeDecl);
461-
if (!typeDecl->hasInterfaceType()) // FIXME: recursion-breaking hack
462-
continue;
460+
if (!typeDecl->hasInterfaceType()) {
461+
dc->getASTContext().getLazyResolver()->resolveDeclSignature(typeDecl);
462+
if (!typeDecl->hasInterfaceType()) // FIXME: recursion-breaking hack
463+
continue;
464+
}
463465

464466
auto memberType = typeDecl->getDeclaredInterfaceType();
465467

@@ -548,7 +550,9 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
548550
ProtocolConformanceState::CheckingTypeWitnesses)
549551
continue;
550552

551-
auto typeDecl = concrete->getTypeWitnessAndDecl(assocType, this).second;
553+
auto lazyResolver = dc->getASTContext().getLazyResolver();
554+
auto typeDecl =
555+
concrete->getTypeWitnessAndDecl(assocType, lazyResolver).second;
552556

553557
assert(typeDecl && "Missing type witness?");
554558

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3042,7 +3042,7 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDerivation(
30423042
// Find the declaration that derives the protocol conformance.
30433043
NominalTypeDecl *derivingTypeDecl = nullptr;
30443044
auto *nominal = Adoptee->getAnyNominal();
3045-
if (DerivedConformance::derivesProtocolConformance(TC, DC, nominal, Proto))
3045+
if (DerivedConformance::derivesProtocolConformance(DC, nominal, Proto))
30463046
derivingTypeDecl = nominal;
30473047

30483048
if (!derivingTypeDecl) {
@@ -3386,7 +3386,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied(
33863386
{ Type(proto->getProtocolSelfType()) },
33873387
proto->getRequirementSignature(),
33883388
QuerySubstitutionMap{substitutions},
3389-
TypeChecker::LookUpConformance(TC, DC),
3389+
TypeChecker::LookUpConformance(DC),
33903390
ConformanceCheckFlags::Used, &listener);
33913391

33923392
switch (result) {
@@ -3692,7 +3692,7 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
36923692
}
36933693
}
36943694

3695-
static void diagnoseConformanceFailure(TypeChecker &TC, Type T,
3695+
static void diagnoseConformanceFailure(Type T,
36963696
ProtocolDecl *Proto,
36973697
DeclContext *DC,
36983698
SourceLoc ComplainLoc) {
@@ -3705,7 +3705,7 @@ static void diagnoseConformanceFailure(TypeChecker &TC, Type T,
37053705
// If we're checking conformance of an existential type to a protocol,
37063706
// do a little bit of extra work to produce a better diagnostic.
37073707
if (T->isExistentialType() &&
3708-
TC.containsProtocol(T, Proto, DC, None)) {
3708+
TypeChecker::containsProtocol(T, Proto, DC, None)) {
37093709

37103710
if (!T->isObjCExistentialType()) {
37113711
diags.diagnose(ComplainLoc, diag::protocol_does_not_conform_objc,
@@ -3729,7 +3729,7 @@ static void diagnoseConformanceFailure(TypeChecker &TC, Type T,
37293729
// conformance to RawRepresentable was inferred.
37303730
if (auto enumDecl = T->getEnumOrBoundGenericEnum()) {
37313731
if (Proto->isSpecificProtocol(KnownProtocolKind::RawRepresentable) &&
3732-
DerivedConformance::derivesProtocolConformance(TC, DC, enumDecl,
3732+
DerivedConformance::derivesProtocolConformance(DC, enumDecl,
37333733
Proto) &&
37343734
enumDecl->hasRawType() &&
37353735
!enumDecl->getRawType()->is<ErrorType>()) {
@@ -3746,7 +3746,8 @@ static void diagnoseConformanceFailure(TypeChecker &TC, Type T,
37463746
if (!equatableProto)
37473747
return;
37483748

3749-
if (!TC.conformsToProtocol(rawType, equatableProto, enumDecl, None)) {
3749+
if (!TypeChecker::conformsToProtocol(rawType, equatableProto, enumDecl,
3750+
None)) {
37503751
SourceLoc loc = enumDecl->getInherited()[0].getSourceRange().Start;
37513752
diags.diagnose(loc, diag::enum_raw_type_not_equatable, rawType);
37523753
return;
@@ -3780,7 +3781,7 @@ void ConformanceChecker::diagnoseOrDefer(
37803781

37813782
// Complain that the type does not conform, once.
37823783
if (isError && !AlreadyComplained) {
3783-
diagnoseConformanceFailure(TC, Adoptee, Proto, DC, Loc);
3784+
diagnoseConformanceFailure(Adoptee, Proto, DC, Loc);
37843785
AlreadyComplained = true;
37853786
}
37863787

@@ -3865,7 +3866,7 @@ Optional<ProtocolConformanceRef> TypeChecker::conformsToProtocol(
38653866
auto lookupResult = M->lookupConformance(T, Proto);
38663867
if (!lookupResult) {
38673868
if (ComplainLoc.isValid())
3868-
diagnoseConformanceFailure(*this, T, Proto, DC, ComplainLoc);
3869+
diagnoseConformanceFailure(T, Proto, DC, ComplainLoc);
38693870
else
38703871
recordDependency();
38713872

@@ -3881,7 +3882,8 @@ Optional<ProtocolConformanceRef> TypeChecker::conformsToProtocol(
38813882

38823883
// If we're using this conformance, note that.
38833884
if (options.contains(ConformanceCheckFlags::Used)) {
3884-
markConformanceUsed(*lookupResult, DC);
3885+
if (auto lazyResolver = DC->getASTContext().getLazyResolver())
3886+
lazyResolver->markConformanceUsed(*lookupResult, DC);
38853887
}
38863888

38873889
auto condReqs = lookupResult->getConditionalRequirementsIfAvailable();
@@ -3909,7 +3911,7 @@ Optional<ProtocolConformanceRef> TypeChecker::conformsToProtocol(
39093911
{Type(lookupResult->getRequirement()->getProtocolSelfType())},
39103912
*condReqs,
39113913
[](SubstitutableType *dependentType) { return Type(dependentType); },
3912-
LookUpConformance(*this, DC), options);
3914+
LookUpConformance(DC), options);
39133915
switch (conditionalCheckResult) {
39143916
case RequirementCheckResult::Success:
39153917
break;
@@ -3922,7 +3924,8 @@ Optional<ProtocolConformanceRef> TypeChecker::conformsToProtocol(
39223924

39233925
// When requested, print the conformance access path used to find this
39243926
// conformance.
3925-
if (Context.LangOpts.DebugGenericSignatures &&
3927+
ASTContext &ctx = Proto->getASTContext();
3928+
if (ctx.LangOpts.DebugGenericSignatures &&
39263929
InExpression && T->is<ArchetypeType>() && lookupResult->isAbstract() &&
39273930
!T->castTo<ArchetypeType>()->isOpenedExistential() &&
39283931
!T->castTo<ArchetypeType>()->requiresClass() &&
@@ -3972,7 +3975,7 @@ TypeChecker::LookUpConformance::operator()(
39723975
if (conformingReplacementType->isTypeParameter())
39733976
return ProtocolConformanceRef(conformedProtocol);
39743977

3975-
return tc.conformsToProtocol(
3978+
return TypeChecker::conformsToProtocol(
39763979
conformingReplacementType,
39773980
conformedProtocol,
39783981
dc,
@@ -4780,7 +4783,7 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc,
47804783
if (auto enumDecl = dyn_cast<EnumDecl>(existingDecl)) {
47814784
if (diag.Protocol->isSpecificProtocol(
47824785
KnownProtocolKind::RawRepresentable) &&
4783-
DerivedConformance::derivesProtocolConformance(*this, dc, enumDecl,
4786+
DerivedConformance::derivesProtocolConformance(dc, enumDecl,
47844787
diag.Protocol) &&
47854788
enumDecl->hasRawType() &&
47864789
enumDecl->getInherited()[0].getSourceRange().isValid()) {

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ Type AssociatedTypeInference::computeDerivedTypeWitness(
886886

887887
// Can we derive conformances for this protocol and adoptee?
888888
NominalTypeDecl *derivingTypeDecl = adoptee->getAnyNominal();
889-
if (!DerivedConformance::derivesProtocolConformance(tc, dc, derivingTypeDecl,
889+
if (!DerivedConformance::derivesProtocolConformance(dc, derivingTypeDecl,
890890
proto))
891891
return Type();
892892

@@ -1117,7 +1117,7 @@ bool AssociatedTypeInference::checkCurrentTypeWitnesses(
11171117
{ Type(proto->getProtocolSelfType()) },
11181118
sanitizedRequirements,
11191119
QuerySubstitutionMap{substitutions},
1120-
TypeChecker::LookUpConformance(tc, dc),
1120+
TypeChecker::LookUpConformance(dc),
11211121
None, nullptr, options);
11221122
switch (result) {
11231123
case RequirementCheckResult::Failure:

0 commit comments

Comments
 (0)