Files
swift-mirror/include/swift/AST/AnyRequest.h
Saleem Abdulrasool 4be44bf3ee AST: SFINAE away template'd constructor
Because we cannot explicitly control which constructor is used, and Visual
Studio also instantiates the templated constructor (even with the copy and move
constructors available, we end up with ambiguity in the constructor when trying
to instantiate a `llvm::SetVector<AnyRequest>` in the Evaluator.

```
	swift\include\swift\AST\AnyRequest.h(98): error C2027: use of undefined type 'swift::TypeID<Request>'
		with
		[
		    Request=ValueType
		]
	swift\include\swift\AST\AnyRequest.h(98): note: see declaration of 'swift::TypeID<Request>'
		with
		[
		    Request=ValueType
		]
	swift\include\swift\AST\AnyRequest.h(97): note: while compiling class template member function 'swift::AnyRequest::Holder<ValueType>::Holder(const Request &)'
		with
		[
		    Request=ValueType
		]
	swift\include\swift\AST\AnyRequest.h(167): note: see reference to function template instantiation 'swift::AnyRequest::Holder<ValueType>::Holder(const Request &)' being compiled
		with
		[
		    Request=ValueType
		]
	swift\include\swift\AST\AnyRequest.h(168): note: see reference to class template instantiation 'swift::AnyRequest::Holder<ValueType>' being compiled
	C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\include\xmemory0(917): note: see reference to function template instantiation 'swift::AnyRequest::AnyRequest<T&>(swift::AnyRequest&)' being compiled
		with
		[
		    T=swift::AnyRequest
		]
	C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\include\xmemory(120): note: see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,T&>(_Alloc &,_Objty *const ,T &)' being compiled
		with
		[
		    _Alloc=std::allocator<swift::AnyRequest>,
		    _Ty=swift::AnyRequest,
		    T=swift::AnyRequest,
		    _Objty=swift::AnyRequest
		]
	C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\include\xmemory(120): note: see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,T&>(_Alloc &,_Objty *const ,T &)' being compiled
		with
		[
		    _Alloc=std::allocator<swift::AnyRequest>,
		    _Ty=swift::AnyRequest,
		    T=swift::AnyRequest,
		    _Objty=swift::AnyRequest
		]
	C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\include\xmemory(153): note: see reference to function template instantiation '_FwdIt std::_Uninitialized_copy_al_unchecked<_Iter,_Iter,_Alloc>(_InIt,_InIt,_FwdIt,_Alloc &,std::_General_ptr_iterator_tag,std::_Any_tag)' being compiled
		with
		[
		    _FwdIt=swift::AnyRequest *,
		    _Iter=swift::AnyRequest *,
		    _Alloc=std::allocator<swift::AnyRequest>,
		    _InIt=swift::AnyRequest *
		]
	C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\include\vector(1939): note: see reference to function template instantiation '_FwdIt *std::_Uninitialized_copy<swift::AnyRequest*,swift::AnyRequest*,std::allocator<_Ty>>(_InIt,_InIt,_FwdIt,_Alloc &)' being compiled
		with
		[
		    _FwdIt=swift::AnyRequest *,
		    _Ty=swift::AnyRequest,
		    _InIt=swift::AnyRequest *,
		    _Alloc=std::allocator<swift::AnyRequest>
		]
	C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\include\vector(1938): note: while compiling class template member function 'void std::vector<T,std::allocator<_Ty>>::_Umove_if_noexcept1(swift::AnyRequest *,swift::AnyRequest *,swift::AnyRequest *,std::false_type)'
		with
		[
		    T=swift::AnyRequest,
		    _Ty=swift::AnyRequest
		]
	C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\include\vector(1944): note: see reference to function template instantiation 'void std::vector<T,std::allocator<_Ty>>::_Umove_if_noexcept1(swift::AnyRequest *,swift::AnyRequest *,swift::AnyRequest *,std::false_type)' being compiled
		with
		[
		    T=swift::AnyRequest,
		    _Ty=swift::AnyRequest
		]
	llvm\include\llvm\ADT\SetVector.h(49): note: see reference to class template instantiation 'std::vector<T,std::allocator<_Ty>>' being compiled
		with
		[
		    T=swift::AnyRequest,
		    _Ty=swift::AnyRequest
		]
	swift\include\swift\AST\Evaluator.h(208): note: see reference to class template instantiation 'llvm::SetVector<swift::AnyRequest,std::vector<T,std::allocator<_Ty>>,llvm::DenseSet<T,llvm::DenseMapInfo<swift::AnyRequest>>>' being compiled
		with
		[
		    T=swift::AnyRequest,
		    _Ty=swift::AnyRequest
		]
	swift\include\swift\AST\AnyRequest.h(97): error C2065: 'value': undeclared identifier
```

Hoist the type alias into the template specialization so that we can use that
in the SFINAE expression rather than duplicating it.
2018-09-14 22:01:51 -07:00

291 lines
9.0 KiB
C++

//===--- AnyRequest.h - Requests Instances ----------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the AnyRequest class, which describes a stored request.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_ANYREQUEST_H
#define SWIFT_AST_ANYREQUEST_H
#include "swift/Basic/TypeID.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include <string>
namespace llvm {
class raw_ostream;
}
namespace swift {
using llvm::hash_code;
using llvm::hash_value;
class DiagnosticEngine;
/// Stores a request (for the \c Evaluator class) of any kind.
///
/// Requests must be value types and provide the following API to be stored in
/// an \c AnyRequest instance:
///
/// - Copy constructor
/// - Equality operator (==)
/// - Hashing support (hash_value)
/// - TypeID support (see swift/Basic/TypeID.h)
/// - Display support (free function):
/// void simple_display(llvm::raw_ostream &, const T &);
/// - Cycle diagnostics operations:
/// void diagnoseCycle(DiagnosticEngine &diags) const;
/// void noteCycleStep(DiagnosticEngine &diags) const;
///
class AnyRequest {
friend llvm::DenseMapInfo<swift::AnyRequest>;
static hash_code hashForHolder(uint64_t typeID, hash_code requestHash) {
return hash_combine(hash_value(typeID), requestHash);
}
/// Abstract base class used to hold the specific request kind.
class HolderBase : public llvm::RefCountedBase<HolderBase> {
public:
/// The type ID of the request being stored.
const uint64_t typeID;
/// Hash value for the request itself.
const hash_code hash;
protected:
/// Initialize base with type ID and hash code.
HolderBase(uint64_t typeID, hash_code hash)
: typeID(typeID), hash(AnyRequest::hashForHolder(typeID, hash)) { }
public:
virtual ~HolderBase();
/// Determine whether this request is equivalent to the \c other
/// request.
virtual bool equals(const HolderBase &other) const = 0;
/// Display.
virtual void display(llvm::raw_ostream &out) const = 0;
/// Diagnose a cycle detected for this request.
virtual void diagnoseCycle(DiagnosticEngine &diags) const = 0;
/// Note that this request is part of a cycle.
virtual void noteCycleStep(DiagnosticEngine &diags) const = 0;
};
/// Holds a value that can be used as a request input/output.
template<typename Request>
class Holder final : public HolderBase {
public:
const Request request;
Holder(const Request &request)
: HolderBase(TypeID<Request>::value, hash_value(request)),
request(request) { }
Holder(Request &&request)
: HolderBase(TypeID<Request>::value, hash_value(request)),
request(std::move(request)) { }
virtual ~Holder() { }
/// Determine whether this request is equivalent to another.
///
/// The caller guarantees that the typeIDs are the same.
virtual bool equals(const HolderBase &other) const override {
assert(typeID == other.typeID && "Caller should match typeIDs");
return request == static_cast<const Holder<Request> &>(other).request;
}
/// Display.
virtual void display(llvm::raw_ostream &out) const override {
simple_display(out, request);
}
/// Diagnose a cycle detected for this request.
virtual void diagnoseCycle(DiagnosticEngine &diags) const override {
request.diagnoseCycle(diags);
}
/// Note that this request is part of a cycle.
virtual void noteCycleStep(DiagnosticEngine &diags) const override {
request.noteCycleStep(diags);
}
};
/// FIXME: Inefficient. Use the low bits.
enum class StorageKind {
Normal,
Empty,
Tombstone,
} storageKind = StorageKind::Normal;
/// The data stored in this value.
llvm::IntrusiveRefCntPtr<HolderBase> stored;
AnyRequest(StorageKind storageKind) : storageKind(storageKind) {
assert(storageKind != StorageKind::Normal);
}
public:
AnyRequest(const AnyRequest &other) = default;
AnyRequest &operator=(const AnyRequest &other) = default;
AnyRequest(AnyRequest &&other)
: storageKind(other.storageKind), stored(std::move(other.stored)) {
other.storageKind = StorageKind::Empty;
}
AnyRequest &operator=(AnyRequest &&other) {
storageKind = other.storageKind;
stored = std::move(other.stored);
other.storageKind = StorageKind::Empty;
other.stored = nullptr;
return *this;
}
AnyRequest(AnyRequest &other)
: storageKind(other.storageKind), stored(other.stored) { }
AnyRequest(const AnyRequest &&other)
: storageKind(other.storageKind), stored(other.stored) { }
// Create a local template typename `ValueType` in the template specialization
// so that we can refer to it in the SFINAE condition as well as the body of
// the template itself. The SFINAE condition allows us to remove this
// constructor from candidacy when evaluating explicit construction with an
// instance of `AnyRequest`. If we do not do so, we will find ourselves with
// ambiguity with this constructor and the defined move constructor above.
/// Construct a new instance with the given value.
template <typename T,
typename ValueType = typename std::remove_cv<
typename std::remove_reference<T>::type>::type,
typename = typename std::enable_if<
!std::is_same<ValueType, AnyRequest>::value>::type>
explicit AnyRequest(T &&value) : storageKind(StorageKind::Normal) {
stored = llvm::IntrusiveRefCntPtr<HolderBase>(
new Holder<ValueType>(std::forward<T>(value)));
}
/// Cast to a specific (known) type.
template<typename Request>
const Request &castTo() const {
assert(stored->typeID == TypeID<Request>::value && "wrong type in cast");
return static_cast<const Holder<Request> *>(stored.get())->request;
}
/// Try casting to a specific (known) type, returning \c nullptr on
/// failure.
template<typename Request>
const Request *getAs() const {
if (stored->typeID != TypeID<Request>::value)
return nullptr;
return &static_cast<const Holder<Request> *>(stored.get())->request;
}
/// Diagnose a cycle detected for this request.
void diagnoseCycle(DiagnosticEngine &diags) const {
stored->diagnoseCycle(diags);
}
/// Note that this request is part of a cycle.
void noteCycleStep(DiagnosticEngine &diags) const {
stored->noteCycleStep(diags);
}
/// Compare two instances for equality.
friend bool operator==(const AnyRequest &lhs, const AnyRequest &rhs) {
if (lhs.storageKind != rhs.storageKind) {
return false;
}
if (lhs.storageKind != StorageKind::Normal)
return true;
if (lhs.stored->typeID != rhs.stored->typeID)
return false;
return lhs.stored->equals(*rhs.stored);
}
friend bool operator!=(const AnyRequest &lhs, const AnyRequest &rhs) {
return !(lhs == rhs);
}
friend hash_code hash_value(const AnyRequest &any) {
if (any.storageKind != StorageKind::Normal)
return 1;
return any.stored->hash;
}
friend void simple_display(llvm::raw_ostream &out, const AnyRequest &any) {
any.stored->display(out);
}
/// Return the result of calling simple_display as a string.
std::string getAsString() const;
static AnyRequest getEmptyKey() {
return AnyRequest(StorageKind::Empty);
}
static AnyRequest getTombstoneKey() {
return AnyRequest(StorageKind::Tombstone);
}
};
} // end namespace swift
namespace llvm {
template<>
struct DenseMapInfo<swift::AnyRequest> {
static inline swift::AnyRequest getEmptyKey() {
return swift::AnyRequest::getEmptyKey();
}
static inline swift::AnyRequest getTombstoneKey() {
return swift::AnyRequest::getTombstoneKey();
}
static unsigned getHashValue(const swift::AnyRequest &request) {
return hash_value(request);
}
template <typename Request>
static unsigned getHashValue(const Request &request) {
return swift::AnyRequest::hashForHolder(swift::TypeID<Request>::value,
hash_value(request));
}
static bool isEqual(const swift::AnyRequest &lhs,
const swift::AnyRequest &rhs) {
return lhs == rhs;
}
template <typename Request>
static bool isEqual(const Request &lhs,
const swift::AnyRequest &rhs) {
if (rhs == getEmptyKey() || rhs == getTombstoneKey())
return false;
const Request *rhsRequest = rhs.getAs<Request>();
if (!rhsRequest)
return false;
return lhs == *rhsRequest;
}
};
} // end namespace llvm
#endif // SWIFT_AST_ANYREQUEST_H