Skip to content

Commit 3b203a5

Browse files
committed
Serialization: Don't serialize requirement environment for witnesses
Generic environments and archetypes can be expensive to deserialize if they involve a generic signature not seen before. Also, canonicalize the witness substitutions to eliminate type aliases, and map them to interface types, which again are cheaper to deserialize.
1 parent ce770cd commit 3b203a5

File tree

5 files changed

+31
-23
lines changed

5 files changed

+31
-23
lines changed

include/swift/AST/Witness.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ class Witness {
117117
return Witness(requirement);
118118
}
119119

120+
/// Create a witness for the given requirement.
121+
///
122+
/// Deserialized witnesses do not have a synthetic environment.
123+
static Witness forDeserialized(ValueDecl *decl,
124+
SubstitutionMap substitutions) {
125+
// TODO: It's probably a good idea to have a separate 'deserialized' bit.
126+
return Witness(decl, substitutions, nullptr, SubstitutionMap());
127+
}
128+
120129
/// Create a witness that requires substitutions.
121130
///
122131
/// \param decl The declaration for the witness.

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t VERSION_MINOR = 449; // Last change: serialize @_implements names
58+
const uint16_t VERSION_MINOR = 450; // Last change: don't serialize requirement environment
5959

6060
using DeclIDField = BCFixed<31>;
6161

lib/Serialization/Deserialization.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5305,15 +5305,6 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
53055305
conformance->setWitness(req, Witness::forOpaque(req));
53065306
};
53075307

5308-
// Requirement -> synthetic map.
5309-
if (auto syntheticSig = getGenericSignature(*rawIDIter++)) {
5310-
// Create the synthetic environment.
5311-
syntheticEnv = syntheticSig->createGenericEnvironment();
5312-
}
5313-
5314-
// Requirement -> synthetic substitutions.
5315-
SubstitutionMap reqToSyntheticSubs = getSubstitutionMap(*rawIDIter++);
5316-
53175308
// Witness substitutions.
53185309
SubstitutionMap witnessSubstitutions = getSubstitutionMap(*rawIDIter++);
53195310

@@ -5324,8 +5315,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
53245315
}
53255316

53265317
// Set the witness.
5327-
trySetWitness(Witness(witness, witnessSubstitutions,
5328-
syntheticEnv, reqToSyntheticSubs));
5318+
trySetWitness(Witness::forDeserialized(witness, witnessSubstitutions));
53295319
}
53305320
assert(rawIDIter <= rawIDs.end() && "read too much");
53315321

lib/Serialization/Serialization.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,18 +1595,21 @@ void Serializer::writeNormalConformance(
15951595
// If there is no witness, we're done.
15961596
if (!witness.getDecl()) return;
15971597

1598-
if (auto *genericEnv = witness.getSyntheticEnvironment()) {
1599-
// Generic signature.
1600-
auto *genericSig = genericEnv->getGenericSignature();
1601-
data.push_back(addGenericSignatureRef(genericSig));
1602-
} else {
1603-
data.push_back(/*null generic signature*/0);
1604-
}
1598+
auto subs = witness.getSubstitutions();
1599+
1600+
// Canonicalize away typealiases, since these substitutions aren't used
1601+
// for diagnostics and we reference fewer declarations that way.
1602+
subs = subs.getCanonical();
1603+
1604+
// Map archetypes to type parameters, since we always substitute them
1605+
// away. Note that in a merge-modules pass, we're serializing conformances
1606+
// that we deserialized, so they will already have their replacement types
1607+
// in terms of interface types; hence the hasArchetypes() check is
1608+
// necessary for correctness, not just as a fast path.
1609+
if (subs.hasArchetypes())
1610+
subs = subs.mapReplacementTypesOutOfContext();
16051611

1606-
data.push_back(
1607-
addSubstitutionMapRef(witness.getRequirementToSyntheticSubs()));
1608-
data.push_back(
1609-
addSubstitutionMapRef(witness.getSubstitutions()));
1612+
data.push_back(addSubstitutionMapRef(subs));
16101613
});
16111614

16121615
unsigned numSignatureConformances =

test/Serialization/Inputs/conformance-multi-file-other.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,9 @@ public protocol BaseProto {
99
extension Base : BaseProto {
1010
public func method() {}
1111
}
12+
13+
// Make sure we can serialize witness substitutions where replacement types
14+
// involve generic parameters.
15+
public class GenericWitness<T> : BaseProto {
16+
public func method() {}
17+
}

0 commit comments

Comments
 (0)