@@ -987,18 +987,14 @@ static bool argumentMismatchIsNearMiss(Type argType, Type paramType) {
987987// / and equal fixed type portions, and return by reference each archetype and
988988// / the matching portion of the actual arg type where that archetype appears.
989989static bool findGenericSubstitutions (DeclContext *dc, Type paramType, Type actualArgType,
990- SmallVector<ArchetypeType *, 4 > &archetypes,
991- SmallVector<Type, 4 > &substitutions) {
990+ TypeSubstitutionMap &archetypesMap) {
992991 class GenericVisitor : public TypeMatcher <GenericVisitor> {
993992 DeclContext *dc;
994- SmallVector<ArchetypeType *, 4 > &archetypes;
995- SmallVector<Type, 4 > &substitutions;
993+ TypeSubstitutionMap &archetypesMap;
996994
997995 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) {}
1002998
1003999 bool mismatch (TypeBase *paramType, TypeBase *argType) {
10041000 return paramType->isEqual (argType);
@@ -1010,12 +1006,10 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, Type actua
10101006 type = ArchetypeBuilder::mapTypeIntoContext (dc, paramType);
10111007
10121008 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;
10191013 return true ;
10201014 }
10211015 return false ;
@@ -1030,15 +1024,22 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, Type actua
10301024 if (dc && original->isTypeParameter ())
10311025 original = ArchetypeBuilder::mapTypeIntoContext (dc, original);
10321026
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;
10371038 }
10381039 return false ;
10391040 });
10401041
1041- GenericVisitor visitor (dc, archetypes, substitutions );
1042+ GenericVisitor visitor (dc, archetypesMap );
10421043 return visitor.match (paramType, actualArgType);
10431044}
10441045
@@ -1085,18 +1086,20 @@ CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
10851086 // their type and count the number of mismatched arguments.
10861087 unsigned mismatchingArgs = 0 ;
10871088
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;
10941092
1095- // Number of args of generic archetype which are mismatched because
1093+ // Number of args of one generic archetype which are mismatched because
10961094 // isSubstitutableFor() has failed. If all mismatches are of this type, we'll
10971095 // return a different closeness for better diagnoses.
1096+ Type nonSubstitutableArchetype = nullptr ;
10981097 unsigned nonSubstitutableArgs = 0 ;
10991098
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+
11001103 // We classify an argument mismatch as being a "near" miss if it is a very
11011104 // likely match due to a common sort of problem (e.g. wrong flags on a
11021105 // function type, optional where none was expected, etc). This allows us to
@@ -1122,75 +1125,77 @@ CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
11221125
11231126 // FIXME: Right now, a "matching" overload is one with a parameter whose
11241127 // 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.
11261129 // We can still do something more sophisticated with this.
11271130 // FIXME: Use TC.isConvertibleTo?
11281131
1129- SmallVector<ArchetypeType *, 4 > archetypes;
1130- SmallVector<Type, 4 > substitutions;
1132+ TypeSubstitutionMap archetypesMap;
11311133 bool matched;
1132- if (paramType->is <UnresolvedType>())
1134+ if (paramType->is <UnresolvedType>() || rArgType-> hasTypeVariable () )
11331135 matched = false ;
11341136 else
1135- matched = findGenericSubstitutions (dc, paramType, rArgType,
1136- archetypes, substitutions);
1137+ matched = findGenericSubstitutions (dc, paramType, rArgType, archetypesMap);
11371138
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 ;
11481143
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+ }
11541167 } 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 {
11561177 // If we have only one nonSubstitutableArg so far, then this different
11571178 // type might be the one that we should be substituting for instead.
11581179 // 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 ;
11631187 }
11641188 }
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- }));
11751189 }
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;
11881190 }
1189- } else {
1190- // Keep track of whether this argument was a near miss or not.
1191- mismatchesAreNearMisses &= argumentMismatchIsNearMiss (argType, paramType);
11921191 }
11931192
1193+ if (matched)
1194+ continue ;
1195+
1196+ if (archetypesMap.empty ())
1197+ mismatchesAreNearMisses &= argumentMismatchIsNearMiss (argType, paramType);
1198+
11941199 ++mismatchingArgs;
11951200
11961201 failureInfo.argumentNumber = argNo;
@@ -1213,10 +1218,23 @@ CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
12131218 // close matches are prioritized against obviously wrong ones.
12141219 if (mismatchingArgs == 1 ) {
12151220 CandidateCloseness closeness;
1216- if (singleArchetype. isNull ()) {
1221+ if (allGenericSubstitutions. empty ()) {
12171222 closeness = mismatchesAreNearMisses ? CC_OneArgumentNearMismatch
12181223 : CC_OneArgumentMismatch;
12191224 } 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+
12201238 closeness = mismatchesAreNearMisses ? CC_OneGenericArgumentNearMismatch
12211239 : CC_OneGenericArgumentMismatch;
12221240 }
@@ -1589,16 +1607,15 @@ bool CalleeCandidateInfo::diagnoseGenericParameterErrors(Expr *badArgExpr) {
15891607 return false ;
15901608
15911609 bool foundFailure = false ;
1592- SmallVector<ArchetypeType *, 4 > archetypes;
1593- SmallVector<Type, 4 > substitutions;
1610+ TypeSubstitutionMap archetypesMap;
15941611
15951612 if (!findGenericSubstitutions (failedArgument.declContext , failedArgument.parameterType ,
1596- argType, archetypes, substitutions ))
1613+ argType, archetypesMap ))
15971614 return false ;
15981615
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 ;
16021619
16031620 // FIXME: Add specific error for not subclass, if the archetype has a superclass?
16041621
0 commit comments