Skip to content

[Still thoroughly unmergeable] Adopt conditional conformance for Indices, Slice, ReversedCollection #13064

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c888725
[stdlib] Make Optional, Array and Dictionary conditionally Equatable.
huonw Nov 11, 2017
0e535c2
Fix some tests due to Equatable Optional/Array/Dictionary change.
DougGregor Nov 13, 2017
fee4d3a
[XCTest overlay] Remove extraneous XCAssert(Not)Equal overloads.
DougGregor Nov 22, 2017
8c71f08
Make Set Equatable.
DougGregor Nov 22, 2017
0adf2ae
Replace ReversedRandomAccessCollection with a conditional extension
airspeedswift Nov 14, 2017
cf9f29a
Refactor Indices and Slice to use conditional conformance
airspeedswift Nov 14, 2017
a6b5cfa
Ooops, no, MutableCollection's Indices don't have to be Mutable
airspeedswift Nov 14, 2017
7029753
Kill a few more gyb es
airspeedswift Nov 14, 2017
75f27ab
Reorganize conformances and add explicit typealiases
airspeedswift Nov 15, 2017
25328d7
refactor Collection into struct+extensions
airspeedswift Nov 15, 2017
b027247
Revise Slice documentation
natecook1000 Nov 17, 2017
9bd721b
[Standard library] Add a bunch of explicit typealiases for associated…
DougGregor Nov 25, 2017
df08fad
[Slice] Minor fixes to address errors in Slice conditional conformances.
DougGregor Nov 25, 2017
ff34491
[simd] Work around associated type inference failure
DougGregor Nov 26, 2017
9ca47de
[IRGen] Factor out binding of local type metadata for self witness ta…
DougGregor Nov 27, 2017
de3873f
[IRGen] Bind conditional requirements for witness table accessors.
DougGregor Nov 27, 2017
c516c9d
[IRGen] Bind conditional requirements in generic witness table instan…
DougGregor Nov 27, 2017
2d18fe9
[Swift Syntax] Work around associated type inference bugs.
DougGregor Nov 28, 2017
4eb74c6
[IRGen] Pass the appropriate conformance down for witness table access.
DougGregor Nov 28, 2017
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
1 change: 1 addition & 0 deletions lib/IRGen/GenOpaque.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace irgen {
class IRGenFunction;
class IRGenModule;
enum class ValueWitness : unsigned;
class StackAddress;
class WitnessIndex;

/// Return the size of a fixed buffer.
Expand Down
123 changes: 78 additions & 45 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "swift/AST/CanTypeVisitor.h"
#include "swift/AST/Types.h"
#include "swift/AST/Decl.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/ClangImporter/ClangModule.h"
Expand Down Expand Up @@ -74,10 +75,6 @@
using namespace swift;
using namespace irgen;

// Return the offset one should do on a witness table pointer to retrieve the
// `index`th piece of private data.
static int privateIndexToTableOffset(unsigned index) { return -1 - (int)index; }

namespace {

/// A class for computing how to pass arguments to a polymorphic
Expand Down Expand Up @@ -574,30 +571,12 @@ void EmitPolymorphicParameters::bindExtraSource(const MetadataSource &source,
}

if (conformance.isConcrete()) {
// Now bind all the conditional witness tables that can be pulled out of
// the self witness table.
SILWitnessTable::enumerateWitnessTableConditionalConformances(
conformance.getConcrete(),
[&](unsigned index, CanType type, ProtocolDecl *proto) {
auto archetype = getTypeInContext(type);
if (isa<ArchetypeType>(archetype)) {
WitnessIndex wIndex(privateIndexToTableOffset(index),
/*prefix*/ false);

auto table =
emitInvariantLoadOfOpaqueWitness(IGF, selfTable, wIndex);
table =
IGF.Builder.CreateBitCast(table, IGF.IGM.WitnessTablePtrTy);
setProtocolWitnessTableName(IGF.IGM, table, archetype, proto);

IGF.setUnscopedLocalTypeData(
archetype,
LocalTypeDataKind::forAbstractProtocolWitnessTable(proto),
table);
}

return /*finished?*/ false;
});
IGF.bindLocalTypeDataFromSelfWitnessTable(
conformance.getConcrete(),
selfTable,
[this](CanType type) {
return getTypeInContext(type);
});
}
return;
}
Expand Down Expand Up @@ -1017,7 +996,7 @@ class irgen::ConformanceInfo {
};

static std::pair<llvm::Value *, llvm::Value *>
emitConditionalConformancesBuffer(IRGenFunction &IGF,
emitConditionalConformancesBuffer(IRGenFunction &IGF, CanType conformingType,
const ProtocolConformance *conformance) {
// Pointers to the witness tables, in the right order, which will be included
// in the buffer that gets passed to the witness table accessor.
Expand All @@ -1026,6 +1005,30 @@ emitConditionalConformancesBuffer(IRGenFunction &IGF,
auto subMap = conformance->getSubstitutions(IGF.IGM.getSwiftModule());
auto rootConformance = conformance->getRootNormalConformance();

// Find the generic environment into which the witness table should be
// mapped.
// FIXME: Passing conformingType down for just this purpose feels like a
// hack.
if (conformingType->hasArchetype() &&
conformance->getType()->hasTypeParameter()) {
GenericEnvironment *conformingTypeEnv = nullptr;
conformingType.findIf([&](Type type) {
if (auto archetype = type->getAs<ArchetypeType>()) {
conformingTypeEnv = archetype->getGenericEnvironment();
return conformingTypeEnv != nullptr;
}

return false;
});

if (conformingTypeEnv) {
subMap = subMap.subst([&](SubstitutableType *dependentType) {
return conformingTypeEnv->mapTypeIntoContext(Type(dependentType));
},
LookUpConformanceInModule(IGF.getSwiftModule()));
}
}

SILWitnessTable::enumerateWitnessTableConditionalConformances(
rootConformance, [&](unsigned, CanType type, ProtocolDecl *proto) {
auto substType = type.subst(subMap)->getCanonicalType();
Expand Down Expand Up @@ -1078,7 +1081,7 @@ static llvm::Value *emitWitnessTableAccessorCall(

llvm::Value *conditionalTables, *numConditionalTables;
std::tie(conditionalTables, numConditionalTables) =
emitConditionalConformancesBuffer(IGF, conformance);
emitConditionalConformancesBuffer(IGF, conformingType, conformance);

call = IGF.Builder.CreateCall(
accessor, {*srcMetadataCache, conditionalTables, numConditionalTables});
Expand Down Expand Up @@ -1414,7 +1417,8 @@ class AccessorConformanceInfo : public ConformanceInfo {
unsigned index) {
assert(index < NextPrivateDataIndex);
return IGF.Builder.CreateConstArrayGEP(
table, privateIndexToTableOffset(index), IGF.IGM.getPointerSize());
table, privateWitnessTableIndexToTableOffset(index),
IGF.IGM.getPointerSize());
}

const FulfillmentMap &getFulfillmentMap() {
Expand Down Expand Up @@ -1488,6 +1492,13 @@ getAssociatedTypeMetadataAccessFunction(AssociatedType requirement,
Address destTable(parameters.claimNext(), IGM.getPointerAlignment());
setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType,
requirement.getSourceProtocol());
IGF.bindLocalTypeDataFromSelfWitnessTable(
&Conformance,
destTable.getAddress(),
[&](CanType type) {
return Conformance.getDeclContext()->mapTypeIntoContext(type)
->getCanonicalType();
});

// If the associated type is directly fulfillable from the type,
// we don't need a cache entry.
Expand Down Expand Up @@ -1541,7 +1552,7 @@ getOrCreateWitnessTableAccessFunction(IRGenModule &IGM, CanType type,
// function.
auto rootConformance = conformance->getRootNormalConformance();
if (rootConformance->witnessTableAccessorRequiresArguments()) {
return getWitnessTableLazyAccessFunction(IGM, rootConformance, type);
return getWitnessTableLazyAccessFunction(IGM, conformance, type);
} else {
return IGM.getAddrOfWitnessTableAccessFunction(rootConformance,
NotForDefinition);
Expand Down Expand Up @@ -1601,6 +1612,13 @@ getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement,
Address destTable(parameters.claimNext(), IGM.getPointerAlignment());
setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType,
Conformance.getProtocol());
IGF.bindLocalTypeDataFromSelfWitnessTable(
&Conformance,
destTable.getAddress(),
[&](CanType type) {
return Conformance.getDeclContext()->mapTypeIntoContext(type)
->getCanonicalType();
});

ProtocolDecl *associatedProtocol = requirement.getAssociatedRequirement();

Expand Down Expand Up @@ -1894,6 +1912,33 @@ llvm::Constant *WitnessTableBuilder::buildInstantiationFunction() {
// All good: now we can actually fill in the witness table.
IGF.Builder.emitBlock(contBB);

/// Run through the conditional conformance witness tables, pulling them out
/// of the slice and putting them into the private data of the witness table.
for (auto idx : indices(ConditionalRequirementPrivateDataIndices)) {
Address conditionalTablePtr =
IGF.Builder.CreateConstArrayGEP(conditionalTables, idx, PointerSize);
Address slot = getAddressOfPrivateDataSlot(
IGF, wtable, ConditionalRequirementPrivateDataIndices[idx]);
auto conditionalTable = IGF.Builder.CreateLoad(conditionalTablePtr);
auto coercedSlot =
IGF.Builder.CreateElementBitCast(slot, conditionalTable->getType());
IGF.Builder.CreateStore(conditionalTable, coercedSlot);

// Register local type data for the conditional conformance witness table.
const auto &condConformance = SILConditionalConformances[idx];
CanType reqTypeInContext =
Conformance.getDeclContext()
->mapTypeIntoContext(condConformance.Requirement)
->getCanonicalType();
if (auto archetype = dyn_cast<ArchetypeType>(reqTypeInContext)) {
auto condProto = condConformance.Conformance.getRequirement();
IGF.setUnscopedLocalTypeData(
archetype,
LocalTypeDataKind::forAbstractProtocolWitnessTable(condProto),
conditionalTable);
}
}

// Initialize all the specialized base conformances.
for (auto &base : SpecializedBaseConformances) {
// Ask the ConformanceInfo to emit the wtable.
Expand All @@ -1907,18 +1952,6 @@ llvm::Constant *WitnessTableBuilder::buildInstantiationFunction() {
IGF.Builder.CreateStore(baseWTable, slot);
}

/// Run through the conditional conformance witness tables, pulling them out
/// of the slice and putting them into the private data of the witness table.
for (auto idx : indices(ConditionalRequirementPrivateDataIndices)) {
Address conditionalTablePtr =
IGF.Builder.CreateConstArrayGEP(conditionalTables, idx, PointerSize);
Address slot = getAddressOfPrivateDataSlot(
IGF, wtable, ConditionalRequirementPrivateDataIndices[idx]);
auto conditionalTable = IGF.Builder.CreateLoad(conditionalTablePtr);
auto coercedSlot =
IGF.Builder.CreateElementBitCast(slot, conditionalTable->getType());
IGF.Builder.CreateStore(conditionalTable, coercedSlot);
}

IGF.Builder.CreateRetVoid();

Expand Down Expand Up @@ -2412,7 +2445,7 @@ llvm::Value *MetadataPath::followComponent(IRGenFunction &IGF,
LocalTypeDataKind::forAbstractProtocolWitnessTable(conformingProto);

if (source) {
WitnessIndex index(privateIndexToTableOffset(reqtIndex),
WitnessIndex index(privateWitnessTableIndexToTableOffset(reqtIndex),
/*prefix*/ false);

source = emitInvariantLoadOfOpaqueWitness(IGF, source, index);
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/GenProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ namespace irgen {
llvm::Value *wtable,
AssociatedType associatedType);

// Return the offset one should do on a witness table pointer to retrieve the
// `index`th piece of private data.
inline int privateWitnessTableIndexToTableOffset(unsigned index) {
return -1 - (int)index;
}

/// Add the witness parameters necessary for calling a function with
/// the given generics clause.
void expandPolymorphicSignature(IRGenModule &IGM,
Expand Down
7 changes: 7 additions & 0 deletions lib/IRGen/IRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,13 @@ class IRGenFunction {
void bindLocalTypeDataFromTypeMetadata(CanType type, IsExact_t isExact,
llvm::Value *metadata);

/// Given the witness table parameter, bind local type data for
/// the witness table itself and any conditional requirements.
void bindLocalTypeDataFromSelfWitnessTable(
const ProtocolConformance *conformance,
llvm::Value *selfTable,
llvm::function_ref<CanType (CanType)> mapTypeIntoContext);

void setDominanceResolver(DominanceResolverFunction resolver) {
assert(DominanceResolver == nullptr);
DominanceResolver = resolver;
Expand Down
28 changes: 28 additions & 0 deletions lib/IRGen/LocalTypeData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "LocalTypeData.h"
#include "Fulfillment.h"
#include "GenMeta.h"
#include "GenOpaque.h"
#include "GenProto.h"
#include "IRGenDebugInfo.h"
#include "IRGenFunction.h"
Expand Down Expand Up @@ -250,6 +251,33 @@ void IRGenFunction::bindLocalTypeDataFromTypeMetadata(CanType type,
.addAbstractForTypeMetadata(*this, type, isExact, metadata);
}

void IRGenFunction::bindLocalTypeDataFromSelfWitnessTable(
const ProtocolConformance *conformance,
llvm::Value *selfTable,
llvm::function_ref<CanType (CanType)> getTypeInContext) {
SILWitnessTable::enumerateWitnessTableConditionalConformances(
conformance,
[&](unsigned index, CanType type, ProtocolDecl *proto) {
auto archetype = getTypeInContext(type);
if (isa<ArchetypeType>(archetype)) {
WitnessIndex wIndex(privateWitnessTableIndexToTableOffset(index),
/*prefix*/ false);

auto table =
emitInvariantLoadOfOpaqueWitness(*this, selfTable, wIndex);
table = Builder.CreateBitCast(table, IGM.WitnessTablePtrTy);
setProtocolWitnessTableName(IGM, table, archetype, proto);

setUnscopedLocalTypeData(
archetype,
LocalTypeDataKind::forAbstractProtocolWitnessTable(proto),
table);
}

return /*finished?*/ false;
});
}

void LocalTypeDataCache::addAbstractForTypeMetadata(IRGenFunction &IGF,
CanType type,
IsExact_t isExact,
Expand Down
Loading