@@ -120,17 +120,33 @@ isUnviableDefaultType(Type defaultType,
120
120
121
121
void ConstraintSystem::PotentialBindings::inferDefaultTypes (
122
122
ConstraintSystem &cs, llvm::SmallPtrSetImpl<CanType> &existingTypes) {
123
+ auto isDirectRequirement = [&](Constraint *constraint) -> bool {
124
+ if (auto *typeVar = constraint->getFirstType ()->getAs <TypeVariableType>()) {
125
+ auto *repr = cs.getRepresentative (typeVar);
126
+ return repr == TypeVar;
127
+ }
128
+
129
+ return false ;
130
+ };
131
+
123
132
// If we have any literal constraints, check whether there is already a
124
133
// binding that provides a type that conforms to that literal protocol. In
125
134
// such cases, don't add the default binding suggestion because the existing
126
135
// suggestion is better.
127
136
//
128
137
// Note that ordering is important when it comes to bindings, we'd like to
129
- // add any "direct" default types first to attempt them before transitive ones.
130
- llvm::SmallMapVector<ProtocolDecl *, bool , 4 > literalProtocols;
138
+ // add any "direct" default types first to attempt them before transitive
139
+ // ones.
140
+ //
141
+ // Key is a literal protocol requirement, Value indicates whether (first)
142
+ // given protocol is a direct requirement, and (second) whether it has been
143
+ // covered by an existing binding.
144
+ llvm::SmallMapVector<ProtocolDecl *, std::pair<bool , bool >, 4 >
145
+ literalProtocols;
131
146
for (auto *constraint : Protocols) {
132
147
if (constraint->getKind () == ConstraintKind::LiteralConformsTo)
133
- literalProtocols.insert ({constraint->getProtocol (), false });
148
+ literalProtocols.insert ({constraint->getProtocol (),
149
+ {isDirectRequirement (constraint), false }});
134
150
}
135
151
136
152
for (auto &binding : Bindings) {
@@ -153,7 +169,8 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
153
169
bool requiresUnwrap = false ;
154
170
for (auto &entry : literalProtocols) {
155
171
auto *protocol = entry.first ;
156
- bool &isCovered = entry.second ;
172
+ bool isDirectRequirement = entry.second .first ;
173
+ bool &isCovered = entry.second .second ;
157
174
158
175
if (isCovered)
159
176
continue ;
@@ -169,6 +186,12 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
169
186
break ;
170
187
}
171
188
189
+ // If this literal protocol is not a direct requirement it
190
+ // would be possible to change optionality while inferring
191
+ // bindings for a supertype, so this hack doesn't apply.
192
+ if (!isDirectRequirement)
193
+ break ;
194
+
172
195
// If we're allowed to bind to subtypes, look through optionals.
173
196
// FIXME: This is really crappy special case of computing a reasonable
174
197
// result based on the given constraints.
@@ -193,7 +216,7 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
193
216
// binding it can't provide a default type.
194
217
auto isUnviableForDefaulting = [&literalProtocols](ProtocolDecl *protocol) {
195
218
auto literal = literalProtocols.find (protocol);
196
- return literal == literalProtocols.end () || literal->second ;
219
+ return literal == literalProtocols.end () || literal->second . second ;
197
220
};
198
221
199
222
for (auto *constraint : Protocols) {
@@ -225,10 +248,8 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
225
248
// We need to figure out whether this is a direct conformance
226
249
// requirement or inferred transitive one to identify binding
227
250
// kind correctly.
228
- auto *conformingVar = cs.getRepresentative (
229
- constraint->getFirstType ()->castTo <TypeVariableType>());
230
251
addPotentialBinding ({defaultType,
231
- TypeVar == conformingVar
252
+ isDirectRequirement (constraint)
232
253
? AllowedBindingKind::Subtypes
233
254
: AllowedBindingKind::Supertypes,
234
255
constraint});
0 commit comments