Skip to content

Commit b99c2c1

Browse files
authored
Merge pull request swiftlang#38837 from slavapestov/refactor-canonical-type-order
Refactor canonical type ordering
2 parents b204cb8 + d4f85a3 commit b99c2c1

File tree

7 files changed

+136
-187
lines changed

7 files changed

+136
-187
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,11 @@ inline bool CanGenericSignature::isActuallyCanonicalOrNull() const {
472472
getPointer()->isCanonical();
473473
}
474474

475+
int compareAssociatedTypes(AssociatedTypeDecl *assocType1,
476+
AssociatedTypeDecl *assocType2);
477+
478+
int compareDependentTypes(Type type1, Type type2);
479+
475480
} // end namespace swift
476481

477482
namespace llvm {

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,9 +1677,6 @@ inline bool isErrorResult(GenericSignatureBuilder::ConstraintResult result) {
16771677
llvm_unreachable("unhandled result");
16781678
}
16791679

1680-
/// Canonical ordering for dependent types.
1681-
int compareDependentTypes(Type type1, Type type2);
1682-
16831680
template<typename T>
16841681
Type GenericSignatureBuilder::Constraint<T>::getSubjectDependentType(
16851682
TypeArrayView<GenericTypeParamType> genericParams) const {

include/swift/AST/Requirement.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class Requirement
9292
/// superclass requirement, 'T : C' cannot be satisfied.
9393
bool canBeSatisfied() const;
9494

95+
/// Linear order on requirements in a generic signature.
96+
int compare(const Requirement &other) const;
97+
9598
SWIFT_DEBUG_DUMP;
9699
void dump(raw_ostream &out) const;
97100
void print(raw_ostream &os, const PrintOptions &opts) const;

lib/AST/GenericSignature.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,3 +1430,105 @@ bool Requirement::canBeSatisfied() const {
14301430

14311431
llvm_unreachable("Bad requirement kind");
14321432
}
1433+
1434+
/// Determine the canonical ordering of requirements.
1435+
static unsigned getRequirementKindOrder(RequirementKind kind) {
1436+
switch (kind) {
1437+
case RequirementKind::Conformance: return 2;
1438+
case RequirementKind::Superclass: return 0;
1439+
case RequirementKind::SameType: return 3;
1440+
case RequirementKind::Layout: return 1;
1441+
}
1442+
llvm_unreachable("unhandled kind");
1443+
}
1444+
1445+
/// Linear order on requirements in a generic signature.
1446+
int Requirement::compare(const Requirement &other) const {
1447+
int compareLHS =
1448+
compareDependentTypes(getFirstType(), other.getFirstType());
1449+
1450+
if (compareLHS != 0)
1451+
return compareLHS;
1452+
1453+
int compareKind = (getRequirementKindOrder(getKind()) -
1454+
getRequirementKindOrder(other.getKind()));
1455+
1456+
if (compareKind != 0)
1457+
return compareKind;
1458+
1459+
// We should only have multiple conformance requirements.
1460+
assert(getKind() == RequirementKind::Conformance);
1461+
1462+
int compareProtos =
1463+
TypeDecl::compare(getProtocolDecl(), other.getProtocolDecl());
1464+
1465+
assert(compareProtos != 0 && "Duplicate conformance requirement");
1466+
return compareProtos;
1467+
}
1468+
1469+
/// Compare two associated types.
1470+
int swift::compareAssociatedTypes(AssociatedTypeDecl *assocType1,
1471+
AssociatedTypeDecl *assocType2) {
1472+
// - by name.
1473+
if (int result = assocType1->getName().str().compare(
1474+
assocType2->getName().str()))
1475+
return result;
1476+
1477+
// Prefer an associated type with no overrides (i.e., an anchor) to one
1478+
// that has overrides.
1479+
bool hasOverridden1 = !assocType1->getOverriddenDecls().empty();
1480+
bool hasOverridden2 = !assocType2->getOverriddenDecls().empty();
1481+
if (hasOverridden1 != hasOverridden2)
1482+
return hasOverridden1 ? +1 : -1;
1483+
1484+
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
1485+
auto proto1 = assocType1->getProtocol();
1486+
auto proto2 = assocType2->getProtocol();
1487+
if (int compareProtocols = TypeDecl::compare(proto1, proto2))
1488+
return compareProtocols;
1489+
1490+
// Error case: if we have two associated types with the same name in the
1491+
// same protocol, just tie-break based on address.
1492+
if (assocType1 != assocType2)
1493+
return assocType1 < assocType2 ? -1 : +1;
1494+
1495+
return 0;
1496+
}
1497+
1498+
/// Canonical ordering for type parameters.
1499+
int swift::compareDependentTypes(Type type1, Type type2) {
1500+
// Fast-path check for equality.
1501+
if (type1->isEqual(type2)) return 0;
1502+
1503+
// Ordering is as follows:
1504+
// - Generic params
1505+
auto gp1 = type1->getAs<GenericTypeParamType>();
1506+
auto gp2 = type2->getAs<GenericTypeParamType>();
1507+
if (gp1 && gp2)
1508+
return GenericParamKey(gp1) < GenericParamKey(gp2) ? -1 : +1;
1509+
1510+
// A generic parameter is always ordered before a nested type.
1511+
if (static_cast<bool>(gp1) != static_cast<bool>(gp2))
1512+
return gp1 ? -1 : +1;
1513+
1514+
// - Dependent members
1515+
auto depMemTy1 = type1->castTo<DependentMemberType>();
1516+
auto depMemTy2 = type2->castTo<DependentMemberType>();
1517+
1518+
// - by base, so t_0_n.`P.T` < t_1_m.`P.T`
1519+
if (int compareBases =
1520+
compareDependentTypes(depMemTy1->getBase(), depMemTy2->getBase()))
1521+
return compareBases;
1522+
1523+
// - by name, so t_n_m.`P.T` < t_n_m.`P.U`
1524+
if (int compareNames = depMemTy1->getName().str().compare(
1525+
depMemTy2->getName().str()))
1526+
return compareNames;
1527+
1528+
auto *assocType1 = depMemTy1->getAssocType();
1529+
auto *assocType2 = depMemTy2->getAssocType();
1530+
if (int result = compareAssociatedTypes(assocType1, assocType2))
1531+
return result;
1532+
1533+
return 0;
1534+
}

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 2 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,35 +1979,6 @@ bool EquivalenceClass::isConformanceSatisfiedBySuperclass(
19791979
return false;
19801980
}
19811981

1982-
/// Compare two associated types.
1983-
static int compareAssociatedTypes(AssociatedTypeDecl *assocType1,
1984-
AssociatedTypeDecl *assocType2) {
1985-
// - by name.
1986-
if (int result = assocType1->getName().str().compare(
1987-
assocType2->getName().str()))
1988-
return result;
1989-
1990-
// Prefer an associated type with no overrides (i.e., an anchor) to one
1991-
// that has overrides.
1992-
bool hasOverridden1 = !assocType1->getOverriddenDecls().empty();
1993-
bool hasOverridden2 = !assocType2->getOverriddenDecls().empty();
1994-
if (hasOverridden1 != hasOverridden2)
1995-
return hasOverridden1 ? +1 : -1;
1996-
1997-
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
1998-
auto proto1 = assocType1->getProtocol();
1999-
auto proto2 = assocType2->getProtocol();
2000-
if (int compareProtocols = TypeDecl::compare(proto1, proto2))
2001-
return compareProtocols;
2002-
2003-
// Error case: if we have two associated types with the same name in the
2004-
// same protocol, just tie-break based on address.
2005-
if (assocType1 != assocType2)
2006-
return assocType1 < assocType2 ? -1 : +1;
2007-
2008-
return 0;
2009-
}
2010-
20111982
static void lookupConcreteNestedType(NominalTypeDecl *decl,
20121983
Identifier name,
20131984
SmallVectorImpl<TypeDecl *> &concreteDecls) {
@@ -2511,44 +2482,6 @@ auto PotentialArchetype::getRepresentative() const -> PotentialArchetype * {
25112482
return result;
25122483
}
25132484

2514-
/// Canonical ordering for dependent types.
2515-
int swift::compareDependentTypes(Type type1, Type type2) {
2516-
// Fast-path check for equality.
2517-
if (type1->isEqual(type2)) return 0;
2518-
2519-
// Ordering is as follows:
2520-
// - Generic params
2521-
auto gp1 = type1->getAs<GenericTypeParamType>();
2522-
auto gp2 = type2->getAs<GenericTypeParamType>();
2523-
if (gp1 && gp2)
2524-
return GenericParamKey(gp1) < GenericParamKey(gp2) ? -1 : +1;
2525-
2526-
// A generic parameter is always ordered before a nested type.
2527-
if (static_cast<bool>(gp1) != static_cast<bool>(gp2))
2528-
return gp1 ? -1 : +1;
2529-
2530-
// - Dependent members
2531-
auto depMemTy1 = type1->castTo<DependentMemberType>();
2532-
auto depMemTy2 = type2->castTo<DependentMemberType>();
2533-
2534-
// - by base, so t_0_n.`P.T` < t_1_m.`P.T`
2535-
if (int compareBases =
2536-
compareDependentTypes(depMemTy1->getBase(), depMemTy2->getBase()))
2537-
return compareBases;
2538-
2539-
// - by name, so t_n_m.`P.T` < t_n_m.`P.U`
2540-
if (int compareNames = depMemTy1->getName().str().compare(
2541-
depMemTy2->getName().str()))
2542-
return compareNames;
2543-
2544-
auto *assocType1 = depMemTy1->getAssocType();
2545-
auto *assocType2 = depMemTy2->getAssocType();
2546-
if (int result = compareAssociatedTypes(assocType1, assocType2))
2547-
return result;
2548-
2549-
return 0;
2550-
}
2551-
25522485
/// Compare two dependent paths to determine which is better.
25532486
static int compareDependentPaths(ArrayRef<AssociatedTypeDecl *> path1,
25542487
ArrayRef<AssociatedTypeDecl *> path2) {
@@ -7915,43 +7848,9 @@ static Optional<Requirement> createRequirement(RequirementKind kind,
79157848
}
79167849
}
79177850

7918-
/// Determine the canonical ordering of requirements.
7919-
static unsigned getRequirementKindOrder(RequirementKind kind) {
7920-
switch (kind) {
7921-
case RequirementKind::Conformance: return 2;
7922-
case RequirementKind::Superclass: return 0;
7923-
case RequirementKind::SameType: return 3;
7924-
case RequirementKind::Layout: return 1;
7925-
}
7926-
llvm_unreachable("unhandled kind");
7927-
}
7928-
79297851
static int compareRequirements(const Requirement *lhsPtr,
79307852
const Requirement *rhsPtr) {
7931-
auto &lhs = *lhsPtr;
7932-
auto &rhs = *rhsPtr;
7933-
7934-
int compareLHS =
7935-
compareDependentTypes(lhs.getFirstType(), rhs.getFirstType());
7936-
7937-
if (compareLHS != 0)
7938-
return compareLHS;
7939-
7940-
int compareKind = (getRequirementKindOrder(lhs.getKind()) -
7941-
getRequirementKindOrder(rhs.getKind()));
7942-
7943-
if (compareKind != 0)
7944-
return compareKind;
7945-
7946-
// We should only have multiple conformance requirements.
7947-
assert(lhs.getKind() == RequirementKind::Conformance);
7948-
7949-
int compareProtos =
7950-
TypeDecl::compare(lhs.getProtocolDecl(), rhs.getProtocolDecl());
7951-
7952-
assert(compareProtos != 0 && "Duplicate conformance requirement");
7953-
7954-
return compareProtos;
7853+
return lhsPtr->compare(*rhsPtr);
79557854
}
79567855

79577856
void GenericSignatureBuilder::enumerateRequirements(
@@ -8180,7 +8079,7 @@ static void checkGenericSignature(CanGenericSignature canSig,
81808079
"Concrete subject type should not have any other requirements");
81818080
}
81828081

8183-
assert(compareRequirements(&prevReqt, &reqt) < 0 &&
8082+
assert(prevReqt.compare(reqt) < 0 &&
81848083
"Out-of-order requirements");
81858084
}
81868085
}

lib/AST/RequirementMachine/GenericSignatureQueries.cpp

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -575,35 +575,6 @@ RequirementMachine::getConformanceAccessPath(Type type,
575575
}
576576
}
577577

578-
/// Compare two associated types.
579-
static int compareAssociatedTypes(AssociatedTypeDecl *assocType1,
580-
AssociatedTypeDecl *assocType2) {
581-
// - by name.
582-
if (int result = assocType1->getName().str().compare(
583-
assocType2->getName().str()))
584-
return result;
585-
586-
// Prefer an associated type with no overrides (i.e., an anchor) to one
587-
// that has overrides.
588-
bool hasOverridden1 = !assocType1->getOverriddenDecls().empty();
589-
bool hasOverridden2 = !assocType2->getOverriddenDecls().empty();
590-
if (hasOverridden1 != hasOverridden2)
591-
return hasOverridden1 ? +1 : -1;
592-
593-
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
594-
auto proto1 = assocType1->getProtocol();
595-
auto proto2 = assocType2->getProtocol();
596-
if (int compareProtocols = TypeDecl::compare(proto1, proto2))
597-
return compareProtocols;
598-
599-
// Error case: if we have two associated types with the same name in the
600-
// same protocol, just tie-break based on address.
601-
if (assocType1 != assocType2)
602-
return assocType1 < assocType2 ? -1 : +1;
603-
604-
return 0;
605-
}
606-
607578
static void lookupConcreteNestedType(NominalTypeDecl *decl,
608579
Identifier name,
609580
SmallVectorImpl<TypeDecl *> &concreteDecls) {

0 commit comments

Comments
 (0)