|
18 | 18 | #include "CSStep.h"
|
19 | 19 | #include "TypeChecker.h"
|
20 | 20 | #include "swift/AST/Types.h"
|
| 21 | +#include "swift/AST/GenericEnvironment.h" |
21 | 22 | #include "swift/Sema/ConstraintSystem.h"
|
22 | 23 | #include "llvm/ADT/ArrayRef.h"
|
23 | 24 | #include "llvm/ADT/SmallVector.h"
|
@@ -528,6 +529,60 @@ StepResult DisjunctionStep::resume(bool prevFailed) {
|
528 | 529 | return take(prevFailed);
|
529 | 530 | }
|
530 | 531 |
|
| 532 | +static bool isDeclSubstitutable(ValueDecl *declA, ValueDecl *declB) { |
| 533 | + auto *typeA = declA->getInterfaceType()->getAs<GenericFunctionType>(); |
| 534 | + auto *typeB = declB->getInterfaceType()->getAs<GenericFunctionType>(); |
| 535 | + |
| 536 | + if (!typeA || !typeB) |
| 537 | + return false; |
| 538 | + |
| 539 | + auto genericSignatureA = typeA->getGenericSignature(); |
| 540 | + auto genericSignatureB = typeB->getGenericSignature(); |
| 541 | + |
| 542 | + // Substitute generic parameters with their archetypes in each generic function. |
| 543 | + Type substTypeA = typeA->substGenericArgs( |
| 544 | + genericSignatureA->getGenericEnvironment()->getForwardingSubstitutionMap()); |
| 545 | + Type substTypeB = typeB->substGenericArgs( |
| 546 | + genericSignatureB->getGenericEnvironment()->getForwardingSubstitutionMap()); |
| 547 | + |
| 548 | + // Attempt to substitute archetypes from the second type with archetypes in the |
| 549 | + // same structural position in the first type. |
| 550 | + TypeSubstitutionMap substMap; |
| 551 | + substTypeB = substTypeB->substituteBindingsTo(substTypeA, |
| 552 | + [&](ArchetypeType *origType, CanType substType, |
| 553 | + ArchetypeType *, ArrayRef<ProtocolConformanceRef>) -> CanType { |
| 554 | + auto interfaceTy = origType->getInterfaceType()->getCanonicalType(); |
| 555 | + substMap[interfaceTy->getAs<SubstitutableType>()] = substType; |
| 556 | + return substType; |
| 557 | + }); |
| 558 | + |
| 559 | + if (!substTypeB) |
| 560 | + return false; |
| 561 | + |
| 562 | + auto result = TypeChecker::checkGenericArguments( |
| 563 | + declA->getDeclContext(), SourceLoc(), SourceLoc(), typeB, |
| 564 | + genericSignatureB->getGenericParams(), |
| 565 | + genericSignatureB->getRequirements(), |
| 566 | + QueryTypeSubstitutionMap{ substMap }); |
| 567 | + |
| 568 | + if (result != RequirementCheckResult::Success) |
| 569 | + return false; |
| 570 | + |
| 571 | + return substTypeA->isEqual(substTypeB); |
| 572 | +} |
| 573 | + |
| 574 | +static bool isGenericDisjunctionChoice(Constraint *constraint) { |
| 575 | + if (constraint->getKind() != ConstraintKind::BindOverload) |
| 576 | + return false; |
| 577 | + |
| 578 | + auto choice = constraint->getOverloadChoice(); |
| 579 | + if (!choice.isDecl()) |
| 580 | + return false; |
| 581 | + |
| 582 | + auto *funcDecl = dyn_cast<AbstractFunctionDecl>(choice.getDecl()); |
| 583 | + return funcDecl && funcDecl->isGeneric(); |
| 584 | +} |
| 585 | + |
531 | 586 | bool DisjunctionStep::shouldSkip(const DisjunctionChoice &choice) const {
|
532 | 587 | auto &ctx = CS.getASTContext();
|
533 | 588 |
|
@@ -556,6 +611,19 @@ bool DisjunctionStep::shouldSkip(const DisjunctionChoice &choice) const {
|
556 | 611 | if (ctx.TypeCheckerOpts.DisableConstraintSolverPerformanceHacks)
|
557 | 612 | return false;
|
558 | 613 |
|
| 614 | + // If the solver already found a solution with a better overload choice that |
| 615 | + // can be unconditionally substituted by the current choice, skip the current |
| 616 | + // choice. |
| 617 | + if (LastSolvedChoice && isGenericDisjunctionChoice(choice)) { |
| 618 | + auto *declA = LastSolvedChoice->first->getOverloadChoice().getDecl(); |
| 619 | + auto *declB = static_cast<Constraint *>(choice)->getOverloadChoice().getDecl(); |
| 620 | + |
| 621 | + if (TypeChecker::compareDeclarations(CS.DC, declA, declB) == Comparison::Better) { |
| 622 | + if (isDeclSubstitutable(declA, /*by=*/declB)) |
| 623 | + return skip("subtype"); |
| 624 | + } |
| 625 | + } |
| 626 | + |
559 | 627 | // If the solver already found a solution with a choice that did not
|
560 | 628 | // introduce any conversions (i.e., the score is not worse than the
|
561 | 629 | // current score), we can skip any generic operators with conformance
|
|
0 commit comments