Skip to content

Commit 0f2de23

Browse files
authored
Merge pull request #15917 from DougGregor/evaluator
Introduce a simple request evaluator.
2 parents 2add64f + f9db209 commit 0f2de23

18 files changed

+1818
-1
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,24 @@ Swift 5.0
5757
Swift 4.2
5858
---------
5959

60+
* [SE-0194][]
61+
62+
The new CaseIterable protocol describes types which have a static
63+
“allCases” property that is used to describe all of the cases of the
64+
type. Swift will synthesize this “allCases” property for enums that
65+
have no associated values. For example:
66+
67+
```swift
68+
enum Suit: CaseIterable {
69+
case heart
70+
case club
71+
case diamond
72+
case spade
73+
}
74+
75+
print(Suit.allCases) // prints [Suit.heart, Suit.club, Suit.diamond, Suit.spade]
76+
```
77+
6078
* [SE-0185][]
6179

6280
Protocol conformances are now able to be synthesized in extensions in the same

include/swift/AST/AnyRequest.h

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
//===--- AnyRequest.h - Requests Instances ----------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the AnyRequest class, which describes a stored request.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_AST_ANYREQUEST_H
18+
#define SWIFT_AST_ANYREQUEST_H
19+
20+
#include "swift/Basic/TypeID.h"
21+
#include "llvm/ADT/DenseMapInfo.h"
22+
#include "llvm/ADT/Hashing.h"
23+
#include <string>
24+
25+
namespace llvm {
26+
class raw_ostream;
27+
}
28+
29+
namespace swift {
30+
31+
using llvm::hash_code;
32+
using llvm::hash_value;
33+
34+
class DiagnosticEngine;
35+
36+
/// Stores a request (for the \c Evaluator class) of any kind.
37+
///
38+
/// Requests must be value types and provide the following API to be stored in
39+
/// an \c AnyRequest instance:
40+
///
41+
/// - Copy constructor
42+
/// - Equality operator (==)
43+
/// - Hashing support (hash_value)
44+
/// - TypeID support (see swift/Basic/TypeID.h)
45+
/// - Display support (free function):
46+
/// void simple_display(llvm::raw_ostream &, const T &);
47+
/// - Cycle diagnostics operations:
48+
/// void diagnoseCycle(DiagnosticEngine &diags) const;
49+
/// void noteCycleStep(DiagnosticEngine &diags) const;
50+
///
51+
class AnyRequest {
52+
/// Abstract base class used to hold the specific request kind.
53+
class HolderBase {
54+
public:
55+
/// The type ID of the request being stored.
56+
const uint64_t typeID;
57+
58+
/// Hash value for the request itself.
59+
const hash_code hash;
60+
61+
protected:
62+
/// Initialize base with type ID and hash code.
63+
HolderBase(uint64_t typeID, hash_code hash)
64+
: typeID(typeID), hash(hash_combine(hash_value(typeID), hash)) { }
65+
66+
public:
67+
virtual ~HolderBase();
68+
69+
/// Determine whether this request is equivalent to the \c other
70+
/// request.
71+
virtual bool equals(const HolderBase &other) const = 0;
72+
73+
/// Display.
74+
virtual void display(llvm::raw_ostream &out) const = 0;
75+
76+
/// Diagnose a cycle detected for this request.
77+
virtual void diagnoseCycle(DiagnosticEngine &diags) const = 0;
78+
79+
/// Note that this request is part of a cycle.
80+
virtual void noteCycleStep(DiagnosticEngine &diags) const = 0;
81+
};
82+
83+
/// Holds a value that can be used as a request input/output.
84+
template<typename Request>
85+
class Holder final : public HolderBase {
86+
public:
87+
const Request request;
88+
89+
Holder(const Request &request)
90+
: HolderBase(TypeID<Request>::value, hash_value(request)),
91+
request(request) { }
92+
93+
Holder(Request &&request)
94+
: HolderBase(TypeID<Request>::value, hash_value(request)),
95+
request(std::move(request)) { }
96+
97+
virtual ~Holder() { }
98+
99+
/// Determine whether this request is equivalent to another.
100+
///
101+
/// The caller guarantees that the typeIDs are the same.
102+
virtual bool equals(const HolderBase &other) const override {
103+
assert(typeID == other.typeID && "Caller should match typeIDs");
104+
return request == static_cast<const Holder<Request> &>(other).request;
105+
}
106+
107+
/// Display.
108+
virtual void display(llvm::raw_ostream &out) const override {
109+
simple_display(out, request);
110+
}
111+
112+
/// Diagnose a cycle detected for this request.
113+
virtual void diagnoseCycle(DiagnosticEngine &diags) const override {
114+
request.diagnoseCycle(diags);
115+
}
116+
117+
/// Note that this request is part of a cycle.
118+
virtual void noteCycleStep(DiagnosticEngine &diags) const override {
119+
request.noteCycleStep(diags);
120+
}
121+
};
122+
123+
/// FIXME: Inefficient. Use the low bits.
124+
enum class StorageKind {
125+
Normal,
126+
Empty,
127+
Tombstone,
128+
} storageKind = StorageKind::Normal;
129+
130+
/// The data stored in this value.
131+
std::shared_ptr<HolderBase> stored;
132+
133+
AnyRequest(StorageKind storageKind) : storageKind(storageKind) {
134+
assert(storageKind != StorageKind::Normal);
135+
}
136+
137+
public:
138+
AnyRequest(const AnyRequest &other) = default;
139+
AnyRequest(AnyRequest &&other) = default;
140+
AnyRequest &operator=(const AnyRequest &other) = default;
141+
AnyRequest &operator=(AnyRequest &&other) = default;
142+
143+
AnyRequest(AnyRequest &other)
144+
: storageKind(other.storageKind), stored(other.stored) { }
145+
146+
AnyRequest(const AnyRequest &&other)
147+
: storageKind(other.storageKind), stored(other.stored) { }
148+
149+
/// Construct a new instance with the given value.
150+
template<typename T>
151+
AnyRequest(T&& value) : storageKind(StorageKind::Normal) {
152+
using ValueType =
153+
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
154+
stored.reset(new Holder<ValueType>(std::forward<T>(value)));
155+
}
156+
157+
/// Cast to a specific (known) type.
158+
template<typename Request>
159+
const Request &castTo() const {
160+
assert(stored->typeID == TypeID<Request>::value && "wrong type in cast");
161+
return static_cast<const Holder<Request> *>(stored.get())->value;
162+
}
163+
164+
/// Try casting to a specific (known) type, returning \c nullptr on
165+
/// failure.
166+
template<typename Request>
167+
const Request *getAs() const {
168+
if (stored->typeID != TypeID<Request>::value)
169+
return nullptr;
170+
171+
return &static_cast<const Holder<Request> *>(stored.get())->value;
172+
}
173+
174+
/// Diagnose a cycle detected for this request.
175+
void diagnoseCycle(DiagnosticEngine &diags) const {
176+
stored->diagnoseCycle(diags);
177+
}
178+
179+
/// Note that this request is part of a cycle.
180+
void noteCycleStep(DiagnosticEngine &diags) const {
181+
stored->noteCycleStep(diags);
182+
}
183+
184+
/// Compare two instances for equality.
185+
friend bool operator==(const AnyRequest &lhs, const AnyRequest &rhs) {
186+
if (lhs.storageKind != rhs.storageKind) {
187+
return false;
188+
}
189+
190+
if (lhs.storageKind != StorageKind::Normal)
191+
return true;
192+
193+
if (lhs.stored->typeID != rhs.stored->typeID)
194+
return false;
195+
196+
return lhs.stored->equals(*rhs.stored);
197+
}
198+
199+
friend bool operator!=(const AnyRequest &lhs, const AnyRequest &rhs) {
200+
return !(lhs == rhs);
201+
}
202+
203+
friend hash_code hash_value(const AnyRequest &any) {
204+
if (any.storageKind != StorageKind::Normal)
205+
return 1;
206+
207+
return any.stored->hash;
208+
}
209+
210+
friend void simple_display(llvm::raw_ostream &out, const AnyRequest &any) {
211+
any.stored->display(out);
212+
}
213+
214+
/// Return the result of calling simple_display as a string.
215+
std::string getAsString() const;
216+
217+
static AnyRequest getEmptyKey() {
218+
return AnyRequest(StorageKind::Empty);
219+
}
220+
221+
static AnyRequest getTombstoneKey() {
222+
return AnyRequest(StorageKind::Tombstone);
223+
}
224+
};
225+
226+
} // end namespace swift
227+
228+
namespace llvm {
229+
template<>
230+
struct DenseMapInfo<swift::AnyRequest> {
231+
static inline swift::AnyRequest getEmptyKey() {
232+
return swift::AnyRequest::getEmptyKey();
233+
}
234+
static inline swift::AnyRequest getTombstoneKey() {
235+
return swift::AnyRequest::getTombstoneKey();
236+
}
237+
static unsigned getHashValue(const swift::AnyRequest &request) {
238+
return hash_value(request);
239+
}
240+
static bool isEqual(const swift::AnyRequest &lhs,
241+
const swift::AnyRequest &rhs) {
242+
return lhs == rhs;
243+
}
244+
};
245+
246+
} // end namespace llvm
247+
248+
#endif // SWIFT_AST_ANYREQUEST_H

0 commit comments

Comments
 (0)