mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
AST: Fix up SubstitutionMap::verify()
This commit is contained in:
@@ -60,10 +60,8 @@ SubstitutionMap::SubstitutionMap(
|
||||
ArrayRef<Type> replacementTypes,
|
||||
ArrayRef<ProtocolConformanceRef> conformances)
|
||||
: storage(Storage::get(genericSig, replacementTypes, conformances)) {
|
||||
#ifndef NDEBUG
|
||||
if (genericSig->getASTContext().LangOpts.VerifyAllSubstitutionMaps)
|
||||
verify();
|
||||
#endif
|
||||
}
|
||||
|
||||
ArrayRef<ProtocolConformanceRef> SubstitutionMap::getConformances() const {
|
||||
@@ -534,78 +532,109 @@ SubstitutionMap::getOverrideSubstitutions(const NominalTypeDecl *baseNominal,
|
||||
LookUpConformanceInOverrideSubs(info));
|
||||
}
|
||||
|
||||
void SubstitutionMap::verify() const {
|
||||
#ifndef NDEBUG
|
||||
void SubstitutionMap::verify(bool allowInvalid) const {
|
||||
if (empty())
|
||||
return;
|
||||
|
||||
auto genericSig = getGenericSignature();
|
||||
auto &ctx = genericSig->getASTContext();
|
||||
|
||||
if (ctx.isRecursivelyConstructingRequirementMachine(
|
||||
genericSig.getCanonicalSignature()))
|
||||
return;
|
||||
|
||||
unsigned conformanceIndex = 0;
|
||||
|
||||
for (const auto &req : getGenericSignature().getRequirements()) {
|
||||
for (const auto &req : genericSig.getRequirements()) {
|
||||
if (req.getKind() != RequirementKind::Conformance)
|
||||
continue;
|
||||
|
||||
SWIFT_DEFER { ++conformanceIndex; };
|
||||
auto substType = req.getFirstType().subst(*this);
|
||||
if (substType->isTypeParameter() ||
|
||||
substType->is<ArchetypeType>() ||
|
||||
substType->isTypeVariableOrMember() ||
|
||||
substType->is<UnresolvedType>() ||
|
||||
substType->hasError())
|
||||
continue;
|
||||
|
||||
auto conformance = getConformances()[conformanceIndex];
|
||||
|
||||
if (conformance.isInvalid())
|
||||
continue;
|
||||
auto substType = req.getFirstType().subst(*this);
|
||||
|
||||
// Unwrap various strange things.
|
||||
substType = substType->getReferenceStorageReferent();
|
||||
if (auto *selfType = substType->getAs<DynamicSelfType>())
|
||||
substType = selfType->getSelfType();
|
||||
|
||||
// Don't bother validating these cases.
|
||||
if (allowInvalid && substType->hasUnboundGenericType())
|
||||
return;
|
||||
|
||||
if (conformance.isInvalid()) {
|
||||
if (!allowInvalid) {
|
||||
llvm::errs() << "Unexpected invalid conformance in substitution map:\n";
|
||||
dump(llvm::dbgs());
|
||||
llvm::errs() << "\n";
|
||||
abort();
|
||||
}
|
||||
|
||||
// All of the conformances should be concrete.
|
||||
if (!conformance.isConcrete()) {
|
||||
llvm::dbgs() << "Concrete type cannot have abstract conformance:\n";
|
||||
substType->dump(llvm::dbgs());
|
||||
llvm::dbgs() << "SubstitutionMap:\n";
|
||||
dump(llvm::dbgs());
|
||||
llvm::dbgs() << "\n";
|
||||
llvm::dbgs() << "Requirement:\n";
|
||||
req.dump(llvm::dbgs());
|
||||
llvm::dbgs() << "\n";
|
||||
}
|
||||
assert(conformance.isConcrete() && "Conformance should be concrete");
|
||||
|
||||
if (substType->is<UnboundGenericType>())
|
||||
continue;
|
||||
|
||||
auto conformanceTy = conformance.getConcrete()->getType();
|
||||
if (conformanceTy->hasTypeParameter()
|
||||
&& !substType->hasTypeParameter()) {
|
||||
conformanceTy = conformance.getConcrete()->getDeclContext()
|
||||
->mapTypeIntoContext(conformanceTy);
|
||||
}
|
||||
|
||||
if (!substType->isEqual(conformanceTy)) {
|
||||
llvm::dbgs() << "Conformance must match concrete replacement type:\n";
|
||||
substType->dump(llvm::dbgs());
|
||||
llvm::dbgs() << "Conformance type:\n";
|
||||
conformance.getConcrete()->getType()->dump(llvm::dbgs());
|
||||
llvm::dbgs() << "Conformance:\n";
|
||||
conformance.dump(llvm::dbgs());
|
||||
llvm::dbgs() << "\n";
|
||||
llvm::dbgs() << "SubstitutionMap:\n";
|
||||
dump(llvm::dbgs());
|
||||
llvm::dbgs() << "\n";
|
||||
llvm::dbgs() << "Requirement:\n";
|
||||
req.dump(llvm::dbgs());
|
||||
llvm::dbgs() << "\n";
|
||||
|
||||
if (conformance.isAbstract()) {
|
||||
if (!substType->isTypeParameter() &&
|
||||
!substType->is<PackElementType>() &&
|
||||
!substType->is<ArchetypeType>() &&
|
||||
!substType->isTypeVariableOrMember() &&
|
||||
!substType->is<UnresolvedType>() &&
|
||||
!substType->is<PlaceholderType>() &&
|
||||
!substType->is<ErrorType>()) {
|
||||
llvm::errs() << "Unexpected abstract conformance in substitution map:\n";
|
||||
dump(llvm::errs());
|
||||
llvm::errs() << "\n";
|
||||
abort();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
assert(substType->isEqual(conformanceTy)
|
||||
&& "conformance should match corresponding type");
|
||||
|
||||
if (conformance.isPack()) {
|
||||
// FIXME: Implement some kind of check here.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *concrete = conformance.getConcrete();
|
||||
|
||||
if (substType->isExistentialType()) {
|
||||
assert(isa<SelfProtocolConformance>(conformance.getConcrete()) &&
|
||||
"Existential type cannot have normal conformance");
|
||||
if (req.getProtocolDecl()->isSpecificProtocol(KnownProtocolKind::Sendable) &&
|
||||
isa<BuiltinProtocolConformance>(concrete)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isa<SelfProtocolConformance>(concrete)) {
|
||||
// A superclass-constrained self-conforming existential might conform
|
||||
// concretely.
|
||||
if (substType->getSuperclass())
|
||||
continue;
|
||||
|
||||
llvm::errs() << "Expected to find a self conformance:\n";
|
||||
substType->dump(llvm::errs());
|
||||
llvm::errs() << "Substitution map:\n";
|
||||
dump(llvm::errs());
|
||||
llvm::errs() << "\n";
|
||||
abort();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (substType->isTypeParameter())
|
||||
continue;
|
||||
|
||||
if (!concrete->getType()->isEqual(substType)) {
|
||||
llvm::errs() << "Conformance with wrong conforming type:\n";
|
||||
concrete->getType()->dump(llvm::errs());
|
||||
llvm::errs() << "Should be:\n";
|
||||
substType->dump(llvm::errs());
|
||||
llvm::errs() << "Substitution map:\n";
|
||||
dump(llvm::errs());
|
||||
llvm::errs() << "\n";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SubstitutionMap::profile(llvm::FoldingSetNodeID &id) const {
|
||||
|
||||
Reference in New Issue
Block a user