Skip to content
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

[SE-0283] Implement Equatable, Comparable, and Hashable conformance for Tuples #28833

Merged
merged 15 commits into from Oct 26, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 24 additions & 15 deletions include/swift/ABI/Metadata.h
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -2295,37 +2295,28 @@ struct TargetTypeMetadataRecord {
union {
/// A direct reference to a nominal type descriptor.
RelativeDirectPointerIntPair<TargetContextDescriptor<Runtime>,
TypeReferenceKind>
TypeMetadataRecordKind>
DirectNominalTypeDescriptor;

/// An indirect reference to a nominal type descriptor.
RelativeDirectPointerIntPair<TargetSignedPointer<Runtime, TargetContextDescriptor<Runtime> * __ptrauth_swift_type_descriptor>,
TypeReferenceKind>
TypeMetadataRecordKind>
IndirectNominalTypeDescriptor;

// We only allow a subset of the TypeReferenceKinds here.
// Should we just acknowledge that this is a different enum?
};

public:
TypeReferenceKind getTypeKind() const {
TypeMetadataRecordKind getTypeKind() const {
return DirectNominalTypeDescriptor.getInt();
}

const TargetContextDescriptor<Runtime> *
getContextDescriptor() const {
switch (getTypeKind()) {
case TypeReferenceKind::DirectTypeDescriptor:
case TypeMetadataRecordKind::DirectTypeDescriptor:
return DirectNominalTypeDescriptor.getPointer();

case TypeReferenceKind::IndirectTypeDescriptor:
case TypeMetadataRecordKind::IndirectTypeDescriptor:
return *IndirectNominalTypeDescriptor.getPointer();

// These types (and any others we might add to TypeReferenceKind
// in the future) are just never used in these lists.
case TypeReferenceKind::DirectObjCClassName:
case TypeReferenceKind::IndirectObjCClass:
return nullptr;
}

return nullptr;
Expand Down Expand Up @@ -2415,6 +2406,9 @@ struct TargetTypeReference {
/// A direct reference to an Objective-C class name.
RelativeDirectPointer<const char>
DirectObjCClassName;

/// A "reference" to some metadata kind, e.g. tuple.
MetadataKind MetadataKind;
};

const TargetContextDescriptor<Runtime> *
Expand All @@ -2428,12 +2422,18 @@ struct TargetTypeReference {

case TypeReferenceKind::DirectObjCClassName:
case TypeReferenceKind::IndirectObjCClass:
case TypeReferenceKind::MetadataKind:
Azoy marked this conversation as resolved.
Show resolved Hide resolved
return nullptr;
}

return nullptr;
}

enum MetadataKind getMetadataKind(TypeReferenceKind kind) const {
assert(kind == TypeReferenceKind::MetadataKind);
return MetadataKind;
}

#if SWIFT_OBJC_INTEROP
/// If this type reference is one of the kinds that supports ObjC
/// references,
Expand Down Expand Up @@ -2519,6 +2519,10 @@ struct TargetProtocolConformanceDescriptor final
return Flags.getTypeReferenceKind();
}

enum MetadataKind getMetadataKind() const {
return TypeRef.getMetadataKind(getTypeKind());
}

const char *getDirectObjCClassName() const {
return TypeRef.getDirectObjCClassName(getTypeKind());
}
Expand Down Expand Up @@ -2546,6 +2550,11 @@ struct TargetProtocolConformanceDescriptor final
TargetRelativeContextPointer<Runtime>>();
}

/// Whether this conformance is builtin by the compiler + runtime.
bool isBuiltin() const {
return getTypeKind() == TypeReferenceKind::MetadataKind;
}

/// Whether this conformance is non-unique because it has been synthesized
/// for a foreign type.
bool isSynthesizedNonUnique() const {
Expand Down
22 changes: 19 additions & 3 deletions include/swift/ABI/MetadataValues.h
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -361,7 +361,19 @@ enum : unsigned {
NumGenericMetadataPrivateDataWords = 16,
};

/// Kinds of type metadata/protocol conformance records.
/// Kinds of type metadata reocrds.
enum class TypeMetadataRecordKind : unsigned {
/// A direct reference to a nominal type descriptor.
DirectTypeDescriptor = 0x00,

/// An indirect reference to a nominal type descriptor.
IndirectTypeDescriptor = 0x01,

First_Kind = DirectTypeDescriptor,
Last_Kind = IndirectTypeDescriptor,
};

/// Kinds of references to type metadata.
enum class TypeReferenceKind : unsigned {
/// The conformance is for a nominal type referenced directly;
/// getTypeDescriptor() points to the type context descriptor.
Expand All @@ -384,10 +396,14 @@ enum class TypeReferenceKind : unsigned {
/// unused.
IndirectObjCClass = 0x03,

/// The conformance is for a non-nominal type whose metadata kind we recorded;
/// getMetadataKind() returns the kind.
MetadataKind = 0x04,

// We only reserve three bits for this in the various places we store it.

First_Kind = DirectTypeDescriptor,
Last_Kind = IndirectObjCClass,
Last_Kind = MetadataKind,
};

/// Flag that indicates whether an existential type is class-constrained or not.
Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/ASTContext.h
Expand Up @@ -103,6 +103,7 @@ namespace swift {
class InheritedProtocolConformance;
class SelfProtocolConformance;
class SpecializedProtocolConformance;
class BuiltinProtocolConformance;
enum class ProtocolConformanceState;
class Pattern;
enum PointerTypeKind : unsigned;
Expand Down Expand Up @@ -948,6 +949,11 @@ class ASTContext final {
SelfProtocolConformance *
getSelfConformance(ProtocolDecl *protocol);

/// Produce the builtin conformance for some structural type to some protocol.
BuiltinProtocolConformance *
getBuiltinConformance(Type type, ProtocolDecl *protocol,
ArrayRef<ProtocolConformanceRef> conformances);

/// 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
118 changes: 114 additions & 4 deletions include/swift/AST/ProtocolConformance.h
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -66,7 +66,10 @@ enum class ProtocolConformanceKind {
Specialized,
/// Conformance of a generic class type projected through one of its
/// superclass's conformances.
Inherited
Inherited,
/// Builtin conformances are special conformaces that the runtime handles
/// and isn't implemented directly in Swift.
Builtin
};

/// Describes the state of a protocol conformance, which may be complete,
Expand Down Expand Up @@ -329,7 +332,9 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
/// - 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).
/// self-conformance) or
/// - the type's conformance is declared within the runtime (a builtin
/// conformance).
class RootProtocolConformance : public ProtocolConformance {
protected:
RootProtocolConformance(ProtocolConformanceKind kind, Type conformingType)
Expand Down Expand Up @@ -380,7 +385,8 @@ class RootProtocolConformance : public ProtocolConformance {

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

Expand Down Expand Up @@ -1014,6 +1020,110 @@ class InheritedProtocolConformance : public ProtocolConformance,
}
};

/// A builtin conformance appears when a special non-nominal type has a runtime
/// declared conformance. E.g. the runtime implements Equatable for tuples.
class BuiltinProtocolConformance final : public RootProtocolConformance,
private llvm::TrailingObjects<BuiltinProtocolConformance,
ProtocolConformanceRef> {
friend ASTContext;
friend TrailingObjects;

ProtocolDecl *protocol = nullptr;
size_t numConformances;

mutable Optional<ArrayRef<Requirement>> conditionalConformances = None;

BuiltinProtocolConformance(Type conformingType, ProtocolDecl *protocol,
ArrayRef<ProtocolConformanceRef> conformances);

size_t numTrailingObjects(OverloadToken<ProtocolConformanceRef>) const {
return numConformances;
}

public:
/// Get the protocol being conformed to.
ProtocolDecl *getProtocol() const {
return protocol;
}

/// Get the trailing conformances that this builtin conformance needs.
MutableArrayRef<ProtocolConformanceRef> getConformances() {
return {getTrailingObjects<ProtocolConformanceRef>(), numConformances};
}

/// Get the trailing conformances that this builtin conformance needs.
ArrayRef<ProtocolConformanceRef> getConformances() const {
return {getTrailingObjects<ProtocolConformanceRef>(), numConformances};
}

/// Get any requirements that must be satisfied for this conformance to apply.
Optional<ArrayRef<Requirement>>
getConditionalRequirementsIfAvailable() const {
return ArrayRef<Requirement>();
}

/// Get any requirements that must be satisfied for this conformance to apply.
ArrayRef<Requirement> getConditionalRequirements() const;

/// Get the declaration context that contains the nominal type declaration.
DeclContext *getDeclContext() const {
return getProtocol();
}

/// Retrieve the state of this conformance.
ProtocolConformanceState getState() const {
return ProtocolConformanceState::Complete;
}

/// Get the kind of source from which this conformance comes.
ConformanceEntryKind getSourceKind() const {
return ConformanceEntryKind::Synthesized;
}
/// Get the protocol conformance which implied this implied conformance.
NormalProtocolConformance *getImplyingConformance() const {
return nullptr;
}

bool hasTypeWitness(AssociatedTypeDecl *assocType) const {
llvm_unreachable("builtin-conformances currently don't have associated \
types");
}

/// Retrieve the type witness and type decl (if one exists)
/// for the given associated type.
TypeWitnessAndDecl
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
SubstOptions options=None) const {
llvm_unreachable("builtin-conformances currently don't have associated \
types");
}

/// Given that the requirement signature of the protocol directly states
/// that the given dependent type must conform to the given protocol,
/// return its associated conformance.
ProtocolConformanceRef
getAssociatedConformance(Type assocType, ProtocolDecl *protocol) const {
llvm_unreachable("builtin-conformances currently don't have associated \
types");
}

/// Retrieve the witness corresponding to the given value requirement.
ConcreteDeclRef getWitnessDeclRef(ValueDecl *requirement) const {
return ConcreteDeclRef(requirement);
}

/// Determine whether the witness for the given requirement
/// is either the default definition or was otherwise deduced.
bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
llvm_unreachable("builtin-conformances currently don't have associated \
types");
}

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

inline bool ProtocolConformance::isInvalid() const {
return getRootConformance()->isInvalid();
}
Expand Down
1 change: 1 addition & 0 deletions include/swift/Frontend/BackDeploymentLibs.def
Expand Up @@ -26,6 +26,7 @@

BACK_DEPLOYMENT_LIB((5, 0), all, "swiftCompatibility50")
BACK_DEPLOYMENT_LIB((5, 1), all, "swiftCompatibility51")
BACK_DEPLOYMENT_LIB((5, 3), all, "swiftCompatibility53")
BACK_DEPLOYMENT_LIB((5, 0), executable, "swiftCompatibilityDynamicReplacements")

#undef BACK_DEPLOYMENT_LIB
5 changes: 4 additions & 1 deletion include/swift/Remote/MetadataReader.h
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -1414,6 +1414,9 @@ class MetadataReader {

return metadataFn(metadata);
}
case TypeReferenceKind::MetadataKind: {
return None;
}
}

return None;
Expand Down