@@ -1539,4 +1539,181 @@ int swift::compareDependentTypes(Type type1, Type type2) {
15391539 return result;
15401540
15411541 return 0 ;
1542+ }
1543+
1544+ void GenericSignature::verify () const {
1545+ auto canSig = getCanonicalSignature ();
1546+
1547+ PrettyStackTraceGenericSignature debugStack (" checking" , canSig);
1548+
1549+ auto canonicalRequirements = canSig.getRequirements ();
1550+
1551+ // We collect conformance requirements to check that they're minimal.
1552+ llvm::SmallDenseMap<CanType, SmallVector<ProtocolDecl *, 2 >, 2 > conformances;
1553+
1554+ // Check that the requirements satisfy certain invariants.
1555+ for (unsigned idx : indices (canonicalRequirements)) {
1556+ debugStack.setRequirement (idx);
1557+
1558+ const auto &reqt = canonicalRequirements[idx];
1559+
1560+ // Left-hand side must be a canonical type parameter.
1561+ if (reqt.getKind () != RequirementKind::SameType) {
1562+ if (!reqt.getFirstType ()->isTypeParameter ()) {
1563+ llvm::errs () << " Left-hand side must be a type parameter: " ;
1564+ reqt.dump (llvm::errs ());
1565+ llvm::errs () << " \n " ;
1566+ abort ();
1567+ }
1568+
1569+ if (!canSig->isCanonicalTypeInContext (reqt.getFirstType ())) {
1570+ llvm::errs () << " Left-hand side is not canonical: " ;
1571+ reqt.dump (llvm::errs ());
1572+ llvm::errs () << " \n " ;
1573+ abort ();
1574+ }
1575+ }
1576+
1577+ // Check canonicalization of requirement itself.
1578+ switch (reqt.getKind ()) {
1579+ case RequirementKind::Superclass:
1580+ if (!canSig->isCanonicalTypeInContext (reqt.getSecondType ())) {
1581+ llvm::errs () << " Right-hand side is not canonical: " ;
1582+ reqt.dump (llvm::errs ());
1583+ llvm::errs () << " \n " ;
1584+ abort ();
1585+ }
1586+ break ;
1587+
1588+ case RequirementKind::Layout:
1589+ break ;
1590+
1591+ case RequirementKind::SameType: {
1592+ auto isCanonicalAnchor = [&](Type type) {
1593+ if (auto *dmt = type->getAs <DependentMemberType>())
1594+ return canSig->isCanonicalTypeInContext (dmt->getBase ());
1595+ return type->is <GenericTypeParamType>();
1596+ };
1597+
1598+ auto firstType = reqt.getFirstType ();
1599+ auto secondType = reqt.getSecondType ();
1600+ if (!isCanonicalAnchor (firstType)) {
1601+ llvm::errs () << " Left hand side does not have a canonical parent: " ;
1602+ reqt.dump (llvm::errs ());
1603+ llvm::errs () << " \n " ;
1604+ abort ();
1605+ }
1606+
1607+ if (reqt.getSecondType ()->isTypeParameter ()) {
1608+ if (!isCanonicalAnchor (secondType)) {
1609+ llvm::errs () << " Right hand side does not have a canonical parent: " ;
1610+ reqt.dump (llvm::errs ());
1611+ llvm::errs () << " \n " ;
1612+ abort ();
1613+ }
1614+ if (compareDependentTypes (firstType, secondType) >= 0 ) {
1615+ llvm::errs () << " Out-of-order type parameters: " ;
1616+ reqt.dump (llvm::errs ());
1617+ llvm::errs () << " \n " ;
1618+ abort ();
1619+ }
1620+ } else {
1621+ if (!canSig->isCanonicalTypeInContext (secondType)) {
1622+ llvm::errs () << " Right hand side is not canonical: " ;
1623+ reqt.dump (llvm::errs ());
1624+ llvm::errs () << " \n " ;
1625+ abort ();
1626+ }
1627+ }
1628+ break ;
1629+ }
1630+
1631+ case RequirementKind::Conformance:
1632+ // Collect all conformance requirements on each type parameter.
1633+ conformances[CanType (reqt.getFirstType ())].push_back (
1634+ reqt.getProtocolDecl ());
1635+ break ;
1636+ }
1637+
1638+ // From here on, we're only interested in requirements beyond the first.
1639+ if (idx == 0 ) continue ;
1640+
1641+ // Make sure that the left-hand sides are in nondecreasing order.
1642+ const auto &prevReqt = canonicalRequirements[idx-1 ];
1643+ int compareLHS =
1644+ compareDependentTypes (prevReqt.getFirstType (), reqt.getFirstType ());
1645+ if (compareLHS > 0 ) {
1646+ llvm::errs () << " Out-of-order left-hand side: " ;
1647+ reqt.dump (llvm::errs ());
1648+ llvm::errs () << " \n " ;
1649+ abort ();
1650+ }
1651+
1652+ // If we have two same-type requirements where the left-hand sides differ
1653+ // but fall into the same equivalence class, we can check the form.
1654+ if (compareLHS < 0 && reqt.getKind () == RequirementKind::SameType &&
1655+ prevReqt.getKind () == RequirementKind::SameType &&
1656+ canSig->areSameTypeParameterInContext (prevReqt.getFirstType (),
1657+ reqt.getFirstType ())) {
1658+ // If it's a it's a type parameter, make sure the equivalence class is
1659+ // wired together sanely.
1660+ if (prevReqt.getSecondType ()->isTypeParameter ()) {
1661+ if (!prevReqt.getSecondType ()->isEqual (reqt.getFirstType ())) {
1662+ llvm::errs () << " Same-type requirement within an equiv. class "
1663+ << " is out-of-order: " ;
1664+ reqt.dump (llvm::errs ());
1665+ llvm::errs () << " \n " ;
1666+ abort ();
1667+ }
1668+ } else {
1669+ // Otherwise, the concrete types must match up.
1670+ if (!prevReqt.getSecondType ()->isEqual (reqt.getSecondType ())) {
1671+ llvm::errs () << " Inconsistent concrete requirement in equiv. class: " ;
1672+ reqt.dump (llvm::errs ());
1673+ llvm::errs () << " \n " ;
1674+ abort ();
1675+ }
1676+ }
1677+ }
1678+
1679+ // If we have a concrete same-type requirement, we shouldn't have any
1680+ // other requirements on the same type.
1681+ if (reqt.getKind () == RequirementKind::SameType &&
1682+ !reqt.getSecondType ()->isTypeParameter ()) {
1683+ if (compareLHS >= 0 ) {
1684+ llvm::errs () << " Concrete subject type should not have "
1685+ << " any other requirements: " ;
1686+ reqt.dump (llvm::errs ());
1687+ llvm::errs () << " \n " ;
1688+ abort ();
1689+ }
1690+ }
1691+
1692+ if (prevReqt.compare (reqt) >= 0 ) {
1693+ llvm::errs () << " Out-of-order requirement: " ;
1694+ reqt.dump (llvm::errs ());
1695+ llvm::errs () << " \n " ;
1696+ abort ();
1697+ }
1698+ }
1699+
1700+ // Make sure we don't have redundant protocol conformance requirements.
1701+ for (auto pair : conformances) {
1702+ const auto &protos = pair.second ;
1703+ auto canonicalProtos = protos;
1704+
1705+ // canonicalizeProtocols() will sort them and filter out any protocols that
1706+ // are refined by other protocols in the list. It should be a no-op at this
1707+ // point.
1708+ ProtocolType::canonicalizeProtocols (canonicalProtos);
1709+
1710+ if (protos.size () != canonicalProtos.size ()) {
1711+ llvm::errs () << " Redundant conformance requirements in signature\n " ;
1712+ abort ();
1713+ }
1714+ if (!std::equal (protos.begin (), protos.end (), canonicalProtos.begin ())) {
1715+ llvm::errs () << " Out-of-order conformance requirements\n " ;
1716+ abort ();
1717+ }
1718+ }
15421719}
0 commit comments