Skip to content

Commit 5e37849

Browse files
authored
Merge pull request swiftlang#82115 from slavapestov/get-superclass-for-decl
Fix RequirementMachine crash with invalid AST via getSuperclassForDecl()
2 parents f3d12ed + 7bbb299 commit 5e37849

File tree

8 files changed

+32
-23
lines changed

8 files changed

+32
-23
lines changed

lib/AST/ConformanceLookupTable.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -862,8 +862,6 @@ DeclContext *ConformanceLookupTable::getConformingContext(
862862
Type classTy = nominal->getDeclaredInterfaceType();
863863
do {
864864
Type superclassTy = classTy->getSuperclassForDecl(superclassDecl);
865-
if (superclassTy->is<ErrorType>())
866-
return nullptr;
867865
auto inheritedConformance = swift::lookupConformance(
868866
superclassTy, protocol, /*allowMissing=*/false);
869867
if (inheritedConformance)
@@ -936,8 +934,6 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal,
936934
// declared.
937935
auto *conformingClass = cast<ClassDecl>(conformingNominal);
938936
Type superclassTy = type->getSuperclassForDecl(conformingClass);
939-
if (superclassTy->is<ErrorType>())
940-
return nullptr;
941937

942938
// Look up the inherited conformance.
943939
auto inheritedConformance = swift::lookupConformance(

lib/AST/RequirementMachine/Symbol.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,8 @@ Symbol Symbol::forLayout(LayoutConstraint layout,
366366
/// Creates a superclass symbol, representing a superclass constraint.
367367
Symbol Symbol::forSuperclass(CanType type, ArrayRef<Term> substitutions,
368368
RewriteContext &ctx) {
369+
ASSERT(type.getClassOrBoundGenericClass() != nullptr);
370+
369371
llvm::FoldingSetNodeID id;
370372
id.AddInteger(unsigned(Kind::Superclass));
371373
id.AddPointer(type.getPointer());

lib/AST/TypeSubstitution.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -523,14 +523,20 @@ Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass,
523523
t = t->getSuperclass(useArchetypes);
524524
}
525525

526-
#ifndef NDEBUG
527-
auto *currentClass = getConcreteTypeForSuperclassTraversing(this)
528-
->getClassOrBoundGenericClass();
529-
assert(baseClass->isSuperclassOf(currentClass) &&
530-
"no inheritance relationship between given classes");
531-
#endif
532-
533-
return ErrorType::get(this);
526+
if (CONDITIONAL_ASSERT_enabled()) {
527+
auto *currentClass = getConcreteTypeForSuperclassTraversing(this)
528+
->getClassOrBoundGenericClass();
529+
ASSERT(baseClass->isSuperclassOf(currentClass) &&
530+
"no inheritance relationship between given classes");
531+
}
532+
533+
// We can end up here if the AST is invalid, because then
534+
// getSuperclassDecl() might resolve to a decl, and yet
535+
// getSuperclass() is just an ErrorType. Make sure we still
536+
// return a nominal type as the result though, and not an
537+
// ErrorType, because that's what callers expect.
538+
return baseClass->getDeclaredInterfaceType()
539+
.subst(SubstitutionMap())->getCanonicalType();
534540
}
535541

536542
SubstitutionMap TypeBase::getContextSubstitutionMap() {
@@ -546,7 +552,7 @@ SubstitutionMap TypeBase::getContextSubstitutionMap() {
546552

547553
Type baseTy(this);
548554

549-
assert(!baseTy->hasLValueType() &&
555+
assert(!baseTy->is<LValueType>() &&
550556
!baseTy->is<AnyMetatypeType>() &&
551557
!baseTy->is<ErrorType>());
552558

@@ -628,7 +634,7 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
628634
assert(dc->isTypeContext());
629635
Type baseTy(this);
630636

631-
assert(!baseTy->hasLValueType() &&
637+
assert(!baseTy->is<LValueType>() &&
632638
!baseTy->is<AnyMetatypeType>() &&
633639
!baseTy->is<ErrorType>());
634640

lib/Sema/TypeCheckStorage.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,12 +1146,7 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
11461146
auto *baseClass = override->getDeclContext()->getSelfClassDecl();
11471147
selfTypeForAccess = selfTypeForAccess->getSuperclassForDecl(baseClass);
11481148

1149-
// Error recovery path. We get an ErrorType here if getSuperclassForDecl()
1150-
// fails (because, for instance, a generic parameter of a generic nominal
1151-
// type cannot be resolved).
1152-
if (!selfTypeForAccess->is<ErrorType>()) {
1153-
subs = selfTypeForAccess->getContextSubstitutionMap(baseClass);
1154-
}
1149+
subs = selfTypeForAccess->getContextSubstitutionMap(baseClass);
11551150

11561151
storage = override;
11571152

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: not %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
3+
4+
class Base<T> {}
5+
class Derived : Base<Foo> {}
6+
// expected-error@-1 {{cannot find type 'Foo' in scope}}
7+
8+
// CHECK-LABEL: unify_superclass_types_invalid.(file).f@
9+
// CHECK: Generic signature: <T where T : Derived>
10+
func f<T>(_: T) where T: Base<Int>, T: Derived {}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// {"signature":"swift::rewriting::PropertyMap::addSuperclassProperty(swift::rewriting::Term, swift::rewriting::Symbol, unsigned int)"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
2+
// RUN: not %target-swift-frontend -typecheck %s
33
class a < b class c : a func d < b where b : a<Int>, b : c
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// {"signature":"swift::ide::printTypeUSR(swift::Type, llvm::raw_ostream&)"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
2+
// RUN: not %target-swift-frontend -typecheck %s
33
class a {
44
class b < c class e : a<> {
55
d = b
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// {"signature":"swift::TypeBase::getContextSubstitutions(swift::DeclContext const*, swift::GenericEnvironment*)"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
2+
// RUN: not %target-swift-frontend -typecheck %s
33
{ $0?={

0 commit comments

Comments
 (0)