Skip to content

Commit e46d71f

Browse files
author
Harlan Haskins
committed
[Sema] Compute superclass of deserialized protocols via generic signature
We don't need to serialize the protocol's superclass, we can compute it from the generic signature. Previously, we would drop the superclass while serializing because we didn't check the generic signature in SuperclassTypeRequest, which would cause us to cache `NULL` when we called `setSuperclass` for a protocol with a superclass constraint. Fixes rdar://50526401
1 parent 0796cdc commit e46d71f

File tree

7 files changed

+61
-16
lines changed

7 files changed

+61
-16
lines changed

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5252
/// describe what change you made. The content of this comment isn't important;
5353
/// it just ensures a conflict if two people change the module format.
5454
/// Don't worry about adhering to the 80-column limit for this line.
55-
const uint16_t SWIFTMODULE_VERSION_MINOR = 493; // backing variables
55+
const uint16_t SWIFTMODULE_VERSION_MINOR = 495; // remove superclass from ProtocolLayout
5656

5757
using DeclIDField = BCFixed<31>;
5858

@@ -997,7 +997,6 @@ namespace decls_block {
997997
BCFixed<1>, // objc?
998998
BCFixed<1>, // existential-type-supported?
999999
GenericEnvironmentIDField, // generic environment
1000-
TypeIDField, // superclass
10011000
AccessLevelField, // access level
10021001
BCArray<DeclIDField> // inherited types
10031002
// Trailed by the generic parameters (if any), the members record, and

lib/AST/NameLookup.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/ClangModuleLoader.h"
2222
#include "swift/AST/DebuggerClient.h"
2323
#include "swift/AST/ExistentialLayout.h"
24+
#include "swift/AST/GenericSignature.h"
2425
#include "swift/AST/LazyResolver.h"
2526
#include "swift/AST/Initializer.h"
2627
#include "swift/AST/NameLookupRequests.h"
@@ -2039,6 +2040,25 @@ SuperclassDeclRequest::evaluate(Evaluator &evaluator,
20392040
NominalTypeDecl *subject) const {
20402041
auto &Ctx = subject->getASTContext();
20412042

2043+
// Protocols may get their superclass bound from a `where Self : Superclass`
2044+
// clause.
2045+
if (auto *proto = dyn_cast<ProtocolDecl>(subject)) {
2046+
// If the protocol came from a serialized module, compute the superclass via
2047+
// its generic signature.
2048+
if (proto->wasDeserialized()) {
2049+
auto superTy = proto->getGenericSignature()
2050+
->getSuperclassBound(proto->getSelfInterfaceType());
2051+
if (superTy)
2052+
return superTy->getClassOrBoundGenericClass();
2053+
}
2054+
2055+
// Otherwise check the where clause.
2056+
auto selfBounds = getSelfBoundsFromWhereClause(proto);
2057+
for (auto inheritedNominal : selfBounds.decls)
2058+
if (auto classDecl = dyn_cast<ClassDecl>(inheritedNominal))
2059+
return classDecl;
2060+
}
2061+
20422062
for (unsigned i : indices(subject->getInherited())) {
20432063
// Find the inherited declarations referenced at this position.
20442064
auto inheritedTypes = evaluateOrDefault(evaluator,
@@ -2058,15 +2078,6 @@ SuperclassDeclRequest::evaluate(Evaluator &evaluator,
20582078
}
20592079
}
20602080

2061-
// Protocols also support '... where Self : Superclass'.
2062-
auto *proto = dyn_cast<ProtocolDecl>(subject);
2063-
if (proto == nullptr)
2064-
return nullptr;
2065-
2066-
auto selfBounds = getSelfBoundsFromWhereClause(proto);
2067-
for (auto inheritedNominal : selfBounds.decls)
2068-
if (auto classDecl = dyn_cast<ClassDecl>(inheritedNominal))
2069-
return classDecl;
20702081

20712082
return nullptr;
20722083
}

lib/Sema/TypeCheckRequestFunctions.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/TypeCheckRequests.h"
1717
#include "swift/AST/Decl.h"
1818
#include "swift/AST/ExistentialLayout.h"
19+
#include "swift/AST/GenericSignature.h"
1920
#include "swift/AST/NameLookupRequests.h"
2021
#include "swift/AST/TypeLoc.h"
2122
#include "swift/AST/Types.h"
@@ -84,6 +85,15 @@ SuperclassTypeRequest::evaluate(Evaluator &evaluator,
8485
TypeResolutionStage stage) const {
8586
assert(isa<ClassDecl>(nominalDecl) || isa<ProtocolDecl>(nominalDecl));
8687

88+
// If this is a protocol that came from a serialized module, compute the
89+
// superclass via its generic signature.
90+
if (auto *proto = dyn_cast<ProtocolDecl>(nominalDecl)) {
91+
if (proto->wasDeserialized()) {
92+
return proto->getGenericSignature()
93+
->getSuperclassBound(proto->getSelfInterfaceType());
94+
}
95+
}
96+
8797
for (unsigned int idx : indices(nominalDecl->getInherited())) {
8898
auto result = evaluator(InheritedTypeRequest{nominalDecl, idx, stage});
8999

lib/Serialization/Deserialization.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3288,15 +3288,13 @@ class swift::DeclDeserializer {
32883288
DeclContextID contextID;
32893289
bool isImplicit, isClassBounded, isObjC, existentialTypeSupported;
32903290
GenericEnvironmentID genericEnvID;
3291-
TypeID superclassID;
32923291
uint8_t rawAccessLevel;
32933292
ArrayRef<uint64_t> rawInheritedIDs;
32943293

32953294
decls_block::ProtocolLayout::readRecord(scratch, nameID, contextID,
32963295
isImplicit, isClassBounded, isObjC,
32973296
existentialTypeSupported,
3298-
genericEnvID, superclassID,
3299-
rawAccessLevel, rawInheritedIDs);
3297+
genericEnvID, rawAccessLevel, rawInheritedIDs);
33003298

33013299
auto DC = MF.getDeclContext(contextID);
33023300
if (declOrOffset.isComplete())
@@ -3307,7 +3305,6 @@ class swift::DeclDeserializer {
33073305
/*TrailingWhere=*/nullptr);
33083306
declOrOffset = proto;
33093307

3310-
proto->setSuperclass(MF.getType(superclassID));
33113308
proto->setRequiresClass(isClassBounded);
33123309
proto->setExistentialTypeSupported(existentialTypeSupported);
33133310

lib/Serialization/Serialization.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3334,7 +3334,6 @@ void Serializer::writeDecl(const Decl *D) {
33343334
/*resolver=*/nullptr),
33353335
addGenericEnvironmentRef(
33363336
proto->getGenericEnvironment()),
3337-
addTypeRef(proto->getSuperclass()),
33383337
rawAccessLevel,
33393338
inherited);
33403339

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
public protocol P: C {}
2+
3+
public class C: P {
4+
public init() {}
5+
public func funcInClass() {}
6+
}
7+
8+
public protocol GenericP: GenericC<Int> {}
9+
10+
public class GenericC<T> {
11+
public init() {}
12+
public func funcInClass() {}
13+
}
14+
15+
extension GenericC: GenericP where T == Int {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -emit-module-path %t/ClassBoundProtocol.swiftmodule %S/Inputs/class-bound-protocol.swift -module-name ClassBoundProtocol
4+
// RUN: %target-swift-frontend -typecheck %s -I %t
5+
6+
import ClassBoundProtocol
7+
8+
func f() {
9+
let p: P = C()
10+
p.funcInClass()
11+
12+
let genericP: GenericP = GenericC<Int>()
13+
genericP.funcInClass()
14+
}

0 commit comments

Comments
 (0)