25
25
#include " swift/AST/Types.h"
26
26
#include " swift/Basic/Defer.h"
27
27
#include " swift/ClangImporter/ClangModule.h"
28
+ #include " llvm/ADT/Statistic.h"
28
29
#include " llvm/ADT/TinyPtrVector.h"
29
30
30
31
#define DEBUG_TYPE " Associated type inference"
31
32
#include " llvm/Support/Debug.h"
32
33
34
+ STATISTIC (NumSolutionStates, " # of solution states visited" );
35
+ STATISTIC (NumSolutionStatesFailedCheck,
36
+ " # of solution states that failed constraints check" );
37
+ STATISTIC (NumConstrainedExtensionChecks,
38
+ " # of constrained extension checks" );
39
+ STATISTIC (NumConstrainedExtensionChecksFailed,
40
+ " # of constrained extension checks failed" );
41
+ STATISTIC (NumDuplicateSolutionStates,
42
+ " # of duplicate solution states " );
43
+
33
44
using namespace swift ;
34
45
35
46
void InferredAssociatedTypesByWitness::dump () const {
@@ -1042,26 +1053,6 @@ AssociatedTypeInference::getSubstOptionsWithCurrentTypeWitnesses() {
1042
1053
bool AssociatedTypeInference::checkCurrentTypeWitnesses (
1043
1054
const SmallVectorImpl<std::pair<ValueDecl *, ValueDecl *>>
1044
1055
&valueWitnesses) {
1045
- // Fold the dependent member types within this type.
1046
- for (auto assocType : proto->getAssociatedTypeMembers ()) {
1047
- if (conformance->hasTypeWitness (assocType))
1048
- continue ;
1049
-
1050
- // If the type binding does not have a type parameter, there's nothing
1051
- // to do.
1052
- auto known = typeWitnesses.begin (assocType);
1053
- assert (known != typeWitnesses.end ());
1054
- if (!known->first ->hasTypeParameter () &&
1055
- !known->first ->hasDependentMember ())
1056
- continue ;
1057
-
1058
- Type replaced = substCurrentTypeWitnesses (known->first );
1059
- if (replaced.isNull ())
1060
- return true ;
1061
-
1062
- known->first = replaced;
1063
- }
1064
-
1065
1056
// If we don't have a requirement signature for this protocol, bail out.
1066
1057
// FIXME: We should never get to this point. Or we should always fail.
1067
1058
if (!proto->isRequirementSignatureComputed ()) return false ;
@@ -1090,6 +1081,7 @@ bool AssociatedTypeInference::checkCurrentTypeWitnesses(
1090
1081
switch (result) {
1091
1082
case RequirementCheckResult::Failure:
1092
1083
case RequirementCheckResult::UnsatisfiedDependency:
1084
+ ++NumSolutionStatesFailedCheck;
1093
1085
return true ;
1094
1086
1095
1087
case RequirementCheckResult::Success:
@@ -1113,7 +1105,11 @@ bool AssociatedTypeInference::checkCurrentTypeWitnesses(
1113
1105
if (!ext->isConstrainedExtension ()) continue ;
1114
1106
if (!checkedExtensions.insert (ext).second ) continue ;
1115
1107
1116
- if (checkConstrainedExtension (ext)) return true ;
1108
+ ++NumConstrainedExtensionChecks;
1109
+ if (checkConstrainedExtension (ext)) {
1110
+ ++NumConstrainedExtensionChecksFailed;
1111
+ return true ;
1112
+ }
1117
1113
}
1118
1114
1119
1115
return false ;
@@ -1204,27 +1200,54 @@ void AssociatedTypeInference::findSolutionsRec(
1204
1200
return ;
1205
1201
}
1206
1202
1207
- // / Check the current set of type witnesses.
1208
- bool invalid = checkCurrentTypeWitnesses (valueWitnesses);
1203
+ ++NumSolutionStates;
1204
+
1205
+ // Fold the dependent member types within this type.
1206
+ for (auto assocType : proto->getAssociatedTypeMembers ()) {
1207
+ if (conformance->hasTypeWitness (assocType))
1208
+ continue ;
1209
1209
1210
- // Determine whether there is already a solution with the same
1211
- // bindings.
1212
- for (const auto &solution : solutions) {
1213
- bool sameSolution = true ;
1210
+ // If the type binding does not have a type parameter, there's nothing
1211
+ // to do.
1212
+ auto known = typeWitnesses.begin (assocType);
1213
+ assert (known != typeWitnesses.end ());
1214
+ if (!known->first ->hasTypeParameter () &&
1215
+ !known->first ->hasDependentMember ())
1216
+ continue ;
1217
+
1218
+ Type replaced = substCurrentTypeWitnesses (known->first );
1219
+ if (replaced.isNull ())
1220
+ return ;
1221
+
1222
+ known->first = replaced;
1223
+ }
1224
+
1225
+ // Check whether our current solution matches the given solution.
1226
+ auto matchesSolution =
1227
+ [&](const InferredTypeWitnessesSolution &solution) {
1214
1228
for (const auto &existingTypeWitness : solution.TypeWitnesses ) {
1215
1229
auto typeWitness = typeWitnesses.begin (existingTypeWitness.first );
1216
- if (!typeWitness->first ->isEqual (existingTypeWitness.second .first )) {
1217
- sameSolution = false ;
1218
- break ;
1219
- }
1230
+ if (!typeWitness->first ->isEqual (existingTypeWitness.second .first ))
1231
+ return false ;
1220
1232
}
1221
1233
1222
- // We found the same solution. There is no point in recording
1223
- // a new one.
1224
- if (sameSolution)
1225
- return ;
1234
+ return true ;
1235
+ };
1236
+
1237
+ // If we've seen this solution already, bail out; there's no point in
1238
+ // checking further.
1239
+ if (std::find_if (solutions.begin (), solutions.end (), matchesSolution)
1240
+ != solutions.end () ||
1241
+ std::find_if (nonViableSolutions.begin (), nonViableSolutions.end (),
1242
+ matchesSolution)
1243
+ != nonViableSolutions.end ()) {
1244
+ ++NumDuplicateSolutionStates;
1245
+ return ;
1226
1246
}
1227
1247
1248
+ // / Check the current set of type witnesses.
1249
+ bool invalid = checkCurrentTypeWitnesses (valueWitnesses);
1250
+
1228
1251
auto &solutionList = invalid ? nonViableSolutions : solutions;
1229
1252
solutionList.push_back (InferredTypeWitnessesSolution ());
1230
1253
auto &solution = solutionList.back ();
0 commit comments