Skip to content

Commit 2614465

Browse files
authored
Merge pull request #41648 from slavapestov/rqm-concrete-contraction-fixes-and-more
RequirementMachine: Fix some problems in concrete contraction and a couple of other issues
2 parents bc3a9d2 + 64f049a commit 2614465

11 files changed

+182
-106
lines changed

lib/AST/RequirementMachine/ConcreteContraction.cpp

Lines changed: 49 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,10 @@ namespace {
157157
class ConcreteContraction {
158158
bool Debug;
159159

160-
llvm::SmallDenseMap<GenericParamKey, Type> ConcreteTypes;
161-
llvm::SmallDenseMap<GenericParamKey, Type> Superclasses;
160+
llvm::SmallDenseMap<GenericParamKey,
161+
llvm::SmallDenseSet<Type, 1>> ConcreteTypes;
162+
llvm::SmallDenseMap<GenericParamKey,
163+
llvm::SmallDenseSet<Type, 1>> Superclasses;
162164
llvm::SmallDenseMap<GenericParamKey,
163165
llvm::SmallVector<ProtocolDecl *, 1>> Conformances;
164166

@@ -229,32 +231,44 @@ Optional<Type> ConcreteContraction::substTypeParameter(
229231
if (!substBaseType)
230232
return None;
231233

232-
auto *decl = (*substBaseType)->getAnyNominal();
233-
if (decl == nullptr) {
234-
llvm::dbgs() << "@@@ Not a nominal type: " << *substBaseType << "\n";
235-
return None;
236-
}
237-
238-
auto *module = decl->getParentModule();
239-
240234
// A resolved DependentMemberType stores an associated type declaration.
241235
//
242236
// Handle this by looking up the corresponding type witness in the base
243237
// type's conformance to the associated type's protocol.
244238
if (auto *assocType = memberType->getAssocType()) {
245-
auto conformance = module->lookupConformance(
246-
*substBaseType, assocType->getProtocol());
239+
auto *proto = assocType->getProtocol();
240+
auto *module = proto->getParentModule();
241+
242+
auto conformance = ((*substBaseType)->isTypeParameter()
243+
? ProtocolConformanceRef(proto)
244+
: module->lookupConformance(*substBaseType, proto));
247245

248246
// The base type doesn't conform, in which case the requirement remains
249247
// unsubstituted.
250-
if (!conformance)
248+
if (!conformance) {
249+
if (Debug) {
250+
llvm::dbgs() << "@@@ " << substBaseType << " does not conform to "
251+
<< proto->getName() << "\n";
252+
}
251253
return None;
254+
}
252255

253256
return assocType->getDeclaredInterfaceType()
254257
->castTo<DependentMemberType>()
255258
->substBaseType(module, *substBaseType);
256259
}
257260

261+
auto *decl = (*substBaseType)->getAnyNominal();
262+
if (decl == nullptr) {
263+
if (Debug) {
264+
llvm::dbgs() << "@@@ Not a nominal type: " << *substBaseType << "\n";
265+
}
266+
267+
return None;
268+
}
269+
270+
auto *module = decl->getParentModule();
271+
258272
// An unresolved DependentMemberType stores an identifier. Handle this
259273
// by performing a name lookup into the base type.
260274
auto *typeDecl = lookupConcreteNestedType(module, decl,
@@ -293,20 +307,22 @@ Type ConcreteContraction::substTypeParameter(
293307
Type concreteType;
294308
{
295309
auto found = ConcreteTypes.find(key);
296-
if (found != ConcreteTypes.end())
297-
concreteType = found->second;
310+
if (found != ConcreteTypes.end() && found->second.size() == 1)
311+
concreteType = *found->second.begin();
298312
}
299313

300314
Type superclass;
301315
{
302316
auto found = Superclasses.find(key);
303-
if (found != Superclasses.end())
304-
superclass = found->second;
317+
if (found != Superclasses.end() && found->second.size() == 1)
318+
superclass = *found->second.begin();
305319
}
306320

307321
if (!concreteType && !superclass)
308322
return type;
309323

324+
// If we have both, prefer the concrete type requirement since it is more
325+
// specific.
310326
if (!concreteType) {
311327
assert(superclass);
312328

@@ -431,35 +447,15 @@ bool ConcreteContraction::performConcreteContraction(
431447
if (constraintType->isTypeParameter())
432448
break;
433449

434-
auto entry = std::make_pair(GenericParamKey(genericParam),
435-
constraintType);
436-
bool inserted = ConcreteTypes.insert(entry).second;
437-
if (!inserted) {
438-
if (Debug) {
439-
llvm::dbgs() << "@ Concrete contraction cannot proceed: "
440-
<< "duplicate concrete type requirements\n";
441-
}
442-
return false;
443-
}
444-
450+
ConcreteTypes[GenericParamKey(genericParam)].insert(constraintType);
445451
break;
446452
}
447453
case RequirementKind::Superclass: {
448454
auto constraintType = req.req.getSecondType();
449455
assert(!constraintType->isTypeParameter() &&
450456
"You forgot to call desugarRequirement()");
451457

452-
auto entry = std::make_pair(GenericParamKey(genericParam),
453-
constraintType);
454-
bool inserted = Superclasses.insert(entry).second;
455-
if (!inserted) {
456-
if (Debug) {
457-
llvm::dbgs() << "@ Concrete contraction cannot proceed: "
458-
<< "duplicate superclass requirements\n";
459-
}
460-
return false;
461-
}
462-
458+
Superclasses[GenericParamKey(genericParam)].insert(constraintType);
463459
break;
464460
}
465461
case RequirementKind::Conformance: {
@@ -481,10 +477,10 @@ bool ConcreteContraction::performConcreteContraction(
481477
for (const auto &pair : Conformances) {
482478
auto subjectType = pair.first;
483479
auto found = Superclasses.find(subjectType);
484-
if (found == Superclasses.end())
480+
if (found == Superclasses.end() || found->second.size() != 1)
485481
continue;
486482

487-
auto superclassTy = found->second;
483+
auto superclassTy = *found->second.begin();
488484

489485
for (const auto *proto : pair.second) {
490486
if (auto otherSuperclassTy = proto->getSuperclass()) {
@@ -508,35 +504,27 @@ bool ConcreteContraction::performConcreteContraction(
508504
if (ConcreteTypes.empty() && Superclasses.empty())
509505
return false;
510506

511-
// If a generic parameter is subject to both a concrete type and superclass
512-
// requirement, bail out because we're not smart enough to figure out what's
513-
// going on.
514-
for (auto pair : ConcreteTypes) {
515-
auto subjectType = pair.first;
516-
517-
if (Superclasses.find(subjectType) != Superclasses.end()) {
518-
if (Debug) {
519-
llvm::dbgs() << "@ Concrete contraction cannot proceed; "
520-
<< "τ_" << subjectType.Depth << "_" << subjectType.Index
521-
<< " has both a concrete type and superclass requirement";
522-
}
523-
return false;
524-
}
525-
}
526-
527507
if (Debug) {
528508
llvm::dbgs() << "@ Concrete types: @\n";
529509
for (auto pair : ConcreteTypes) {
530510
llvm::dbgs() << "- τ_" << pair.first.Depth
531-
<< "_" << pair.first.Index << " == "
532-
<< pair.second << "\n";
511+
<< "_" << pair.first.Index;
512+
if (pair.second.size() == 1) {
513+
llvm::dbgs() << " == " << *pair.second.begin() << "\n";
514+
} else {
515+
llvm::dbgs() << " has duplicate concrete type requirements\n";
516+
}
533517
}
534518

535519
llvm::dbgs() << "@ Superclasses: @\n";
536520
for (auto pair : Superclasses) {
537521
llvm::dbgs() << "- τ_" << pair.first.Depth
538-
<< "_" << pair.first.Index << " : "
539-
<< pair.second << "\n";
522+
<< "_" << pair.first.Index;
523+
if (pair.second.size() == 1) {
524+
llvm::dbgs() << " : " << *pair.second.begin() << "\n";
525+
} else {
526+
llvm::dbgs() << " has duplicate superclass requirements\n";
527+
}
540528
}
541529
}
542530

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -864,18 +864,15 @@ RewriteSystem::getMinimizedGenericSignatureRules() const {
864864

865865
/// Verify that each loop begins and ends at its basepoint.
866866
void RewriteSystem::verifyRewriteLoops() const {
867-
#ifndef NDEBUG
868867
for (const auto &loop : Loops) {
869868
loop.verify(*this);
870869
}
871-
#endif
872870
}
873871

874872
/// Assert if homotopy reduction failed to eliminate a redundant conformance,
875873
/// since this suggests a misunderstanding on my part.
876874
void RewriteSystem::verifyRedundantConformances(
877875
const llvm::DenseSet<unsigned> &redundantConformances) const {
878-
#ifndef NDEBUG
879876
for (unsigned ruleID : redundantConformances) {
880877
const auto &rule = getRule(ruleID);
881878
assert(!rule.isPermanent() &&
@@ -893,14 +890,12 @@ void RewriteSystem::verifyRedundantConformances(
893890
abort();
894891
}
895892
}
896-
#endif
897893
}
898894

899895
// Assert if homotopy reduction failed to eliminate a rewrite rule it was
900896
// supposed to delete.
901897
void RewriteSystem::verifyMinimizedRules(
902898
const llvm::DenseSet<unsigned> &redundantConformances) const {
903-
#ifndef NDEBUG
904899
unsigned redundantRuleCount = 0;
905900

906901
for (unsigned ruleID : indices(Rules)) {
@@ -982,5 +977,4 @@ void RewriteSystem::verifyMinimizedRules(
982977
abort();
983978
}
984979
}
985-
#endif
986980
}

lib/AST/RequirementMachine/MinimalConformances.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -418,16 +418,25 @@ void MinimalConformances::collectConformanceRules() {
418418

419419
// Sort the list of conformance rules in reverse order; we're going to try
420420
// to minimize away less canonical rules first.
421-
std::sort(ConformanceRules.begin(), ConformanceRules.end(),
422-
[&](unsigned lhs, unsigned rhs) -> bool {
423-
const auto &lhsRule = System.getRule(lhs);
424-
const auto &rhsRule = System.getRule(rhs);
425-
426-
if (lhsRule.isExplicit() != rhsRule.isExplicit())
427-
return !lhsRule.isExplicit();
428-
429-
return *lhsRule.getLHS().compare(rhsRule.getLHS(), Context) > 0;
430-
});
421+
std::stable_sort(ConformanceRules.begin(), ConformanceRules.end(),
422+
[&](unsigned lhs, unsigned rhs) -> bool {
423+
const auto &lhsRule = System.getRule(lhs);
424+
const auto &rhsRule = System.getRule(rhs);
425+
426+
if (lhsRule.isExplicit() != rhsRule.isExplicit())
427+
return !lhsRule.isExplicit();
428+
429+
auto result = lhsRule.getLHS().compare(rhsRule.getLHS(), Context);
430+
431+
// Concrete conformance rules are unordered if they name the
432+
// same protocol but have different types. This can come up
433+
// if we have a class inheritance relationship 'Derived : Base',
434+
// and Base conforms to a protocol:
435+
//
436+
// T.[Base : P] => T
437+
// T.[Derived : P] => T
438+
return (result ? *result > 0 : 0);
439+
});
431440

432441
Context.ConformanceRulesHistogram.add(ConformanceRules.size());
433442
}
@@ -742,7 +751,6 @@ void MinimalConformances::dumpMinimalConformanceEquation(
742751
}
743752

744753
void MinimalConformances::verifyMinimalConformanceEquations() const {
745-
#ifndef NDEBUG
746754
for (const auto &pair : ConformancePaths) {
747755
const auto &rule = System.getRule(pair.first);
748756
auto *proto = rule.getLHS().back().getProtocol();
@@ -804,7 +812,6 @@ void MinimalConformances::verifyMinimalConformanceEquations() const {
804812
}
805813
}
806814
}
807-
#endif
808815
}
809816

810817
bool MinimalConformances::isDerivedViaCircularConformanceRule(
@@ -884,7 +891,6 @@ void MinimalConformances::computeMinimalConformances() {
884891

885892
/// Check invariants.
886893
void MinimalConformances::verifyMinimalConformances() const {
887-
#ifndef NDEBUG
888894
for (const auto &pair : ConformancePaths) {
889895
unsigned ruleID = pair.first;
890896
const auto &rule = System.getRule(ruleID);
@@ -913,7 +919,6 @@ void MinimalConformances::verifyMinimalConformances() const {
913919
abort();
914920
}
915921
}
916-
#endif
917922
}
918923

919924
void MinimalConformances::dumpMinimalConformances(

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,9 @@ AbstractGenericSignatureRequestRQM::evaluate(
524524
auto result = GenericSignature::get(genericParams, minimalRequirements);
525525
bool hadError = machine->hadError();
526526

527+
if (!hadError)
528+
result.verify();
529+
527530
return GenericSignatureWithError(result, hadError);
528531
}
529532

@@ -669,5 +672,9 @@ InferredGenericSignatureRequestRQM::evaluate(
669672

670673
// FIXME: Handle allowConcreteGenericParams
671674

675+
// Check invariants.
676+
if (!hadError)
677+
result.verify();
678+
672679
return GenericSignatureWithError(result, hadError);
673680
}

lib/AST/RequirementMachine/RewriteLoop.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ void RewritePath::dumpLong(llvm::raw_ostream &out,
203203
}
204204

205205
void RewriteLoop::verify(const RewriteSystem &system) const {
206-
#ifndef NDEBUG
207206
RewritePathEvaluator evaluator(Basepoint);
208207

209208
for (const auto &step : Path) {
@@ -222,7 +221,6 @@ void RewriteLoop::verify(const RewriteSystem &system) const {
222221
evaluator.dump(llvm::errs());
223222
abort();
224223
}
225-
#endif
226224
}
227225

228226
void RewriteLoop::dump(llvm::raw_ostream &out,

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -631,14 +631,12 @@ void RewriteSystem::recordRewriteLoop(MutableTerm basepoint,
631631
}
632632

633633
void RewriteSystem::verifyRewriteRules(ValidityPolicy policy) const {
634-
#ifndef NDEBUG
635-
636634
#define ASSERT_RULE(expr) \
637635
if (!(expr)) { \
638636
llvm::errs() << "&&& Malformed rewrite rule: " << rule << "\n"; \
639637
llvm::errs() << "&&& " << #expr << "\n\n"; \
640638
dump(llvm::errs()); \
641-
assert(expr); \
639+
abort(); \
642640
}
643641

644642
for (const auto &rule : Rules) {
@@ -705,7 +703,6 @@ void RewriteSystem::verifyRewriteRules(ValidityPolicy policy) const {
705703
}
706704

707705
#undef ASSERT_RULE
708-
#endif
709706
}
710707

711708
void RewriteSystem::dump(llvm::raw_ostream &out) const {

0 commit comments

Comments
 (0)