Skip to content

Support the explicit representation of self-conformances #20607

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 1 commit into from
Nov 15, 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
3 changes: 3 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ Globals

global ::= type 'w' VALUE-WITNESS-KIND // value witness

global ::= protocol 'MS' // protocol self-conformance descriptor
global ::= protocol 'WS' // protocol self-conformance witness table
global ::= protocol-conformance 'Mc' // protocol conformance descriptor
global ::= protocol-conformance 'WP' // protocol witness table
global ::= protocol-conformance 'Wa' // protocol witness table accessor (HISTORICAL)
Expand Down Expand Up @@ -181,6 +183,7 @@ types where the metadata itself has unknown layout.)
global ::= type label-list? 'D' // type mangling for the debugger with label list for function types.
global ::= type 'TC' // continuation prototype (not actually used for real symbols)
global ::= protocol-conformance entity 'TW' // protocol witness thunk
global ::= protocol-conformance entity 'TS' // protocol self-conformance witness thunk
global ::= context identifier identifier 'TB' // property behavior initializer thunk (not used currently)
global ::= context identifier identifier 'Tb' // property behavior setter thunk (not used currently)
global ::= global specialization // function specialization
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ namespace swift {
class NominalTypeDecl;
class NormalProtocolConformance;
class InheritedProtocolConformance;
class SelfProtocolConformance;
class SpecializedProtocolConformance;
enum class ProtocolConformanceState;
class Pattern;
Expand Down Expand Up @@ -750,6 +751,10 @@ class ASTContext final {
AbstractStorageDecl *storage,
ProtocolConformanceState state);

/// Produce a self-conformance for the given protocol.
SelfProtocolConformance *
getSelfConformance(ProtocolDecl *protocol);

/// A callback used to produce a diagnostic for an ill-formed protocol
/// conformance that was type-checked before we're actually walking the
/// conformance itself, along with a bit indicating whether this diagnostic
Expand Down
6 changes: 3 additions & 3 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace swift {

class AbstractClosureExpr;
class ConformanceAccessPath;
class RootProtocolConformance;

namespace Mangle {

Expand Down Expand Up @@ -114,7 +115,7 @@ class ASTMangler : public Mangler {
const ConstructorDecl *Derived,
bool isAllocating);

std::string mangleWitnessTable(const NormalProtocolConformance *C);
std::string mangleWitnessTable(const RootProtocolConformance *C);

std::string mangleWitnessThunk(const ProtocolConformance *Conformance,
const ValueDecl *Requirement);
Expand Down Expand Up @@ -295,8 +296,7 @@ class ASTMangler : public Mangler {
void appendEntity(const ValueDecl *decl);

void appendProtocolConformance(const ProtocolConformance *conformance);
void appendProtocolConformanceRef(
const NormalProtocolConformance *conformance);
void appendProtocolConformanceRef(const RootProtocolConformance *conformance);
void appendConcreteProtocolConformance(
const ProtocolConformance *conformance);
void appendDependentProtocolConformance(const ConformanceAccessPath &path);
Expand Down
158 changes: 151 additions & 7 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class ASTContext;
class DiagnosticEngine;
class GenericParamList;
class NormalProtocolConformance;
class RootProtocolConformance;
class ProtocolConformance;
class ModuleDecl;
class SubstitutableType;
Expand All @@ -58,6 +59,8 @@ enum class ProtocolConformanceKind {
/// "Normal" conformance of a (possibly generic) nominal type, which
/// contains complete mappings.
Normal,
/// Self-conformance of a protocol to itself.
Self,
/// Conformance for a specialization of a generic type, which projects the
/// underlying generic conformance.
Specialized,
Expand Down Expand Up @@ -259,6 +262,7 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
SubstitutionMap getSubstitutions(ModuleDecl *M) const;

/// Get the underlying normal conformance.
/// FIXME: remove uses of this.
const NormalProtocolConformance *getRootNormalConformance() const;

/// Get the underlying normal conformance.
Expand All @@ -268,6 +272,15 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
->getRootNormalConformance());
}

/// Get the underlying root conformance.
const RootProtocolConformance *getRootConformance() const;

/// Get the underlying root conformance.
RootProtocolConformance *getRootConformance() {
return const_cast<RootProtocolConformance *>(
const_cast<const ProtocolConformance *>(this)->getRootConformance());
}

/// Determine whether this protocol conformance is visible from the
/// given declaration context.
bool isVisibleFrom(const DeclContext *dc) const;
Expand Down Expand Up @@ -322,6 +335,41 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;
};

/// A "root" protocol conformance states some sort of ground truth
/// about the conforming type and the required protocol. Either:
///
/// - the type is directly declared to conform to the protocol (a
/// normal conformance) or
/// - the protocol's existential type is known to conform to itself (a
/// self-conformance).
class RootProtocolConformance : public ProtocolConformance {
protected:
RootProtocolConformance(ProtocolConformanceKind kind, Type conformingType)
: ProtocolConformance(kind, conformingType) {}

public:
/// Retrieve the location of this conformance.
SourceLoc getLoc() const;

/// Is this a behavior conformance?
bool isBehaviorConformance() const;

bool isInvalid() const;

bool hasWitness(ValueDecl *requirement) const;
Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const;

/// Retrieve the witness corresponding to the given value requirement.
/// TODO: maybe this should return a Witness?
ConcreteDeclRef getWitnessDeclRef(ValueDecl *requirement,
LazyResolver *resolver) const;

static bool classof(const ProtocolConformance *conformance) {
return conformance->getKind() == ProtocolConformanceKind::Normal ||
conformance->getKind() == ProtocolConformanceKind::Self;
}
};

/// Normal protocol conformance, which involves mapping each of the protocol
/// requirements to a witness.
///
Expand All @@ -337,7 +385,7 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
/// Here, there is a normal protocol conformance for both \c A and \c B<T>,
/// providing the witnesses \c A.foo and \c B<T>.foo, respectively, for the
/// requirement \c foo.
class NormalProtocolConformance : public ProtocolConformance,
class NormalProtocolConformance : public RootProtocolConformance,
public llvm::FoldingSetNode
{
/// \brief The protocol being conformed to and its current state.
Expand Down Expand Up @@ -406,7 +454,7 @@ class NormalProtocolConformance : public ProtocolConformance,
NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol,
SourceLoc loc, DeclContext *dc,
ProtocolConformanceState state)
: ProtocolConformance(ProtocolConformanceKind::Normal, conformingType),
: RootProtocolConformance(ProtocolConformanceKind::Normal, conformingType),
ProtocolAndState(protocol, state), Loc(loc), ContextAndInvalid(dc, false)
{
assert(!conformingType->hasArchetype() &&
Expand All @@ -417,7 +465,7 @@ class NormalProtocolConformance : public ProtocolConformance,
ProtocolDecl *protocol,
SourceLoc loc, AbstractStorageDecl *behaviorStorage,
ProtocolConformanceState state)
: ProtocolConformance(ProtocolConformanceKind::Normal, conformingType),
: RootProtocolConformance(ProtocolConformanceKind::Normal, conformingType),
ProtocolAndState(protocol, state), Loc(loc),
ContextAndInvalid(behaviorStorage, false)
{
Expand Down Expand Up @@ -579,8 +627,6 @@ class NormalProtocolConformance : public ProtocolConformance,

/// Retrieve the value witness corresponding to the given requirement.
Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const;
ConcreteDeclRef getWitnessDeclRef(ValueDecl *requirement,
LazyResolver *resolver) const;

/// Determine whether the protocol conformance has a witness for the given
/// requirement.
Expand Down Expand Up @@ -670,6 +716,104 @@ class NormalProtocolConformance : public ProtocolConformance,
}
};

/// The conformance of a protocol to itself.
///
/// For now, we generally do not use this type in ProtocolConformanceRefs;
/// it's only used to anchor structures relating to emitting witness tables
/// for self-conformances.
class SelfProtocolConformance : public RootProtocolConformance {
friend class ASTContext;

SelfProtocolConformance(Type conformingType)
: RootProtocolConformance(ProtocolConformanceKind::Self, conformingType) {
}

public:
/// Get the protocol being conformed to.
ProtocolDecl *getProtocol() const {
return getType()->castTo<ProtocolType>()->getDecl();
}

/// Get the declaration context in which this conformance was declared.
DeclContext *getDeclContext() const {
return getProtocol();
}

/// Retrieve the location of this conformance.
SourceLoc getLoc() const {
return getProtocol()->getLoc();
}

ProtocolConformanceState getState() const {
return ProtocolConformanceState::Complete;
}

bool isInvalid() const {
return false;
}

ConformanceEntryKind getSourceKind() const {
return ConformanceEntryKind::Explicit; // FIXME?
}

NormalProtocolConformance *getImplyingConformance() const {
llvm_unreachable("never an implied conformance");
}

bool hasTypeWitness(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const {
llvm_unreachable("self-conformances never have associated types");
}

std::pair<Type, TypeDecl *>
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
LazyResolver *resolver,
SubstOptions options) const {
llvm_unreachable("self-conformances never have associated types");
}

Type getTypeWitness(AssociatedTypeDecl *assocType,
LazyResolver *resolver,
SubstOptions options) const {
llvm_unreachable("self-conformances never have associated types");
}

bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
llvm_unreachable("self-conformances never have associated types");
}

ProtocolConformanceRef getAssociatedConformance(Type assocType,
ProtocolDecl *protocol,
LazyResolver *resolver) const{
llvm_unreachable("self-conformances never have associated types");
}

bool hasWitness(ValueDecl *requirement) const {
return true;
}
Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const;

Optional<ArrayRef<Requirement>> getConditionalRequirementsIfAvailable() const{
return ArrayRef<Requirement>();
}

/// Get any additional requirements that are required for this conformance to
/// be satisfied.
ArrayRef<Requirement> getConditionalRequirements() const {
return ArrayRef<Requirement>();
}

static bool classof(const ProtocolConformance *conformance) {
return conformance->getKind() == ProtocolConformanceKind::Self;
}
};

inline bool RootProtocolConformance::isBehaviorConformance() const {
if (auto normal = dyn_cast<NormalProtocolConformance>(this))
return normal->isBehaviorConformance();
return false;
}

/// Specialized protocol conformance, which projects a generic protocol
/// conformance to one of the specializations of the generic type.
///
Expand Down Expand Up @@ -934,11 +1078,11 @@ class InheritedProtocolConformance : public ProtocolConformance,
};

inline bool ProtocolConformance::isInvalid() const {
return getRootNormalConformance()->isInvalid();
return getRootConformance()->isInvalid();
}

inline bool ProtocolConformance::hasWitness(ValueDecl *requirement) const {
return getRootNormalConformance()->hasWitness(requirement);
return getRootConformance()->hasWitness(requirement);
}

} // end namespace swift
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ NODE(ProtocolConformanceDescriptor)
NODE(ProtocolList)
NODE(ProtocolListWithClass)
NODE(ProtocolListWithAnyObject)
NODE(ProtocolSelfConformanceDescriptor)
NODE(ProtocolSelfConformanceWitness)
NODE(ProtocolSelfConformanceWitnessTable)
NODE(ProtocolWitness)
NODE(ProtocolWitnessTable)
NODE(ProtocolWitnessTableAccessor)
Expand Down
28 changes: 18 additions & 10 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@ class LinkEntity {
// These next few are protocol-conformance kinds.

/// A direct protocol witness table. The secondary pointer is a
/// ProtocolConformance*.
DirectProtocolWitnessTable,
/// RootProtocolConformance*.
ProtocolWitnessTable,

/// A protocol witness table pattern. The secondary pointer is a
/// ProtocolConformance*.
Expand All @@ -284,7 +284,7 @@ class LinkEntity {
ReflectionAssociatedTypeDescriptor,

/// The protocol conformance descriptor for a conformance.
/// The pointer is a NormalProtocolConformance*.
/// The pointer is a RootProtocolConformance*.
ProtocolConformanceDescriptor,

// These are both type kinds and protocol-conformance kinds.
Expand Down Expand Up @@ -350,8 +350,13 @@ class LinkEntity {
return k >= Kind::ProtocolWitnessTableLazyAccessFunction;
}

static bool isRootProtocolConformanceKind(Kind k) {
return (k == Kind::ProtocolConformanceDescriptor ||
k == Kind::ProtocolWitnessTable);
}

static bool isProtocolConformanceKind(Kind k) {
return (k >= Kind::DirectProtocolWitnessTable &&
return (k >= Kind::ProtocolWitnessTable &&
k <= Kind::ProtocolWitnessTableLazyCacheVariable);
}

Expand Down Expand Up @@ -746,10 +751,9 @@ class LinkEntity {
return entity;
}

static LinkEntity
forDirectProtocolWitnessTable(const ProtocolConformance *C) {
static LinkEntity forProtocolWitnessTable(const RootProtocolConformance *C) {
LinkEntity entity;
entity.setForProtocolConformance(Kind::DirectProtocolWitnessTable, C);
entity.setForProtocolConformance(Kind::ProtocolWitnessTable, C);
return entity;
}

Expand Down Expand Up @@ -848,10 +852,9 @@ class LinkEntity {
}

static LinkEntity
forProtocolConformanceDescriptor(const NormalProtocolConformance *C) {
forProtocolConformanceDescriptor(const RootProtocolConformance *C) {
LinkEntity entity;
entity.setForProtocolConformance(
Kind::ProtocolConformanceDescriptor, C);
entity.setForProtocolConformance(Kind::ProtocolConformanceDescriptor, C);
return entity;
}

Expand Down Expand Up @@ -936,6 +939,11 @@ class LinkEntity {
assert(getKind() == Kind::SILGlobalVariable);
return reinterpret_cast<SILGlobalVariable*>(Pointer);
}

const RootProtocolConformance *getRootProtocolConformance() const {
assert(isRootProtocolConformanceKind(getKind()));
return cast<RootProtocolConformance>(getProtocolConformance());
}

const ProtocolConformance *getProtocolConformance() const {
assert(isProtocolConformanceKind(getKind()));
Expand Down
Loading