@@ -1539,4 +1539,181 @@ int swift::compareDependentTypes(Type type1, Type type2) {
1539
1539
return result;
1540
1540
1541
1541
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
+ }
1542
1719
}
0 commit comments