@@ -2186,7 +2186,119 @@ IgnoreDefaultExprTypeMismatch::create(ConstraintSystem &cs, Type argType,
2186
2186
2187
2187
bool AddExplicitExistentialCoercion::diagnose (const Solution &solution,
2188
2188
bool asNote) const {
2189
- return false ;
2189
+ MissingExplicitExistentialCoercion failure (solution, ErasedResultType,
2190
+ getLocator ());
2191
+ return failure.diagnose (asNote);
2192
+ }
2193
+
2194
+ bool AddExplicitExistentialCoercion::isRequired (
2195
+ ConstraintSystem &cs, Type resultTy,
2196
+ SmallVectorImpl<std::pair<TypeVariableType *, OpenedArchetypeType *>>
2197
+ &openedExistentials,
2198
+ ConstraintLocatorBuilder locator) {
2199
+ using ExistentialList =
2200
+ SmallVectorImpl<std::pair<TypeVariableType *, OpenedArchetypeType *>> &;
2201
+
2202
+ struct CoercionChecker : public TypeWalker {
2203
+ bool RequiresCoercion = false ;
2204
+
2205
+ ConstraintSystem &cs;
2206
+ ExistentialList OpenedExistentials;
2207
+
2208
+ CoercionChecker (ConstraintSystem &cs, ExistentialList openedExistentials)
2209
+ : cs(cs), OpenedExistentials(openedExistentials) {}
2210
+
2211
+ Action walkToTypePre (Type componentTy) override {
2212
+ // In cases where result references a member type, we need to check
2213
+ // whether such type would is resolved to concrete or not.
2214
+ if (auto *member = componentTy->getAs <DependentMemberType>()) {
2215
+ Type memberBaseTy = member->getBase ();
2216
+
2217
+ // Find the base of this member chain.
2218
+ while (true ) {
2219
+ if (auto *memberTy = memberBaseTy->getAs <DependentMemberType>()) {
2220
+ memberBaseTy = memberTy->getBase ();
2221
+ } else {
2222
+ break ;
2223
+ }
2224
+ }
2225
+
2226
+ auto typeVar = memberBaseTy->getAs <TypeVariableType>();
2227
+ if (!typeVar)
2228
+ return Action::SkipChildren;
2229
+
2230
+ // If the base is an opened existential type, let's see whether
2231
+ // erase would produce an existential in this case and if so,
2232
+ // we need to check whether any requirements are going to be lost
2233
+ // in process.
2234
+
2235
+ auto opened =
2236
+ llvm::find_if (OpenedExistentials, [&typeVar](const auto &entry) {
2237
+ return typeVar == entry.first ;
2238
+ });
2239
+
2240
+ if (opened == OpenedExistentials.end ())
2241
+ return Action::SkipChildren;
2242
+
2243
+ auto erasedMemberTy = typeEraseOpenedExistentialReference (
2244
+ Type (member), opened->second ->getExistentialType (), opened->first ,
2245
+ TypePosition::Covariant);
2246
+
2247
+ // If result is an existential type and the base has `where` clauses
2248
+ // associated with its associated types, the call needs a coercion.
2249
+ if (erasedMemberTy->isExistentialType () &&
2250
+ hasConstrainedAssociatedTypes (opened->second )) {
2251
+ RequiresCoercion = true ;
2252
+ return Action::Stop;
2253
+ }
2254
+
2255
+ return Action::SkipChildren;
2256
+ }
2257
+
2258
+ // The case where there is a direct access to opened existential type
2259
+ // e.g. `$T` or `[$T]`.
2260
+ if (auto *typeVar = componentTy->getAs <TypeVariableType>()) {
2261
+ auto opened =
2262
+ llvm::find_if (OpenedExistentials, [&typeVar](const auto &entry) {
2263
+ return typeVar == entry.first ;
2264
+ });
2265
+
2266
+ if (opened != OpenedExistentials.end ()) {
2267
+ RequiresCoercion |= hasConstrainedAssociatedTypes (opened->second );
2268
+ return RequiresCoercion ? Action::Stop : Action::SkipChildren;
2269
+ }
2270
+ }
2271
+
2272
+ return Action::Continue;
2273
+ }
2274
+
2275
+ private:
2276
+ bool hasConstrainedAssociatedTypes (ArchetypeType *archetypeTy) {
2277
+ assert (archetypeTy);
2278
+ for (auto *protocol : archetypeTy->getConformsTo ()) {
2279
+ if (llvm::any_of (protocol->getAssociatedTypeMembers (),
2280
+ [](const auto *assocTypeDecl) {
2281
+ return bool (assocTypeDecl->getTrailingWhereClause ());
2282
+ }))
2283
+ return true ;
2284
+ }
2285
+ return false ;
2286
+ }
2287
+ };
2288
+
2289
+ // First, let's check whether coercion is already there.
2290
+ if (auto *anchor = getAsExpr (locator.getAnchor ())) {
2291
+ auto *parent = cs.getParentExpr (anchor);
2292
+ // Support both `as` and `as!` coercions.
2293
+ if (parent &&
2294
+ (isa<CoerceExpr>(parent) || isa<ForcedCheckedCastExpr>(parent)))
2295
+ return false ;
2296
+ }
2297
+
2298
+ CoercionChecker check (cs, openedExistentials);
2299
+ resultTy.walk (check);
2300
+
2301
+ return check.RequiresCoercion ;
2190
2302
}
2191
2303
2192
2304
AddExplicitExistentialCoercion *
0 commit comments