Skip to content

Commit 5cdc9a6

Browse files
committed
AST: More robust TypeBase::getSuperclassForDecl()
This can return ErrorType if the AST is invalid. A handful of callers handle the ErrorType result, but most don't, blindly assuming the result is always a nominal type. This resulted in a crash in at least one test case. Lift the burden from callers by always returning a nominal type here.
1 parent 3796b32 commit 5cdc9a6

File tree

4 files changed

+26
-10
lines changed

4 files changed

+26
-10
lines changed

lib/AST/TypeSubstitution.cpp

Lines changed: 14 additions & 8 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() {
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

0 commit comments

Comments
 (0)