blob: 4ee2550239ae41a990c7de011e058ad364df7e28 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Runtime/Config.h"
#include "swift/Basic/Lazy.h"
#include "swift/Runtime/Concurrent.h"
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Metadata.h"
#include "../runtime/Private.h"
using namespace swift;
/// The name demangles to "protocol descriptor for Swift.Hashable".
extern "C" const ProtocolDescriptor _TMps8Hashable;
namespace {
struct HashableConformanceKey {
/// The lookup key, the metadata of a type that is possibly derived
/// from a type that conforms to `Hashable`.
const Metadata *derivedType;
};
struct HashableConformanceEntry {
/// The lookup key, the metadata of a type that is possibly derived
/// from a type that conforms to `Hashable`.
const Metadata *derivedType;
/// The highest (closest to the root) type in the superclass chain
/// that conforms to `Hashable`.
const Metadata *baseTypeThatConformsToHashable;
HashableConformanceEntry(HashableConformanceKey key,
const Metadata *baseTypeThatConformsToHashable)
: derivedType(key.derivedType),
baseTypeThatConformsToHashable(baseTypeThatConformsToHashable) {}
int compareWithKey(const HashableConformanceKey &key) const {
if (key.derivedType != derivedType) {
return (uintptr_t(key.derivedType) < uintptr_t(derivedType) ? -1 : 1);
} else {
return 0;
}
}
static size_t
getExtraAllocationSize(HashableConformanceKey key,
const Metadata *baseTypeThatConformsToHashable) {
return 0;
}
};
} // end unnamed namesapce
static Lazy<ConcurrentMap<HashableConformanceEntry>> HashableConformances;
/// Find the base type that introduces the `Hashable` conformance.
///
/// - Precondition: `type` conforms to `Hashable` (not checked).
static const Metadata *findHashableBaseType(const Metadata *type) {
if (HashableConformanceEntry *entry =
HashableConformances->find(HashableConformanceKey{type})) {
return entry->baseTypeThatConformsToHashable;
}
const Metadata *baseTypeThatConformsToHashable = type;
while (true) {
const Metadata *superclass =
_swift_class_getSuperclass(baseTypeThatConformsToHashable);
if (!superclass)
break;
if (!swift_conformsToProtocol(superclass, &_TMps8Hashable))
break;
baseTypeThatConformsToHashable = superclass;
}
HashableConformances->getOrInsert(HashableConformanceKey{type},
baseTypeThatConformsToHashable);
return baseTypeThatConformsToHashable;
}
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
extern "C" void _swift_stdlib_makeAnyHashableUsingDefaultRepresentation(
const OpaqueValue *value,
const void *anyHashableResultPointer,
const Metadata *T,
const WitnessTable *hashableWT
);
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
extern "C" void _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType(
const OpaqueValue *value,
const void *anyHashableResultPointer,
const Metadata *type,
const WitnessTable *hashableWT
) {
switch (type->getKind()) {
case MetadataKind::Class:
case MetadataKind::ObjCClassWrapper:
case MetadataKind::ForeignClass: {
_swift_stdlib_makeAnyHashableUsingDefaultRepresentation(
value, anyHashableResultPointer, findHashableBaseType(type),
hashableWT);
return;
}
case MetadataKind::Struct:
case MetadataKind::Enum:
case MetadataKind::Optional:
_swift_stdlib_makeAnyHashableUsingDefaultRepresentation(
value, anyHashableResultPointer, type, hashableWT);
return;
case MetadataKind::ErrorObject:
// ErrorObject metadata is not used for any Swift-level values, so
// this case is unreachable.
_failCorruptType(type);
case MetadataKind::Opaque:
case MetadataKind::Tuple:
case MetadataKind::Function:
case MetadataKind::Existential:
case MetadataKind::Metatype:
case MetadataKind::ExistentialMetatype:
case MetadataKind::HeapLocalVariable:
case MetadataKind::HeapGenericLocalVariable:
// We assume that the value can not be an existential,
// because existentials can't conform to Hashable today.
//
// FIXME: handle generalized existentials when Swift has them.
_failCorruptType(type);
}
_failCorruptType(type);
}