Skip to content

Commit d09e084

Browse files
committed
Abstract FulfillmentMap a little bit better so that it can be
made to work on archetypes instead of interface types. NFC.
1 parent 49a7e5d commit d09e084

File tree

3 files changed

+124
-22
lines changed

3 files changed

+124
-22
lines changed

lib/IRGen/Fulfillment.cpp

Lines changed: 97 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,79 @@
2323
using namespace swift;
2424
using namespace irgen;
2525

26+
/// Is metadata for the given type kind a "leaf", or does it possibly
27+
/// store any other type metadata that we can statically extract?
28+
///
29+
/// It's okay to conservatively answer "no". It's more important for this
30+
/// to be quick than for it to be accurate; don't recurse.
31+
static bool isLeafTypeMetadata(CanType type) {
32+
switch (type->getKind()) {
33+
#define SUGARED_TYPE(ID, SUPER) \
34+
case TypeKind::ID:
35+
#define UNCHECKED_TYPE(ID, SUPER) \
36+
case TypeKind::ID:
37+
#define TYPE(ID, SUPER)
38+
#include "swift/AST/TypeNodes.def"
39+
llvm_unreachable("kind is invalid for a canonical type");
40+
41+
#define ARTIFICIAL_TYPE(ID, SUPER) \
42+
case TypeKind::ID:
43+
#define TYPE(ID, SUPER)
44+
#include "swift/AST/TypeNodes.def"
45+
case TypeKind::LValue:
46+
case TypeKind::InOut:
47+
case TypeKind::DynamicSelf:
48+
llvm_unreachable("these types do not have metadata");
49+
50+
// All the builtin types are leaves.
51+
#define BUILTIN_TYPE(ID, SUPER) \
52+
case TypeKind::ID:
53+
#define TYPE(ID, SUPER)
54+
#include "swift/AST/TypeNodes.def"
55+
case TypeKind::Module:
56+
return true;
57+
58+
// Type parameters are statically opaque.
59+
case TypeKind::Archetype:
60+
case TypeKind::GenericTypeParam:
61+
case TypeKind::DependentMember:
62+
return true;
63+
64+
// Only the empty tuple is a leaf.
65+
case TypeKind::Tuple:
66+
return cast<TupleType>(type)->getNumElements() == 0;
67+
68+
// Nominal types might have parents.
69+
case TypeKind::Class:
70+
case TypeKind::Enum:
71+
case TypeKind::Protocol:
72+
case TypeKind::Struct:
73+
return !cast<NominalType>(type)->getParent();
74+
75+
// Bound generic types have type arguments.
76+
case TypeKind::BoundGenericClass:
77+
case TypeKind::BoundGenericEnum:
78+
case TypeKind::BoundGenericStruct:
79+
return false;
80+
81+
// Functions have component types.
82+
case TypeKind::Function:
83+
case TypeKind::PolymorphicFunction:
84+
case TypeKind::GenericFunction: // included for future-proofing
85+
return false;
86+
87+
// Protocol compositions have component types.
88+
case TypeKind::ProtocolComposition:
89+
return false;
90+
91+
// Metatypes have instance types.
92+
case TypeKind::Metatype:
93+
case TypeKind::ExistentialMetatype:
94+
return false;
95+
}
96+
llvm_unreachable("bad type kind");
97+
}
98+
2699
/// Given that we have a source for metadata of the given type, check
27100
/// to see if it fulfills anything.
28101
///
@@ -31,11 +104,21 @@ using namespace irgen;
31104
bool FulfillmentMap::searchTypeMetadata(ModuleDecl &M, CanType type,
32105
IsExact_t isExact,
33106
unsigned source, MetadataPath &&path,
34-
const InterestingKeysCallback *keys) {
107+
const InterestingKeysCallback &keys) {
35108

36-
// Type parameters. Inexact metadata are useless here.
37-
if (isExact && type->isTypeParameter()) {
38-
return addFulfillment({type, nullptr}, source, std::move(path));
109+
// If this is an exact source, and it's an interesting type, add this
110+
// as a fulfillment.
111+
if (isExact && keys.isInterestingType(type)) {
112+
// If the type isn't a leaf type, also check it as an inexact match.
113+
bool hadFulfillment = false;
114+
if (!isLeafTypeMetadata(type)) {
115+
hadFulfillment |= searchTypeMetadata(M, type, IsInexact, source,
116+
MetadataPath(path), keys);
117+
}
118+
119+
// Add the fulfillment.
120+
hadFulfillment |= addFulfillment({type, nullptr}, source, std::move(path));
121+
return hadFulfillment;
39122
}
40123

41124
// Inexact metadata will be a problem if we ever try to use this
@@ -58,7 +141,7 @@ bool FulfillmentMap::searchTypeMetadata(ModuleDecl &M, CanType type,
58141
bool FulfillmentMap::searchParentTypeMetadata(ModuleDecl &M, CanType parent,
59142
unsigned source,
60143
MetadataPath &&path,
61-
const InterestingKeysCallback *keys) {
144+
const InterestingKeysCallback &keys) {
62145
// We might not have a parent type.
63146
if (!parent) return false;
64147

@@ -71,7 +154,7 @@ bool FulfillmentMap::searchNominalTypeMetadata(ModuleDecl &M,
71154
CanNominalType type,
72155
unsigned source,
73156
MetadataPath &&path,
74-
const InterestingKeysCallback *keys) {
157+
const InterestingKeysCallback &keys) {
75158
// Nominal types add no generic arguments themselves, but they
76159
// may have the arguments of their parents.
77160
return searchParentTypeMetadata(M, type.getParent(),
@@ -82,7 +165,7 @@ bool FulfillmentMap::searchBoundGenericTypeMetadata(ModuleDecl &M,
82165
CanBoundGenericType type,
83166
unsigned source,
84167
MetadataPath &&path,
85-
const InterestingKeysCallback *keys) {
168+
const InterestingKeysCallback &keys) {
86169
auto params = type->getDecl()->getGenericParams()->getAllArchetypes();
87170
auto substitutions = type->getSubstitutions(&M, nullptr);
88171
assert(params.size() >= substitutions.size() &&
@@ -94,11 +177,12 @@ bool FulfillmentMap::searchBoundGenericTypeMetadata(ModuleDecl &M,
94177
auto sub = substitutions[i];
95178
CanType arg = sub.getReplacement()->getCanonicalType();
96179

97-
if (keys && !keys->isInterestingType(arg))
180+
// Skip uninteresting type arguments.
181+
if (!keys.hasInterestingType(arg))
98182
continue;
99183

100184
// If the argument is a type parameter, fulfill conformances for it.
101-
if (arg->isTypeParameter()) {
185+
if (keys.isInterestingType(arg)) {
102186
hadFulfillment |=
103187
searchTypeArgConformances(M, arg, params[i], source, path, i, keys);
104188
}
@@ -122,18 +206,17 @@ bool FulfillmentMap::searchTypeArgConformances(ModuleDecl &M, CanType arg,
122206
unsigned source,
123207
const MetadataPath &path,
124208
unsigned argIndex,
125-
const InterestingKeysCallback *keys) {
209+
const InterestingKeysCallback &keys) {
126210
// Our sources are the protocol conformances that are recorded in
127211
// the generic metadata.
128212
auto storedConformances = param->getConformsTo();
129213
if (storedConformances.empty()) return false;
130214

131215
bool hadFulfillment = false;
132216

133-
// If we don't have an interesting-keys callback, add fulfillments
217+
// If we're not limiting the interesting conformances, just add fulfillments
134218
// for all of the stored conformances.
135-
if (!keys) {
136-
// Check each of the stored conformances.
219+
if (!keys.hasLimitedInterestingConformances(arg)) {
137220
for (size_t confIndex : indices(storedConformances)) {
138221
MetadataPath confPath = path;
139222
confPath.addNominalTypeArgumentConformanceComponent(argIndex,
@@ -148,7 +231,7 @@ bool FulfillmentMap::searchTypeArgConformances(ModuleDecl &M, CanType arg,
148231

149232
// Otherwise, our targets are the interesting conformances for the type
150233
// argument.
151-
auto requiredConformances = keys->getInterestingConformances(arg);
234+
auto requiredConformances = keys.getInterestingConformances(arg);
152235
if (requiredConformances.empty()) return false;
153236

154237
for (auto target : requiredConformances) {

lib/IRGen/Fulfillment.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,23 @@ class FulfillmentMap {
5151
enum IsExact_t : bool { IsInexact = false, IsExact = true };
5252

5353
struct InterestingKeysCallback {
54+
/// Is the given type something that we should add fulfillments for?
5455
virtual bool isInterestingType(CanType type) const = 0;
56+
57+
/// Is the given type expressed in terms of types that we should add
58+
/// fulfillments for?
59+
///
60+
/// It's okay to conservatively return true here.
61+
virtual bool hasInterestingType(CanType type) const = 0;
62+
63+
/// Are we only interested in a subset of the conformances for a
64+
/// given type?
65+
virtual bool hasLimitedInterestingConformances(CanType type) const = 0;
66+
67+
/// Return the limited interesting conformances for an interesting type.
5568
virtual GenericSignature::ConformsToArray
5669
getInterestingConformances(CanType type) const = 0;
70+
5771
virtual ~InterestingKeysCallback() = default;
5872
};
5973

@@ -72,7 +86,7 @@ class FulfillmentMap {
7286
/// \return true if any fulfillments were added by this search.
7387
bool searchTypeMetadata(ModuleDecl &M, CanType type, IsExact_t isExact,
7488
unsigned sourceIndex, MetadataPath &&path,
75-
const InterestingKeysCallback *interestingKeys = nullptr);
89+
const InterestingKeysCallback &interestingKeys);
7690

7791
/// Register a fulfillment for the given key.
7892
///
@@ -101,21 +115,21 @@ class FulfillmentMap {
101115
private:
102116
bool searchParentTypeMetadata(ModuleDecl &M, CanType parent,
103117
unsigned source, MetadataPath &&path,
104-
const InterestingKeysCallback *interestingKeys);
118+
const InterestingKeysCallback &keys);
105119

106120
bool searchNominalTypeMetadata(ModuleDecl &M, CanNominalType type,
107121
unsigned source, MetadataPath &&path,
108-
const InterestingKeysCallback *interestingKeys);
122+
const InterestingKeysCallback &keys);
109123

110124
bool searchBoundGenericTypeMetadata(ModuleDecl &M, CanBoundGenericType type,
111125
unsigned source, MetadataPath &&path,
112-
const InterestingKeysCallback *interestingKeys);
126+
const InterestingKeysCallback &keys);
113127

114128
bool searchTypeArgConformances(ModuleDecl &M, CanType arg,
115129
ArchetypeType *param,
116130
unsigned source, const MetadataPath &path,
117131
unsigned argIndex,
118-
const InterestingKeysCallback *interestingKeys);
132+
const InterestingKeysCallback &keys);
119133
};
120134

121135
}

lib/IRGen/GenProto.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,16 +2288,21 @@ namespace {
22882288
Callback(PolymorphicConvention &self) : Self(self) {}
22892289

22902290
bool isInterestingType(CanType type) const override {
2291-
return FulfillmentMap::isInterestingTypeForFulfillments(type);
2291+
return type->isTypeParameter();
2292+
}
2293+
bool hasInterestingType(CanType type) const override {
2294+
return type->hasTypeParameter();
2295+
}
2296+
bool hasLimitedInterestingConformances(CanType type) const override {
2297+
return true;
22922298
}
2293-
22942299
GenericSignature::ConformsToArray
22952300
getInterestingConformances(CanType type) const override {
22962301
return Self.getConformsTo(type);
22972302
}
22982303
} callbacks(*this);
22992304
return Fulfillments.searchTypeMetadata(M, type, isExact, sourceIndex,
2300-
std::move(path), &callbacks);
2305+
std::move(path), callbacks);
23012306
}
23022307

23032308
/// Testify to generic parameters in the Self type.

0 commit comments

Comments
 (0)