Skip to content

[Serialization] Refactor normal conformance serialization #16023

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions include/swift/AST/Witness.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,6 @@ class Witness {
/// Determines whether there is a witness at all.
explicit operator bool() const { return !storage.isNull(); }

/// Determine whether this witness requires any substitutions.
bool requiresSubstitution() const { return storage.is<StoredWitness *>(); }

/// Retrieve the substitutions required to use this witness from the
/// synthetic environment.
///
Expand All @@ -164,15 +161,17 @@ class Witness {

/// Retrieve the synthetic generic environment.
GenericEnvironment *getSyntheticEnvironment() const {
assert(requiresSubstitution() && "No substitutions required for witness");
return storage.get<StoredWitness *>()->syntheticEnvironment;
if (auto *storedWitness = storage.dyn_cast<StoredWitness *>())
return storedWitness->syntheticEnvironment;
return nullptr;
}

/// Retrieve the substitution map that maps the interface types of the
/// requirement to the interface types of the synthetic environment.
SubstitutionList getRequirementToSyntheticSubs() const {
assert(requiresSubstitution() && "No substitutions required for witness");
return storage.get<StoredWitness *>()->reqToSyntheticEnvSubs;
if (auto *storedWitness = storage.dyn_cast<StoredWitness *>())
return storedWitness->reqToSyntheticEnvSubs;
return {};
}

LLVM_ATTRIBUTE_DEPRECATED(
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t VERSION_MINOR = 408; // Last change: begin_access [nontracking]
const uint16_t VERSION_MINOR = 409; // Last change: standalone requirement subs

using DeclIDField = BCFixed<31>;

Expand Down
17 changes: 11 additions & 6 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2507,13 +2507,18 @@ class Verifier : public ASTWalker {
// Check the witness substitutions.
const auto &witness = normal->getWitness(req, nullptr);

if (witness.requiresSubstitution()) {
GenericEnv.push_back({witness.getSyntheticEnvironment()});
for (const auto &sub : witness.getSubstitutions()) {
verifyChecked(sub.getReplacement());
}
if (auto *genericEnv = witness.getSyntheticEnvironment())
GenericEnv.push_back({genericEnv});

for (const auto &sub : witness.getRequirementToSyntheticSubs())
verifyChecked(sub.getReplacement());

for (const auto &sub : witness.getSubstitutions())
verifyChecked(sub.getReplacement());

if (auto *genericEnv = witness.getSyntheticEnvironment()) {
assert(GenericEnv.back().storage.dyn_cast<GenericEnvironment *>()
== witness.getSyntheticEnvironment());
== genericEnv);
GenericEnv.pop_back();
}

Expand Down
7 changes: 6 additions & 1 deletion lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,13 @@ using namespace swift;
Witness::Witness(ValueDecl *decl, SubstitutionList substitutions,
GenericEnvironment *syntheticEnv,
SubstitutionList reqToSynthesizedEnvSubs) {
auto &ctx = decl->getASTContext();
if (!syntheticEnv && substitutions.empty() &&
reqToSynthesizedEnvSubs.empty()) {
storage = decl;
return;
}

auto &ctx = decl->getASTContext();
auto declRef = ConcreteDeclRef(ctx, decl, substitutions);
auto storedMem = ctx.Allocate(sizeof(StoredWitness), alignof(StoredWitness));
auto stored = new (storedMem)
Expand Down
19 changes: 6 additions & 13 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5309,13 +5309,13 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
if (auto syntheticSig = getGenericSignature(*rawIDIter++)) {
// Create the synthetic environment.
syntheticEnv = syntheticSig->createGenericEnvironment();
}

// Requirement -> synthetic substitutions.
if (unsigned numReqSubstitutions = *rawIDIter++) {
while (numReqSubstitutions--) {
auto sub = maybeReadSubstitution(DeclTypeCursor, nullptr);
reqToSyntheticSubs.push_back(*sub);
}
// Requirement -> synthetic substitutions.
if (unsigned numReqSubstitutions = *rawIDIter++) {
while (numReqSubstitutions--) {
auto sub = maybeReadSubstitution(DeclTypeCursor, nullptr);
reqToSyntheticSubs.push_back(*sub);
}
}

Expand All @@ -5334,13 +5334,6 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
continue;
}

// Handle simple witnesses.
if (witnessSubstitutions.empty() && !syntheticSig && !syntheticEnv &&
reqToSyntheticSubs.empty()) {
trySetWitness(Witness(witness));
continue;
}

// Set the witness.
trySetWitness(Witness(witness, witnessSubstitutions,
syntheticEnv, reqToSyntheticSubs));
Expand Down
23 changes: 8 additions & 15 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1530,19 +1530,17 @@ void Serializer::writeNormalConformance(
// If there is no witness, we're done.
if (!witness.getDecl()) return;

if (auto genericEnv = witness.requiresSubstitution()
? witness.getSyntheticEnvironment()
: nullptr) {
if (auto *genericEnv = witness.getSyntheticEnvironment()) {
// Generic signature.
auto *genericSig = genericEnv->getGenericSignature();
data.push_back(addGenericSignatureRef(genericSig));

auto reqToSyntheticSubs = witness.getRequirementToSyntheticSubs();
data.push_back(reqToSyntheticSubs.size());
} else {
data.push_back(/*null generic signature*/0);
}

auto reqToSyntheticSubs = witness.getRequirementToSyntheticSubs();

data.push_back(reqToSyntheticSubs.size());
data.push_back(witness.getSubstitutions().size());
});

Expand All @@ -1568,19 +1566,14 @@ void Serializer::writeNormalConformance(
// Bail out early for simple witnesses.
if (!witness.getDecl()) return;

if (witness.requiresSubstitution()) {
// Write requirement-to-synthetic substitutions.
writeSubstitutions(witness.getRequirementToSyntheticSubs(),
DeclTypeAbbrCodes,
nullptr);
}
// Write requirement-to-synthetic substitutions.
writeSubstitutions(witness.getRequirementToSyntheticSubs(),
DeclTypeAbbrCodes, nullptr);

// Write the witness substitutions.
writeSubstitutions(witness.getSubstitutions(),
DeclTypeAbbrCodes,
witness.requiresSubstitution()
? witness.getSyntheticEnvironment()
: nullptr);
witness.getSyntheticEnvironment());
});
}

Expand Down
44 changes: 44 additions & 0 deletions validation-test/compiler_crashers_2_fixed/0153-rdar36497404.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: %target-build-swift -emit-module -o %t %s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be possible to produce a smaller test case, and it should go in test/Serialization

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will check how serialization tests are set up but if there is not way to check layout of the binary the test i have is good enough becuase it exposes the problem through one of the substitutions being error type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should still be in test/Serialization since its testing serialization

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've put it into crashers because it was a crash, but I can put it where ever you tell me to put it.


public protocol P1 {}
public protocol P2 {}

public protocol P3 {
static func a()

func b()
func b<I: P1>(_: (I) -> Void)

static func c<I: P1>(_: I)
static func d()
static func d<I: P1>(_: ([(I, I)]) -> Void)
static func d<I: P1>(_: ([I: I]) -> Void)
static func d<Q: P1>(_: Q)

static func e<Q: P1, I: P2>(_: Q, _: (I) -> Void)
static func f<Q: P1, I: P2>(_: Q, _: (I) -> Void)

func g<I: P1>(_: I)
}

public extension P3 {
static func a() {}

func b() {}
func b<I: P1>(_: (I) -> Void) {}

static func c<I: P1>(_: I) {}

static func d() {}
static func d<I: P1>(_: ([(I, I)]) -> Void) {}
static func d<I: P1>(_: ([I: I]) -> Void) {}
static func d<Q: P1>(_: Q) {}

static func e<Q: P1, I: P2>(_: Q, _: (I) -> Void) {}
static func f<Q: P1, I: P2>(_: Q, _: (I) -> Void) {}

func g<I: P1>(_: I) {}
}

struct S: P3 {
}