Skip to content
Closed
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: 13 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,14 @@ class ASTContext final {
llvm::BumpPtrAllocator &
getAllocator(AllocationArena arena = AllocationArena::Permanent) const;

/// Record of conformances that have come about by extending a protocol
llvm::DenseMap<ProtocolDecl *, llvm::DenseMap<NominalTypeDecl *,
ExtensionDecl *>> ExtendedConformances;

public:
llvm::DenseMap<ProtocolDecl *, llvm::DenseMap<NominalTypeDecl *,
ExtensionDecl *>> &getExtendedConformances() { return ExtendedConformances; }

/// Allocate - Allocate memory from the ASTContext bump pointer.
void *Allocate(unsigned long bytes, unsigned alignment,
AllocationArena arena = AllocationArena::Permanent) const {
Expand Down Expand Up @@ -729,6 +736,12 @@ class ASTContext final {
/// one.
void loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration);

/// Iterate over conformances arising from protocol extensions.
///
/// \param emitWitness A function to call to emit a witness table.
void forEachExtendedConformance(ModuleDecl *module,
std::function<void (NormalProtocolConformance *)> emitWitness);

/// Load the methods within the given class that produce
/// Objective-C class or instance methods with the given selector.
///
Expand Down
14 changes: 10 additions & 4 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1754,7 +1754,7 @@ class ExtensionDecl final : public GenericContext, public Decl,
MutableArrayRef<TypeLoc> getInherited() { return Inherited; }
ArrayRef<TypeLoc> getInherited() const { return Inherited; }

void setInherited(MutableArrayRef<TypeLoc> i) { Inherited = i; }
void setInherited(MutableArrayRef<TypeLoc> i);

bool hasDefaultAccessLevel() const {
return Bits.ExtensionDecl.DefaultAndMaxAccessLevel != 0;
Expand Down Expand Up @@ -3367,9 +3367,6 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
/// a given nominal type.
mutable ConformanceLookupTable *ConformanceTable = nullptr;

/// Prepare the conformance table.
void prepareConformanceTable() const;

/// Returns the protocol requirements that \c Member conforms to.
ArrayRef<ValueDecl *>
getSatisfiedProtocolRequirementsForMember(const ValueDecl *Member,
Expand Down Expand Up @@ -3479,6 +3476,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
/// conform, such as AnyObject (for classes).
void getImplicitProtocols(SmallVectorImpl<ProtocolDecl *> &protocols);

/// Prepare the conformance table (also acts as accessor).
ConformanceLookupTable *prepareConformanceTable() const;

/// Look for conformances of this nominal type to the given
/// protocol.
///
Expand Down Expand Up @@ -4332,6 +4332,9 @@ class ProtocolDecl final : public NominalTypeDecl {
/// Retrieve the set of protocols inherited from this protocol.
ArrayRef<ProtocolDecl *> getInheritedProtocols() const;

/// An extension has inherited a new protocol
void inheritedProtocolsChanged();

/// Determine whether this protocol has a superclass.
bool hasSuperclass() const { return (bool)getSuperclassDecl(); }

Expand Down Expand Up @@ -4422,6 +4425,9 @@ class ProtocolDecl final : public NominalTypeDecl {
/// contain 'Self' in 'parameter' or 'other' position.
bool existentialTypeSupported() const;

/// Track conformances that have come about due to a protocol extension
void recordExtendedNominal(NominalTypeDecl *nomial, ExtensionDecl *ext);

private:
void computeKnownProtocolKind() const;

Expand Down
10 changes: 8 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,8 @@ NOTE(composition_in_extended_type_alternative,none,
ERROR(extension_access_with_conformances,none,
"%0 modifier cannot be used with extensions that declare "
"protocol conformances", (DeclAttribute))
ERROR(protocol_extension_access_with_conformances,none,
"protocol extensions with conformances must currently be public", ())
ERROR(extension_metatype,none,
"cannot extend a metatype %0", (Type))
ERROR(extension_specialization,none,
Expand All @@ -1764,8 +1766,12 @@ ERROR(extension_nongeneric_trailing_where,none,
"trailing 'where' clause for extension of non-generic type %0",
(Identifier))
ERROR(extension_protocol_inheritance,none,
"extension of protocol %0 cannot have an inheritance clause",
(Identifier))
"inheritance clause in extension of protocol %0. "
"use -enable-conforming-protocol-extensions to enable this feature",
(DeclName))
ERROR(extension_protocol_limitation,none,
"cannot extend protocol %0 that %1 already conforms to in another module",
(DeclName, Type))
ERROR(objc_generic_extension_using_type_parameter,none,
"extension of a generic Objective-C class cannot access the class's "
"generic parameters at runtime", ())
Expand Down
4 changes: 3 additions & 1 deletion include/swift/AST/NameLookupRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ class InheritedProtocolsRequest

public:
// Caching
bool isCached() const { return true; }
bool isCached() const {
return std::get<0>(getStorage())->areInheritedProtocolsValid();
}
Optional<ArrayRef<ProtocolDecl *>> getCachedResult() const;
void cacheResult(ArrayRef<ProtocolDecl *> value) const;

Expand Down
23 changes: 23 additions & 0 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,34 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
/// conformance definition.
Type ConformingType;

// The conformance has been used during Sema.
mutable bool hasBeenReferenced = false;

// Ad-hoc conformances from protocol extensions must be private.
mutable bool fromProtocolExtension = false;

protected:
ProtocolConformance(ProtocolConformanceKind kind, Type conformingType)
: Kind(kind), ConformingType(conformingType) {}

public:
ProtocolConformance *recordReferenced() const {
hasBeenReferenced = true;
return const_cast<ProtocolConformance *>(this);
}

bool isInUse() {
return hasBeenReferenced;
}

void makePrivate() const {
fromProtocolExtension = true;
}

bool isFromProtocolExtension() const {
return fromProtocolExtension;
}

/// Determine the kind of protocol conformance.
ProtocolConformanceKind getKind() const { return Kind; }

Expand Down
4 changes: 1 addition & 3 deletions include/swift/AST/ProtocolConformanceRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,7 @@ class ProtocolConformanceRef {
bool isConcrete() const {
return !isInvalid() && Union.is<ProtocolConformance*>();
}
ProtocolConformance *getConcrete() const {
return Union.get<ProtocolConformance*>();
}
ProtocolConformance *getConcrete() const;

bool isAbstract() const {
return !isInvalid() && Union.is<ProtocolDecl*>();
Expand Down
11 changes: 9 additions & 2 deletions include/swift/AST/Requirement.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@ class Requirement {
LayoutConstraint SecondLayout;
};

/// Module this requirement was derived from. Used to re-order witness table.
unsigned ModuleNumber;

public:
/// Create a conformance or same-type requirement.
Requirement(RequirementKind kind, Type first, Type second)
: FirstTypeAndKind(first, kind), SecondType(second) {
Requirement(RequirementKind kind, Type first, Type second, unsigned moduleNumber = 0)
: FirstTypeAndKind(first, kind), SecondType(second), ModuleNumber(moduleNumber) {
assert(first);
assert(second);
}
Expand All @@ -89,6 +92,10 @@ class Requirement {
return SecondType;
}

unsigned getModuleNumber() const {
return ModuleNumber;
}

/// Subst the types involved in this requirement.
///
/// The \c args arguments are passed through to Type::subst. This doesn't
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ namespace swift {
/// when using RequireExplicitAvailability.
std::string RequireExplicitAvailabilityTarget;

/// Gate for conforming protocol extensions code.
bool EnableConformingExtensions = false;

/// If false, '#file' evaluates to the full path rather than a
/// human-readable string.
bool EnableConcisePoundFile = false;
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,11 @@ def enable_experimental_additive_arithmetic_derivation :
Flags<[FrontendOption]>,
HelpText<"Enable experimental 'AdditiveArithmetic' derived conformances">;

def enable_conforming_protocol_extensions : Flag<["-"],
"enable-conforming-protocol-extensions">,
Flags<[FrontendOption]>,
HelpText<"Enable experimental feature to conforming protocol extensions">;

def enable_experimental_concise_pound_file : Flag<["-"],
"enable-experimental-concise-pound-file">,
Flags<[FrontendOption]>,
Expand Down
27 changes: 24 additions & 3 deletions include/swift/SIL/SILWitnessVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,19 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {

public:
void visitProtocolDecl(ProtocolDecl *protocol) {
// This chicanery is to move conformances arising from
// protocol extensions to the end of the witness table.
unsigned moduleNumber = 0;
while (visitProtocolDecl(protocol, moduleNumber++)) {}
}

bool visitProtocolDecl(ProtocolDecl *protocol, unsigned moduleNumber) {
bool emittedConformance = false;
llvm::DenseMap<ProtocolDecl *,bool> seen;

// The protocol conformance descriptor gets added first.
asDerived().addProtocolConformanceDescriptor();
if (moduleNumber == 0)
asDerived().addProtocolConformanceDescriptor();

for (const auto &reqt : protocol->getRequirementSignature()) {
switch (reqt.getKind()) {
Expand All @@ -72,6 +83,9 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(requirement))
continue;

if (reqt.getModuleNumber() != moduleNumber)
continue;

// If the type parameter is 'self', consider this to be protocol
// inheritance. In the canonical signature, these should all
// come before any protocol requirements on associated types.
Expand All @@ -80,18 +94,23 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
assert(parameter->getDepth() == 0 && parameter->getIndex() == 0 &&
"non-self type parameter in protocol");
asDerived().addOutOfLineBaseProtocol(requirement);
emittedConformance = true;
continue;
}

// Otherwise, add an associated requirement.
AssociatedConformance assocConf(protocol, type, requirement);
asDerived().addAssociatedConformance(assocConf);
emittedConformance = true;
continue;
}
}
llvm_unreachable("bad requirement kind");
}

if (moduleNumber)
return emittedConformance;

// Add the associated types.
for (auto *associatedType : protocol->getAssociatedTypeMembers()) {
// If this is a new associated type (which does not override an
Expand All @@ -100,13 +119,15 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
asDerived().addAssociatedType(AssociatedType(associatedType));
}

if (asDerived().shouldVisitRequirementSignatureOnly())
return;
// if (asDerived().shouldVisitRequirementSignatureOnly())
// return true;

// Visit the witnesses for the direct members of a protocol.
for (Decl *member : protocol->getMembers()) {
ASTVisitor<T>::visit(member);
}

return true;
}

/// If true, only the base protocols and associated types will be visited.
Expand Down
Loading