Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 54 additions & 38 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2776,45 +2776,61 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,

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

llvm::SmallDenseMap<TypeVariableType *, SmallVector<Type, 4>> conflicts;
llvm::SmallDenseMap<TypeVariableType *,
std::pair<GenericTypeParamType *, SourceLoc>, 4>
genericParams;
// Consider only representative type variables shared across
// all of the solutions.
for (auto *typeVar : cs.getTypeVariables()) {
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
auto *locator = typeVar->getImpl().getLocator();
auto *repr = cs.getRepresentative(typeVar);
// If representative is another generic parameter let's
// use its generic parameter type instead of originator's,
// but it's possible that generic parameter is equated to
// some other type e.g.
//
// func foo<T>(_: T) -> T {}
//
// In this case when reference to function `foo` is "opened"
// type variable representing `T` would be equated to
// type variable representing a result type of the reference.
if (auto *reprGP = repr->getImpl().getGenericParameter())
GP = reprGP;

genericParams[repr] = {GP, locator->getAnchor()->getLoc()};
}
}

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

if (!typeVar->getImpl().getGenericParameter())
continue;
for (const auto &entry : genericParams) {
auto *typeVar = entry.first;
auto GP = entry.second;

llvm::SmallSetVector<Type, 4> arguments;
arguments.insert(binding.second);

if (!llvm::all_of(solutions.slice(1), [&](const Solution &solution) {
auto binding = solution.typeBindings.find(typeVar);
if (binding == solution.typeBindings.end())
return false;

// Contextual opaque result type is uniquely identified by
// declaration it's associated with, so we have to compare
// declarations instead of using pointer equality on such types.
if (auto *opaque =
binding->second->getAs<OpaqueTypeArchetypeType>()) {
auto *decl = opaque->getDecl();
arguments.remove_if([&](Type argType) -> bool {
if (auto *otherOpaque =
argType->getAs<OpaqueTypeArchetypeType>()) {
return decl == otherOpaque->getDecl();
}
return false;
});
for (const auto &solution : solutions) {
auto type = solution.typeBindings.lookup(typeVar);
// Contextual opaque result type is uniquely identified by
// declaration it's associated with, so we have to compare
// declarations instead of using pointer equality on such types.
if (auto *opaque = type->getAs<OpaqueTypeArchetypeType>()) {
auto *decl = opaque->getDecl();
arguments.remove_if([&](Type argType) -> bool {
if (auto *otherOpaque = argType->getAs<OpaqueTypeArchetypeType>()) {
return decl == otherOpaque->getDecl();
}
return false;
});
}

arguments.insert(binding->second);
return true;
}))
continue;

if (arguments.size() > 1) {
conflicts[typeVar].append(arguments.begin(), arguments.end());
arguments.insert(type);
}

if (arguments.size() > 1)
conflicts[GP].append(arguments.begin(), arguments.end());
}

auto getGenericTypeDecl = [&](ArchetypeType *archetype) -> ValueDecl * {
Expand All @@ -2831,8 +2847,10 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,

bool diagnosed = false;
for (auto &conflict : conflicts) {
auto *typeVar = conflict.first;
auto *locator = typeVar->getImpl().getLocator();
SourceLoc loc;
GenericTypeParamType *GP;

std::tie(GP, loc) = conflict.first;
auto conflictingArguments = conflict.second;

llvm::SmallString<64> arguments;
Expand All @@ -2857,10 +2875,8 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
},
[&OS] { OS << " vs. "; });

auto *anchor = locator->getAnchor();
DE.diagnose(anchor->getLoc(),
diag::conflicting_arguments_for_generic_parameter,
typeVar->getImpl().getGenericParameter(), OS.str());
DE.diagnose(loc, diag::conflicting_arguments_for_generic_parameter, GP,
OS.str());
diagnosed = true;
}

Expand Down