34
34
#include " swift/Basic/Defer.h"
35
35
#include " swift/Basic/Statistic.h"
36
36
#include " llvm/ADT/GraphTraits.h"
37
+ #include " llvm/ADT/DenseMap.h"
37
38
#include " llvm/ADT/SetVector.h"
38
39
#include " llvm/ADT/SmallPtrSet.h"
39
40
#include " llvm/ADT/SmallString.h"
@@ -4894,7 +4895,6 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenTypeParameters(
4894
4895
std::swap (T1, T2);
4895
4896
std::swap (OrigT1, OrigT2);
4896
4897
std::swap (equivClass, equivClass2);
4897
- std::swap (depType1, depType2);
4898
4898
}
4899
4899
4900
4900
// T1 must have an equivalence class; create one if we don't already have
@@ -4903,6 +4903,8 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenTypeParameters(
4903
4903
equivClass = T1->getOrCreateEquivalenceClass (*this );
4904
4904
4905
4905
// Record this same-type constraint.
4906
+ // Let's keep type order in the new constraint the same as it's written
4907
+ // in source, which makes it much easier to diagnose later.
4906
4908
equivClass->sameTypeConstraints .push_back ({depType1, depType2, source});
4907
4909
4908
4910
// Determine the anchor types of the two equivalence classes.
@@ -6905,34 +6907,121 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
6905
6907
// connect all of the components, or else we wouldn't have an equivalence
6906
6908
// class.
6907
6909
if (intercomponentEdges.size () > numComponents - 1 ) {
6908
- std::vector<bool > connected (numComponents, false );
6909
- const auto &firstEdge = intercomponentEdges.front ();
6910
- for (const auto &edge : intercomponentEdges) {
6911
- // If both the source and target are already connected, this edge is
6912
- // not part of the spanning tree.
6913
- if (connected[edge.source ] && connected[edge.target ]) {
6914
- if (edge.constraint .source ->shouldDiagnoseRedundancy (true ) &&
6915
- firstEdge.constraint .source ->shouldDiagnoseRedundancy (false )) {
6916
- Diags.diagnose (edge.constraint .source ->getLoc (),
6917
- diag::redundant_same_type_constraint,
6918
- edge.constraint .getSubjectDependentType (
6919
- genericParams),
6920
- edge.constraint .value );
6921
-
6922
- Diags.diagnose (firstEdge.constraint .source ->getLoc (),
6923
- diag::previous_same_type_constraint,
6924
- firstEdge.constraint .source ->classifyDiagKind (),
6925
- firstEdge.constraint .getSubjectDependentType (
6926
- genericParams),
6927
- firstEdge.constraint .value );
6910
+ auto &sourceMgr = getASTContext ().SourceMgr ;
6911
+
6912
+ // First let's order all of the intercomponent edges
6913
+ // as written in source, this helps us to diagnose
6914
+ // all of the duplicate constraints in correct order.
6915
+ std::vector<unsigned > sourceOrderedEdges;
6916
+ for (unsigned i : indices (intercomponentEdges))
6917
+ sourceOrderedEdges.push_back (i);
6918
+
6919
+ std::sort (sourceOrderedEdges.begin (), sourceOrderedEdges.end (),
6920
+ [&sourceMgr, &intercomponentEdges](
6921
+ const unsigned &indexA, const unsigned &indexB) -> bool {
6922
+ auto &a = intercomponentEdges[indexA];
6923
+ auto &b = intercomponentEdges[indexB];
6924
+
6925
+ auto locA = a.constraint .source ->getLoc ();
6926
+ auto locB = b.constraint .source ->getLoc ();
6927
+
6928
+ auto bufferA = sourceMgr.findBufferContainingLoc (locA);
6929
+ auto bufferB = sourceMgr.findBufferContainingLoc (locB);
6930
+
6931
+ if (bufferA != bufferB)
6932
+ return bufferA < bufferB;
6933
+
6934
+ auto offsetA = sourceMgr.getLocOffsetInBuffer (locA, bufferA);
6935
+ auto offsetB = sourceMgr.getLocOffsetInBuffer (locB, bufferB);
6936
+
6937
+ return offsetA < offsetB;
6938
+ });
6939
+
6940
+ auto isDiagnosable = [](const IntercomponentEdge &edge, bool isPrimary) {
6941
+ return edge.constraint .source ->shouldDiagnoseRedundancy (isPrimary);
6942
+ };
6943
+
6944
+ using EquivClass = llvm::DenseMap<Type, unsigned >;
6945
+ llvm::DenseMap<Type, EquivClass> equivalences;
6946
+ // The idea here is to form an equivalence class per representative
6947
+ // (picked from each edge constraint in type parameter order) and
6948
+ // propagate all new equivalent types up the chain until duplicate
6949
+ // entry is found, that entry is going to point to previous
6950
+ // declaration and is going to mark current edge as a duplicate of
6951
+ // such entry.
6952
+ for (const unsigned edgeIdx : sourceOrderedEdges) {
6953
+ const auto &edge = intercomponentEdges[edgeIdx];
6954
+
6955
+ Type lhs = edge.constraint .getSubjectDependentType (genericParams);
6956
+ Type rhs = edge.constraint .value ;
6957
+
6958
+ // Make sure that representative for equivalence class is picked
6959
+ // in canonical type parameter order.
6960
+ if (compareDependentTypes (rhs, lhs) < 0 )
6961
+ std::swap (lhs, rhs);
6962
+
6963
+ // Index of the previous declaration of the same-type constraint
6964
+ // which current edge might be a duplicate of.
6965
+ Optional<unsigned > previousIndex;
6966
+
6967
+ bool isDuplicate = false ;
6968
+ auto &representative = equivalences[lhs];
6969
+ if (representative.insert ({rhs, edgeIdx}).second ) {
6970
+ // Since this is a new equivalence, and right-hand side might
6971
+ // be a representative of some other equivalence class,
6972
+ // its existing members have to be merged up.
6973
+ auto RHSEquivClass = equivalences.find (rhs);
6974
+ if (RHSEquivClass != equivalences.end ()) {
6975
+ auto &equivClass = RHSEquivClass->getSecond ();
6976
+ representative.insert (equivClass.begin (), equivClass.end ());
6928
6977
}
6929
6978
6930
- continue ;
6979
+ // If left-hand side is involved in any other equivalences
6980
+ // let's propagate new information up the chain.
6981
+ for (auto &e : equivalences) {
6982
+ auto &repr = e.first ;
6983
+ auto &equivClass = e.second ;
6984
+
6985
+ if (repr->isEqual (lhs) || !equivClass.count (lhs))
6986
+ continue ;
6987
+
6988
+ if (!equivClass.insert ({rhs, edgeIdx}).second ) {
6989
+ // Even if "previous" edge is not diagnosable we
6990
+ // still need to produce diagnostic about main duplicate.
6991
+ isDuplicate = true ;
6992
+
6993
+ auto prevIdx = equivClass[rhs];
6994
+ if (!isDiagnosable (intercomponentEdges[prevIdx],
6995
+ /* isPrimary=*/ false ))
6996
+ continue ;
6997
+
6998
+ // If there is a diagnosable duplicate equivalence,
6999
+ // it means that we've found our previous declaration.
7000
+ previousIndex = prevIdx;
7001
+ break ;
7002
+ }
7003
+ }
7004
+ } else {
7005
+ // Looks like this is a situation like T.A == T.B, ..., T.B == T.A
7006
+ previousIndex = representative[rhs];
7007
+ isDuplicate = true ;
6931
7008
}
6932
7009
6933
- // Put the source and target into the spanning tree.
6934
- connected[edge.source ] = true ;
6935
- connected[edge.target ] = true ;
7010
+ if (!isDuplicate || !isDiagnosable (edge, /* isPrimary=*/ true ))
7011
+ continue ;
7012
+
7013
+ Diags.diagnose (edge.constraint .source ->getLoc (),
7014
+ diag::redundant_same_type_constraint,
7015
+ edge.constraint .getSubjectDependentType (genericParams),
7016
+ edge.constraint .value );
7017
+
7018
+ if (previousIndex) {
7019
+ auto &prevEquiv = intercomponentEdges[*previousIndex].constraint ;
7020
+ Diags.diagnose (
7021
+ prevEquiv.source ->getLoc (), diag::previous_same_type_constraint,
7022
+ prevEquiv.source ->classifyDiagKind (),
7023
+ prevEquiv.getSubjectDependentType (genericParams), prevEquiv.value );
7024
+ }
6936
7025
}
6937
7026
}
6938
7027
0 commit comments