mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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`.
This commit is contained in:
@@ -2778,45 +2778,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;
|
||||
|
||||
for (const auto &binding : solutions[0].typeBindings) {
|
||||
auto *typeVar = binding.first;
|
||||
genericParams[repr] = {GP, locator->getAnchor()->getLoc()};
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeVar->getImpl().getGenericParameter())
|
||||
continue;
|
||||
llvm::SmallDenseMap<std::pair<GenericTypeParamType *, SourceLoc>,
|
||||
SmallVector<Type, 4>>
|
||||
conflicts;
|
||||
|
||||
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 * {
|
||||
@@ -2833,8 +2849,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;
|
||||
@@ -2859,10 +2877,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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user