mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
This commit is contained in:
@@ -636,6 +636,16 @@ See also \SecRef{src:declarations}.
|
||||
\item \texttt{getProtocolDependencies()} evaluates the \texttt{ProtocolDependenciesRequest}.
|
||||
\end{itemize}
|
||||
|
||||
\IndexSource{protocol inverses request}
|
||||
\apiref{ProtocolInversesRequest}{class}
|
||||
A request evaluator request which enumerates the inverse requirements written on the given protocol and its associated types.
|
||||
|
||||
\apiref{ProtocolDecl}{class}
|
||||
See also \SecRef{src:declarations}.
|
||||
\begin{itemize}
|
||||
\item \texttt{getInverseRequirements()} evaluates the \texttt{ProtocolInversesRequest}.
|
||||
\end{itemize}
|
||||
|
||||
\IndexSource{requirement machine}
|
||||
\apiref{rewriting::RequirementMachine}{class}
|
||||
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:
|
||||
|
||||
@@ -5578,6 +5578,7 @@ class ProtocolDecl final : public NominalTypeDecl {
|
||||
friend class StructuralRequirementsRequest;
|
||||
friend class TypeAliasRequirementsRequest;
|
||||
friend class ProtocolDependenciesRequest;
|
||||
friend class ProtocolInversesRequest;
|
||||
friend class RequirementSignatureRequest;
|
||||
friend class ProtocolRequiresClassRequest;
|
||||
friend class ExistentialConformsToSelfRequest;
|
||||
|
||||
@@ -619,6 +619,25 @@ public:
|
||||
bool isCached() const { return true; }
|
||||
};
|
||||
|
||||
class ProtocolInversesRequest :
|
||||
public SimpleRequest<ProtocolInversesRequest,
|
||||
ArrayRef<InverseRequirement>(ProtocolDecl *),
|
||||
RequestFlags::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
|
||||
private:
|
||||
friend SimpleRequest;
|
||||
|
||||
// Evaluation.
|
||||
ArrayRef<InverseRequirement>
|
||||
evaluate(Evaluator &evaluator, ProtocolDecl *proto) const;
|
||||
|
||||
public:
|
||||
// Caching.
|
||||
bool isCached() const { return true; }
|
||||
};
|
||||
|
||||
/// Compute the requirements that describe a protocol.
|
||||
class RequirementSignatureRequest :
|
||||
public SimpleRequest<RequirementSignatureRequest,
|
||||
|
||||
@@ -309,6 +309,9 @@ SWIFT_REQUEST(TypeChecker, TypeAliasRequirementsRequest,
|
||||
SWIFT_REQUEST(TypeChecker, ProtocolDependenciesRequest,
|
||||
ArrayRef<ProtocolDecl *>(ProtocolDecl *), Cached,
|
||||
HasNearestLocation)
|
||||
SWIFT_REQUEST(TypeChecker, ProtocolInversesRequest,
|
||||
ArrayRef<InverseRequirement>(ProtocolDecl *), Cached,
|
||||
HasNearestLocation)
|
||||
SWIFT_REQUEST(TypeChecker, RequirementSignatureRequest,
|
||||
RequirementSignature(ProtocolDecl *), SeparatelyCached,
|
||||
NoLocationInfo)
|
||||
|
||||
@@ -7478,8 +7478,8 @@ ProtocolDecl::getStructuralRequirements() const {
|
||||
ArrayRef<InverseRequirement>
|
||||
ProtocolDecl::getInverseRequirements() const {
|
||||
return evaluateOrDefault(
|
||||
getASTContext().evaluator,
|
||||
StructuralRequirementsRequest{const_cast<ProtocolDecl *>(this)}, {}).second;
|
||||
getASTContext().evaluator,
|
||||
ProtocolInversesRequest{const_cast<ProtocolDecl *>(this)}, {});
|
||||
}
|
||||
|
||||
ArrayRef<Requirement>
|
||||
|
||||
@@ -1329,3 +1329,26 @@ ProtocolDependenciesRequest::evaluate(Evaluator &evaluator,
|
||||
|
||||
return ctx.AllocateCopy(result);
|
||||
}
|
||||
|
||||
ArrayRef<InverseRequirement>
|
||||
ProtocolInversesRequest::evaluate(Evaluator &evaluator,
|
||||
ProtocolDecl *proto) const {
|
||||
auto &ctx = proto->getASTContext();
|
||||
|
||||
// If we have a serialized requirement signature, deserialize it and
|
||||
// query it for the inverses.
|
||||
if (proto->hasLazyRequirementSignature()) {
|
||||
SmallVector<Requirement, 2> _ignored;
|
||||
SmallVector<InverseRequirement, 2> result;
|
||||
auto reqSig = proto->getRequirementSignature();
|
||||
reqSig.getRequirementsWithInverses(proto, _ignored, result);
|
||||
return ctx.AllocateCopy(result);
|
||||
}
|
||||
|
||||
// Otherwise, we must avoid building a RequirementSignature, as this query
|
||||
// needs to be safe to ask while building the protocol's RequirementSignature.
|
||||
//
|
||||
// So, use a StructuralRequirementsRequest to get the inverses.
|
||||
return evaluateOrDefault(ctx.evaluator,
|
||||
StructuralRequirementsRequest{proto}, {}).second;
|
||||
}
|
||||
|
||||
@@ -942,45 +942,17 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
|
||||
|
||||
auto *extendedNominal = ext->getExtendedNominal();
|
||||
|
||||
// Avoid building a generic signature if we have an unconstrained protocol
|
||||
// extension of a protocol that does not suppress conformance to ~Copyable
|
||||
// or ~Escapable. This avoids a request cycle when referencing a protocol
|
||||
// extension type alias via an unqualified name from a `where` clause on
|
||||
// the protocol.
|
||||
// Optimization: avoid building a generic signature if we have an
|
||||
// unconstrained protocol extension, as they have the same signature as the
|
||||
// protocol itself.
|
||||
//
|
||||
// Protocols who suppress conformance to ~Copyable or ~Escapable either on
|
||||
// Self or its associated types will infer default requirements in
|
||||
// ordinary extensions of that protocol, so the signature can differ there.
|
||||
if (auto *proto = dyn_cast<ProtocolDecl>(extendedNominal)) {
|
||||
if (extraReqs.empty() &&
|
||||
!ext->getTrailingWhereClause()) {
|
||||
// Check for inverse requirements on Self or any associated types.
|
||||
auto reqSig = proto->getRequirementSignature();
|
||||
SmallVector<Requirement, 2> _ignored;
|
||||
SmallVector<InverseRequirement, 2> inverses;
|
||||
reqSig.getRequirementsWithInverses(proto, _ignored, inverses);
|
||||
|
||||
if (inverses.empty())
|
||||
return extendedNominal->getGenericSignatureOfContext();
|
||||
|
||||
if (ctx.LangOpts.hasFeature(Feature::SuppressedAssociatedTypes) &&
|
||||
!ctx.LangOpts.hasFeature(
|
||||
Feature::SuppressedAssociatedTypesWithDefaults)) {
|
||||
// NOTE: remove this once SuppressedAssociatedTypes is deprecated.
|
||||
//
|
||||
// We don't infer defaults for the associated types in the legacy
|
||||
// version of the feature, only for Self. If there's no inverse on
|
||||
// Self, then we need to reuse the generic signature of the context,
|
||||
// or else we'll crash with some generic signature verifier error.
|
||||
//
|
||||
// We can assume the subject is Self if it's a GenericTypeParamType.
|
||||
bool hasInverseOnSelf = false;
|
||||
for (auto const &ir : inverses) {
|
||||
if (ir.subject->getAs<GenericTypeParamType>()) {
|
||||
hasInverseOnSelf = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasInverseOnSelf) {
|
||||
return extendedNominal->getGenericSignatureOfContext();
|
||||
}
|
||||
}
|
||||
if (extraReqs.empty() && !ext->getTrailingWhereClause() &&
|
||||
proto->getInverseRequirements().empty()) {
|
||||
return extendedNominal->getGenericSignatureOfContext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user