Skip to content

Commit bf6d8e0

Browse files
committed
Requestify Witness Resolution
Witness matching is a source of a lot of ad-hoc cycles, and mixes the logic that performs resolution, caching, validation, and cycle detection into one place. To make matters worse, some checkers kick off other checks in order to cache work for further declarations, and access an internal cache on their subject conformance for many requirements at once, or sometimes just one requirement. None of this fits into the request evaluator's central view of the caching. This is further evidenced by the fact that if you attempt to move the caching step into the evaluator, it overcaches the same witness and trips asserts. As a start, define requests for the resolution steps, and flush some hacks around forcing witness resolution. The caching logic is mostly untouched (the requests don't actually cache anything), but some cycle breaking is now handled in the evaluator itself. Once witness matching has been refactored to cache with the evaluator, all of these hacks can go away. My urge to destroy the LazyResolver outweighs the compromises here.
1 parent aeea756 commit bf6d8e0

18 files changed

+265
-118
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ SWIFT_TYPEID(Requirement)
2525
SWIFT_TYPEID(ResilienceExpansion)
2626
SWIFT_TYPEID(Type)
2727
SWIFT_TYPEID(TypePair)
28+
SWIFT_TYPEID(TypeWitnessAndDecl)
29+
SWIFT_TYPEID(Witness)
2830
SWIFT_TYPEID_NAMED(ConstructorDecl *, ConstructorDecl)
2931
SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr)
3032
SWIFT_TYPEID_NAMED(Decl *, Decl)

include/swift/AST/ASTTypeIDs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@ enum class ResilienceExpansion : unsigned;
5151
class Type;
5252
class ValueDecl;
5353
class VarDecl;
54+
class Witness;
5455
class TypeAliasDecl;
5556
class Type;
5657
struct TypePair;
58+
struct TypeWitnessAndDecl;
5759
enum class AncestryFlags : uint8_t;
5860

5961
// Define the AST type zone (zone 1)

include/swift/AST/Decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7289,6 +7289,11 @@ inline void simple_display(llvm::raw_ostream &out,
72897289
simple_display(out, static_cast<const Decl *>(decl));
72907290
}
72917291

7292+
inline void simple_display(llvm::raw_ostream &out,
7293+
const AssociatedTypeDecl *decl) {
7294+
simple_display(out, static_cast<const Decl *>(decl));
7295+
}
7296+
72927297
/// Display GenericContext.
72937298
///
72947299
/// The template keeps this sorted down in the overload set relative to the

include/swift/AST/LazyResolver.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,6 @@ class LazyResolver {
4343
public:
4444
virtual ~LazyResolver();
4545

46-
/// Resolve the type witnesses for the given associated type within the given
47-
/// protocol conformance.
48-
virtual void resolveTypeWitness(const NormalProtocolConformance *conformance,
49-
AssociatedTypeDecl *assocType) = 0;
50-
51-
/// Resolve the witness for the given non-type requirement within
52-
/// the given protocol conformance.
53-
virtual void resolveWitness(const NormalProtocolConformance *conformance,
54-
ValueDecl *requirement) = 0;
55-
5646
/// Resolve any implicitly-declared constructors within the given nominal.
5747
virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) = 0;
5848

include/swift/AST/ProtocolConformance.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ typedef llvm::DenseMap<ValueDecl *, Witness> WitnessMap;
5252

5353
/// Map from associated type requirements to the corresponding type and
5454
/// the type declaration that was used to satisfy the requirement.
55-
typedef llvm::DenseMap<AssociatedTypeDecl *, std::pair<Type, TypeDecl*>>
55+
typedef llvm::DenseMap<AssociatedTypeDecl *, TypeWitnessAndDecl>
5656
TypeWitnessMap;
5757

5858
/// Describes the kind of protocol conformance structure used to encode
@@ -157,7 +157,7 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
157157

158158
/// Retrieve the type witness and type decl (if one exists)
159159
/// for the given associated type.
160-
std::pair<Type, TypeDecl *>
160+
TypeWitnessAndDecl
161161
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
162162
SubstOptions options=None) const;
163163

@@ -182,7 +182,7 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
182182
continue;
183183

184184
const auto &TWInfo = getTypeWitnessAndDecl(assocTypeReq);
185-
if (f(assocTypeReq, TWInfo.first, TWInfo.second))
185+
if (f(assocTypeReq, TWInfo.getWitnessType(), TWInfo.getWitnessDecl()))
186186
return true;
187187
}
188188

@@ -404,6 +404,9 @@ class RootProtocolConformance : public ProtocolConformance {
404404
class NormalProtocolConformance : public RootProtocolConformance,
405405
public llvm::FoldingSetNode
406406
{
407+
friend class ValueWitnessRequest;
408+
friend class TypeWitnessRequest;
409+
407410
/// The protocol being conformed to and its current state.
408411
llvm::PointerIntPair<ProtocolDecl *, 2, ProtocolConformanceState>
409412
ProtocolAndState;
@@ -588,10 +591,13 @@ class NormalProtocolConformance : public RootProtocolConformance,
588591

589592
/// Retrieve the type witness and type decl (if one exists)
590593
/// for the given associated type.
591-
std::pair<Type, TypeDecl *>
594+
TypeWitnessAndDecl
592595
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
593596
SubstOptions options=None) const;
594597

598+
TypeWitnessAndDecl
599+
getTypeWitnessUncached(AssociatedTypeDecl *requirement) const;
600+
595601
/// Determine whether the protocol conformance has a type witness for the
596602
/// given associated type.
597603
bool hasTypeWitness(AssociatedTypeDecl *assocType) const;
@@ -610,6 +616,8 @@ class NormalProtocolConformance : public RootProtocolConformance,
610616
/// Retrieve the value witness corresponding to the given requirement.
611617
Witness getWitness(ValueDecl *requirement) const;
612618

619+
Witness getWitnessUncached(ValueDecl *requirement) const;
620+
613621
/// Determine whether the protocol conformance has a witness for the given
614622
/// requirement.
615623
bool hasWitness(ValueDecl *requirement) const {
@@ -641,7 +649,7 @@ class NormalProtocolConformance : public RootProtocolConformance,
641649
/// Determine whether the witness for the given type requirement
642650
/// is the default definition.
643651
bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
644-
TypeDecl *witnessDecl = getTypeWitnessAndDecl(requirement).second;
652+
TypeDecl *witnessDecl = getTypeWitnessAndDecl(requirement).getWitnessDecl();
645653
if (witnessDecl)
646654
return witnessDecl->isImplicit();
647655
// Conservatively assume it does not.
@@ -713,7 +721,7 @@ class SelfProtocolConformance : public RootProtocolConformance {
713721
llvm_unreachable("self-conformances never have associated types");
714722
}
715723

716-
std::pair<Type, TypeDecl *>
724+
TypeWitnessAndDecl
717725
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
718726
SubstOptions options=None) const {
719727
llvm_unreachable("self-conformances never have associated types");
@@ -859,7 +867,7 @@ class SpecializedProtocolConformance : public ProtocolConformance,
859867

860868
/// Retrieve the type witness and type decl (if one exists)
861869
/// for the given associated type.
862-
std::pair<Type, TypeDecl *>
870+
TypeWitnessAndDecl
863871
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
864872
SubstOptions options=None) const;
865873

@@ -971,7 +979,7 @@ class InheritedProtocolConformance : public ProtocolConformance,
971979

972980
/// Retrieve the type witness and type decl (if one exists)
973981
/// for the given associated type.
974-
std::pair<Type, TypeDecl *>
982+
TypeWitnessAndDecl
975983
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
976984
SubstOptions options=None) const {
977985
return InheritedConformance->getTypeWitnessAndDecl(assocType, options);
@@ -1015,6 +1023,8 @@ inline bool ProtocolConformance::hasWitness(ValueDecl *requirement) const {
10151023
return getRootConformance()->hasWitness(requirement);
10161024
}
10171025

1026+
void simple_display(llvm::raw_ostream &out, const ProtocolConformance *conf);
1027+
10181028
} // end namespace swift
10191029

10201030
#endif // LLVM_SWIFT_AST_PROTOCOLCONFORMANCE_H

include/swift/AST/TypeCheckRequests.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class RequirementRepr;
4141
class SpecializeAttr;
4242
class TypeAliasDecl;
4343
struct TypeLoc;
44+
class Witness;
45+
struct TypeWitnessAndDecl;
4446
class ValueDecl;
4547
enum class OpaqueReadOwnership: uint8_t;
4648
class StorageImplInfo;
@@ -1668,6 +1670,51 @@ class InheritsSuperclassInitializersRequest
16681670
void cacheResult(bool value) const;
16691671
};
16701672

1673+
class TypeWitnessRequest
1674+
: public SimpleRequest<TypeWitnessRequest,
1675+
TypeWitnessAndDecl(NormalProtocolConformance *,
1676+
AssociatedTypeDecl *),
1677+
CacheKind::SeparatelyCached> {
1678+
public:
1679+
using SimpleRequest::SimpleRequest;
1680+
1681+
private:
1682+
friend SimpleRequest;
1683+
1684+
// Evaluation.
1685+
llvm::Expected<TypeWitnessAndDecl>
1686+
evaluate(Evaluator &evaluator, NormalProtocolConformance *conformance,
1687+
AssociatedTypeDecl *ATD) const;
1688+
1689+
public:
1690+
// Separate caching.
1691+
bool isCached() const { return true; }
1692+
Optional<TypeWitnessAndDecl> getCachedResult() const;
1693+
void cacheResult(TypeWitnessAndDecl value) const;
1694+
};
1695+
1696+
class ValueWitnessRequest
1697+
: public SimpleRequest<ValueWitnessRequest,
1698+
Witness(NormalProtocolConformance *, ValueDecl *),
1699+
CacheKind::SeparatelyCached> {
1700+
public:
1701+
using SimpleRequest::SimpleRequest;
1702+
1703+
private:
1704+
friend SimpleRequest;
1705+
1706+
// Evaluation.
1707+
llvm::Expected<Witness> evaluate(Evaluator &evaluator,
1708+
NormalProtocolConformance *conformance,
1709+
ValueDecl *VD) const;
1710+
1711+
public:
1712+
// Separate caching.
1713+
bool isCached() const { return true; }
1714+
Optional<Witness> getCachedResult() const;
1715+
void cacheResult(Witness value) const;
1716+
};
1717+
16711718
// Allow AnyValue to compare two Type values, even though Type doesn't
16721719
// support ==.
16731720
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ SWIFT_REQUEST(TypeChecker, InheritedTypeRequest,
6868
Type(llvm::PointerUnion<TypeDecl *, ExtensionDecl *>, unsigned,
6969
TypeResolutionStage),
7070
SeparatelyCached, HasNearestLocation)
71+
SWIFT_REQUEST(TypeChecker, InheritsSuperclassInitializersRequest,
72+
bool(ClassDecl *), SeparatelyCached, NoLocationInfo)
7173
SWIFT_REQUEST(TypeChecker, InitKindRequest,
7274
CtorInitializerKind(ConstructorDecl *), Cached, NoLocationInfo)
7375
SWIFT_REQUEST(TypeChecker, InterfaceTypeRequest,
@@ -180,5 +182,10 @@ SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,
180182
bool(NominalTypeDecl *), Cached, NoLocationInfo)
181183
SWIFT_REQUEST(TypeChecker, SynthesizeDefaultInitRequest,
182184
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
183-
SWIFT_REQUEST(TypeChecker, InheritsSuperclassInitializersRequest,
184-
bool(ClassDecl *), SeparatelyCached, NoLocationInfo)
185+
SWIFT_REQUEST(TypeChecker, TypeWitnessRequest,
186+
TypeWitnessAndDecl(NormalProtocolConformance *,
187+
AssociatedTypeDecl *),
188+
SeparatelyCached, NoLocationInfo)
189+
SWIFT_REQUEST(TypeChecker, ValueWitnessRequest,
190+
Witness(NormalProtocolConformance *, ValueDecl *),
191+
SeparatelyCached, NoLocationInfo)

include/swift/AST/Witness.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,40 @@ class Witness {
188188
void dump(llvm::raw_ostream &out) const;
189189
};
190190

191+
struct TypeWitnessAndDecl {
192+
Type witnessType;
193+
TypeDecl *witnessDecl = nullptr;
194+
195+
TypeWitnessAndDecl() = default;
196+
TypeWitnessAndDecl(Type ty, TypeDecl *decl)
197+
: witnessType(ty), witnessDecl(decl) {}
198+
199+
public:
200+
Type getWitnessType() const {
201+
return witnessType;
202+
}
203+
204+
TypeDecl *getWitnessDecl() const {
205+
return witnessDecl;
206+
}
207+
208+
friend llvm::hash_code hash_value(const TypeWitnessAndDecl &owner) {
209+
return llvm::hash_combine(owner.witnessType,
210+
owner.witnessDecl);
211+
}
212+
213+
friend bool operator==(const TypeWitnessAndDecl &lhs,
214+
const TypeWitnessAndDecl &rhs) {
215+
return lhs.witnessType->isEqual(rhs.witnessType) &&
216+
lhs.witnessDecl == rhs.witnessDecl;
217+
}
218+
219+
friend bool operator!=(const TypeWitnessAndDecl &lhs,
220+
const TypeWitnessAndDecl &rhs) {
221+
return !(lhs == rhs);
222+
}
223+
};
224+
191225
} // end namespace swift
192226

193227
#endif // SWIFT_AST_WITNESS_H

lib/AST/ASTVerifier.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2645,7 +2645,8 @@ class Verifier : public ASTWalker {
26452645

26462646
// Make sure that the replacement type only uses archetypes allowed
26472647
// in the context where the normal conformance exists.
2648-
auto replacementType = normal->getTypeWitness(assocType);
2648+
auto replacementType =
2649+
normal->getTypeWitnessUncached(assocType).getWitnessType();
26492650
Verifier(M, normal->getDeclContext())
26502651
.verifyChecked(replacementType);
26512652
continue;
@@ -2677,7 +2678,7 @@ class Verifier : public ASTWalker {
26772678
}
26782679

26792680
// Check the witness substitutions.
2680-
const auto &witness = normal->getWitness(req);
2681+
const auto &witness = normal->getWitnessUncached(req);
26812682

26822683
if (auto *genericEnv = witness.getSyntheticEnvironment())
26832684
Generics.push_back(genericEnv->getGenericSignature());

0 commit comments

Comments
 (0)