mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #39629 from slavapestov/rqm-protocol-signatures
RequirementMachine: Wire up protocol requirement signature minimization
This commit is contained in:
@@ -481,6 +481,11 @@ namespace swift {
|
|||||||
/// algorithm.
|
/// algorithm.
|
||||||
unsigned RequirementMachineDepthLimit = 10;
|
unsigned RequirementMachineDepthLimit = 10;
|
||||||
|
|
||||||
|
/// Enable the new experimental protocol requirement signature minimization
|
||||||
|
/// algorithm.
|
||||||
|
RequirementMachineMode RequirementMachineProtocolSignatures =
|
||||||
|
RequirementMachineMode::Disabled;
|
||||||
|
|
||||||
/// Sets the target we are building for and updates platform conditions
|
/// Sets the target we are building for and updates platform conditions
|
||||||
/// to match.
|
/// to match.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -616,6 +616,10 @@ def requirement_machine_EQ : Joined<["-"], "requirement-machine=">,
|
|||||||
Flags<[FrontendOption, ModuleInterfaceOption]>,
|
Flags<[FrontendOption, ModuleInterfaceOption]>,
|
||||||
HelpText<"Control usage of experimental generics implementation: 'on', 'off', or 'verify'">;
|
HelpText<"Control usage of experimental generics implementation: 'on', 'off', or 'verify'">;
|
||||||
|
|
||||||
|
def requirement_machine_protocol_signatures_EQ : Joined<["-"], "requirement-machine-protocol-signatures=">,
|
||||||
|
Flags<[FrontendOption]>,
|
||||||
|
HelpText<"Control usage of experimental protocol requirement signature minimization: 'on', 'off', or 'verify'">;
|
||||||
|
|
||||||
// Diagnostic control options
|
// Diagnostic control options
|
||||||
def suppress_warnings : Flag<["-"], "suppress-warnings">,
|
def suppress_warnings : Flag<["-"], "suppress-warnings">,
|
||||||
Flags<[FrontendOption]>,
|
Flags<[FrontendOption]>,
|
||||||
|
|||||||
@@ -1483,11 +1483,7 @@ int Requirement::compare(const Requirement &other) const {
|
|||||||
// We should only have multiple conformance requirements.
|
// We should only have multiple conformance requirements.
|
||||||
assert(getKind() == RequirementKind::Conformance);
|
assert(getKind() == RequirementKind::Conformance);
|
||||||
|
|
||||||
int compareProtos =
|
return TypeDecl::compare(getProtocolDecl(), other.getProtocolDecl());
|
||||||
TypeDecl::compare(getProtocolDecl(), other.getProtocolDecl());
|
|
||||||
|
|
||||||
assert(compareProtos != 0 && "Duplicate conformance requirement");
|
|
||||||
return compareProtos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compare two associated types.
|
/// Compare two associated types.
|
||||||
|
|||||||
@@ -34,6 +34,26 @@
|
|||||||
// decompositions can be found for all "derived" conformance rules, producing
|
// decompositions can be found for all "derived" conformance rules, producing
|
||||||
// a minimal set of generating conformances.
|
// a minimal set of generating conformances.
|
||||||
//
|
//
|
||||||
|
// There are two small complications to handle implementation details of
|
||||||
|
// Swift generics:
|
||||||
|
//
|
||||||
|
// 1) Inherited witness tables must be derivable by following other protocol
|
||||||
|
// refinement requirements only, without looking at non-Self associated
|
||||||
|
// types. This is expressed by saying that the generating conformance
|
||||||
|
// equations for a protocol refinement can only be written in terms of
|
||||||
|
// other protocol refinements; conformance paths involving non-Self
|
||||||
|
// associated types are not considered.
|
||||||
|
//
|
||||||
|
// 2) The subject type of each conformance requirement must be derivable at
|
||||||
|
// runtime as well, so for each generating conformance, it must be
|
||||||
|
// possible to write down a conformance path for the parent type without
|
||||||
|
// using any generating conformance recursively in the parent path of
|
||||||
|
// itself.
|
||||||
|
//
|
||||||
|
// The generating conformances finds fewer conformance requirements to be
|
||||||
|
// redundant than homotopy reduction, which is why homotopy reduction only
|
||||||
|
// deletes non-protocol conformance requirements.
|
||||||
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "swift/AST/Decl.h"
|
#include "swift/AST/Decl.h"
|
||||||
@@ -283,23 +303,48 @@ void RewriteSystem::computeCandidateConformancePaths(
|
|||||||
llvm::dbgs() << "\n";
|
llvm::dbgs() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Two conformance rules in empty context (T.[P] => T) and (T'.[P] => T)
|
||||||
|
// are interchangeable, and contribute a trivial pair of conformance
|
||||||
|
// equations expressing that each one can be written in terms of the
|
||||||
|
// other:
|
||||||
|
//
|
||||||
|
// (T.[P] => T) := (T'.[P])
|
||||||
|
// (T'.[P] => T') := (T.[P])
|
||||||
|
for (unsigned candidateRuleID : notInContext) {
|
||||||
|
for (unsigned otherRuleID : notInContext) {
|
||||||
|
if (otherRuleID == candidateRuleID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SmallVector<unsigned, 2> path;
|
||||||
|
path.push_back(otherRuleID);
|
||||||
|
conformancePaths[candidateRuleID].push_back(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
|
// Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
|
||||||
// context, and a conformance rule (V.[P] => V) with a possibly non-empty
|
// context, and a conformance rule (V.[P] => V) with a non-empty left
|
||||||
// left context U and empty right context.
|
// context U.
|
||||||
|
//
|
||||||
|
// The 3-cell looks something like this:
|
||||||
|
//
|
||||||
|
// ... ⊗ (T.[P] => T) ⊗ ... ⊗ U.(V => V.[P]) ⊗ ...
|
||||||
|
// ^ ^
|
||||||
|
// | |
|
||||||
|
// + basepoint ========================= basepoint +
|
||||||
//
|
//
|
||||||
// We can decompose U into a product of conformance rules:
|
// We can decompose U into a product of conformance rules:
|
||||||
//
|
//
|
||||||
// (V1.[P1] => V1)...(Vn.[Pn] => Vn),
|
// (V1.[P1] => V1)...(Vn.[Pn] => Vn),
|
||||||
//
|
//
|
||||||
|
// Note that (V1)...(Vn) is canonically equivalent to U.
|
||||||
|
//
|
||||||
// Now, we can record a candidate decomposition of (T.[P] => T) as a
|
// Now, we can record a candidate decomposition of (T.[P] => T) as a
|
||||||
// product of conformance rules:
|
// product of conformance rules:
|
||||||
//
|
//
|
||||||
// (T.[P] => T) := (V1.[P1] => V1)...(Vn.[Pn] => Vn).(V.[P] => V)
|
// (T.[P] => T) := (V1.[P1] => V1)...(Vn.[Pn] => Vn).(V.[P] => V)
|
||||||
//
|
//
|
||||||
// Now if U is empty, this becomes the trivial candidate:
|
// Again, note that (V1)...(Vn).V is canonically equivalent to U.V,
|
||||||
//
|
// and therefore T.
|
||||||
// (T.[P] => T) := (V.[P] => V)
|
|
||||||
SmallVector<SmallVector<unsigned, 2>, 2> candidatePaths;
|
|
||||||
for (auto pair : inContext) {
|
for (auto pair : inContext) {
|
||||||
// We have a term U, and a rule V.[P] => V.
|
// We have a term U, and a rule V.[P] => V.
|
||||||
SmallVector<unsigned, 2> conformancePath;
|
SmallVector<unsigned, 2> conformancePath;
|
||||||
@@ -313,26 +358,10 @@ void RewriteSystem::computeCandidateConformancePaths(
|
|||||||
decomposeTermIntoConformanceRuleLeftHandSides(term, pair.second,
|
decomposeTermIntoConformanceRuleLeftHandSides(term, pair.second,
|
||||||
conformancePath);
|
conformancePath);
|
||||||
|
|
||||||
candidatePaths.push_back(conformancePath);
|
// This decomposition defines a conformance access path for each
|
||||||
}
|
// conformance rule we saw in empty context.
|
||||||
|
for (unsigned otherRuleID : notInContext)
|
||||||
for (unsigned candidateRuleID : notInContext) {
|
conformancePaths[otherRuleID].push_back(conformancePath);
|
||||||
// If multiple conformance rules appear in an empty context, each one
|
|
||||||
// can be replaced with any other conformance rule.
|
|
||||||
for (unsigned otherRuleID : notInContext) {
|
|
||||||
if (otherRuleID == candidateRuleID)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SmallVector<unsigned, 2> path;
|
|
||||||
path.push_back(otherRuleID);
|
|
||||||
conformancePaths[candidateRuleID].push_back(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If conformance rules appear in non-empty context, they define a
|
|
||||||
// conformance access path for each conformance rule in empty context.
|
|
||||||
for (const auto &path : candidatePaths) {
|
|
||||||
conformancePaths[candidateRuleID].push_back(path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,6 +521,48 @@ void RewriteSystem::verifyGeneratingConformanceEquations(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const ProtocolDecl *getParentConformanceForTerm(Term lhs) {
|
||||||
|
// The last element is a protocol symbol, because this is the left hand side
|
||||||
|
// of a conformance rule.
|
||||||
|
assert(lhs.back().getKind() == Symbol::Kind::Protocol);
|
||||||
|
|
||||||
|
// The second to last symbol is either an associated type, protocol or generic
|
||||||
|
// parameter symbol.
|
||||||
|
assert(lhs.size() >= 2);
|
||||||
|
|
||||||
|
auto parentSymbol = lhs[lhs.size() - 2];
|
||||||
|
|
||||||
|
switch (parentSymbol.getKind()) {
|
||||||
|
case Symbol::Kind::AssociatedType: {
|
||||||
|
// In a conformance rule of the form [P:T].[Q] => [P:T], the parent type is
|
||||||
|
// trivial.
|
||||||
|
if (lhs.size() == 2)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// If we have a rule of the form X.[P:Y].[Q] => X.[P:Y] wih non-empty X,
|
||||||
|
// then the parent type is X.[P].
|
||||||
|
const auto protos = parentSymbol.getProtocols();
|
||||||
|
assert(protos.size() == 1);
|
||||||
|
|
||||||
|
return protos[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
case Symbol::Kind::GenericParam:
|
||||||
|
case Symbol::Kind::Protocol:
|
||||||
|
// The parent type is trivial (either a generic parameter, or the protocol
|
||||||
|
// 'Self' type).
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
case Symbol::Kind::Name:
|
||||||
|
case Symbol::Kind::Layout:
|
||||||
|
case Symbol::Kind::Superclass:
|
||||||
|
case Symbol::Kind::ConcreteType:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm_unreachable("Bad symbol kind");
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes a minimal set of generating conformances, assuming that homotopy
|
/// Computes a minimal set of generating conformances, assuming that homotopy
|
||||||
/// reduction has already eliminated all redundant rewrite rules that are not
|
/// reduction has already eliminated all redundant rewrite rules that are not
|
||||||
/// conformance rules.
|
/// conformance rules.
|
||||||
@@ -536,49 +607,21 @@ void RewriteSystem::computeGeneratingConformances(
|
|||||||
|
|
||||||
auto lhs = rule.getLHS();
|
auto lhs = rule.getLHS();
|
||||||
|
|
||||||
auto parentSymbol = lhs[lhs.size() - 2];
|
// Record a parent path if the subject type itself requires a non-trivial
|
||||||
|
// conformance path to derive.
|
||||||
// The last element is a protocol symbol, because this is a conformance rule.
|
if (auto *parentProto = getParentConformanceForTerm(lhs)) {
|
||||||
// The second to last symbol is either an associated type, protocol or generic
|
|
||||||
// parameter symbol.
|
|
||||||
switch (parentSymbol.getKind()) {
|
|
||||||
case Symbol::Kind::AssociatedType: {
|
|
||||||
// If we have a rule of the form X.[P:Y].[Q] => X.[P:Y] wih non-empty X,
|
|
||||||
// then the parent type is X.[P].
|
|
||||||
if (lhs.size() == 2)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
MutableTerm mutTerm(lhs.begin(), lhs.end() - 2);
|
MutableTerm mutTerm(lhs.begin(), lhs.end() - 2);
|
||||||
assert(!mutTerm.empty());
|
assert(!mutTerm.empty());
|
||||||
|
|
||||||
const auto protos = parentSymbol.getProtocols();
|
|
||||||
assert(protos.size() == 1);
|
|
||||||
|
|
||||||
bool simplified = simplify(mutTerm);
|
bool simplified = simplify(mutTerm);
|
||||||
assert(!simplified || rule.isSimplified());
|
assert(!simplified || rule.isSimplified());
|
||||||
(void) simplified;
|
(void) simplified;
|
||||||
|
|
||||||
mutTerm.add(Symbol::forProtocol(protos[0], Context));
|
mutTerm.add(Symbol::forProtocol(parentProto, Context));
|
||||||
|
|
||||||
// Get a conformance path for X.[P] and record it.
|
// Get a conformance path for X.[P] and record it.
|
||||||
decomposeTermIntoConformanceRuleLeftHandSides(mutTerm, parentPaths[ruleID]);
|
decomposeTermIntoConformanceRuleLeftHandSides(mutTerm, parentPaths[ruleID]);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case Symbol::Kind::GenericParam:
|
|
||||||
case Symbol::Kind::Protocol:
|
|
||||||
// Don't record a parent path, since the parent type is trivial (either a
|
|
||||||
// generic parameter, or the protocol 'Self' type).
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case Symbol::Kind::Name:
|
|
||||||
case Symbol::Kind::Layout:
|
|
||||||
case Symbol::Kind::Superclass:
|
|
||||||
case Symbol::Kind::ConcreteType:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm_unreachable("Bad symbol kind");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
computeCandidateConformancePaths(conformancePaths);
|
computeCandidateConformancePaths(conformancePaths);
|
||||||
|
|||||||
@@ -751,7 +751,7 @@ void RewriteSystem::performHomotopyReduction(
|
|||||||
redundantConformances,
|
redundantConformances,
|
||||||
replacementPath);
|
replacementPath);
|
||||||
|
|
||||||
// If there no redundant rules remain in this pass, stop.
|
// If no redundant rules remain which can be eliminated by this pass, stop.
|
||||||
if (!optRuleID)
|
if (!optRuleID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ using namespace rewriting;
|
|||||||
void ProtocolGraph::visitRequirements(ArrayRef<Requirement> reqs) {
|
void ProtocolGraph::visitRequirements(ArrayRef<Requirement> reqs) {
|
||||||
for (auto req : reqs) {
|
for (auto req : reqs) {
|
||||||
if (req.getKind() == RequirementKind::Conformance) {
|
if (req.getKind() == RequirementKind::Conformance) {
|
||||||
addProtocol(req.getProtocolDecl());
|
addProtocol(req.getProtocolDecl(), /*initialComponent=*/false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ void ProtocolGraph::visitRequirements(ArrayRef<Requirement> reqs) {
|
|||||||
/// \p protos.
|
/// \p protos.
|
||||||
void ProtocolGraph::visitProtocols(ArrayRef<const ProtocolDecl *> protos) {
|
void ProtocolGraph::visitProtocols(ArrayRef<const ProtocolDecl *> protos) {
|
||||||
for (auto proto : protos) {
|
for (auto proto : protos) {
|
||||||
addProtocol(proto);
|
addProtocol(proto, /*initialComponent=*/true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,13 +50,15 @@ const ProtocolInfo &ProtocolGraph::getProtocolInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Record information about a protocol if we have no seen it yet.
|
/// Record information about a protocol if we have no seen it yet.
|
||||||
void ProtocolGraph::addProtocol(const ProtocolDecl *proto) {
|
void ProtocolGraph::addProtocol(const ProtocolDecl *proto,
|
||||||
|
bool initialComponent) {
|
||||||
if (Info.count(proto) > 0)
|
if (Info.count(proto) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Info[proto] = {proto->getInheritedProtocols(),
|
Info[proto] = {proto->getInheritedProtocols(),
|
||||||
proto->getAssociatedTypeMembers(),
|
proto->getAssociatedTypeMembers(),
|
||||||
proto->getRequirementSignature()};
|
proto->getProtocolDependencies(),
|
||||||
|
initialComponent};
|
||||||
Protocols.push_back(proto);
|
Protocols.push_back(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +68,9 @@ void ProtocolGraph::computeTransitiveClosure() {
|
|||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
while (i < Protocols.size()) {
|
while (i < Protocols.size()) {
|
||||||
auto *proto = Protocols[i++];
|
auto *proto = Protocols[i++];
|
||||||
visitRequirements(getProtocolInfo(proto).Requirements);
|
for (auto *proto : getProtocolInfo(proto).Dependencies) {
|
||||||
|
addProtocol(proto, /*initialComponent=*/false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ struct ProtocolInfo {
|
|||||||
/// ProtocolGraph::computeInheritedAssociatedTypes().
|
/// ProtocolGraph::computeInheritedAssociatedTypes().
|
||||||
llvm::TinyPtrVector<AssociatedTypeDecl *> InheritedAssociatedTypes;
|
llvm::TinyPtrVector<AssociatedTypeDecl *> InheritedAssociatedTypes;
|
||||||
|
|
||||||
/// The protocol's requirement signature.
|
/// The protocol's dependencies.
|
||||||
ArrayRef<Requirement> Requirements;
|
ArrayRef<ProtocolDecl *> Dependencies;
|
||||||
|
|
||||||
/// Used by ProtocolGraph::computeProtocolDepth() to detect circularity.
|
/// Used by ProtocolGraph::computeProtocolDepth() to detect circularity.
|
||||||
unsigned Mark : 1;
|
unsigned Mark : 1;
|
||||||
@@ -55,27 +55,34 @@ struct ProtocolInfo {
|
|||||||
|
|
||||||
/// Index of the protocol in the linear order. Computed by
|
/// Index of the protocol in the linear order. Computed by
|
||||||
/// ProtocolGraph::computeLinearOrder().
|
/// ProtocolGraph::computeLinearOrder().
|
||||||
unsigned Index : 32;
|
unsigned Index : 31;
|
||||||
|
|
||||||
|
/// When building a protocol requirement signature, the initial set of
|
||||||
|
/// protocols are marked with this bit.
|
||||||
|
unsigned InitialComponent : 1;
|
||||||
|
|
||||||
ProtocolInfo() {
|
ProtocolInfo() {
|
||||||
Mark = 0;
|
Mark = 0;
|
||||||
Depth = 0;
|
Depth = 0;
|
||||||
Index = 0;
|
Index = 0;
|
||||||
|
InitialComponent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolInfo(ArrayRef<ProtocolDecl *> inherited,
|
ProtocolInfo(ArrayRef<ProtocolDecl *> inherited,
|
||||||
ArrayRef<AssociatedTypeDecl *> &&types,
|
ArrayRef<AssociatedTypeDecl *> &&types,
|
||||||
ArrayRef<Requirement> reqs)
|
ArrayRef<ProtocolDecl *> deps,
|
||||||
|
bool initialComponent)
|
||||||
: Inherited(inherited),
|
: Inherited(inherited),
|
||||||
AssociatedTypes(types),
|
AssociatedTypes(types),
|
||||||
Requirements(reqs) {
|
Dependencies(deps) {
|
||||||
Mark = 0;
|
Mark = 0;
|
||||||
Depth = 0;
|
Depth = 0;
|
||||||
Index = 0;
|
Index = 0;
|
||||||
|
InitialComponent = initialComponent;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Stores cached information about all protocols transtively
|
/// Stores cached information about all protocols transitively
|
||||||
/// referenced from a set of generic requirements.
|
/// referenced from a set of generic requirements.
|
||||||
///
|
///
|
||||||
/// Out-of-line methods are documented in ProtocolGraph.cpp.
|
/// Out-of-line methods are documented in ProtocolGraph.cpp.
|
||||||
@@ -101,7 +108,8 @@ public:
|
|||||||
const ProtocolDecl *proto) const;
|
const ProtocolDecl *proto) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addProtocol(const ProtocolDecl *proto);
|
void addProtocol(const ProtocolDecl *proto,
|
||||||
|
bool initialComponent);
|
||||||
void computeTransitiveClosure();
|
void computeTransitiveClosure();
|
||||||
void computeLinearOrder();
|
void computeLinearOrder();
|
||||||
void computeInheritedAssociatedTypes();
|
void computeInheritedAssociatedTypes();
|
||||||
|
|||||||
@@ -243,8 +243,20 @@ void RewriteSystemBuilder::processProtocolDependencies() {
|
|||||||
for (auto *assocType : info.InheritedAssociatedTypes)
|
for (auto *assocType : info.InheritedAssociatedTypes)
|
||||||
addAssociatedType(assocType, proto);
|
addAssociatedType(assocType, proto);
|
||||||
|
|
||||||
for (auto req : info.Requirements)
|
// If this protocol is part of the initial connected component, we're
|
||||||
addRequirement(req.getCanonical(), proto);
|
// building requirement signatures for all protocols in this component,
|
||||||
|
// and so we must start with the structural requirements.
|
||||||
|
//
|
||||||
|
// Otherwise, we should either already have a requirement signature, or
|
||||||
|
// we can trigger the computation of the requirement signatures of the
|
||||||
|
// next component recursively.
|
||||||
|
if (info.InitialComponent) {
|
||||||
|
for (auto req : proto->getStructuralRequirements())
|
||||||
|
addRequirement(req.req.getCanonical(), proto);
|
||||||
|
} else {
|
||||||
|
for (auto req : proto->getRequirementSignature())
|
||||||
|
addRequirement(req.getCanonical(), proto);
|
||||||
|
}
|
||||||
|
|
||||||
if (Dump) {
|
if (Dump) {
|
||||||
llvm::dbgs() << "}\n";
|
llvm::dbgs() << "}\n";
|
||||||
@@ -397,7 +409,8 @@ void RequirementMachine::initWithGenericSignature(CanGenericSignature sig) {
|
|||||||
|
|
||||||
// Add the initial set of rewrite rules to the rewrite system, also
|
// Add the initial set of rewrite rules to the rewrite system, also
|
||||||
// providing the protocol graph to use for the linear order on terms.
|
// providing the protocol graph to use for the linear order on terms.
|
||||||
System.initialize(std::move(builder.AssociatedTypeRules),
|
System.initialize(/*recordHomotopyGenerators=*/false,
|
||||||
|
std::move(builder.AssociatedTypeRules),
|
||||||
std::move(builder.RequirementRules),
|
std::move(builder.RequirementRules),
|
||||||
std::move(builder.Protocols));
|
std::move(builder.Protocols));
|
||||||
|
|
||||||
@@ -438,7 +451,8 @@ void RequirementMachine::initWithProtocols(ArrayRef<const ProtocolDecl *> protos
|
|||||||
|
|
||||||
// Add the initial set of rewrite rules to the rewrite system, also
|
// Add the initial set of rewrite rules to the rewrite system, also
|
||||||
// providing the protocol graph to use for the linear order on terms.
|
// providing the protocol graph to use for the linear order on terms.
|
||||||
System.initialize(std::move(builder.AssociatedTypeRules),
|
System.initialize(/*recordHomotopyGenerators=*/true,
|
||||||
|
std::move(builder.AssociatedTypeRules),
|
||||||
std::move(builder.RequirementRules),
|
std::move(builder.RequirementRules),
|
||||||
std::move(builder.Protocols));
|
std::move(builder.Protocols));
|
||||||
|
|
||||||
@@ -522,108 +536,3 @@ void RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy)
|
|||||||
bool RequirementMachine::isComplete() const {
|
bool RequirementMachine::isComplete() const {
|
||||||
return Complete;
|
return Complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a list of non-permanent, non-redundant rewrite rules into a minimal
|
|
||||||
/// protocol requirement signature for \p proto. The requirements are sorted in
|
|
||||||
/// canonical order, and same-type requirements are canonicalized.
|
|
||||||
std::vector<Requirement>
|
|
||||||
RequirementMachine::buildRequirementSignature(ArrayRef<unsigned> rules,
|
|
||||||
const ProtocolDecl *proto) const {
|
|
||||||
std::vector<Requirement> reqs;
|
|
||||||
llvm::SmallDenseMap<TypeBase *, llvm::SmallVector<Type, 2>> sameTypeReqs;
|
|
||||||
|
|
||||||
auto genericParams = proto->getGenericSignature().getGenericParams();
|
|
||||||
|
|
||||||
// Convert a rewrite rule into a requirement.
|
|
||||||
auto createRequirementFromRule = [&](const Rule &rule) {
|
|
||||||
if (auto prop = rule.isPropertyRule()) {
|
|
||||||
auto subjectType = Context.getTypeForTerm(rule.getRHS(), genericParams,
|
|
||||||
System.getProtocols());
|
|
||||||
|
|
||||||
switch (prop->getKind()) {
|
|
||||||
case Symbol::Kind::Protocol:
|
|
||||||
reqs.emplace_back(RequirementKind::Conformance,
|
|
||||||
subjectType,
|
|
||||||
prop->getProtocol()->getDeclaredInterfaceType());
|
|
||||||
return;
|
|
||||||
|
|
||||||
case Symbol::Kind::Layout:
|
|
||||||
case Symbol::Kind::ConcreteType:
|
|
||||||
case Symbol::Kind::Superclass:
|
|
||||||
// FIXME
|
|
||||||
return;
|
|
||||||
|
|
||||||
case Symbol::Kind::Name:
|
|
||||||
case Symbol::Kind::AssociatedType:
|
|
||||||
case Symbol::Kind::GenericParam:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm_unreachable("Invalid symbol kind");
|
|
||||||
} else if (rule.getLHS().back().getKind() != Symbol::Kind::Protocol) {
|
|
||||||
auto constraintType = Context.getTypeForTerm(rule.getLHS(), genericParams,
|
|
||||||
System.getProtocols());
|
|
||||||
auto subjectType = Context.getTypeForTerm(rule.getRHS(), genericParams,
|
|
||||||
System.getProtocols());
|
|
||||||
|
|
||||||
sameTypeReqs[subjectType.getPointer()].push_back(constraintType);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build the list of requirements, storing same-type requirements off
|
|
||||||
// to the side.
|
|
||||||
for (unsigned ruleID : rules) {
|
|
||||||
const auto &rule = System.getRule(ruleID);
|
|
||||||
createRequirementFromRule(rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A set of rewrite rules of the form:
|
|
||||||
//
|
|
||||||
// B => A
|
|
||||||
// C => A
|
|
||||||
// D => A
|
|
||||||
//
|
|
||||||
// Become a series of same-type requirements
|
|
||||||
//
|
|
||||||
// A == B, B == C, C == D
|
|
||||||
//
|
|
||||||
for (auto &pair : sameTypeReqs) {
|
|
||||||
std::sort(pair.second.begin(), pair.second.end(),
|
|
||||||
[](Type first, Type second) -> bool {
|
|
||||||
return compareDependentTypes(first, second) < 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
Type subjectType(pair.first);
|
|
||||||
for (auto constraintType : pair.second) {
|
|
||||||
reqs.emplace_back(RequirementKind::SameType, subjectType, constraintType);
|
|
||||||
subjectType = constraintType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort the requirements in canonical order.
|
|
||||||
std::sort(reqs.begin(), reqs.end(),
|
|
||||||
[](const Requirement &lhs, const Requirement &rhs) -> bool {
|
|
||||||
return lhs.compare(rhs) < 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
return reqs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds the requirement signatures for each protocol in this strongly
|
|
||||||
/// connected component.
|
|
||||||
llvm::DenseMap<const ProtocolDecl *, std::vector<Requirement>>
|
|
||||||
RequirementMachine::computeMinimalRequirements() {
|
|
||||||
assert(Protos.size() > 0);
|
|
||||||
System.minimizeRewriteSystem();
|
|
||||||
|
|
||||||
auto rules = System.getMinimizedRules(Protos);
|
|
||||||
|
|
||||||
// Note that we build 'result' by iterating over 'Protos' rather than
|
|
||||||
// 'rules'; this is intentional, so that even if a protocol has no
|
|
||||||
// rules, we still end up creating an entry for it in 'result'.
|
|
||||||
llvm::DenseMap<const ProtocolDecl *, std::vector<Requirement>> result;
|
|
||||||
for (const auto *proto : Protos)
|
|
||||||
result[proto] = buildRequirementSignature(rules[proto], proto);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,19 +10,28 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// This file implements the main entry points into the requirement machine
|
// This file implements the main entry points for computing minimized generic
|
||||||
// via the request evaluator.
|
// signatures using the requirement machine via the request evaluator.
|
||||||
|
//
|
||||||
|
// The actual logic for finding a minimal set of rewrite rules is implemented in
|
||||||
|
// HomotopyReduction.cpp and GeneratingConformances.cpp.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "swift/AST/ASTContext.h"
|
#include "swift/AST/ASTContext.h"
|
||||||
#include "swift/AST/Decl.h"
|
#include "swift/AST/Decl.h"
|
||||||
|
#include "swift/AST/GenericSignature.h"
|
||||||
#include "swift/AST/GenericSignatureBuilder.h"
|
#include "swift/AST/GenericSignatureBuilder.h"
|
||||||
#include "swift/AST/LazyResolver.h"
|
#include "swift/AST/LazyResolver.h"
|
||||||
|
#include "swift/AST/Requirement.h"
|
||||||
#include "swift/AST/TypeCheckRequests.h"
|
#include "swift/AST/TypeCheckRequests.h"
|
||||||
#include "swift/Basic/Statistic.h"
|
#include "swift/Basic/Statistic.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "RequirementMachine.h"
|
||||||
|
|
||||||
using namespace swift;
|
using namespace swift;
|
||||||
|
using namespace rewriting;
|
||||||
|
|
||||||
#define DEBUG_TYPE "Serialization"
|
#define DEBUG_TYPE "Serialization"
|
||||||
|
|
||||||
@@ -31,6 +40,111 @@ STATISTIC(NumLazyRequirementSignaturesLoaded,
|
|||||||
|
|
||||||
#undef DEBUG_TYPE
|
#undef DEBUG_TYPE
|
||||||
|
|
||||||
|
/// Convert a list of non-permanent, non-redundant rewrite rules into a minimal
|
||||||
|
/// protocol requirement signature for \p proto. The requirements are sorted in
|
||||||
|
/// canonical order, and same-type requirements are canonicalized.
|
||||||
|
std::vector<Requirement>
|
||||||
|
RequirementMachine::buildRequirementSignature(ArrayRef<unsigned> rules,
|
||||||
|
const ProtocolDecl *proto) const {
|
||||||
|
std::vector<Requirement> reqs;
|
||||||
|
llvm::SmallDenseMap<TypeBase *, llvm::SmallVector<Type, 2>> sameTypeReqs;
|
||||||
|
|
||||||
|
auto genericParams = proto->getGenericSignature().getGenericParams();
|
||||||
|
|
||||||
|
// Convert a rewrite rule into a requirement.
|
||||||
|
auto createRequirementFromRule = [&](const Rule &rule) {
|
||||||
|
if (auto prop = rule.isPropertyRule()) {
|
||||||
|
auto subjectType = Context.getTypeForTerm(rule.getRHS(), genericParams,
|
||||||
|
System.getProtocols());
|
||||||
|
|
||||||
|
switch (prop->getKind()) {
|
||||||
|
case Symbol::Kind::Protocol:
|
||||||
|
reqs.emplace_back(RequirementKind::Conformance,
|
||||||
|
subjectType,
|
||||||
|
prop->getProtocol()->getDeclaredInterfaceType());
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Symbol::Kind::Layout:
|
||||||
|
case Symbol::Kind::ConcreteType:
|
||||||
|
case Symbol::Kind::Superclass:
|
||||||
|
// FIXME
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Symbol::Kind::Name:
|
||||||
|
case Symbol::Kind::AssociatedType:
|
||||||
|
case Symbol::Kind::GenericParam:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm_unreachable("Invalid symbol kind");
|
||||||
|
} else if (rule.getLHS().back().getKind() != Symbol::Kind::Protocol) {
|
||||||
|
auto constraintType = Context.getTypeForTerm(rule.getLHS(), genericParams,
|
||||||
|
System.getProtocols());
|
||||||
|
auto subjectType = Context.getTypeForTerm(rule.getRHS(), genericParams,
|
||||||
|
System.getProtocols());
|
||||||
|
|
||||||
|
sameTypeReqs[subjectType.getPointer()].push_back(constraintType);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build the list of requirements, storing same-type requirements off
|
||||||
|
// to the side.
|
||||||
|
for (unsigned ruleID : rules) {
|
||||||
|
const auto &rule = System.getRule(ruleID);
|
||||||
|
createRequirementFromRule(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A set of rewrite rules of the form:
|
||||||
|
//
|
||||||
|
// B => A
|
||||||
|
// C => A
|
||||||
|
// D => A
|
||||||
|
//
|
||||||
|
// Become a series of same-type requirements
|
||||||
|
//
|
||||||
|
// A == B, B == C, C == D
|
||||||
|
//
|
||||||
|
for (auto &pair : sameTypeReqs) {
|
||||||
|
std::sort(pair.second.begin(), pair.second.end(),
|
||||||
|
[](Type first, Type second) -> bool {
|
||||||
|
return compareDependentTypes(first, second) < 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
Type subjectType(pair.first);
|
||||||
|
for (auto constraintType : pair.second) {
|
||||||
|
reqs.emplace_back(RequirementKind::SameType, subjectType, constraintType);
|
||||||
|
subjectType = constraintType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the requirements in canonical order.
|
||||||
|
std::sort(reqs.begin(), reqs.end(),
|
||||||
|
[](const Requirement &lhs, const Requirement &rhs) -> bool {
|
||||||
|
return lhs.compare(rhs) < 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return reqs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds the requirement signatures for each protocol in this strongly
|
||||||
|
/// connected component.
|
||||||
|
llvm::DenseMap<const ProtocolDecl *, std::vector<Requirement>>
|
||||||
|
RequirementMachine::computeMinimalRequirements() {
|
||||||
|
assert(Protos.size() > 0);
|
||||||
|
System.minimizeRewriteSystem();
|
||||||
|
|
||||||
|
auto rules = System.getMinimizedRules(Protos);
|
||||||
|
|
||||||
|
// Note that we build 'result' by iterating over 'Protos' rather than
|
||||||
|
// 'rules'; this is intentional, so that even if a protocol has no
|
||||||
|
// rules, we still end up creating an entry for it in 'result'.
|
||||||
|
llvm::DenseMap<const ProtocolDecl *, std::vector<Requirement>> result;
|
||||||
|
for (const auto *proto : Protos)
|
||||||
|
result[proto] = buildRequirementSignature(rules[proto], proto);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ArrayRef<Requirement>
|
ArrayRef<Requirement>
|
||||||
RequirementSignatureRequest::evaluate(Evaluator &evaluator,
|
RequirementSignatureRequest::evaluate(Evaluator &evaluator,
|
||||||
ProtocolDecl *proto) const {
|
ProtocolDecl *proto) const {
|
||||||
@@ -54,27 +168,82 @@ RequirementSignatureRequest::evaluate(Evaluator &evaluator,
|
|||||||
return ctx.AllocateCopy(requirements);
|
return ctx.AllocateCopy(requirements);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericSignatureBuilder builder(proto->getASTContext());
|
auto buildViaGSB = [&]() {
|
||||||
|
GenericSignatureBuilder builder(proto->getASTContext());
|
||||||
|
|
||||||
// Add all of the generic parameters.
|
// Add all of the generic parameters.
|
||||||
for (auto gp : *proto->getGenericParams())
|
for (auto gp : *proto->getGenericParams())
|
||||||
builder.addGenericParameter(gp);
|
builder.addGenericParameter(gp);
|
||||||
|
|
||||||
// Add the conformance of 'self' to the protocol.
|
// Add the conformance of 'self' to the protocol.
|
||||||
auto selfType =
|
auto selfType =
|
||||||
proto->getSelfInterfaceType()->castTo<GenericTypeParamType>();
|
proto->getSelfInterfaceType()->castTo<GenericTypeParamType>();
|
||||||
auto requirement =
|
auto requirement =
|
||||||
Requirement(RequirementKind::Conformance, selfType,
|
Requirement(RequirementKind::Conformance, selfType,
|
||||||
proto->getDeclaredInterfaceType());
|
proto->getDeclaredInterfaceType());
|
||||||
|
|
||||||
builder.addRequirement(
|
builder.addRequirement(
|
||||||
requirement,
|
requirement,
|
||||||
GenericSignatureBuilder::RequirementSource::forRequirementSignature(
|
GenericSignatureBuilder::RequirementSource::forRequirementSignature(
|
||||||
builder, selfType, proto),
|
builder, selfType, proto),
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
auto reqSignature = std::move(builder).computeGenericSignature(
|
auto reqSignature = std::move(builder).computeGenericSignature(
|
||||||
/*allowConcreteGenericParams=*/false,
|
/*allowConcreteGenericParams=*/false,
|
||||||
/*requirementSignatureSelfProto=*/proto);
|
/*requirementSignatureSelfProto=*/proto);
|
||||||
return reqSignature.getRequirements();
|
return reqSignature.getRequirements();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto buildViaRQM = [&]() {
|
||||||
|
// We build requirement signatures for all protocols in a strongly connected
|
||||||
|
// component at the same time.
|
||||||
|
auto *machine = ctx.getOrCreateRequirementMachine(proto);
|
||||||
|
auto requirements = machine->computeMinimalRequirements();
|
||||||
|
|
||||||
|
bool debug = machine->getDebugOptions().contains(DebugFlags::Minimization);
|
||||||
|
|
||||||
|
// The requirement signature for the actual protocol that the result
|
||||||
|
// was kicked off with.
|
||||||
|
ArrayRef<Requirement> result;
|
||||||
|
|
||||||
|
for (const auto &pair : requirements) {
|
||||||
|
auto *otherProto = pair.first;
|
||||||
|
const auto &reqs = pair.second;
|
||||||
|
|
||||||
|
// setRequirementSignature() doesn't take ownership of the memory, so
|
||||||
|
// we have to make a copy of the std::vector temporary.
|
||||||
|
ArrayRef<Requirement> reqsCopy = ctx.AllocateCopy(reqs);
|
||||||
|
|
||||||
|
// Don't call setRequirementSignature() on the original proto; the
|
||||||
|
// request evaluator will do it for us.
|
||||||
|
if (otherProto == proto)
|
||||||
|
result = reqsCopy;
|
||||||
|
else
|
||||||
|
const_cast<ProtocolDecl *>(otherProto)->setRequirementSignature(reqsCopy);
|
||||||
|
|
||||||
|
// Dump the result if requested.
|
||||||
|
if (debug) {
|
||||||
|
llvm::dbgs() << "Protocol " << otherProto->getName() << ": ";
|
||||||
|
|
||||||
|
auto sig = GenericSignature::get(
|
||||||
|
otherProto->getGenericSignature().getGenericParams(),
|
||||||
|
reqsCopy);
|
||||||
|
llvm::dbgs() << sig << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the result for the specific protocol this request was kicked off on.
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (ctx.LangOpts.RequirementMachineProtocolSignatures) {
|
||||||
|
case RequirementMachineMode::Disabled:
|
||||||
|
return buildViaGSB();
|
||||||
|
|
||||||
|
case RequirementMachineMode::Enabled:
|
||||||
|
return buildViaRQM();
|
||||||
|
|
||||||
|
case RequirementMachineMode::Verify:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ RewriteSystem::RewriteSystem(RewriteContext &ctx)
|
|||||||
Initialized = 0;
|
Initialized = 0;
|
||||||
Complete = 0;
|
Complete = 0;
|
||||||
Minimized = 0;
|
Minimized = 0;
|
||||||
|
RecordHomotopyGenerators = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RewriteSystem::~RewriteSystem() {
|
RewriteSystem::~RewriteSystem() {
|
||||||
@@ -96,12 +97,14 @@ RewriteSystem::~RewriteSystem() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RewriteSystem::initialize(
|
void RewriteSystem::initialize(
|
||||||
|
bool recordHomotopyGenerators,
|
||||||
std::vector<std::pair<MutableTerm, MutableTerm>> &&associatedTypeRules,
|
std::vector<std::pair<MutableTerm, MutableTerm>> &&associatedTypeRules,
|
||||||
std::vector<std::pair<MutableTerm, MutableTerm>> &&requirementRules,
|
std::vector<std::pair<MutableTerm, MutableTerm>> &&requirementRules,
|
||||||
ProtocolGraph &&graph) {
|
ProtocolGraph &&graph) {
|
||||||
assert(!Initialized);
|
assert(!Initialized);
|
||||||
Initialized = 1;
|
Initialized = 1;
|
||||||
|
|
||||||
|
RecordHomotopyGenerators = recordHomotopyGenerators;
|
||||||
Protos = graph;
|
Protos = graph;
|
||||||
|
|
||||||
for (const auto &rule : associatedTypeRules) {
|
for (const auto &rule : associatedTypeRules) {
|
||||||
@@ -170,7 +173,7 @@ bool RewriteSystem::addRule(MutableTerm lhs, MutableTerm rhs,
|
|||||||
if (path) {
|
if (path) {
|
||||||
// We already have a loop, since the simplified lhs is identical to the
|
// We already have a loop, since the simplified lhs is identical to the
|
||||||
// simplified rhs.
|
// simplified rhs.
|
||||||
HomotopyGenerators.emplace_back(lhs, loop);
|
recordHomotopyGenerator(lhs, loop);
|
||||||
|
|
||||||
if (Debug.contains(DebugFlags::Add)) {
|
if (Debug.contains(DebugFlags::Add)) {
|
||||||
llvm::dbgs() << "## Recorded trivial loop at " << lhs << ": ";
|
llvm::dbgs() << "## Recorded trivial loop at " << lhs << ": ";
|
||||||
@@ -206,7 +209,7 @@ bool RewriteSystem::addRule(MutableTerm lhs, MutableTerm rhs,
|
|||||||
// add a rewrite step applying the new rule in reverse to close the loop.
|
// add a rewrite step applying the new rule in reverse to close the loop.
|
||||||
loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
|
loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
|
||||||
newRuleID, /*inverse=*/true));
|
newRuleID, /*inverse=*/true));
|
||||||
HomotopyGenerators.emplace_back(lhs, loop);
|
recordHomotopyGenerator(lhs, loop);
|
||||||
|
|
||||||
if (Debug.contains(DebugFlags::Add)) {
|
if (Debug.contains(DebugFlags::Add)) {
|
||||||
llvm::dbgs() << "## Recorded non-trivial loop at " << lhs << ": ";
|
llvm::dbgs() << "## Recorded non-trivial loop at " << lhs << ": ";
|
||||||
@@ -376,7 +379,7 @@ void RewriteSystem::simplifyRewriteSystem() {
|
|||||||
loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
|
loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
|
||||||
newRuleID, /*inverse=*/true));
|
newRuleID, /*inverse=*/true));
|
||||||
|
|
||||||
HomotopyGenerators.emplace_back(MutableTerm(lhs), loop);
|
recordHomotopyGenerator(MutableTerm(lhs), loop);
|
||||||
|
|
||||||
if (Debug.contains(DebugFlags::Completion)) {
|
if (Debug.contains(DebugFlags::Completion)) {
|
||||||
llvm::dbgs() << "$ Right hand side simplification recorded a loop: ";
|
llvm::dbgs() << "$ Right hand side simplification recorded a loop: ";
|
||||||
|
|||||||
@@ -379,6 +379,9 @@ class RewriteSystem final {
|
|||||||
/// Whether we've minimized the rewrite system.
|
/// Whether we've minimized the rewrite system.
|
||||||
unsigned Minimized : 1;
|
unsigned Minimized : 1;
|
||||||
|
|
||||||
|
/// If set, record homotopy generators in the completion procedure.
|
||||||
|
unsigned RecordHomotopyGenerators : 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RewriteSystem(RewriteContext &ctx);
|
explicit RewriteSystem(RewriteContext &ctx);
|
||||||
~RewriteSystem();
|
~RewriteSystem();
|
||||||
@@ -394,7 +397,8 @@ public:
|
|||||||
/// Return the object recording information about known protocols.
|
/// Return the object recording information about known protocols.
|
||||||
const ProtocolGraph &getProtocols() const { return Protos; }
|
const ProtocolGraph &getProtocols() const { return Protos; }
|
||||||
|
|
||||||
void initialize(std::vector<std::pair<MutableTerm, MutableTerm>> &&assocaitedTypeRules,
|
void initialize(bool recordHomotopyGenerators,
|
||||||
|
std::vector<std::pair<MutableTerm, MutableTerm>> &&assocaitedTypeRules,
|
||||||
std::vector<std::pair<MutableTerm, MutableTerm>> &&requirementRules,
|
std::vector<std::pair<MutableTerm, MutableTerm>> &&requirementRules,
|
||||||
ProtocolGraph &&protos);
|
ProtocolGraph &&protos);
|
||||||
|
|
||||||
@@ -452,6 +456,21 @@ public:
|
|||||||
void verifyRewriteRules(ValidityPolicy policy) const;
|
void verifyRewriteRules(ValidityPolicy policy) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void recordHomotopyGenerator(HomotopyGenerator loop) {
|
||||||
|
if (!RecordHomotopyGenerators)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HomotopyGenerators.push_back(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recordHomotopyGenerator(MutableTerm basepoint,
|
||||||
|
RewritePath path) {
|
||||||
|
if (!RecordHomotopyGenerators)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HomotopyGenerators.emplace_back(basepoint, path);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
computeCriticalPair(
|
computeCriticalPair(
|
||||||
ArrayRef<Symbol>::const_iterator from,
|
ArrayRef<Symbol>::const_iterator from,
|
||||||
|
|||||||
@@ -291,6 +291,10 @@ void RewriteSystem::processMergedAssociatedTypes() {
|
|||||||
/// If so, record this rule for later. We'll try to merge the associated
|
/// If so, record this rule for later. We'll try to merge the associated
|
||||||
/// types in RewriteSystem::processMergedAssociatedTypes().
|
/// types in RewriteSystem::processMergedAssociatedTypes().
|
||||||
void RewriteSystem::checkMergedAssociatedType(Term lhs, Term rhs) {
|
void RewriteSystem::checkMergedAssociatedType(Term lhs, Term rhs) {
|
||||||
|
// FIXME: Figure out 3-cell representation for merged associated types
|
||||||
|
if (RecordHomotopyGenerators)
|
||||||
|
return;
|
||||||
|
|
||||||
if (lhs.size() == rhs.size() &&
|
if (lhs.size() == rhs.size() &&
|
||||||
std::equal(lhs.begin(), lhs.end() - 1, rhs.begin()) &&
|
std::equal(lhs.begin(), lhs.end() - 1, rhs.begin()) &&
|
||||||
lhs.back().getKind() == Symbol::Kind::AssociatedType &&
|
lhs.back().getKind() == Symbol::Kind::AssociatedType &&
|
||||||
@@ -581,7 +585,7 @@ RewriteSystem::computeConfluentCompletion(unsigned maxIterations,
|
|||||||
llvm::dbgs() << "\n\n";
|
llvm::dbgs() << "\n\n";
|
||||||
|
|
||||||
// Record the trivial loop.
|
// Record the trivial loop.
|
||||||
HomotopyGenerators.push_back(loop);
|
recordHomotopyGenerator(loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -831,13 +831,12 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto A =
|
if (auto A = Args.getLastArg(OPT_requirement_machine_EQ)) {
|
||||||
Args.getLastArg(OPT_requirement_machine_EQ)) {
|
|
||||||
auto value = llvm::StringSwitch<Optional<RequirementMachineMode>>(A->getValue())
|
auto value = llvm::StringSwitch<Optional<RequirementMachineMode>>(A->getValue())
|
||||||
.Case("off", RequirementMachineMode::Disabled)
|
.Case("off", RequirementMachineMode::Disabled)
|
||||||
.Case("on", RequirementMachineMode::Enabled)
|
.Case("on", RequirementMachineMode::Enabled)
|
||||||
.Case("verify", RequirementMachineMode::Verify)
|
.Case("verify", RequirementMachineMode::Verify)
|
||||||
.Default(None);
|
.Default(None);
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
Opts.EnableRequirementMachine = *value;
|
Opts.EnableRequirementMachine = *value;
|
||||||
@@ -846,6 +845,20 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
|||||||
A->getAsString(Args), A->getValue());
|
A->getAsString(Args), A->getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto A = Args.getLastArg(OPT_requirement_machine_protocol_signatures_EQ)) {
|
||||||
|
auto value = llvm::StringSwitch<Optional<RequirementMachineMode>>(A->getValue())
|
||||||
|
.Case("off", RequirementMachineMode::Disabled)
|
||||||
|
.Case("on", RequirementMachineMode::Enabled)
|
||||||
|
.Case("verify", RequirementMachineMode::Verify)
|
||||||
|
.Default(None);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
Opts.RequirementMachineProtocolSignatures = *value;
|
||||||
|
else
|
||||||
|
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
|
||||||
|
A->getAsString(Args), A->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
Opts.DumpRequirementMachine = Args.hasArg(
|
Opts.DumpRequirementMachine = Args.hasArg(
|
||||||
OPT_dump_requirement_machine);
|
OPT_dump_requirement_machine);
|
||||||
Opts.AnalyzeRequirementMachine = Args.hasArg(
|
Opts.AnalyzeRequirementMachine = Args.hasArg(
|
||||||
|
|||||||
@@ -1093,7 +1093,12 @@ ProtocolDependenciesRequest::evaluate(Evaluator &evaluator,
|
|||||||
|
|
||||||
// If we have a serialized requirement signature, deserialize it and
|
// If we have a serialized requirement signature, deserialize it and
|
||||||
// look at conformance requirements.
|
// look at conformance requirements.
|
||||||
if (proto->hasLazyRequirementSignature()) {
|
//
|
||||||
|
// FIXME: For now we just fall back to the GSB for all protocols
|
||||||
|
// unless -requirement-machine-protocol-signatures=on is passed.
|
||||||
|
if (proto->hasLazyRequirementSignature() ||
|
||||||
|
(ctx.LangOpts.RequirementMachineProtocolSignatures
|
||||||
|
== RequirementMachineMode::Disabled)) {
|
||||||
for (auto req : proto->getRequirementSignature()) {
|
for (auto req : proto->getRequirementSignature()) {
|
||||||
if (req.getKind() == RequirementKind::Conformance) {
|
if (req.getKind() == RequirementKind::Conformance) {
|
||||||
result.push_back(req.getProtocolDecl());
|
result.push_back(req.getProtocolDecl());
|
||||||
|
|||||||
61
test/Generics/rdar33654588.swift
Normal file
61
test/Generics/rdar33654588.swift
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=on 2>&1
|
||||||
|
|
||||||
|
protocol FP {}
|
||||||
|
|
||||||
|
protocol FPSign {
|
||||||
|
associatedtype Positive: FPIntDigit
|
||||||
|
associatedtype Negative: FPIntDigit
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol FPIntDigit: FP {
|
||||||
|
associatedtype Zero: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype One: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype Two: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype Three: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype Four: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype Five: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype Six: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype Seven: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype Eight: FPIntDigit, FPPoint, FPExponent
|
||||||
|
associatedtype Nine: FPIntDigit, FPPoint, FPExponent
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol FPPoint: FP {
|
||||||
|
associatedtype Point: FPFractionDigit, FPExponent
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol FPFractionDigit: FP {
|
||||||
|
associatedtype Zero: FPFractionDigit, FPExponent
|
||||||
|
associatedtype One: FPFractionDigit, FPExponent
|
||||||
|
associatedtype Two: FPFractionDigit, FPExponent
|
||||||
|
associatedtype Three: FPFractionDigit, FPExponent
|
||||||
|
associatedtype Four: FPFractionDigit, FPExponent
|
||||||
|
associatedtype Five: FPFractionDigit, FPExponent
|
||||||
|
associatedtype Six: FPFractionDigit, FPExponent
|
||||||
|
associatedtype Seven: FPFractionDigit, FPExponent
|
||||||
|
associatedtype Eight: FPFractionDigit, FPExponent
|
||||||
|
associatedtype Nine: FPFractionDigit, FPExponent
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol FPExponent {
|
||||||
|
associatedtype E: FPExponentSign, FPExponentDigit
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol FPExponentSign {
|
||||||
|
associatedtype Positive: FPExponentDigit
|
||||||
|
associatedtype Negative: FPExponentDigit
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol FPExponentDigit: FP {
|
||||||
|
associatedtype Zero: FPExponentDigit
|
||||||
|
associatedtype One: FPExponentDigit
|
||||||
|
associatedtype Two: FPExponentDigit
|
||||||
|
associatedtype Three: FPExponentDigit
|
||||||
|
associatedtype Four: FPExponentDigit
|
||||||
|
associatedtype Five: FPExponentDigit
|
||||||
|
associatedtype Six: FPExponentDigit
|
||||||
|
associatedtype Seven: FPExponentDigit
|
||||||
|
associatedtype Eight: FPExponentDigit
|
||||||
|
associatedtype Nine: FPExponentDigit
|
||||||
|
}
|
||||||
|
|
||||||
7
test/Generics/rdar65015626.swift
Normal file
7
test/Generics/rdar65015626.swift
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: 65015626.(file).G@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.Word : FixedWidthInteger, Self.Word == Self.Word.Magnitude>
|
||||||
|
public protocol G {
|
||||||
|
associatedtype Word: FixedWidthInteger where Word.Magnitude == Word
|
||||||
|
}
|
||||||
41
test/Generics/rdar68084643.swift
Normal file
41
test/Generics/rdar68084643.swift
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: 68084643.(file).R@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.RT : F>
|
||||||
|
protocol R {
|
||||||
|
associatedtype RT: F
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 68084643.(file).F@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.OT.RT, Self.OT : R>
|
||||||
|
protocol F {
|
||||||
|
associatedtype OT: R where OT.RT == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 68084643.(file).P@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self>
|
||||||
|
protocol P {
|
||||||
|
associatedtype PT
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 68084643.(file).O@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.O : P>
|
||||||
|
protocol O {
|
||||||
|
associatedtype O: P
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 68084643.(file).B@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.LO : O, Self.OT == Self.LO.O, Self.RT : F, Self.OT.PT == Self.RT.OT>
|
||||||
|
protocol B {
|
||||||
|
associatedtype RT: F
|
||||||
|
associatedtype LO: O where LO.O == OT
|
||||||
|
associatedtype OT where OT.PT == RT.OT
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 68084643.(file).Boom@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.D : B, Self.E : Sequence, Self.F : Sequence, Self.E.Element == Self.F.Element>
|
||||||
|
protocol Boom {
|
||||||
|
associatedtype D: B
|
||||||
|
associatedtype E: Sequence
|
||||||
|
associatedtype F: Sequence where E.Element == F.Element
|
||||||
|
}
|
||||||
38
test/Generics/rdar78643612.swift
Normal file
38
test/Generics/rdar78643612.swift
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: 78643612.(file).Z1@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.T>
|
||||||
|
protocol Z1 {
|
||||||
|
associatedtype T where T == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 78643612.(file).Z2@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.T.T, Self.T : Z2>
|
||||||
|
protocol Z2 {
|
||||||
|
associatedtype T : Z2 where T.T == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 78643612.(file).Z3@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.T.T.T, Self.T : Z3>
|
||||||
|
protocol Z3 {
|
||||||
|
associatedtype T : Z3 where T.T.T == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 78643612.(file).Z4@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.T.T.T.T, Self.T : Z4>
|
||||||
|
protocol Z4 {
|
||||||
|
associatedtype T : Z4 where T.T.T.T == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 78643612.(file).Z5@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.T.T.T.T.T, Self.T : Z5>
|
||||||
|
protocol Z5 {
|
||||||
|
associatedtype T : Z5 where T.T.T.T.T == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 78643612.(file).Z6@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.T.T.T.T.T.T, Self.T : Z6>
|
||||||
|
protocol Z6 {
|
||||||
|
associatedtype T : Z6 where T.T.T.T.T.T == Self
|
||||||
|
}
|
||||||
|
|
||||||
59
test/Generics/rdar83308672.swift
Normal file
59
test/Generics/rdar83308672.swift
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: rdar83308672.(file).A@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.X.T, Self.X : P1, Self.Y : P2>
|
||||||
|
protocol A {
|
||||||
|
associatedtype X : P1
|
||||||
|
associatedtype Y : P2
|
||||||
|
where X.T == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: rdar83308672.(file).P1@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self>
|
||||||
|
protocol P1 {
|
||||||
|
associatedtype T
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: rdar83308672.(file).P2@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.T : B>
|
||||||
|
protocol P2 {
|
||||||
|
associatedtype T : B
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: rdar83308672.(file).B@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.X == Self.Y>
|
||||||
|
protocol B {
|
||||||
|
associatedtype X
|
||||||
|
associatedtype Y
|
||||||
|
where X == Y
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that T.X == T.Y implies T : B, but also T : B implies T.X == T.Y;
|
||||||
|
// we can drop one requirement but not both.
|
||||||
|
//
|
||||||
|
// If T : B was explicitly stated, we drop T.X == T.Y; otherwise we keep
|
||||||
|
// T.X == T.Y and drop T : B.
|
||||||
|
|
||||||
|
// CHECK: rdar83308672.(file).G1@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.T : A, Self.T.X == Self.T.Y>
|
||||||
|
protocol G1 {
|
||||||
|
associatedtype T : A where T.X == T.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: rdar83308672.(file).G2@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.T : A, Self.T : B>
|
||||||
|
protocol G2 {
|
||||||
|
associatedtype T : A where T : B, T.X == T.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: rdar83308672.(file).G3@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.T : A, Self.T : B>
|
||||||
|
protocol G3 {
|
||||||
|
associatedtype T : A where T.X == T.Y, T : B
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: rdar83308672.(file).G4@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.T : A, Self.T : B>
|
||||||
|
protocol G4 {
|
||||||
|
associatedtype T : A where T : B
|
||||||
|
}
|
||||||
31
test/Generics/rdar83848546.swift
Normal file
31
test/Generics/rdar83848546.swift
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: 83848546.(file).Reporter@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.SubReporterType : SubReporter>
|
||||||
|
protocol Reporter {
|
||||||
|
associatedtype SubReporterType: SubReporter
|
||||||
|
func makeSubReporter() -> SubReporterType
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 83848546.(file).SubReporter@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.SubReporterType : SubReporter>
|
||||||
|
protocol SubReporter {
|
||||||
|
associatedtype SubReporterType: SubReporter
|
||||||
|
func makeSubReporter() -> SubReporterType
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 83848546.(file).CausesCompilerCrash@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.ReporterType : Reporter, Self.SubReporterType == Self.ReporterType.SubReporterType, Self.ReporterType.SubReporterType == Self.SubReporterType.SubReporterType>
|
||||||
|
protocol CausesCompilerCrash {
|
||||||
|
associatedtype ReporterType: Reporter
|
||||||
|
associatedtype SubReporterType
|
||||||
|
where ReporterType.SubReporterType == SubReporterType,
|
||||||
|
SubReporterType.SubReporterType == SubReporterType
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: 83848546.(file).DoesNotCrash@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.ReporterType : Reporter, Self.ReporterType.SubReporterType == Self.ReporterType.SubReporterType.SubReporterType>
|
||||||
|
protocol DoesNotCrash {
|
||||||
|
associatedtype ReporterType: Reporter
|
||||||
|
where ReporterType.SubReporterType == ReporterType.SubReporterType.SubReporterType
|
||||||
|
}
|
||||||
12
test/Generics/rdar83955123.swift
Normal file
12
test/Generics/rdar83955123.swift
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: rdar83955123.(file).Cyclo@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.L.R, Self.D : Cyclo, Self.L : Cyclo, Self.R : Cyclo, Self.U : Cyclo, Self.L.R == Self.U.D>
|
||||||
|
protocol Cyclo {
|
||||||
|
associatedtype L: Cyclo
|
||||||
|
associatedtype R: Cyclo
|
||||||
|
associatedtype U: Cyclo
|
||||||
|
associatedtype D: Cyclo
|
||||||
|
where L.R == Self,
|
||||||
|
U.D == Self
|
||||||
|
}
|
||||||
28
test/Generics/sr10438.swift
Normal file
28
test/Generics/sr10438.swift
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: sr10438.(file).AuthenticationFlowStateMachine@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.FlowError.StateMachine, Self.FlowError : AuthenticationFlowStateMachineFlowError, Self.NonFinalState : AuthenticationFlowStateMachineNonFinalState, Self.StartState : AuthenticationFlowStateMachineStartState, Self.FlowError.StateMachine == Self.NonFinalState.StateMachine, Self.NonFinalState.StateMachine == Self.StartState.StateMachine>
|
||||||
|
protocol AuthenticationFlowStateMachine {
|
||||||
|
associatedtype StartState: AuthenticationFlowStateMachineStartState where StartState.StateMachine == Self
|
||||||
|
associatedtype NonFinalState: AuthenticationFlowStateMachineNonFinalState where NonFinalState.StateMachine == Self
|
||||||
|
associatedtype FlowError: AuthenticationFlowStateMachineFlowError where FlowError.StateMachine == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr10438.(file).AuthenticationFlowStateMachineFlowError@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self : Error, Self == Self.StateMachine.FlowError, Self.StateMachine : AuthenticationFlowStateMachine>
|
||||||
|
protocol AuthenticationFlowStateMachineFlowError: Error {
|
||||||
|
associatedtype StateMachine: AuthenticationFlowStateMachine where StateMachine.FlowError == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr10438.(file).AuthenticationFlowStateMachineStartState@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.StateMachine.StartState, Self.StateMachine : AuthenticationFlowStateMachine>
|
||||||
|
protocol AuthenticationFlowStateMachineStartState {
|
||||||
|
associatedtype StateMachine: AuthenticationFlowStateMachine where StateMachine.StartState == Self
|
||||||
|
var nonFinalState: StateMachine.NonFinalState { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr10438.(file).AuthenticationFlowStateMachineNonFinalState@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.StateMachine.NonFinalState, Self.StateMachine : AuthenticationFlowStateMachine>
|
||||||
|
protocol AuthenticationFlowStateMachineNonFinalState {
|
||||||
|
associatedtype StateMachine: AuthenticationFlowStateMachine where StateMachine.NonFinalState == Self
|
||||||
|
}
|
||||||
27
test/Generics/sr10532.swift
Normal file
27
test/Generics/sr10532.swift
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: sr10532.(file).ScalarProtocol@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self : ScalarMultiplicative, Self == Self.Scalar>
|
||||||
|
public protocol ScalarProtocol: ScalarMultiplicative where Self == Scalar { }
|
||||||
|
|
||||||
|
// CHECK: sr10532.(file).ScalarMultiplicative@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.Scalar : ScalarProtocol>
|
||||||
|
public protocol ScalarMultiplicative {
|
||||||
|
associatedtype Scalar : ScalarProtocol
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr10532.(file).MapReduceArithmetic@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self : Collection, Self : ScalarMultiplicative, Self.Element : ScalarMultiplicative, Self.Scalar == Self.Element.Scalar>
|
||||||
|
public protocol MapReduceArithmetic : ScalarMultiplicative, Collection where Element : ScalarMultiplicative, Scalar == Element.Scalar { }
|
||||||
|
|
||||||
|
// CHECK: sr10532.(file).Tensor@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self : MapReduceArithmetic, Self.Element : BinaryFloatingPoint, Self.Element : ScalarProtocol>
|
||||||
|
public protocol Tensor : MapReduceArithmetic where Scalar : BinaryFloatingPoint, Element == Scalar {
|
||||||
|
var magnitude: Scalar { get set }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Tensor {
|
||||||
|
public var magnitude: Scalar {
|
||||||
|
return self.reduce(0) { $0 + $1 * $1 }.squareRoot()
|
||||||
|
}
|
||||||
|
}
|
||||||
14
test/Generics/sr10752.swift
Normal file
14
test/Generics/sr10752.swift
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: sr10752.(file).P@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.A : P, Self.A == Self.A.A>
|
||||||
|
protocol P {
|
||||||
|
associatedtype A : P where A.A == A
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr10752.(file).Q@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.A == Self.C.A, Self.C : P>
|
||||||
|
protocol Q {
|
||||||
|
associatedtype A : P
|
||||||
|
associatedtype C : P where A == C.A
|
||||||
|
}
|
||||||
16
test/Generics/sr11100.swift
Normal file
16
test/Generics/sr11100.swift
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
protocol P1 {
|
||||||
|
associatedtype A
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol P2 {
|
||||||
|
associatedtype C: P1
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr11100.(file).Q@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.X == Self.X.A, Self.Y : P2, Self.X.A == Self.Y.C>
|
||||||
|
protocol Q {
|
||||||
|
associatedtype X
|
||||||
|
associatedtype Y : P2 where X == X.A, X.A == Y.C
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | not %FileCheck %s
|
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures -requirement-machine-protocol-signatures=on %s 2>&1 | %FileCheck %s
|
||||||
// RUN: %target-swift-frontend -emit-ir %s
|
// RUN: %target-swift-frontend -emit-ir -requirement-machine-protocol-signatures=on %s
|
||||||
|
|
||||||
// XFAIL: asserts
|
|
||||||
|
|
||||||
// CHECK: Requirement signature: <Self where Self.Field : FieldAlgebra>
|
// CHECK: Requirement signature: <Self where Self.Field : FieldAlgebra>
|
||||||
public protocol VectorSpace {
|
public protocol VectorSpace {
|
||||||
|
|||||||
30
test/Generics/sr11997.swift
Normal file
30
test/Generics/sr11997.swift
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: sr11997.(file).A@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.X.Y, Self.X : B>
|
||||||
|
protocol A {
|
||||||
|
associatedtype X: B where X.Y == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr11997.(file).B@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.Y.X, Self.Y : A>
|
||||||
|
protocol B {
|
||||||
|
associatedtype Y: A where Y.X == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr11997.(file).AA@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self : A, Self.X : BB>
|
||||||
|
protocol AA: A where X: BB { }
|
||||||
|
|
||||||
|
// CHECK: sr11997.(file).BB@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self : B, Self == Self.Z.T, Self.Y : AA, Self.Z : C>
|
||||||
|
protocol BB: B where Y: AA {
|
||||||
|
associatedtype Z: C where Z.T == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr11997.(file).C@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.T.Z, Self.T : BB>
|
||||||
|
protocol C {
|
||||||
|
associatedtype T: BB where T.Z == Self
|
||||||
|
}
|
||||||
|
|
||||||
32
test/Generics/sr12120.swift
Normal file
32
test/Generics/sr12120.swift
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: sr12120.(file).Swappable1@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.Swapped.Swapped, Self.A == Self.Swapped.B, Self.Swapped : Swappable1>
|
||||||
|
protocol Swappable1 {
|
||||||
|
associatedtype A
|
||||||
|
associatedtype B
|
||||||
|
associatedtype Swapped : Swappable1
|
||||||
|
where Swapped.B == A,
|
||||||
|
Swapped.A == B, // FIXME: Diagnose redundancy
|
||||||
|
Swapped.Swapped == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr12120.(file).Swappable2@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.Swapped.Swapped, Self.A == Self.Swapped.B, Self.Swapped : Swappable2>
|
||||||
|
protocol Swappable2 {
|
||||||
|
associatedtype A
|
||||||
|
associatedtype B
|
||||||
|
associatedtype Swapped : Swappable2
|
||||||
|
where Swapped.B == A,
|
||||||
|
Swapped.Swapped == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr12120.(file).Swappable3@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.Swapped.Swapped, Self.B == Self.Swapped.A, Self.Swapped : Swappable3>
|
||||||
|
protocol Swappable3 {
|
||||||
|
associatedtype A
|
||||||
|
associatedtype B
|
||||||
|
associatedtype Swapped : Swappable3
|
||||||
|
where Swapped.A == B,
|
||||||
|
Swapped.Swapped == Self
|
||||||
|
}
|
||||||
22
test/Generics/sr12736.swift
Normal file
22
test/Generics/sr12736.swift
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: sr12736.(file).ColorModel@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.Float32Components.Model, Self.Float32Components : ColorComponents>
|
||||||
|
public protocol ColorModel {
|
||||||
|
associatedtype Float32Components: ColorComponents where Float32Components.Model == Self
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol ColorComponents {
|
||||||
|
associatedtype Model: ColorModel
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol ColorPixel {
|
||||||
|
associatedtype Model: ColorModel
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: sr12736.(file).P@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.A : ColorPixel, Self.B : ColorPixel, Self.A.Model == Self.B.Model>
|
||||||
|
public protocol P {
|
||||||
|
associatedtype A: ColorPixel
|
||||||
|
associatedtype B: ColorPixel where B.Model == A.Model
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
// RUN: %target-typecheck-verify-swift -debug-generic-signatures 2>&1 | %FileCheck %s
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=off 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
// https://bugs.swift.org/browse/SR-13850
|
// https://bugs.swift.org/browse/SR-13850
|
||||||
|
|
||||||
|
|||||||
10
test/Generics/sr14485.swift
Normal file
10
test/Generics/sr14485.swift
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: sr14485.(file).P@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self.Input == Self.Output.Magnitude, Self.Output : FixedWidthInteger, Self.Output : SignedInteger>
|
||||||
|
protocol P {
|
||||||
|
associatedtype Input: FixedWidthInteger & UnsignedInteger & BinaryInteger
|
||||||
|
associatedtype Output: FixedWidthInteger & SignedInteger & BinaryInteger
|
||||||
|
where Output.Magnitude == Input
|
||||||
|
}
|
||||||
|
|
||||||
9
test/Generics/sr15009.swift
Normal file
9
test/Generics/sr15009.swift
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: sr15009.(file).P@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self == Self.A.B, Self.A : Q>
|
||||||
|
protocol P { associatedtype A: Q where A.B == Self }
|
||||||
|
|
||||||
|
// CHECK: sr15009.(file).Q@
|
||||||
|
// CHECK-NEXT: Requirement signature: <Self where Self : CaseIterable, Self == Self.B.A, Self.B : P>
|
||||||
|
protocol Q: CaseIterable { associatedtype B: P where B.A == Self }
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// RUN: %target-swift-frontend -typecheck %s
|
|
||||||
|
|
||||||
protocol AuthenticationFlowStateMachine {
|
|
||||||
associatedtype StartState: AuthenticationFlowStateMachineStartState where StartState.StateMachine == Self
|
|
||||||
associatedtype NonFinalState: AuthenticationFlowStateMachineNonFinalState where NonFinalState.StateMachine == Self
|
|
||||||
associatedtype FlowError: AuthenticationFlowStateMachineFlowError where FlowError.StateMachine == Self
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol AuthenticationFlowStateMachineFlowError: Error {
|
|
||||||
associatedtype StateMachine: AuthenticationFlowStateMachine where StateMachine.FlowError == Self
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol AuthenticationFlowStateMachineStartState {
|
|
||||||
associatedtype StateMachine: AuthenticationFlowStateMachine where StateMachine.StartState == Self
|
|
||||||
var nonFinalState: StateMachine.NonFinalState { get }
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol AuthenticationFlowStateMachineNonFinalState {
|
|
||||||
associatedtype StateMachine: AuthenticationFlowStateMachine where StateMachine.NonFinalState == Self
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user