Skip to content

[ConstraintSystem] Improve the "transitive conformance" heuristic and remove early conformance checking from DisjunctionStep::shouldSkip #38700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6479,6 +6479,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo(
// If the type doesn't conform, let's check whether
// an Optional or Unsafe{Mutable}Pointer from it would.

// If the current score is equal to the best score, fail without checking
// implicit conversions, because an implicit conversion would lead to a
// worse score anyway.
if (solverState && solverState->BestScore && CurrentScore == *solverState->BestScore)
return SolutionKind::Error;

SmallVector<Type, 4> typesToCheck;

// T -> Optional<T>
Expand Down
53 changes: 0 additions & 53 deletions lib/Sema/CSStep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,59 +639,6 @@ bool DisjunctionStep::shouldSkip(const DisjunctionChoice &choice) const {
}
}

// If the solver already found a solution with a choice that did not
// introduce any conversions (i.e., the score is not worse than the
// current score), we can skip any generic operators with conformance
// requirements that are not satisfied by any known argument types.
auto argFnType = CS.getAppliedDisjunctionArgumentFunction(Disjunction);
auto checkRequirementsEarly = [&]() -> bool {
auto bestScore = getBestScore(Solutions);
if (!(bestScore && choice.isGenericOperator() && argFnType))
return false;

auto currentScore = getCurrentScore();
for (unsigned i = 0; i < NumScoreKinds; ++i) {
if (i == SK_NonDefaultLiteral)
continue;

if (bestScore->Data[i] > currentScore.Data[i])
return false;
}

return true;
};
if (checkRequirementsEarly()) {
Constraint *constraint = choice;
auto *decl = constraint->getOverloadChoice().getDecl();
if (decl->getBaseIdentifier().isArithmeticOperator()) {
auto *useDC = constraint->getOverloadUseDC();
auto choiceType = CS.getEffectiveOverloadType(
constraint->getLocator(), constraint->getOverloadChoice(),
/*allowMembers=*/true, useDC);
auto choiceFnType = choiceType->getAs<FunctionType>();
auto genericFnType = decl->getInterfaceType()->getAs<GenericFunctionType>();
auto signature = genericFnType->getGenericSignature();

for (auto argParamPair : llvm::zip(argFnType->getParams(),
choiceFnType->getParams())) {
auto argType = std::get<0>(argParamPair).getPlainType();
auto paramType = std::get<1>(argParamPair).getPlainType();

// Only check argument types with no type variables that will be matched
// against a plain type parameter.
argType = argType->getCanonicalType()->getWithoutSpecifierType();
if (argType->hasTypeVariable() || !paramType->isTypeParameter())
continue;

for (auto *protocol : signature->getRequiredProtocols(paramType)) {
if (!TypeChecker::conformsToProtocol(argType, protocol,
useDC->getParentModule()))
return skip("unsatisfied");
}
}
}
}

// Don't attempt to solve for generic operators if we already have
// a non-generic solution.

Expand Down