@@ -2186,7 +2186,119 @@ IgnoreDefaultExprTypeMismatch::create(ConstraintSystem &cs, Type argType,
21862186
21872187bool AddExplicitExistentialCoercion::diagnose (const Solution &solution,
21882188 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 ;
21902302}
21912303
21922304AddExplicitExistentialCoercion *
0 commit comments