@@ -987,18 +987,14 @@ static bool argumentMismatchIsNearMiss(Type argType, Type paramType) {
987
987
// / and equal fixed type portions, and return by reference each archetype and
988
988
// / the matching portion of the actual arg type where that archetype appears.
989
989
static bool findGenericSubstitutions (DeclContext *dc, Type paramType, Type actualArgType,
990
- SmallVector<ArchetypeType *, 4 > &archetypes,
991
- SmallVector<Type, 4 > &substitutions) {
990
+ TypeSubstitutionMap &archetypesMap) {
992
991
class GenericVisitor : public TypeMatcher <GenericVisitor> {
993
992
DeclContext *dc;
994
- SmallVector<ArchetypeType *, 4 > &archetypes;
995
- SmallVector<Type, 4 > &substitutions;
993
+ TypeSubstitutionMap &archetypesMap;
996
994
997
995
public:
998
- GenericVisitor (DeclContext *dc,
999
- SmallVector<ArchetypeType *, 4 > &archetypes,
1000
- SmallVector<Type, 4 > &substitutions)
1001
- : dc(dc), archetypes(archetypes), substitutions(substitutions) {}
996
+ GenericVisitor (DeclContext *dc, TypeSubstitutionMap &archetypesMap)
997
+ : dc(dc), archetypesMap(archetypesMap) {}
1002
998
1003
999
bool mismatch (TypeBase *paramType, TypeBase *argType) {
1004
1000
return paramType->isEqual (argType);
@@ -1010,12 +1006,10 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, Type actua
1010
1006
type = ArchetypeBuilder::mapTypeIntoContext (dc, paramType);
1011
1007
1012
1008
if (auto archetype = type->getAs <ArchetypeType>()) {
1013
- for (unsigned i = 0 , c = archetypes.size (); i < c; i++) {
1014
- if (archetypes[i]->isEqual (archetype))
1015
- return substitutions[i]->isEqual (argType);
1016
- }
1017
- archetypes.push_back (archetype);
1018
- substitutions.push_back (argType);
1009
+ auto existing = archetypesMap[archetype];
1010
+ if (existing)
1011
+ return existing->isEqual (argType);
1012
+ archetypesMap[archetype] = argType;
1019
1013
return true ;
1020
1014
}
1021
1015
return false ;
@@ -1030,15 +1024,22 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, Type actua
1030
1024
if (dc && original->isTypeParameter ())
1031
1025
original = ArchetypeBuilder::mapTypeIntoContext (dc, original);
1032
1026
1033
- if (auto archetype = original->getAs <ArchetypeType>()) {
1034
- archetypes.push_back (archetype);
1035
- substitutions.push_back (substitution->getReplacementType ());
1036
- }
1027
+ Type replacement = substitution->getReplacementType ();
1028
+ // If the replacement is itself an archetype, then the constraint
1029
+ // system was asserting equivalencies between different levels of
1030
+ // generics, rather than binding a generic to a concrete type (and we
1031
+ // don't/won't have a concrete type). In which case, it is the
1032
+ // replacement we are interested in, since it is the one in our current
1033
+ // context. That generic type should equal itself.
1034
+ if (auto ourGeneric = replacement->getAs <ArchetypeType>())
1035
+ archetypesMap[ourGeneric] = replacement;
1036
+ else if (auto archetype = original->getAs <ArchetypeType>())
1037
+ archetypesMap[archetype] = replacement;
1037
1038
}
1038
1039
return false ;
1039
1040
});
1040
1041
1041
- GenericVisitor visitor (dc, archetypes, substitutions );
1042
+ GenericVisitor visitor (dc, archetypesMap );
1042
1043
return visitor.match (paramType, actualArgType);
1043
1044
}
1044
1045
@@ -1085,18 +1086,20 @@ CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
1085
1086
// their type and count the number of mismatched arguments.
1086
1087
unsigned mismatchingArgs = 0 ;
1087
1088
1088
- // Checking of archetypes.
1089
- // FIXME: For now just trying to verify applicability of arguments with only
1090
- // a single generic variable. Ideally we'd create a ConstraintSystem with
1091
- // type variables for all generics and solve it with the given argument types.
1092
- Type singleArchetype = nullptr ;
1093
- Type matchingArgType = nullptr ;
1089
+ // Known mapping of archetypes in all arguments so far. An archetype may map
1090
+ // to another archetype if the constraint system substituted one for another.
1091
+ TypeSubstitutionMap allGenericSubstitutions;
1094
1092
1095
- // Number of args of generic archetype which are mismatched because
1093
+ // Number of args of one generic archetype which are mismatched because
1096
1094
// isSubstitutableFor() has failed. If all mismatches are of this type, we'll
1097
1095
// return a different closeness for better diagnoses.
1096
+ Type nonSubstitutableArchetype = nullptr ;
1098
1097
unsigned nonSubstitutableArgs = 0 ;
1099
1098
1099
+ // The type of failure is that multiple occurrences of the same generic are
1100
+ // being passed arguments with different concrete types.
1101
+ bool genericWithDifferingConcreteTypes = false ;
1102
+
1100
1103
// We classify an argument mismatch as being a "near" miss if it is a very
1101
1104
// likely match due to a common sort of problem (e.g. wrong flags on a
1102
1105
// function type, optional where none was expected, etc). This allows us to
@@ -1122,75 +1125,77 @@ CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
1122
1125
1123
1126
// FIXME: Right now, a "matching" overload is one with a parameter whose
1124
1127
// type is identical to the argument type, or substitutable via handling
1125
- // of functions with a single archetype in one or more parameters.
1128
+ // of functions with primary archetypes in one or more parameters.
1126
1129
// We can still do something more sophisticated with this.
1127
1130
// FIXME: Use TC.isConvertibleTo?
1128
1131
1129
- SmallVector<ArchetypeType *, 4 > archetypes;
1130
- SmallVector<Type, 4 > substitutions;
1132
+ TypeSubstitutionMap archetypesMap;
1131
1133
bool matched;
1132
- if (paramType->is <UnresolvedType>())
1134
+ if (paramType->is <UnresolvedType>() || rArgType-> hasTypeVariable () )
1133
1135
matched = false ;
1134
1136
else
1135
- matched = findGenericSubstitutions (dc, paramType, rArgType,
1136
- archetypes, substitutions);
1137
+ matched = findGenericSubstitutions (dc, paramType, rArgType, archetypesMap);
1137
1138
1138
- if (matched && archetypes.size () == 0 )
1139
- continue ;
1140
- if (matched && archetypes.size () == 1 && !rArgType->hasTypeVariable ()) {
1141
- auto archetype = archetypes[0 ];
1142
- auto substitution = substitutions[0 ];
1143
-
1144
- if (singleArchetype) {
1145
- if (!archetype->isEqual (singleArchetype))
1146
- // Multiple archetypes, too complicated.
1147
- return { CC_ArgumentMismatch, {}};
1139
+ if (matched) {
1140
+ for (auto pair : archetypesMap) {
1141
+ auto archetype = pair.first ->castTo <ArchetypeType>();
1142
+ auto substitution = pair.second ;
1148
1143
1149
- if (substitution->isEqual (matchingArgType)) {
1150
- if (nonSubstitutableArgs == 0 )
1151
- continue ;
1152
- ++nonSubstitutableArgs;
1153
- mismatchesAreNearMisses = false ;
1144
+ auto existingSubstitution = allGenericSubstitutions[archetype];
1145
+ if (!existingSubstitution) {
1146
+ // New substitution for this callee.
1147
+ allGenericSubstitutions[archetype] = substitution;
1148
+
1149
+ // Not yet handling nested archetypes.
1150
+ if (!archetype->isPrimary ())
1151
+ return { CC_ArgumentMismatch, {}};
1152
+
1153
+ if (!CS->TC .isSubstitutableFor (substitution, archetype, CS->DC )) {
1154
+ // If we have multiple non-substitutable types, this is just a mismatched mess.
1155
+ if (!nonSubstitutableArchetype.isNull ())
1156
+ return { CC_ArgumentMismatch, {}};
1157
+
1158
+ if (auto argOptType = argType->getOptionalObjectType ())
1159
+ mismatchesAreNearMisses &= CS->TC .isSubstitutableFor (argOptType, archetype, CS->DC );
1160
+ else
1161
+ mismatchesAreNearMisses = false ;
1162
+
1163
+ nonSubstitutableArchetype = archetype;
1164
+ nonSubstitutableArgs = 1 ;
1165
+ matched = false ;
1166
+ }
1154
1167
} else {
1155
- if (nonSubstitutableArgs == 1 ) {
1168
+ // Substitution for the same archetype as in a previous argument.
1169
+ bool isNonSubstitutableArchetype = !nonSubstitutableArchetype.isNull () &&
1170
+ nonSubstitutableArchetype->isEqual (archetype);
1171
+ if (substitution->isEqual (existingSubstitution)) {
1172
+ if (isNonSubstitutableArchetype) {
1173
+ ++nonSubstitutableArgs;
1174
+ matched = false ;
1175
+ }
1176
+ } else {
1156
1177
// If we have only one nonSubstitutableArg so far, then this different
1157
1178
// type might be the one that we should be substituting for instead.
1158
1179
// Note that failureInfo is already set correctly for that case.
1159
- if (CS->TC .isSubstitutableFor (substitution, archetype, CS->DC )) {
1160
- mismatchesAreNearMisses = argumentMismatchIsNearMiss (matchingArgType, substitution);
1161
- matchingArgType = substitution;
1162
- continue ;
1180
+ if (isNonSubstitutableArchetype && nonSubstitutableArgs == 1 &&
1181
+ CS->TC .isSubstitutableFor (substitution, archetype, CS->DC )) {
1182
+ mismatchesAreNearMisses = argumentMismatchIsNearMiss (existingSubstitution, substitution);
1183
+ allGenericSubstitutions[archetype] = substitution;
1184
+ } else {
1185
+ genericWithDifferingConcreteTypes = true ;
1186
+ matched = false ;
1163
1187
}
1164
1188
}
1165
-
1166
- // This substitution doesn't match a previous substitution. Set up the nearMiss
1167
- // and failureInfo.paramType with the expected substitution inserted.
1168
- // (Note that this transform assumes only a single archetype.)
1169
- mismatchesAreNearMisses &= argumentMismatchIsNearMiss (substitution, matchingArgType);
1170
- paramType = paramType.transform (([&](Type type) -> Type {
1171
- if (type->is <SubstitutableType>())
1172
- return matchingArgType;
1173
- return type;
1174
- }));
1175
1189
}
1176
- } else {
1177
- matchingArgType = substitution;
1178
- singleArchetype = archetype;
1179
-
1180
- if (CS->TC .isSubstitutableFor (substitution, archetype, CS->DC ))
1181
- continue ;
1182
-
1183
- if (auto argOptType = argType->getOptionalObjectType ())
1184
- mismatchesAreNearMisses &= CS->TC .isSubstitutableFor (argOptType, archetype, CS->DC );
1185
- else
1186
- mismatchesAreNearMisses = false ;
1187
- ++nonSubstitutableArgs;
1188
1190
}
1189
- } else {
1190
- // Keep track of whether this argument was a near miss or not.
1191
- mismatchesAreNearMisses &= argumentMismatchIsNearMiss (argType, paramType);
1192
1191
}
1193
1192
1193
+ if (matched)
1194
+ continue ;
1195
+
1196
+ if (archetypesMap.empty ())
1197
+ mismatchesAreNearMisses &= argumentMismatchIsNearMiss (argType, paramType);
1198
+
1194
1199
++mismatchingArgs;
1195
1200
1196
1201
failureInfo.argumentNumber = argNo;
@@ -1213,10 +1218,23 @@ CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
1213
1218
// close matches are prioritized against obviously wrong ones.
1214
1219
if (mismatchingArgs == 1 ) {
1215
1220
CandidateCloseness closeness;
1216
- if (singleArchetype. isNull ()) {
1221
+ if (allGenericSubstitutions. empty ()) {
1217
1222
closeness = mismatchesAreNearMisses ? CC_OneArgumentNearMismatch
1218
1223
: CC_OneArgumentMismatch;
1219
1224
} else {
1225
+ // If the failure is that different occurrences of the same generic have
1226
+ // different concrete types, substitute in all the concrete types we've found
1227
+ // into the failureInfo to improve diagnosis.
1228
+ if (genericWithDifferingConcreteTypes) {
1229
+ auto newType = failureInfo.parameterType .transform ([&](Type type) -> Type {
1230
+ if (auto archetype = type->getAs <ArchetypeType>())
1231
+ if (auto replacement = allGenericSubstitutions[archetype])
1232
+ return replacement;
1233
+ return type;
1234
+ });
1235
+ failureInfo.parameterType = newType;
1236
+ }
1237
+
1220
1238
closeness = mismatchesAreNearMisses ? CC_OneGenericArgumentNearMismatch
1221
1239
: CC_OneGenericArgumentMismatch;
1222
1240
}
@@ -1589,16 +1607,15 @@ bool CalleeCandidateInfo::diagnoseGenericParameterErrors(Expr *badArgExpr) {
1589
1607
return false ;
1590
1608
1591
1609
bool foundFailure = false ;
1592
- SmallVector<ArchetypeType *, 4 > archetypes;
1593
- SmallVector<Type, 4 > substitutions;
1610
+ TypeSubstitutionMap archetypesMap;
1594
1611
1595
1612
if (!findGenericSubstitutions (failedArgument.declContext , failedArgument.parameterType ,
1596
- argType, archetypes, substitutions ))
1613
+ argType, archetypesMap ))
1597
1614
return false ;
1598
1615
1599
- for (unsigned i = 0 , c = archetypes. size (); i < c; i++ ) {
1600
- auto archetype = archetypes[i] ;
1601
- auto substitution = substitutions[i] ;
1616
+ for (auto pair : archetypesMap ) {
1617
+ auto archetype = pair. first -> castTo <ArchetypeType>() ;
1618
+ auto substitution = pair. second ;
1602
1619
1603
1620
// FIXME: Add specific error for not subclass, if the archetype has a superclass?
1604
1621
0 commit comments