Skip to content

Commit 080f3d2

Browse files
committed
AST: Fix up SubstitutionMap::verify()
1 parent 2c3ee09 commit 080f3d2

File tree

2 files changed

+85
-55
lines changed

2 files changed

+85
-55
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,9 @@ class SubstitutionMap {
213213
/// interface types.
214214
SubstitutionMap mapReplacementTypesOutOfContext() const;
215215

216-
/// Verify that this substitution map is valid.
217-
void verify() const;
216+
/// Verify that the conformances stored in this substitution map match the
217+
/// replacement types provided.
218+
void verify(bool allowInvalid=true) const;
218219

219220
/// Whether to dump the full substitution map, or just a minimal useful subset
220221
/// (on a single line).

lib/AST/SubstitutionMap.cpp

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,8 @@ SubstitutionMap::SubstitutionMap(
6060
ArrayRef<Type> replacementTypes,
6161
ArrayRef<ProtocolConformanceRef> conformances)
6262
: storage(Storage::get(genericSig, replacementTypes, conformances)) {
63-
#ifndef NDEBUG
6463
if (genericSig->getASTContext().LangOpts.VerifyAllSubstitutionMaps)
6564
verify();
66-
#endif
6765
}
6866

6967
ArrayRef<ProtocolConformanceRef> SubstitutionMap::getConformances() const {
@@ -534,78 +532,109 @@ SubstitutionMap::getOverrideSubstitutions(const NominalTypeDecl *baseNominal,
534532
LookUpConformanceInOverrideSubs(info));
535533
}
536534

537-
void SubstitutionMap::verify() const {
538-
#ifndef NDEBUG
535+
void SubstitutionMap::verify(bool allowInvalid) const {
539536
if (empty())
540537
return;
541538

539+
auto genericSig = getGenericSignature();
540+
auto &ctx = genericSig->getASTContext();
541+
542+
if (ctx.isRecursivelyConstructingRequirementMachine(
543+
genericSig.getCanonicalSignature()))
544+
return;
545+
542546
unsigned conformanceIndex = 0;
543547

544-
for (const auto &req : getGenericSignature().getRequirements()) {
548+
for (const auto &req : genericSig.getRequirements()) {
545549
if (req.getKind() != RequirementKind::Conformance)
546550
continue;
547551

548552
SWIFT_DEFER { ++conformanceIndex; };
553+
auto conformance = getConformances()[conformanceIndex];
554+
549555
auto substType = req.getFirstType().subst(*this);
550-
if (substType->isTypeParameter() ||
551-
substType->is<ArchetypeType>() ||
552-
substType->isTypeVariableOrMember() ||
553-
substType->is<UnresolvedType>() ||
554-
substType->hasError())
555-
continue;
556556

557-
auto conformance = getConformances()[conformanceIndex];
557+
// Unwrap various strange things.
558+
substType = substType->getReferenceStorageReferent();
559+
if (auto *selfType = substType->getAs<DynamicSelfType>())
560+
substType = selfType->getSelfType();
558561

559-
if (conformance.isInvalid())
560-
continue;
562+
// Don't bother validating these cases.
563+
if (allowInvalid && substType->hasUnboundGenericType())
564+
return;
565+
566+
if (conformance.isInvalid()) {
567+
if (!allowInvalid) {
568+
llvm::errs() << "Unexpected invalid conformance in substitution map:\n";
569+
dump(llvm::dbgs());
570+
llvm::errs() << "\n";
571+
abort();
572+
}
561573

562-
// All of the conformances should be concrete.
563-
if (!conformance.isConcrete()) {
564-
llvm::dbgs() << "Concrete type cannot have abstract conformance:\n";
565-
substType->dump(llvm::dbgs());
566-
llvm::dbgs() << "SubstitutionMap:\n";
567-
dump(llvm::dbgs());
568-
llvm::dbgs() << "\n";
569-
llvm::dbgs() << "Requirement:\n";
570-
req.dump(llvm::dbgs());
571-
llvm::dbgs() << "\n";
574+
continue;
572575
}
573-
assert(conformance.isConcrete() && "Conformance should be concrete");
574-
575-
if (substType->is<UnboundGenericType>())
576+
577+
if (conformance.isAbstract()) {
578+
if (!substType->isTypeParameter() &&
579+
!substType->is<PackElementType>() &&
580+
!substType->is<ArchetypeType>() &&
581+
!substType->isTypeVariableOrMember() &&
582+
!substType->is<UnresolvedType>() &&
583+
!substType->is<PlaceholderType>() &&
584+
!substType->is<ErrorType>()) {
585+
llvm::errs() << "Unexpected abstract conformance in substitution map:\n";
586+
dump(llvm::errs());
587+
llvm::errs() << "\n";
588+
abort();
589+
}
590+
576591
continue;
577-
578-
auto conformanceTy = conformance.getConcrete()->getType();
579-
if (conformanceTy->hasTypeParameter()
580-
&& !substType->hasTypeParameter()) {
581-
conformanceTy = conformance.getConcrete()->getDeclContext()
582-
->mapTypeIntoContext(conformanceTy);
583592
}
584-
585-
if (!substType->isEqual(conformanceTy)) {
586-
llvm::dbgs() << "Conformance must match concrete replacement type:\n";
587-
substType->dump(llvm::dbgs());
588-
llvm::dbgs() << "Conformance type:\n";
589-
conformance.getConcrete()->getType()->dump(llvm::dbgs());
590-
llvm::dbgs() << "Conformance:\n";
591-
conformance.dump(llvm::dbgs());
592-
llvm::dbgs() << "\n";
593-
llvm::dbgs() << "SubstitutionMap:\n";
594-
dump(llvm::dbgs());
595-
llvm::dbgs() << "\n";
596-
llvm::dbgs() << "Requirement:\n";
597-
req.dump(llvm::dbgs());
598-
llvm::dbgs() << "\n";
593+
594+
if (conformance.isPack()) {
595+
// FIXME: Implement some kind of check here.
596+
continue;
599597
}
600-
assert(substType->isEqual(conformanceTy)
601-
&& "conformance should match corresponding type");
598+
599+
auto *concrete = conformance.getConcrete();
602600

603601
if (substType->isExistentialType()) {
604-
assert(isa<SelfProtocolConformance>(conformance.getConcrete()) &&
605-
"Existential type cannot have normal conformance");
602+
if (req.getProtocolDecl()->isSpecificProtocol(KnownProtocolKind::Sendable) &&
603+
isa<BuiltinProtocolConformance>(concrete)) {
604+
continue;
605+
}
606+
607+
if (!isa<SelfProtocolConformance>(concrete)) {
608+
// A superclass-constrained self-conforming existential might conform
609+
// concretely.
610+
if (substType->getSuperclass())
611+
continue;
612+
613+
llvm::errs() << "Expected to find a self conformance:\n";
614+
substType->dump(llvm::errs());
615+
llvm::errs() << "Substitution map:\n";
616+
dump(llvm::errs());
617+
llvm::errs() << "\n";
618+
abort();
619+
}
620+
621+
continue;
622+
}
623+
624+
if (substType->isTypeParameter())
625+
continue;
626+
627+
if (!concrete->getType()->isEqual(substType)) {
628+
llvm::errs() << "Conformance with wrong conforming type:\n";
629+
concrete->getType()->dump(llvm::errs());
630+
llvm::errs() << "Should be:\n";
631+
substType->dump(llvm::errs());
632+
llvm::errs() << "Substitution map:\n";
633+
dump(llvm::errs());
634+
llvm::errs() << "\n";
635+
abort();
606636
}
607637
}
608-
#endif
609638
}
610639

611640
void SubstitutionMap::profile(llvm::FoldingSetNodeID &id) const {

0 commit comments

Comments
 (0)