Skip to content

Commit 29ebb3d

Browse files
authored
Merge pull request #41592 from slavapestov/rqm-verify-generic-signatures
RequirementMachine: Fix -verify-generic-signatures mode to not violate invariants
2 parents 417adb5 + 628af19 commit 29ebb3d

File tree

5 files changed

+76
-7
lines changed

5 files changed

+76
-7
lines changed

lib/AST/GenericSignature.cpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,39 @@ void GenericSignature::verify(ArrayRef<Requirement> reqts) const {
994994
}
995995
}
996996

997+
static Type stripBoundDependentMemberTypes(Type t) {
998+
if (auto *depMemTy = t->getAs<DependentMemberType>()) {
999+
return DependentMemberType::get(
1000+
stripBoundDependentMemberTypes(depMemTy->getBase()),
1001+
depMemTy->getName());
1002+
}
1003+
1004+
return t;
1005+
}
1006+
1007+
static Requirement stripBoundDependentMemberTypes(Requirement req) {
1008+
auto subjectType = stripBoundDependentMemberTypes(req.getFirstType());
1009+
1010+
switch (req.getKind()) {
1011+
case RequirementKind::Conformance:
1012+
return Requirement(RequirementKind::Conformance, subjectType,
1013+
req.getSecondType());
1014+
1015+
case RequirementKind::Superclass:
1016+
case RequirementKind::SameType:
1017+
return Requirement(req.getKind(), subjectType,
1018+
req.getSecondType().transform([](Type t) {
1019+
return stripBoundDependentMemberTypes(t);
1020+
}));
1021+
1022+
case RequirementKind::Layout:
1023+
return Requirement(RequirementKind::Layout, subjectType,
1024+
req.getLayoutConstraint());
1025+
}
1026+
1027+
llvm_unreachable("Bad requirement kind");
1028+
}
1029+
9971030
void swift::validateGenericSignature(ASTContext &context,
9981031
GenericSignature sig) {
9991032
llvm::errs() << "Validating generic signature: ";
@@ -1007,7 +1040,7 @@ void swift::validateGenericSignature(ASTContext &context,
10071040

10081041
SmallVector<Requirement, 2> requirements;
10091042
for (auto requirement : sig.getRequirements())
1010-
requirements.push_back(requirement);
1043+
requirements.push_back(stripBoundDependentMemberTypes(requirement));
10111044

10121045
{
10131046
PrettyStackTraceGenericSignature debugStack("verifying", sig);
@@ -1043,7 +1076,7 @@ void swift::validateGenericSignature(ASTContext &context,
10431076
SmallVector<Requirement, 2> newRequirements;
10441077
for (unsigned i : indices(requirements)) {
10451078
if (i != victimIndex)
1046-
newRequirements.push_back(requirements[i]);
1079+
newRequirements.push_back(stripBoundDependentMemberTypes(requirements[i]));
10471080
}
10481081

10491082
auto newSigWithError = evaluateOrDefault(

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,12 +775,17 @@ void RewriteSystem::minimizeRewriteSystem() {
775775
}
776776

777777
/// In a conformance-valid rewrite system, any rule with unresolved symbols on
778-
/// the left or right hand side should have been simplified by another rule.
778+
/// the left or right hand side should be redundant. The presence of unresolved
779+
/// non-redundant rules means one of the original requirements written by the
780+
/// user was invalid.
779781
bool RewriteSystem::hadError() const {
780782
assert(Complete);
781783
assert(Minimized);
782784

783785
for (const auto &rule : Rules) {
786+
if (!isInMinimizationDomain(rule.getLHS().getRootProtocol()))
787+
continue;
788+
784789
if (rule.isPermanent())
785790
continue;
786791

lib/AST/RequirementMachine/InterfaceType.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,16 @@ getTypeForSymbolRange(const Symbol *begin, const Symbol *end, Type root,
261261
// Return a sugared GenericTypeParamType if we're given an array of
262262
// sugared types to substitute.
263263
unsigned index = GenericParamKey(genericParam).findIndexIn(genericParams);
264+
265+
if (index == genericParams.size()) {
266+
llvm::errs() << "Invalid generic parameter: " << genericParam << "\n";
267+
llvm::errs() << "Valid generic parameters are";
268+
for (auto *otherParam : genericParams)
269+
llvm::errs() << " " << Type(otherParam);
270+
llvm::errs() << "\n";
271+
abort();
272+
}
273+
264274
result = genericParams[index];
265275
return;
266276
}
@@ -344,7 +354,14 @@ getTypeForSymbolRange(const Symbol *begin, const Symbol *end, Type root,
344354
assert(prefix.size() > 0);
345355

346356
auto *props = map.lookUpProperties(prefix.rbegin(), prefix.rend());
347-
assert(props != nullptr);
357+
if (props == nullptr) {
358+
llvm::errs() << "Cannot build interface type for term "
359+
<< MutableTerm(begin, end) << "\n";
360+
llvm::errs() << "Prefix does not conform to any protocols: "
361+
<< prefix << "\n\n";
362+
map.dump(llvm::errs());
363+
abort();
364+
}
348365

349366
// Assert that the associated type's protocol appears among the set
350367
// of protocols that the prefix conforms to.
@@ -356,6 +373,18 @@ getTypeForSymbolRange(const Symbol *begin, const Symbol *end, Type root,
356373
#endif
357374

358375
assocType = props->getAssociatedType(symbol.getName());
376+
if (assocType == nullptr) {
377+
llvm::errs() << "Cannot build interface type for term "
378+
<< MutableTerm(begin, end) << "\n";
379+
llvm::errs() << "Prefix term does not not have a nested type named "
380+
<< symbol.getName() << ": "
381+
<< prefix << "\n";
382+
llvm::errs() << "Property map entry: ";
383+
props->dump(llvm::errs());
384+
llvm::errs() << "\n\n";
385+
map.dump(llvm::errs());
386+
abort();
387+
}
359388
}
360389

361390
result = DependentMemberType::get(result, assocType);

lib/AST/RequirementMachine/MinimalConformances.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,9 @@ void MinimalConformances::collectConformanceRules() {
470470
/// That is, we can choose to eliminate <X>.[P], but not <Y>.[P], or vice
471471
/// versa; but it is never valid to eliminate both.
472472
void MinimalConformances::computeCandidateConformancePaths() {
473-
for (const auto &loop : System.getLoops()) {
473+
for (unsigned loopID : indices(System.getLoops())) {
474+
const auto &loop = System.getLoops()[loopID];
475+
474476
if (loop.isDeleted())
475477
continue;
476478

@@ -483,7 +485,7 @@ void MinimalConformances::computeCandidateConformancePaths() {
483485
continue;
484486

485487
if (Debug.contains(DebugFlags::MinimalConformances)) {
486-
llvm::dbgs() << "Candidate homotopy generator: ";
488+
llvm::dbgs() << "Candidate homotopy generator: (#" << loopID << ") ";
487489
loop.dump(llvm::dbgs(), System);
488490
llvm::dbgs() << "\n";
489491
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// Verifies that all of the generic signatures in the standard library are
22
// minimal and canonical.
33

4-
// RUN: %target-typecheck-verify-swift -verify-generic-signatures Swift
4+
// RUN: %target-typecheck-verify-swift -verify-generic-signatures Swift -requirement-machine-abstract-signatures=on

0 commit comments

Comments
 (0)