|
45 | 45 | #include "swift/AST/Types.h"
|
46 | 46 | #include "swift/AST/TypeCheckRequests.h"
|
47 | 47 | #include "swift/Basic/Defer.h"
|
| 48 | +#include "swift/Basic/Statistic.h" |
48 | 49 | #include "swift/ClangImporter/ClangModule.h"
|
49 | 50 | #include "llvm/ADT/Statistic.h"
|
50 | 51 | #include "llvm/ADT/TinyPtrVector.h"
|
@@ -578,6 +579,24 @@ struct InferredAssociatedTypesByWitness {
|
578 | 579 |
|
579 | 580 | void dump(llvm::raw_ostream &out, unsigned indent) const;
|
580 | 581 |
|
| 582 | + bool operator==(const InferredAssociatedTypesByWitness &other) const { |
| 583 | + if (Inferred.size() != other.Inferred.size()) |
| 584 | + return false; |
| 585 | + |
| 586 | + for (unsigned i = 0, e = Inferred.size(); i < e; ++i) { |
| 587 | + if (Inferred[i].first != other.Inferred[i].first) |
| 588 | + return false; |
| 589 | + if (!Inferred[i].second->isEqual(other.Inferred[i].second)) |
| 590 | + return false; |
| 591 | + } |
| 592 | + |
| 593 | + return true; |
| 594 | + } |
| 595 | + |
| 596 | + bool operator!=(const InferredAssociatedTypesByWitness &other) const { |
| 597 | + return !(*this == other); |
| 598 | + } |
| 599 | + |
581 | 600 | SWIFT_DEBUG_DUMP;
|
582 | 601 | };
|
583 | 602 |
|
@@ -1533,6 +1552,39 @@ static InferenceCandidateKind checkInferenceCandidate(
|
1533 | 1552 | return InferenceCandidateKind::Good;
|
1534 | 1553 | }
|
1535 | 1554 |
|
| 1555 | +/// If all terms introduce identical bindings and none come from a protocol |
| 1556 | +/// extension, no choice between them can change the chosen solution, so |
| 1557 | +/// collapse down to one. |
| 1558 | +/// |
| 1559 | +/// WARNING: This does not readily generalize to disjunctions that have |
| 1560 | +/// multiple duplicated terms, eg A \/ A \/ B \/ B, because the relative |
| 1561 | +/// order of the value witnesses binding each A and each B might be weird. |
| 1562 | +static void tryOptimizeDisjunction(InferredAssociatedTypesByWitnesses &result) { |
| 1563 | + // We assume there is at least one term. |
| 1564 | + if (result.empty()) |
| 1565 | + return; |
| 1566 | + |
| 1567 | + for (unsigned i = 0, e = result.size(); i < e; ++i) { |
| 1568 | + // Skip the optimization if we have non-viable bindings anywhere. |
| 1569 | + if (!result[i].NonViable.empty()) |
| 1570 | + return; |
| 1571 | + |
| 1572 | + // Skip the optimization if anything came from a default type alias |
| 1573 | + // or protocol extension; the ranking is hairier in that case. |
| 1574 | + if (!result[i].Witness || |
| 1575 | + result[i].Witness->getDeclContext()->getExtendedProtocolDecl()) |
| 1576 | + return; |
| 1577 | + |
| 1578 | + // Skip the optimization if any two consecutive terms contain distinct |
| 1579 | + // bindings. |
| 1580 | + if (i > 0 && result[i - 1] != result[i]) |
| 1581 | + return; |
| 1582 | + } |
| 1583 | + |
| 1584 | + // This disjunction is trivial. |
| 1585 | + result.resize(1); |
| 1586 | +} |
| 1587 | + |
1536 | 1588 | /// Create an initial constraint system for the associated type inference solver.
|
1537 | 1589 | ///
|
1538 | 1590 | /// Each protocol requirement defines a disjunction, where each disjunction
|
@@ -1743,7 +1795,9 @@ AssociatedTypeInference::getPotentialTypeWitnessesFromRequirement(
|
1743 | 1795 |
|
1744 | 1796 | result.push_back(std::move(witnessResult));
|
1745 | 1797 | next_witness:;
|
1746 |
| -} |
| 1798 | + } |
| 1799 | + |
| 1800 | + tryOptimizeDisjunction(result); |
1747 | 1801 |
|
1748 | 1802 | if (hadTautologicalWitness && !result.empty()) {
|
1749 | 1803 | // Create a dummy entry, but only if there was at least one other witness;
|
@@ -3380,6 +3434,9 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
|
3380 | 3434 | void AssociatedTypeInference::findSolutions(
|
3381 | 3435 | ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes,
|
3382 | 3436 | SmallVectorImpl<InferredTypeWitnessesSolution> &solutions) {
|
| 3437 | + FrontendStatsTracer StatsTracer(getASTContext().Stats, |
| 3438 | + "associated-type-inference", conformance); |
| 3439 | + |
3383 | 3440 | SmallVector<InferredTypeWitnessesSolution, 4> nonViableSolutions;
|
3384 | 3441 | SmallVector<std::pair<ValueDecl *, ValueDecl *>, 4> valueWitnesses;
|
3385 | 3442 | findSolutionsRec(unresolvedAssocTypes, solutions, nonViableSolutions,
|
|
0 commit comments