Skip to content

Commit c9d2f52

Browse files
committed
Sema: introduce ProtocolInversesRequest
We need special handling for protocols whose requirement signature exists but is in a serialized state, as we cannot run the StructuralRequirementsRequest on such a protocol as there's no work to be done, effectively.
1 parent 6f95203 commit c9d2f52

File tree

7 files changed

+68
-40
lines changed

7 files changed

+68
-40
lines changed

docs/Generics/chapters/basic-operation.tex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,16 @@ \subsection*{The Rewrite Context}
636636
\item \texttt{getProtocolDependencies()} evaluates the \texttt{ProtocolDependenciesRequest}.
637637
\end{itemize}
638638

639+
\IndexSource{protocol inverses request}
640+
\apiref{ProtocolInversesRequest}{class}
641+
A request evaluator request which enumerates the inverse requirements written on the given protocol and its associated types.
642+
643+
\apiref{ProtocolDecl}{class}
644+
See also \SecRef{src:declarations}.
645+
\begin{itemize}
646+
\item \texttt{getInverseRequirements()} evaluates the \texttt{ProtocolInversesRequest}.
647+
\end{itemize}
648+
639649
\IndexSource{requirement machine}
640650
\apiref{rewriting::RequirementMachine}{class}
641651
A list of rewrite rules and a property map. See also \SecRef{src:symbols terms rules} and \SecRef{property map sourceref}. Entry points for initializing a requirement machine, called by the rewrite context and various requests:

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5578,6 +5578,7 @@ class ProtocolDecl final : public NominalTypeDecl {
55785578
friend class StructuralRequirementsRequest;
55795579
friend class TypeAliasRequirementsRequest;
55805580
friend class ProtocolDependenciesRequest;
5581+
friend class ProtocolInversesRequest;
55815582
friend class RequirementSignatureRequest;
55825583
friend class ProtocolRequiresClassRequest;
55835584
friend class ExistentialConformsToSelfRequest;

include/swift/AST/TypeCheckRequests.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,25 @@ class ProtocolDependenciesRequest :
619619
bool isCached() const { return true; }
620620
};
621621

622+
class ProtocolInversesRequest :
623+
public SimpleRequest<ProtocolInversesRequest,
624+
ArrayRef<InverseRequirement>(ProtocolDecl *),
625+
RequestFlags::Cached> {
626+
public:
627+
using SimpleRequest::SimpleRequest;
628+
629+
private:
630+
friend SimpleRequest;
631+
632+
// Evaluation.
633+
ArrayRef<InverseRequirement>
634+
evaluate(Evaluator &evaluator, ProtocolDecl *proto) const;
635+
636+
public:
637+
// Caching.
638+
bool isCached() const { return true; }
639+
};
640+
622641
/// Compute the requirements that describe a protocol.
623642
class RequirementSignatureRequest :
624643
public SimpleRequest<RequirementSignatureRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ SWIFT_REQUEST(TypeChecker, TypeAliasRequirementsRequest,
309309
SWIFT_REQUEST(TypeChecker, ProtocolDependenciesRequest,
310310
ArrayRef<ProtocolDecl *>(ProtocolDecl *), Cached,
311311
HasNearestLocation)
312+
SWIFT_REQUEST(TypeChecker, ProtocolInversesRequest,
313+
ArrayRef<InverseRequirement>(ProtocolDecl *), Cached,
314+
HasNearestLocation)
312315
SWIFT_REQUEST(TypeChecker, RequirementSignatureRequest,
313316
RequirementSignature(ProtocolDecl *), SeparatelyCached,
314317
NoLocationInfo)

lib/AST/Decl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7478,8 +7478,8 @@ ProtocolDecl::getStructuralRequirements() const {
74787478
ArrayRef<InverseRequirement>
74797479
ProtocolDecl::getInverseRequirements() const {
74807480
return evaluateOrDefault(
7481-
getASTContext().evaluator,
7482-
StructuralRequirementsRequest{const_cast<ProtocolDecl *>(this)}, {}).second;
7481+
getASTContext().evaluator,
7482+
ProtocolInversesRequest{const_cast<ProtocolDecl *>(this)}, {});
74837483
}
74847484

74857485
ArrayRef<Requirement>

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,3 +1329,26 @@ ProtocolDependenciesRequest::evaluate(Evaluator &evaluator,
13291329

13301330
return ctx.AllocateCopy(result);
13311331
}
1332+
1333+
ArrayRef<InverseRequirement>
1334+
ProtocolInversesRequest::evaluate(Evaluator &evaluator,
1335+
ProtocolDecl *proto) const {
1336+
auto &ctx = proto->getASTContext();
1337+
1338+
// If we have a serialized requirement signature, deserialize it and
1339+
// query it for the inverses.
1340+
if (proto->hasLazyRequirementSignature()) {
1341+
SmallVector<Requirement, 2> _ignored;
1342+
SmallVector<InverseRequirement, 2> result;
1343+
auto reqSig = proto->getRequirementSignature();
1344+
reqSig.getRequirementsWithInverses(proto, _ignored, result);
1345+
return ctx.AllocateCopy(result);
1346+
}
1347+
1348+
// Otherwise, we must avoid building a RequirementSignature, as this query
1349+
// needs to be safe to ask while building the protocol's RequirementSignature.
1350+
//
1351+
// So, use a StructuralRequirementsRequest to get the inverses.
1352+
return evaluateOrDefault(ctx.evaluator,
1353+
StructuralRequirementsRequest{proto}, {}).second;
1354+
}

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -942,45 +942,17 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
942942

943943
auto *extendedNominal = ext->getExtendedNominal();
944944

945-
// Avoid building a generic signature if we have an unconstrained protocol
946-
// extension of a protocol that does not suppress conformance to ~Copyable
947-
// or ~Escapable. This avoids a request cycle when referencing a protocol
948-
// extension type alias via an unqualified name from a `where` clause on
949-
// the protocol.
945+
// Optimization: avoid building a generic signature if we have an
946+
// unconstrained protocol extension, as they have the same signature as the
947+
// protocol itself.
948+
//
949+
// Protocols who suppress conformance to ~Copyable or ~Escapable either on
950+
// Self or its associated types will infer default requirements in
951+
// ordinary extensions of that protocol, so the signature can differ there.
950952
if (auto *proto = dyn_cast<ProtocolDecl>(extendedNominal)) {
951-
if (extraReqs.empty() &&
952-
!ext->getTrailingWhereClause()) {
953-
// Check for inverse requirements on Self or any associated types.
954-
auto reqSig = proto->getRequirementSignature();
955-
SmallVector<Requirement, 2> _ignored;
956-
SmallVector<InverseRequirement, 2> inverses;
957-
reqSig.getRequirementsWithInverses(proto, _ignored, inverses);
958-
959-
if (inverses.empty())
960-
return extendedNominal->getGenericSignatureOfContext();
961-
962-
if (ctx.LangOpts.hasFeature(Feature::SuppressedAssociatedTypes) &&
963-
!ctx.LangOpts.hasFeature(
964-
Feature::SuppressedAssociatedTypesWithDefaults)) {
965-
// NOTE: remove this once SuppressedAssociatedTypes is deprecated.
966-
//
967-
// We don't infer defaults for the associated types in the legacy
968-
// version of the feature, only for Self. If there's no inverse on
969-
// Self, then we need to reuse the generic signature of the context,
970-
// or else we'll crash with some generic signature verifier error.
971-
//
972-
// We can assume the subject is Self if it's a GenericTypeParamType.
973-
bool hasInverseOnSelf = false;
974-
for (auto const &ir : inverses) {
975-
if (ir.subject->getAs<GenericTypeParamType>()) {
976-
hasInverseOnSelf = true;
977-
break;
978-
}
979-
}
980-
if (!hasInverseOnSelf) {
981-
return extendedNominal->getGenericSignatureOfContext();
982-
}
983-
}
953+
if (extraReqs.empty() && !ext->getTrailingWhereClause() &&
954+
proto->getInverseRequirements().empty()) {
955+
return extendedNominal->getGenericSignatureOfContext();
984956
}
985957
}
986958

0 commit comments

Comments
 (0)