Skip to content

Introduce a simple request evaluator. #15917

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 14 commits into from
Jun 12, 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
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ Swift 5.0
Swift 4.2
---------

* [SE-0194][]

The new CaseIterable protocol describes types which have a static
“allCases” property that is used to describe all of the cases of the
type. Swift will synthesize this “allCases” property for enums that
have no associated values. For example:

```swift
enum Suit: CaseIterable {
case heart
case club
case diamond
case spade
}

print(Suit.allCases) // prints [Suit.heart, Suit.club, Suit.diamond, Suit.spade]
```

* [SE-0185][]

Protocol conformances are now able to be synthesized in extensions in the same
Expand Down
248 changes: 248 additions & 0 deletions include/swift/AST/AnyRequest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
//===--- 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 <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 {
/// Abstract base class used to hold the specific request kind.
class 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(hash_combine(hash_value(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.
std::shared_ptr<HolderBase> stored;

AnyRequest(StorageKind storageKind) : storageKind(storageKind) {
assert(storageKind != StorageKind::Normal);
}

public:
AnyRequest(const AnyRequest &other) = default;
AnyRequest(AnyRequest &&other) = default;
AnyRequest &operator=(const AnyRequest &other) = default;
AnyRequest &operator=(AnyRequest &&other) = default;

AnyRequest(AnyRequest &other)
: storageKind(other.storageKind), stored(other.stored) { }

AnyRequest(const AnyRequest &&other)
: storageKind(other.storageKind), stored(other.stored) { }

/// Construct a new instance with the given value.
template<typename T>
AnyRequest(T&& value) : storageKind(StorageKind::Normal) {
using ValueType =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
stored.reset(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())->value;
}

/// 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())->value;
}

/// 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);
}
static bool isEqual(const swift::AnyRequest &lhs,
const swift::AnyRequest &rhs) {
return lhs == rhs;
}
};

} // end namespace llvm

#endif // SWIFT_AST_ANYREQUEST_H
Loading