Skip to content

Commit 1617727

Browse files
committed
GSB: Refactor computeRedundantRequirements() in preparation for redoing conflict checking
1 parent 8f52c26 commit 1617727

File tree

1 file changed

+179
-111
lines changed

1 file changed

+179
-111
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 179 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -704,13 +704,18 @@ struct GenericSignatureBuilder::Implementation {
704704
SmallVector<Requirement, 2> ExplicitSameTypeRequirements;
705705

706706
/// A mapping of redundant explicit requirements to the best root requirement
707-
/// that implies them.
707+
/// that implies them. Built by computeRedundantRequirements().
708708
using RedundantRequirementMap =
709709
llvm::DenseMap<ExplicitRequirement,
710710
llvm::SmallDenseSet<ExplicitRequirement, 2>>;
711711

712712
RedundantRequirementMap RedundantRequirements;
713713

714+
/// Requirements which conflict with other requirements, for example if a
715+
/// there are two unrelated superclass requirements on the same type,
716+
/// the second one is recorded here. Built by computeRedundantRequirements().
717+
llvm::DenseMap<ExplicitRequirement, RequirementRHS> ConflictingRequirements;
718+
714719
#ifndef NDEBUG
715720
/// Whether we've already computed redundant requiremnts.
716721
bool computedRedundantRequirements = false;
@@ -5769,12 +5774,11 @@ class RedundantRequirementGraph {
57695774
SmallVector<VertexID, 2> stack;
57705775

57715776
public:
5772-
template<typename T, typename Fn>
5777+
template<typename T>
57735778
void addConstraintsFromEquivClass(
5774-
GenericSignatureBuilder &builder,
5775-
const std::vector<Constraint<T>> &constraints,
57765779
RequirementKind kind,
5777-
Fn filter) {
5780+
SmallVectorImpl<Constraint<T>> &exact,
5781+
SmallVectorImpl<Constraint<T>> &lessSpecific) {
57785782
// The set of 'redundant explicit requirements', which are known to be less
57795783
// specific than some other explicit requirements. An example is a type
57805784
// parameter with multiple superclass constraints:
@@ -5802,15 +5806,8 @@ class RedundantRequirementGraph {
58025806
// These 'root requirements' imply the 'explicit requirements'.
58035807
SmallVector<ExplicitRequirement, 1> rootReqs;
58045808

5805-
for (auto constraint : constraints) {
5806-
auto *source = constraint.source;
5807-
5808-
if (source->isDerivedNonRootRequirement()) {
5809-
// If the derived requirement was filtered by our predicate, it doesn't
5810-
// make our explicit requirements redundant.
5811-
if (filter(constraint))
5812-
continue;
5813-
5809+
for (auto constraint : exact) {
5810+
if (constraint.source->isDerivedNonRootRequirement()) {
58145811
auto req = ExplicitRequirement::fromDerivedConstraint(kind, constraint);
58155812

58165813
rootReqs.push_back(req);
@@ -5825,16 +5822,27 @@ class RedundantRequirementGraph {
58255822
#endif
58265823
(void) v;
58275824

5828-
// If the explicit requirement was filtered by our predicate, it doesn't
5829-
// make the other explicit requirements redundant.
5830-
if (filter(constraint)) {
5831-
redundantExplicitReqs.push_back(req);
5832-
} else {
5833-
explicitReqs.push_back(req);
5834-
}
5825+
explicitReqs.push_back(req);
58355826
}
58365827
}
58375828

5829+
for (auto constraint : lessSpecific) {
5830+
if (constraint.source->isDerivedNonRootRequirement())
5831+
continue;
5832+
5833+
auto req = ExplicitRequirement::fromExplicitConstraint(kind, constraint);
5834+
5835+
VertexID v = addVertex(req);
5836+
#ifndef NDEBUG
5837+
// Record that we saw an actual explicit requirement rooted at this vertex,
5838+
// for verification purposes.
5839+
vertices[v].sawVertex = true;
5840+
#endif
5841+
(void) v;
5842+
5843+
redundantExplicitReqs.push_back(req);
5844+
}
5845+
58385846
// If all requirements are derived, there is nothing to do.
58395847
if (explicitReqs.empty()) {
58405848
if (!redundantExplicitReqs.empty()) {
@@ -6208,111 +6216,171 @@ void GenericSignatureBuilder::computeRedundantRequirements() {
62086216
// source.
62096217
for (auto &equivClass : Impl->EquivalenceClasses) {
62106218
for (auto &entry : equivClass.conformsTo) {
6211-
graph.addConstraintsFromEquivClass(
6212-
*this, entry.second,
6213-
RequirementKind::Conformance,
6214-
[&](Constraint<ProtocolDecl *> constraint) -> bool {
6215-
auto *source = constraint.source;
6216-
6217-
bool derivedViaConcrete = false;
6218-
if (source->getMinimalConformanceSource(
6219-
*this, constraint.getSubjectDependentType({ }), entry.first,
6220-
derivedViaConcrete)
6221-
!= source)
6222-
return true;
6223-
6224-
if (derivedViaConcrete)
6225-
return true;
6219+
SmallVector<Constraint<ProtocolDecl *>, 2> exact;
6220+
SmallVector<Constraint<ProtocolDecl *>, 2> lessSpecific;
62266221

6227-
return false;
6228-
});
6222+
for (const auto &constraint : entry.second) {
6223+
auto *source = constraint.source;
6224+
6225+
// FIXME: Remove this check.
6226+
bool derivedViaConcrete = false;
6227+
if (source->getMinimalConformanceSource(
6228+
*this, constraint.getSubjectDependentType({ }), entry.first,
6229+
derivedViaConcrete)
6230+
!= source)
6231+
continue;
6232+
6233+
if (derivedViaConcrete)
6234+
continue;
6235+
6236+
// FIXME: Check for a conflict via the concrete type.
6237+
exact.push_back(constraint);
6238+
}
6239+
6240+
graph.addConstraintsFromEquivClass(RequirementKind::Conformance,
6241+
exact, lessSpecific);
62296242
}
62306243

62316244
if (equivClass.concreteType) {
62326245
Type resolvedConcreteType =
62336246
getCanonicalTypeInContext(equivClass.concreteType, { });
6234-
graph.addConstraintsFromEquivClass(
6235-
*this, equivClass.concreteTypeConstraints,
6236-
RequirementKind::SameType,
6237-
[&](Constraint<Type> constraint) -> bool {
6238-
auto *source = constraint.source;
6239-
Type t = constraint.value;
6240-
6241-
bool derivedViaConcrete = false;
6242-
if (source->getMinimalConformanceSource(
6243-
*this, constraint.getSubjectDependentType({ }), nullptr,
6244-
derivedViaConcrete)
6245-
!= source)
6246-
return true;
6247-
6248-
if (derivedViaConcrete)
6249-
return true;
6250-
6251-
if (t->isEqual(resolvedConcreteType))
6252-
return false;
6253-
6254-
auto resolvedType = getCanonicalTypeInContext(t, { });
6255-
if (resolvedType->isEqual(resolvedConcreteType))
6256-
return false;
6257-
6258-
// We have a less-specific constraint.
6259-
return true;
6260-
});
6247+
6248+
SmallVector<Constraint<Type>, 2> exact;
6249+
SmallVector<Constraint<Type>, 2> lessSpecific;
6250+
6251+
for (const auto &constraint : equivClass.concreteTypeConstraints) {
6252+
auto *source = constraint.source;
6253+
Type t = constraint.value;
6254+
6255+
// FIXME: Remove this check.
6256+
bool derivedViaConcrete = false;
6257+
if (source->getMinimalConformanceSource(
6258+
*this, constraint.getSubjectDependentType({ }), nullptr,
6259+
derivedViaConcrete)
6260+
!= source)
6261+
continue;
6262+
6263+
if (derivedViaConcrete)
6264+
continue;
6265+
6266+
if (t->isEqual(resolvedConcreteType)) {
6267+
exact.push_back(constraint);
6268+
continue;
6269+
}
6270+
6271+
auto resolvedType = getCanonicalTypeInContext(t, { });
6272+
if (resolvedType->isEqual(resolvedConcreteType)) {
6273+
exact.push_back(constraint);
6274+
}
6275+
6276+
// Record the conflict.
6277+
if (!source->isDerivedRequirement()) {
6278+
auto req =
6279+
ExplicitRequirement::fromExplicitConstraint(
6280+
RequirementKind::SameType, constraint);
6281+
Impl->ConflictingRequirements.insert(
6282+
std::make_pair(req, resolvedConcreteType));
6283+
}
6284+
6285+
lessSpecific.push_back(constraint);
6286+
}
6287+
6288+
graph.addConstraintsFromEquivClass(RequirementKind::SameType,
6289+
exact, lessSpecific);
62616290
}
62626291

62636292
if (equivClass.superclass) {
62646293
// Resolve any thus-far-unresolved dependent types.
62656294
Type resolvedSuperclass =
62666295
getCanonicalTypeInContext(equivClass.superclass, { });
6267-
graph.addConstraintsFromEquivClass(
6268-
*this, equivClass.superclassConstraints,
6269-
RequirementKind::Superclass,
6270-
[&](Constraint<Type> constraint) -> bool {
6271-
auto *source = constraint.source;
6272-
Type t = constraint.value;
6273-
6274-
bool derivedViaConcrete = false;
6275-
if (source->getMinimalConformanceSource(
6276-
*this, constraint.getSubjectDependentType({ }), nullptr,
6277-
derivedViaConcrete)
6278-
!= source)
6279-
return true;
6280-
6281-
if (derivedViaConcrete)
6282-
return true;
6283-
6284-
if (t->isEqual(resolvedSuperclass))
6285-
return false;
6286-
6287-
Type resolvedType = getCanonicalTypeInContext(t, { });
6288-
if (resolvedType->isEqual(resolvedSuperclass))
6289-
return false;
6290-
6291-
// We have a less-specific constraint.
6292-
return true;
6293-
});
6296+
6297+
SmallVector<Constraint<Type>, 2> exact;
6298+
SmallVector<Constraint<Type>, 2> lessSpecific;
6299+
6300+
for (const auto &constraint : equivClass.superclassConstraints) {
6301+
auto *source = constraint.source;
6302+
Type t = constraint.value;
6303+
6304+
// FIXME: Remove this check.
6305+
bool derivedViaConcrete = false;
6306+
if (source->getMinimalConformanceSource(
6307+
*this, constraint.getSubjectDependentType({ }), nullptr,
6308+
derivedViaConcrete)
6309+
!= source)
6310+
continue;
6311+
6312+
if (derivedViaConcrete)
6313+
continue;
6314+
6315+
if (t->isEqual(resolvedSuperclass)) {
6316+
exact.push_back(constraint);
6317+
continue;
6318+
}
6319+
6320+
Type resolvedType = getCanonicalTypeInContext(t, { });
6321+
if (resolvedType->isEqual(resolvedSuperclass)) {
6322+
exact.push_back(constraint);
6323+
continue;
6324+
}
6325+
6326+
// Check for a conflict.
6327+
if (!source->isDerivedRequirement() &&
6328+
!resolvedType->isExactSuperclassOf(resolvedSuperclass)) {
6329+
auto req =
6330+
ExplicitRequirement::fromExplicitConstraint(
6331+
RequirementKind::Superclass, constraint);
6332+
Impl->ConflictingRequirements.insert(
6333+
std::make_pair(req, resolvedSuperclass));
6334+
}
6335+
6336+
// FIXME: Check for a conflict via the concrete type.
6337+
lessSpecific.push_back(constraint);
6338+
}
6339+
6340+
graph.addConstraintsFromEquivClass(RequirementKind::Superclass,
6341+
exact, lessSpecific);
62946342
}
62956343

62966344
if (equivClass.layout) {
6297-
graph.addConstraintsFromEquivClass(
6298-
*this, equivClass.layoutConstraints,
6299-
RequirementKind::Layout,
6300-
[&](Constraint<LayoutConstraint> constraint) -> bool {
6301-
auto *source = constraint.source;
6302-
auto layout = constraint.value;
6303-
6304-
bool derivedViaConcrete = false;
6305-
if (source->getMinimalConformanceSource(
6306-
*this, constraint.getSubjectDependentType({ }), nullptr,
6307-
derivedViaConcrete)
6308-
!= source)
6309-
return true;
6310-
6311-
if (derivedViaConcrete)
6312-
return true;
6313-
6314-
return layout != equivClass.layout;
6315-
});
6345+
SmallVector<Constraint<LayoutConstraint>, 2> exact;
6346+
SmallVector<Constraint<LayoutConstraint>, 2> lessSpecific;
6347+
6348+
for (const auto &constraint : equivClass.layoutConstraints) {
6349+
auto *source = constraint.source;
6350+
auto layout = constraint.value;
6351+
6352+
// FIXME: Remove this check.
6353+
bool derivedViaConcrete = false;
6354+
if (source->getMinimalConformanceSource(
6355+
*this, constraint.getSubjectDependentType({ }), nullptr,
6356+
derivedViaConcrete)
6357+
!= source)
6358+
continue;
6359+
6360+
if (derivedViaConcrete)
6361+
continue;
6362+
6363+
if (layout == equivClass.layout) {
6364+
exact.push_back(constraint);
6365+
continue;
6366+
}
6367+
6368+
// Check for a conflict.
6369+
if (!source->isDerivedRequirement() &&
6370+
!layout.merge(equivClass.layout)->isKnownLayout()) {
6371+
auto req =
6372+
ExplicitRequirement::fromExplicitConstraint(
6373+
RequirementKind::Layout, constraint);
6374+
Impl->ConflictingRequirements.insert(
6375+
std::make_pair(req, equivClass.layout));
6376+
}
6377+
6378+
// FIXME: Check for a conflict via the concrete type.
6379+
lessSpecific.push_back(constraint);
6380+
}
6381+
6382+
graph.addConstraintsFromEquivClass(RequirementKind::Layout,
6383+
exact, lessSpecific);
63166384
}
63176385
}
63186386

0 commit comments

Comments
 (0)