Skip to content

Commit 0a6b444

Browse files
committed
[ConstraintSystem] Diagnose argument conflicts only for "representative" generic parameters
Consider following example: ```swift struct MyType<TyA, TyB> { var a : TyA, b : TyB } typealias B<T1> = MyType<T1, T1> _ = B(a: "foo", b: 42) ``` Here `T1` is equal to `TyA` and `TyB` so diagnostic about conflicting arguments ('String' vs. 'Int') should only be produced for "representative" `T1`.
1 parent 9f09add commit 0a6b444

File tree

1 file changed

+54
-38
lines changed

1 file changed

+54
-38
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,45 +2778,61 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
27782778

27792779
auto &DE = cs.getASTContext().Diags;
27802780

2781-
llvm::SmallDenseMap<TypeVariableType *, SmallVector<Type, 4>> conflicts;
2781+
llvm::SmallDenseMap<TypeVariableType *,
2782+
std::pair<GenericTypeParamType *, SourceLoc>, 4>
2783+
genericParams;
2784+
// Consider only representative type variables shared across
2785+
// all of the solutions.
2786+
for (auto *typeVar : cs.getTypeVariables()) {
2787+
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
2788+
auto *locator = typeVar->getImpl().getLocator();
2789+
auto *repr = cs.getRepresentative(typeVar);
2790+
// If representative is another generic parameter let's
2791+
// use its generic parameter type instead of originator's,
2792+
// but it's possible that generic parameter is equated to
2793+
// some other type e.g.
2794+
//
2795+
// func foo<T>(_: T) -> T {}
2796+
//
2797+
// In this case when reference to function `foo` is "opened"
2798+
// type variable representing `T` would be equated to
2799+
// type variable representing a result type of the reference.
2800+
if (auto *reprGP = repr->getImpl().getGenericParameter())
2801+
GP = reprGP;
2802+
2803+
genericParams[repr] = {GP, locator->getAnchor()->getLoc()};
2804+
}
2805+
}
27822806

2783-
for (const auto &binding : solutions[0].typeBindings) {
2784-
auto *typeVar = binding.first;
2807+
llvm::SmallDenseMap<std::pair<GenericTypeParamType *, SourceLoc>,
2808+
SmallVector<Type, 4>>
2809+
conflicts;
27852810

2786-
if (!typeVar->getImpl().getGenericParameter())
2787-
continue;
2811+
for (const auto &entry : genericParams) {
2812+
auto *typeVar = entry.first;
2813+
auto GP = entry.second;
27882814

27892815
llvm::SmallSetVector<Type, 4> arguments;
2790-
arguments.insert(binding.second);
2791-
2792-
if (!llvm::all_of(solutions.slice(1), [&](const Solution &solution) {
2793-
auto binding = solution.typeBindings.find(typeVar);
2794-
if (binding == solution.typeBindings.end())
2795-
return false;
2796-
2797-
// Contextual opaque result type is uniquely identified by
2798-
// declaration it's associated with, so we have to compare
2799-
// declarations instead of using pointer equality on such types.
2800-
if (auto *opaque =
2801-
binding->second->getAs<OpaqueTypeArchetypeType>()) {
2802-
auto *decl = opaque->getDecl();
2803-
arguments.remove_if([&](Type argType) -> bool {
2804-
if (auto *otherOpaque =
2805-
argType->getAs<OpaqueTypeArchetypeType>()) {
2806-
return decl == otherOpaque->getDecl();
2807-
}
2808-
return false;
2809-
});
2816+
for (const auto &solution : solutions) {
2817+
auto type = solution.typeBindings.lookup(typeVar);
2818+
// Contextual opaque result type is uniquely identified by
2819+
// declaration it's associated with, so we have to compare
2820+
// declarations instead of using pointer equality on such types.
2821+
if (auto *opaque = type->getAs<OpaqueTypeArchetypeType>()) {
2822+
auto *decl = opaque->getDecl();
2823+
arguments.remove_if([&](Type argType) -> bool {
2824+
if (auto *otherOpaque = argType->getAs<OpaqueTypeArchetypeType>()) {
2825+
return decl == otherOpaque->getDecl();
28102826
}
2827+
return false;
2828+
});
2829+
}
28112830

2812-
arguments.insert(binding->second);
2813-
return true;
2814-
}))
2815-
continue;
2816-
2817-
if (arguments.size() > 1) {
2818-
conflicts[typeVar].append(arguments.begin(), arguments.end());
2831+
arguments.insert(type);
28192832
}
2833+
2834+
if (arguments.size() > 1)
2835+
conflicts[GP].append(arguments.begin(), arguments.end());
28202836
}
28212837

28222838
auto getGenericTypeDecl = [&](ArchetypeType *archetype) -> ValueDecl * {
@@ -2833,8 +2849,10 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
28332849

28342850
bool diagnosed = false;
28352851
for (auto &conflict : conflicts) {
2836-
auto *typeVar = conflict.first;
2837-
auto *locator = typeVar->getImpl().getLocator();
2852+
SourceLoc loc;
2853+
GenericTypeParamType *GP;
2854+
2855+
std::tie(GP, loc) = conflict.first;
28382856
auto conflictingArguments = conflict.second;
28392857

28402858
llvm::SmallString<64> arguments;
@@ -2859,10 +2877,8 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
28592877
},
28602878
[&OS] { OS << " vs. "; });
28612879

2862-
auto *anchor = locator->getAnchor();
2863-
DE.diagnose(anchor->getLoc(),
2864-
diag::conflicting_arguments_for_generic_parameter,
2865-
typeVar->getImpl().getGenericParameter(), OS.str());
2880+
DE.diagnose(loc, diag::conflicting_arguments_for_generic_parameter, GP,
2881+
OS.str());
28662882
diagnosed = true;
28672883
}
28682884

0 commit comments

Comments
 (0)