@@ -5598,6 +5598,29 @@ static void expandSameTypeConstraints(GenericSignatureBuilder &builder,
55985598 }
55995599}
56005600
5601+ static bool compareSourceLocs (SourceManager &SM, SourceLoc lhsLoc, SourceLoc rhsLoc) {
5602+ if (lhsLoc.isValid () != rhsLoc.isValid ())
5603+ return lhsLoc.isValid ();
5604+
5605+ if (lhsLoc.isValid () && rhsLoc.isValid ()) {
5606+ unsigned lhsBuffer = SM.findBufferContainingLoc (lhsLoc);
5607+ unsigned rhsBuffer = SM.findBufferContainingLoc (rhsLoc);
5608+
5609+ // If the buffers are the same, use source location ordering.
5610+ if (lhsBuffer == rhsBuffer) {
5611+ if (SM.isBeforeInBuffer (lhsLoc, rhsLoc))
5612+ return true ;
5613+ } else {
5614+ // Otherwise, order by buffer identifier.
5615+ if (SM.getIdentifierForBuffer (lhsBuffer)
5616+ .compare (SM.getIdentifierForBuffer (lhsBuffer)))
5617+ return true ;
5618+ }
5619+ }
5620+
5621+ return false ;
5622+ }
5623+
56015624// / A directed graph where the vertices are explicit requirement sources and
56025625// / an edge (v, w) records that the explicit source v implies the explicit
56035626// / source w.
@@ -5996,29 +6019,10 @@ class RedundantRequirementGraph {
59966019 if (cmpTypes != 0 )
59976020 return cmpTypes < 0 ;
59986021
5999- // Prefer source-location-based over abstract.
60006022 auto existingLoc = existingSource->getLoc ();
60016023 auto currentLoc = currentSource->getLoc ();
6002- if (existingLoc.isValid () != currentLoc.isValid ())
6003- return currentLoc.isValid ();
6004-
6005- if (existingLoc.isValid () && currentLoc.isValid ()) {
6006- unsigned existingBuffer = SM.findBufferContainingLoc (existingLoc);
6007- unsigned currentBuffer = SM.findBufferContainingLoc (currentLoc);
60086024
6009- // If the buffers are the same, use source location ordering.
6010- if (existingBuffer == currentBuffer) {
6011- if (SM.isBeforeInBuffer (currentLoc, existingLoc))
6012- return true ;
6013- } else {
6014- // Otherwise, order by buffer identifier.
6015- if (SM.getIdentifierForBuffer (currentBuffer)
6016- .compare (SM.getIdentifierForBuffer (existingBuffer)))
6017- return true ;
6018- }
6019- }
6020-
6021- return true ;
6025+ return compareSourceLocs (SM, currentLoc, existingLoc);
60226026 }
60236027
60246028public:
@@ -6230,6 +6234,7 @@ GenericSignatureBuilder::finalize(TypeArrayView<GenericTypeParamType> genericPar
62306234 processDelayedRequirements ();
62316235
62326236 computeRedundantRequirements ();
6237+ diagnoseRedundantRequirements ();
62336238
62346239 assert (!Impl->finalized && " Already finalized builder" );
62356240#ifndef NDEBUG
@@ -6868,41 +6873,95 @@ void GenericSignatureBuilder::checkConformanceConstraints(
68686873
68696874 // Remove any self-derived constraints.
68706875 removeSelfDerived (*this , entry.second , entry.first );
6876+ }
6877+ }
68716878
6872- checkConstraintList<ProtocolDecl *, ProtocolDecl *>(
6873- genericParams, entry.second , RequirementKind::Conformance,
6874- [](const Constraint<ProtocolDecl *> &constraint) {
6875- return true ;
6876- },
6877- [&](const Constraint<ProtocolDecl *> &constraint) {
6878- auto proto = constraint.value ;
6879- assert (proto == entry.first && " Mixed up protocol constraints" );
6879+ void GenericSignatureBuilder::diagnoseRedundantRequirements () const {
6880+ SmallVector<ExplicitRequirement, 2 > redundantRequirements;
6881+
6882+ for (auto pair : Impl->RedundantRequirements ) {
6883+ auto *source = pair.first .getSource ();
6884+
6885+ // Don't diagnose anything without a source location.
6886+ if (source->getLoc ().isInvalid ())
6887+ continue ;
6888+
6889+ // Don't diagnose redundant inferred requirements.
6890+ if (source->isInferredRequirement ())
6891+ continue ;
6892+
6893+ // Don't diagnose explicit requirements that are implied by
6894+ // inferred requirements.
6895+ if (llvm::all_of (pair.second ,
6896+ [&](const ExplicitRequirement &otherReq) {
6897+ return otherReq.getSource ()->isInferredRequirement ();
6898+ }))
6899+ continue ;
68806900
6881- // If this conformance requirement recursively makes a protocol
6882- // conform to itself, don't complain here.
6883- auto source = constraint.source ;
6901+ redundantRequirements.push_back (pair.first );
6902+ }
6903+
6904+ auto &SM = Context.SourceMgr ;
6905+
6906+ std::sort (redundantRequirements.begin (), redundantRequirements.end (),
6907+ [&](ExplicitRequirement lhs, ExplicitRequirement rhs) {
6908+ return compareSourceLocs (SM,
6909+ lhs.getSource ()->getLoc (),
6910+ rhs.getSource ()->getLoc ());
6911+ });
6912+
6913+ for (const auto &req : redundantRequirements) {
6914+ auto *source = req.getSource ();
6915+ auto loc = source->getLoc ();
6916+ assert (loc.isValid ());
6917+
6918+ auto subjectType = getSugaredDependentType (source->getStoredType (),
6919+ getGenericParams ());
6920+
6921+ switch (req.getKind ()) {
6922+ case RequirementKind::Conformance: {
6923+ auto *proto = req.getRHS ().get <ProtocolDecl *>();
6924+
6925+ // If this conformance requirement recursively makes a protocol
6926+ // conform to itself, don't complain here, because we diagnose
6927+ // the circular inheritance elsewhere.
6928+ {
68846929 auto rootSource = source->getRoot ();
6885- if (rootSource->kind == RequirementSource::RequirementSignatureSelf &&
6886- source != rootSource &&
6887- proto == rootSource->getProtocolDecl () &&
6888- areInSameEquivalenceClass (rootSource->getRootType (),
6889- source->getAffectedType ())) {
6890- return ConstraintRelation::Unrelated;
6930+ if (proto == rootSource->getProtocolDecl () &&
6931+ rootSource->kind == RequirementSource::RequirementSignatureSelf &&
6932+ rootSource->getRootType ()->isEqual (source->getAffectedType ())) {
6933+ break ;
68916934 }
6935+ }
68926936
6893- // If this is a redundantly inherited Objective-C protocol, treat it
6894- // as "unrelated" to silence the warning about the redundant
6895- // conformance.
6896- if (isRedundantlyInheritableObjCProtocol (proto, constraint. source ))
6897- return ConstraintRelation::Unrelated ;
6937+ // If this is a redundantly inherited Objective-C protocol, treat it
6938+ // as "unrelated" to silence the warning about the redundant
6939+ // conformance.
6940+ if (isRedundantlyInheritableObjCProtocol (proto, source))
6941+ break ;
68986942
6899- return ConstraintRelation::Redundant;
6900- },
6901- None,
6902- diag::redundant_conformance_constraint,
6903- diag::redundant_conformance_here,
6904- [](ProtocolDecl *proto) { return proto; },
6905- /* removeSelfDerived=*/ false );
6943+ Context.Diags .diagnose (loc, diag::redundant_conformance_constraint,
6944+ subjectType, proto);
6945+
6946+ for (auto otherReq : Impl->RedundantRequirements [req]) {
6947+ auto *otherSource = otherReq.getSource ();
6948+ auto otherLoc = otherSource->getLoc ();
6949+ if (otherLoc.isInvalid ())
6950+ continue ;
6951+
6952+ Context.Diags .diagnose (otherLoc, diag::redundant_conformance_here,
6953+ 1 , subjectType, proto);
6954+ }
6955+
6956+ break ;
6957+ }
6958+
6959+ case RequirementKind::Superclass:
6960+ case RequirementKind::Layout:
6961+ case RequirementKind::SameType:
6962+ // TODO
6963+ break ;
6964+ }
69066965 }
69076966}
69086967
0 commit comments