Skip to content

Commit cfdb937

Browse files
committed
AST: Stricter invariants in GenericSignature::verify()
1 parent b6a641b commit cfdb937

File tree

1 file changed

+41
-28
lines changed

1 file changed

+41
-28
lines changed

lib/AST/GenericSignature.cpp

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,9 @@ void GenericSignature::verify(ArrayRef<Requirement> reqts) const {
827827
// We collect conformance requirements to check that they're minimal.
828828
llvm::SmallDenseMap<CanType, SmallVector<ProtocolDecl *, 2>, 2> conformances;
829829

830+
// We collect same-type requirements to check that they're minimal.
831+
llvm::SmallDenseMap<CanType, SmallVector<Type, 2>, 2> sameTypeComponents;
832+
830833
// Check that the requirements satisfy certain invariants.
831834
for (unsigned idx : indices(reqts)) {
832835
const auto &reqt = reqts[idx].getCanonical();
@@ -873,6 +876,10 @@ void GenericSignature::verify(ArrayRef<Requirement> reqts) const {
873876

874877
auto firstType = reqt.getFirstType();
875878
auto secondType = reqt.getSecondType();
879+
880+
auto canType = canSig->getCanonicalTypeInContext(firstType);
881+
auto &component = sameTypeComponents[canType];
882+
876883
if (!hasCanonicalOrConcreteParent(firstType)) {
877884
llvm::errs() << "Left hand side does not have a canonical parent: ";
878885
reqt.dump(llvm::errs());
@@ -893,13 +900,34 @@ void GenericSignature::verify(ArrayRef<Requirement> reqts) const {
893900
llvm::errs() << "\n";
894901
abort();
895902
}
903+
904+
if (component.empty()) {
905+
component.push_back(firstType);
906+
} else if (!component.back()->isEqual(firstType)) {
907+
llvm::errs() << "Same-type requirement within an equiv. class "
908+
<< "is out-of-order: ";
909+
reqt.dump(llvm::errs());
910+
llvm::errs() << "\n";
911+
abort();
912+
}
913+
914+
component.push_back(secondType);
896915
} else {
897916
if (!canSig->isCanonicalTypeInContext(secondType)) {
898917
llvm::errs() << "Right hand side is not canonical: ";
899918
reqt.dump(llvm::errs());
900919
llvm::errs() << "\n";
901920
abort();
902921
}
922+
923+
if (component.empty()) {
924+
component.push_back(secondType);
925+
} else if (!component.back()->isEqual(secondType)) {
926+
llvm::errs() << "Inconsistent concrete requirement in equiv. class: ";
927+
reqt.dump(llvm::errs());
928+
llvm::errs() << "\n";
929+
abort();
930+
}
903931
}
904932
break;
905933
}
@@ -925,33 +953,6 @@ void GenericSignature::verify(ArrayRef<Requirement> reqts) const {
925953
abort();
926954
}
927955

928-
// If we have two same-type requirements where the left-hand sides differ
929-
// but fall into the same equivalence class, we can check the form.
930-
if (compareLHS < 0 && reqt.getKind() == RequirementKind::SameType &&
931-
prevReqt.getKind() == RequirementKind::SameType &&
932-
canSig->areSameTypeParameterInContext(prevReqt.getFirstType(),
933-
reqt.getFirstType())) {
934-
// If it's a it's a type parameter, make sure the equivalence class is
935-
// wired together sanely.
936-
if (prevReqt.getSecondType()->isTypeParameter()) {
937-
if (!prevReqt.getSecondType()->isEqual(reqt.getFirstType())) {
938-
llvm::errs() << "Same-type requirement within an equiv. class "
939-
<< "is out-of-order: ";
940-
reqt.dump(llvm::errs());
941-
llvm::errs() << "\n";
942-
abort();
943-
}
944-
} else {
945-
// Otherwise, the concrete types must match up.
946-
if (!prevReqt.getSecondType()->isEqual(reqt.getSecondType())) {
947-
llvm::errs() << "Inconsistent concrete requirement in equiv. class: ";
948-
reqt.dump(llvm::errs());
949-
llvm::errs() << "\n";
950-
abort();
951-
}
952-
}
953-
}
954-
955956
// If we have a concrete same-type requirement, we shouldn't have any
956957
// other requirements on the same type.
957958
if (reqt.getKind() == RequirementKind::SameType &&
@@ -974,7 +975,7 @@ void GenericSignature::verify(ArrayRef<Requirement> reqts) const {
974975
}
975976

976977
// Make sure we don't have redundant protocol conformance requirements.
977-
for (auto pair : conformances) {
978+
for (const auto &pair : conformances) {
978979
const auto &protos = pair.second;
979980
auto canonicalProtos = protos;
980981

@@ -992,6 +993,18 @@ void GenericSignature::verify(ArrayRef<Requirement> reqts) const {
992993
abort();
993994
}
994995
}
996+
997+
// Check same-type components for consistency.
998+
for (const auto &pair : sameTypeComponents) {
999+
if (pair.second.front()->isTypeParameter() &&
1000+
!canSig->isCanonicalTypeInContext(pair.second.front())) {
1001+
llvm::errs() << "Abstract same-type requirement involving concrete types\n";
1002+
llvm::errs() << "Canonical type: " << pair.first << "\n";
1003+
llvm::errs() << "Left hand side of first requirement: "
1004+
<< pair.second.front() << "\n";
1005+
abort();
1006+
}
1007+
}
9951008
}
9961009

9971010
static Type stripBoundDependentMemberTypes(Type t) {

0 commit comments

Comments
 (0)