@@ -1061,16 +1061,6 @@ class AssociatedTypeInference {
1061
1061
bool isBetterSolution (const InferredTypeWitnessesSolution &first,
1062
1062
const InferredTypeWitnessesSolution &second);
1063
1063
1064
- // / Find the best solution.
1065
- // /
1066
- // / \param solutions All of the solutions to consider. On success,
1067
- // / this will contain only the best solution.
1068
- // /
1069
- // / \returns \c false if there was a single best solution,
1070
- // / \c true if no single best solution exists.
1071
- bool findBestSolution (
1072
- SmallVectorImpl<InferredTypeWitnessesSolution> &solutions);
1073
-
1074
1064
// / Emit a diagnostic for the case where there are no solutions at all
1075
1065
// / to consider.
1076
1066
// /
@@ -3015,8 +3005,11 @@ void AssociatedTypeInference::findSolutionsRec(
3015
3005
3016
3006
++NumSolutionStates;
3017
3007
3018
- // Validate and complete the solution.
3019
- // Fold the dependent member types within this type.
3008
+ // Fold any concrete dependent member types that remain among our
3009
+ // tentative type witnesses.
3010
+ //
3011
+ // FIXME: inferAbstractTypeWitnesses() also does this in a different way;
3012
+ // combine the two.
3020
3013
for (auto assocType : proto->getAssociatedTypeMembers ()) {
3021
3014
if (conformance->hasTypeWitness (assocType))
3022
3015
continue ;
@@ -3039,33 +3032,6 @@ void AssociatedTypeInference::findSolutionsRec(
3039
3032
known->first = replaced;
3040
3033
}
3041
3034
3042
- // Check whether our current solution matches the given solution.
3043
- auto matchesSolution =
3044
- [&](const InferredTypeWitnessesSolution &solution) {
3045
- for (const auto &existingTypeWitness : solution.TypeWitnesses ) {
3046
- auto typeWitness = typeWitnesses.begin (existingTypeWitness.first );
3047
- if (!typeWitness->first ->isEqual (existingTypeWitness.second .first ))
3048
- return false ;
3049
- }
3050
-
3051
- return true ;
3052
- };
3053
-
3054
- // If we've seen this solution already, bail out; there's no point in
3055
- // checking further.
3056
- if (llvm::any_of (solutions, matchesSolution)) {
3057
- LLVM_DEBUG (llvm::dbgs () << std::string (valueWitnesses.size (), ' +' )
3058
- << " + Duplicate valid solution found\n " ;);
3059
- ++NumDuplicateSolutionStates;
3060
- return ;
3061
- }
3062
- if (llvm::any_of (nonViableSolutions, matchesSolution)) {
3063
- LLVM_DEBUG (llvm::dbgs () << std::string (valueWitnesses.size (), ' +' )
3064
- << " + Duplicate invalid solution found\n " ;);
3065
- ++NumDuplicateSolutionStates;
3066
- return ;
3067
- }
3068
-
3069
3035
// / Check the current set of type witnesses.
3070
3036
bool invalid = checkCurrentTypeWitnesses (valueWitnesses);
3071
3037
@@ -3077,9 +3043,8 @@ void AssociatedTypeInference::findSolutionsRec(
3077
3043
<< " + Valid solution found\n " ;);
3078
3044
}
3079
3045
3080
- auto &solutionList = invalid ? nonViableSolutions : solutions;
3081
- solutionList.push_back (InferredTypeWitnessesSolution ());
3082
- auto &solution = solutionList.back ();
3046
+ // Build the solution.
3047
+ InferredTypeWitnessesSolution solution;
3083
3048
3084
3049
// Copy the type witnesses.
3085
3050
for (auto assocType : unresolvedAssocTypes) {
@@ -3092,14 +3057,58 @@ void AssociatedTypeInference::findSolutionsRec(
3092
3057
solution.NumValueWitnessesInProtocolExtensions
3093
3058
= numValueWitnessesInProtocolExtensions;
3094
3059
3095
- // If this solution was clearly better than the previous best solution,
3096
- // swap them.
3097
- if (solutionList.back ().NumValueWitnessesInProtocolExtensions
3098
- < solutionList.front ().NumValueWitnessesInProtocolExtensions ) {
3099
- std::swap (solutionList.front (), solutionList.back ());
3060
+ // We fold away non-viable solutions that have the same type witnesses.
3061
+ if (invalid) {
3062
+ auto matchesSolution = [&](const InferredTypeWitnessesSolution &other) {
3063
+ for (const auto &otherTypeWitness : other.TypeWitnesses ) {
3064
+ auto typeWitness = solution.TypeWitnesses .find (otherTypeWitness.first );
3065
+ if (!typeWitness->second .first ->isEqual (otherTypeWitness.second .first ))
3066
+ return false ;
3067
+ }
3068
+
3069
+ return true ;
3070
+ };
3071
+
3072
+ if (llvm::any_of (nonViableSolutions, matchesSolution)) {
3073
+ LLVM_DEBUG (llvm::dbgs () << std::string (valueWitnesses.size (), ' +' )
3074
+ << " + Duplicate invalid solution found\n " ;);
3075
+ ++NumDuplicateSolutionStates;
3076
+ return ;
3077
+ }
3078
+
3079
+ nonViableSolutions.push_back (std::move (solution));
3080
+ return ;
3100
3081
}
3101
3082
3102
- // We're done recording the solution.
3083
+ // For valid solutions, we want to find the best solution if one exists.
3084
+ // We maintain the invariant that no viable solution is clearly worse than
3085
+ // any other viable solution. If multiple viable solutions remain after
3086
+ // we're considered the entire search space, we have an ambiguous situation.
3087
+
3088
+ // If this solution is clearly worse than some existing solution, give up.
3089
+ if (llvm::any_of (solutions, [&](const InferredTypeWitnessesSolution &other) {
3090
+ return isBetterSolution (other, solution);
3091
+ })) {
3092
+ LLVM_DEBUG (llvm::dbgs () << std::string (valueWitnesses.size (), ' +' )
3093
+ << " + Solution is worse than some existing solution\n " ;);
3094
+ ++NumDuplicateSolutionStates;
3095
+ return ;
3096
+ }
3097
+
3098
+ // If any existing solutions are clearly worse than this solution,
3099
+ // remove them.
3100
+ llvm::erase_if (solutions, [&](const InferredTypeWitnessesSolution &other) {
3101
+ if (isBetterSolution (solution, other)) {
3102
+ LLVM_DEBUG (llvm::dbgs () << std::string (valueWitnesses.size (), ' +' )
3103
+ << " + Solution is better than some existing solution\n " ;);
3104
+ ++NumDuplicateSolutionStates;
3105
+ return true ;
3106
+ }
3107
+
3108
+ return false ;
3109
+ });
3110
+
3111
+ solutions.push_back (std::move (solution));
3103
3112
return ;
3104
3113
}
3105
3114
@@ -3414,6 +3423,23 @@ bool AssociatedTypeInference::isBetterSolution(
3414
3423
const InferredTypeWitnessesSolution &first,
3415
3424
const InferredTypeWitnessesSolution &second) {
3416
3425
assert (first.ValueWitnesses .size () == second.ValueWitnesses .size ());
3426
+
3427
+ if (first.NumValueWitnessesInProtocolExtensions <
3428
+ second.NumValueWitnessesInProtocolExtensions )
3429
+ return true ;
3430
+
3431
+ if (first.NumValueWitnessesInProtocolExtensions >
3432
+ second.NumValueWitnessesInProtocolExtensions )
3433
+ return false ;
3434
+
3435
+ // Dear reader: this is not a lexicographic order on tuple of value witnesses;
3436
+ // rather, (x_1, ..., x_n) < (y_1, ..., y_n) if and only if:
3437
+ //
3438
+ // - there exists at least one index i such that x_i < y_i.
3439
+ // - there does not exist any i such that y_i < x_i.
3440
+ //
3441
+ // that is, the order relation is independent of the order in which value
3442
+ // witnesses were pushed onto the stack.
3417
3443
bool firstBetter = false ;
3418
3444
bool secondBetter = false ;
3419
3445
for (unsigned i = 0 , n = first.ValueWitnesses .size (); i != n; ++i) {
@@ -3446,58 +3472,6 @@ bool AssociatedTypeInference::isBetterSolution(
3446
3472
return firstBetter;
3447
3473
}
3448
3474
3449
- bool AssociatedTypeInference::findBestSolution (
3450
- SmallVectorImpl<InferredTypeWitnessesSolution> &solutions) {
3451
- if (solutions.empty ()) return true ;
3452
- if (solutions.size () == 1 ) return false ;
3453
-
3454
- // The solution at the front has the smallest number of value witnesses found
3455
- // in protocol extensions, by construction.
3456
- unsigned bestNumValueWitnessesInProtocolExtensions
3457
- = solutions.front ().NumValueWitnessesInProtocolExtensions ;
3458
-
3459
- // Erase any solutions with more value witnesses in protocol
3460
- // extensions than the best.
3461
- solutions.erase (
3462
- std::remove_if (solutions.begin (), solutions.end (),
3463
- [&](const InferredTypeWitnessesSolution &solution) {
3464
- return solution.NumValueWitnessesInProtocolExtensions >
3465
- bestNumValueWitnessesInProtocolExtensions;
3466
- }),
3467
- solutions.end ());
3468
-
3469
- // If we're down to one solution, success!
3470
- if (solutions.size () == 1 ) return false ;
3471
-
3472
- // Find a solution that's at least as good as the solutions that follow it.
3473
- unsigned bestIdx = 0 ;
3474
- for (unsigned i = 1 , n = solutions.size (); i != n; ++i) {
3475
- if (isBetterSolution (solutions[i], solutions[bestIdx]))
3476
- bestIdx = i;
3477
- }
3478
-
3479
- // Make sure that solution is better than any of the other solutions.
3480
- bool ambiguous = false ;
3481
- for (unsigned i = 1 , n = solutions.size (); i != n; ++i) {
3482
- if (i != bestIdx && !isBetterSolution (solutions[bestIdx], solutions[i])) {
3483
- ambiguous = true ;
3484
- break ;
3485
- }
3486
- }
3487
-
3488
- // If the result was ambiguous, fail.
3489
- if (ambiguous) {
3490
- assert (solutions.size () != 1 && " should have succeeded somewhere above?" );
3491
- return true ;
3492
-
3493
- }
3494
- // Keep the best solution, erasing all others.
3495
- if (bestIdx != 0 )
3496
- solutions[0 ] = std::move (solutions[bestIdx]);
3497
- solutions.erase (solutions.begin () + 1 , solutions.end ());
3498
- return false ;
3499
- }
3500
-
3501
3475
namespace {
3502
3476
// / A failed type witness binding.
3503
3477
struct FailedTypeWitness {
@@ -3897,9 +3871,8 @@ auto AssociatedTypeInference::solve()
3897
3871
}
3898
3872
}
3899
3873
3900
- // Find the best solution.
3901
- if (!findBestSolution (solutions)) {
3902
- assert (solutions.size () == 1 && " Not a unique best solution?" );
3874
+ // Happy case: we found exactly one viable solution.
3875
+ if (solutions.size () == 1 ) {
3903
3876
// Form the resulting solution.
3904
3877
auto &typeWitnesses = solutions.front ().TypeWitnesses ;
3905
3878
for (auto assocType : unresolvedAssocTypes) {
0 commit comments