diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h index 961d87d87bcd7..c46d7ffd18235 100644 --- a/include/swift/AST/SubstitutionMap.h +++ b/include/swift/AST/SubstitutionMap.h @@ -340,7 +340,6 @@ struct OuterSubstitutions { SubstitutionMap subs; unsigned depth; - bool isUnsubstitutedTypeParameter(Type type) const; Type operator()(SubstitutableType *type) const; ProtocolConformanceRef operator()(CanType dependentType, Type conformingReplacementType, diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index 915c19f5ea34e..4cda36c2512e2 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -317,9 +317,13 @@ GenericEnvironment::maybeApplyOuterContextSubstitutions(Type type) const { case Kind::OpenedExistential: case Kind::OpenedElement: case Kind::Opaque: { - OuterSubstitutions replacer{ - getOuterSubstitutions(), getGenericSignature()->getMaxDepth()}; - return type.subst(replacer, replacer); + if (auto subs = getOuterSubstitutions()) { + OuterSubstitutions replacer{subs, + getGenericSignature()->getMaxDepth()}; + return type.subst(replacer, replacer); + } + + return type; } } } diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index eb2410760426a..dca03e2d6efa7 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -669,21 +669,8 @@ SubstitutionMap SubstitutionMap::mapIntoTypeExpansionContext( SubstFlags::PreservePackExpansionLevel); } -bool OuterSubstitutions::isUnsubstitutedTypeParameter(Type type) const { - if (!type->isTypeParameter()) - return false; - - if (auto depMemTy = type->getAs()) - return isUnsubstitutedTypeParameter(depMemTy->getBase()); - - if (auto genericParam = type->getAs()) - return genericParam->getDepth() >= depth; - - return false; -} - Type OuterSubstitutions::operator()(SubstitutableType *type) const { - if (isUnsubstitutedTypeParameter(type)) + if (cast(type)->getDepth() >= depth) return Type(type); return QuerySubstitutionMap{subs}(type); @@ -693,9 +680,23 @@ ProtocolConformanceRef OuterSubstitutions::operator()( CanType dependentType, Type conformingReplacementType, ProtocolDecl *conformedProtocol) const { - if (isUnsubstitutedTypeParameter(dependentType)) - return ProtocolConformanceRef::forAbstract( + auto sig = subs.getGenericSignature(); + if (!sig->isValidTypeParameter(dependentType) || + !sig->requiresProtocol(dependentType, conformedProtocol)) { + // FIXME: We need the isValidTypeParameter() check instead of just looking + // at the root generic parameter because in the case of an existential + // environment, the reduced type of a member type of Self might be an outer + // type parameter that is not formed from the outer generic signature's + // conformance requirements. Ideally, we'd either add these supplementary + // conformance requirements to the generalization signature, or we would + // store the supplementary conformances directly in the generic environment + // somehow. + // + // Once we check for that and handle it properly, the lookupConformance() + // can become a forAbstract(). + return swift::lookupConformance( conformingReplacementType, conformedProtocol); + } return LookUpConformanceInSubstitutionMap(subs)( dependentType, conformingReplacementType, conformedProtocol); diff --git a/lib/Sema/OpenedExistentials.cpp b/lib/Sema/OpenedExistentials.cpp index 21c8bff0b158c..00d978bc6b88e 100644 --- a/lib/Sema/OpenedExistentials.cpp +++ b/lib/Sema/OpenedExistentials.cpp @@ -823,10 +823,11 @@ Type swift::typeEraseOpenedExistentialReference( auto applyOuterSubstitutions = [&](Type t) -> Type { if (t->hasTypeParameter()) { - auto outerSubs = existentialSig.Generalization; - unsigned depth = existentialSig.OpenedSig->getMaxDepth(); - OuterSubstitutions replacer{outerSubs, depth}; - return t.subst(replacer, replacer); + if (auto outerSubs = existentialSig.Generalization) { + unsigned depth = existentialSig.OpenedSig->getMaxDepth(); + OuterSubstitutions replacer{outerSubs, depth}; + return t.subst(replacer, replacer); + } } return t; diff --git a/test/SILGen/existential_erasure_length_2.swift b/test/SILGen/existential_erasure_length_2.swift new file mode 100644 index 0000000000000..9c1e981caf1f0 --- /dev/null +++ b/test/SILGen/existential_erasure_length_2.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-emit-silgen %s + +protocol N { + associatedtype A: N +} + +protocol P { + associatedtype A: N + associatedtype B + + func f0(_: A) -> B + func f1(_: A.A) -> B + func f2(_: A.A.A) -> B +} + +struct G: N { + typealias A = G> +} + +func call(x: any P>) -> (Any, Any, Any) { + let y0 = x.f0(G()) + let y1 = x.f1(G>()) + let y2 = x.f2(G>>()) + return (y0, y1, y2) +}