Skip to content

Commit c88720e

Browse files
committed
Merge pull request #2565 from jckarter/extension-conformance-sema-order
ConformanceLookupTable: Recursively inherit into subclasses when incrementally adding extension conformances.
2 parents bfbd2ff + b545e19 commit c88720e

12 files changed

+127
-29
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,6 +3203,10 @@ class ClassDecl : public NominalTypeDecl {
32033203
/// Retrieve the superclass of this class, or null if there is no superclass.
32043204
Type getSuperclass() const { return LazySemanticInfo.Superclass.getPointer(); }
32053205

3206+
/// Retrieve the ClassDecl for the superclass of this class, or null if there
3207+
/// is no superclass.
3208+
ClassDecl *getSuperclassDecl() const;
3209+
32063210
/// Set the superclass of this class.
32073211
void setSuperclass(Type superclass) {
32083212
LazySemanticInfo.Superclass.setPointerAndInt(superclass, true);

include/swift/AST/TypeAlignments.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace swift {
3333
class Decl;
3434
class DeclContext;
3535
class Expr;
36+
class ExtensionDecl;
3637
class GenericTypeParamDecl;
3738
class NormalProtocolConformance;
3839
class OperatorDecl;
@@ -80,6 +81,7 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::GenericTypeParamDecl, swift::DeclAlignInBits)
8081
LLVM_DECLARE_TYPE_ALIGNMENT(swift::OperatorDecl, swift::DeclAlignInBits)
8182
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ProtocolDecl, swift::DeclAlignInBits)
8283
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ValueDecl, swift::DeclAlignInBits)
84+
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ExtensionDecl, swift::DeclAlignInBits)
8385

8486
LLVM_DECLARE_TYPE_ALIGNMENT(swift::TypeBase, swift::TypeAlignInBits)
8587
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ArchetypeType, swift::TypeAlignInBits)

lib/AST/ConformanceLookupTable.cpp

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,10 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage,
141141
ExtensionFunc extensionFunc) {
142142
assert(static_cast<unsigned>(stage) < NumConformanceStages &&
143143
"NumConformanceStages has not been updated");
144-
LastProcessedEntry &lastProcessed
145-
= LastProcessed[static_cast<unsigned>(stage)];
146144

145+
LastProcessedEntry &lastProcessed
146+
= LastProcessed[nominal][static_cast<unsigned>(stage)];
147+
147148
// Handle the nominal type.
148149
if (!lastProcessed.getInt()) {
149150
lastProcessed.setInt(true);
@@ -300,23 +301,26 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
300301
if (resolver)
301302
resolver->resolveSuperclass(classDecl);
302303

303-
if (Type superclass = classDecl->getSuperclass()) {
304-
if (auto superclassDecl
305-
= superclass->getClassOrBoundGenericClass()) {
306-
// Break infinite recursion when visiting ill-formed classes
307-
// with circular inheritance.
308-
if (VisitingSuperclass)
309-
return;
310-
llvm::SaveAndRestore<bool> visiting(VisitingSuperclass, true);
311-
312-
// Resolve the conformances of the superclass.
313-
superclassDecl->prepareConformanceTable();
314-
superclassDecl->ConformanceTable->updateLookupTable(
315-
superclassDecl,
316-
ConformanceStage::Resolved,
317-
resolver);
318-
319-
// Expand inherited conformances.
304+
if (auto superclassDecl = classDecl->getSuperclassDecl()) {
305+
// Break infinite recursion when visiting ill-formed classes
306+
// with circular inheritance.
307+
if (VisitingSuperclass)
308+
return;
309+
llvm::SaveAndRestore<bool> visiting(VisitingSuperclass, true);
310+
311+
// Resolve the conformances of the superclass.
312+
superclassDecl->prepareConformanceTable();
313+
superclassDecl->ConformanceTable->updateLookupTable(
314+
superclassDecl,
315+
ConformanceStage::Resolved,
316+
resolver);
317+
318+
// Expand inherited conformances from all superclasses.
319+
// We may have circular inheritance in ill-formed classes, so keep an
320+
// eye out for that.
321+
auto circularSuperclass = superclassDecl->getSuperclassDecl();
322+
323+
do {
320324
forEachInStage(stage, superclassDecl, resolver,
321325
[&](NominalTypeDecl *superclass) {
322326
inheritConformances(classDecl, superclassDecl,
@@ -326,7 +330,12 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
326330
inheritConformances(classDecl, superclassDecl, ext,
327331
resolver);
328332
});
329-
}
333+
superclassDecl = superclassDecl->getSuperclassDecl();
334+
if (circularSuperclass)
335+
circularSuperclass = circularSuperclass->getSuperclassDecl();
336+
if (circularSuperclass)
337+
circularSuperclass = circularSuperclass->getSuperclassDecl();
338+
} while (superclassDecl != circularSuperclass);
330339
}
331340
}
332341
break;
@@ -742,11 +751,11 @@ DeclContext *ConformanceLookupTable::getConformingContext(
742751
return nullptr;
743752

744753
// If we had a circular dependency, the superclass may not exist.
745-
if (!classDecl->getSuperclass())
746-
return nullptr;
747-
748754
auto superclassDecl
749-
= classDecl->getSuperclass()->getClassOrBoundGenericClass();
755+
= classDecl->getSuperclassDecl();
756+
757+
if (!superclassDecl)
758+
return nullptr;
750759

751760
if (!classDecl->ConformanceTable->VisitingSuperclass) {
752761
llvm::SaveAndRestore<bool> visiting(

lib/AST/ConformanceLookupTable.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "llvm/ADT/MapVector.h"
2828
#include "llvm/ADT/PointerUnion.h"
2929
#include "llvm/ADT/SetVector.h"
30+
#include <unordered_map>
3031

3132
namespace swift {
3233

@@ -67,11 +68,16 @@ class ConformanceLookupTable {
6768
/// at that stage.
6869
typedef llvm::PointerIntPair<ExtensionDecl *, 1, bool> LastProcessedEntry;
6970

70-
/// Array indicating how far we have gotten in processing the
71+
/// Array indicating how far we have gotten in processing each
7172
/// nominal type and list of extensions for each stage of
7273
/// conformance checking.
73-
LastProcessedEntry LastProcessed[NumConformanceStages];
74-
74+
///
75+
/// Uses std::unordered_map instead of DenseMap so that stable interior
76+
/// references can be taken.
77+
std::unordered_map<NominalTypeDecl *,
78+
std::array<LastProcessedEntry, NumConformanceStages>>
79+
LastProcessed;
80+
7581
/// The list of parsed extension declarations that have been delayed because
7682
/// no resolver was available at the time.
7783
///

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4677,3 +4677,9 @@ Type TypeBase::getSwiftNewtypeUnderlyingType() {
46774677

46784678
return {};
46794679
}
4680+
4681+
ClassDecl *ClassDecl::getSuperclassDecl() const {
4682+
if (auto superclass = getSuperclass())
4683+
return superclass->getClassOrBoundGenericClass();
4684+
return nullptr;
4685+
}

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4838,7 +4838,7 @@ namespace {
48384838

48394839
// Synthesize trivial conformances for each of the protocols.
48404840
SmallVector<ProtocolConformance *, 4> conformances;
4841-
;
4841+
48424842
auto dc = decl->getInnermostDeclContext();
48434843
auto &ctx = Impl.SwiftContext;
48444844
for (unsigned i = 0, n = protocols.size(); i != n; ++i) {

lib/SILGen/SILGenPattern.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,8 @@ void PatternMatchEmission::bindNamedPattern(NamedPattern *pattern,
11711171
bool forIrrefutableRow,
11721172
bool hasMultipleItems) {
11731173
bindVariable(pattern, pattern->getDecl(), value,
1174-
pattern->getType()->getCanonicalType(), forIrrefutableRow, hasMultipleItems);
1174+
pattern->getType()->getCanonicalType(), forIrrefutableRow,
1175+
hasMultipleItems);
11751176
}
11761177

11771178
/// Should we take control of the mang
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
extension Responder {}
2+
extension View {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
__attribute__((objc_root_class))
2+
@interface Object
3+
+alloc;
4+
-init;
5+
@end
6+
7+
@interface Responder: Object
8+
@end
9+
10+
@interface View: Responder
11+
@end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-frontend -parse -verify %s
2+
3+
class Object {}
4+
class Responder: Object {}
5+
class View: Responder {}
6+
7+
extension View {}
8+
9+
protocol Foo {}
10+
11+
extension Foo {
12+
func bar() -> Self { return self }
13+
}
14+
15+
extension Object: Foo {}
16+
17+
_ = Object().bar()
18+
_ = Responder().bar()
19+
_ = View().bar()
20+

0 commit comments

Comments
 (0)