Spicy
type.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <list>
6 #include <set>
7 #include <utility>
8 
9 #include <hilti/ast/id.h>
10 #include <hilti/ast/node.h>
11 #include <hilti/base/type_erase.h>
12 
13 namespace hilti {
14 
15 namespace trait {
17 class isType : public isNode {};
18 } // namespace trait
19 
20 class Type;
21 
22 namespace declaration {
23 class Parameter;
24 }
25 
26 namespace type {
27 
28 namespace function {
29 using Parameter = declaration::Parameter;
30 }
31 
32 namespace trait {
33 class isAllocable {};
35 class isIterable {};
36 class isIterator {};
37 class isMutable {};
38 class isParameterized {};
39 class isReferenceType {};
41 class isView {};
42 class isViewable {};
44 class takesArguments {};
45 } // namespace trait
46 
47 using ResolvedState = std::set<uintptr_t>;
48 
50 enum class Flag {
52  Constant = (1U << 0U),
53 
55  NonConstant = (1U << 1U),
56 
61  NoInheritScope = (1U << 2U),
62 
65  PruneWalk = (1U << 3U),
66 };
67 
73 class Flags {
74 public:
75  Flags() = default;
76  Flags(Flag f) : _flags(static_cast<uint64_t>(f)) {}
77  Flags(const Flags&) = default;
78  Flags(Flags&&) noexcept = default;
79  ~Flags() = default;
80 
82  bool has(Flag f) const { return _flags & static_cast<uint64_t>(f); }
83 
85  void set(type::Flag flag, bool set = true) {
86  if ( set )
87  _flags |= static_cast<uint64_t>(flag);
88  else
89  _flags &= ~static_cast<uint64_t>(flag);
90  }
91 
92  Flags operator+(Flag f) {
93  auto x = Flags(*this);
94  x.set(f);
95  return x;
96  }
97 
98  Flags operator+(const Flags& other) const {
99  auto x = Flags();
100  x._flags = _flags | other._flags;
101  return x;
102  }
103 
104  Flags& operator+=(Flag f) {
105  set(f);
106  return *this;
107  }
108  Flags& operator+=(const Flags& other) {
109  _flags |= other._flags;
110  return *this;
111  }
112 
113  Flags operator-(const Flags& other) const {
114  auto x = Flags();
115  x._flags = _flags & ~other._flags;
116  return x;
117  }
118 
119  Flags& operator-=(Flag f) {
120  set(f, false);
121  return *this;
122  }
123  Flags& operator-=(const Flags& other) {
124  _flags &= ~other._flags;
125  return *this;
126  }
127 
128  Flags& operator=(Flag f) {
129  set(f);
130  return *this;
131  }
132  Flags& operator=(const Flags&) = default;
133  Flags& operator=(Flags&&) noexcept = default;
134 
135  bool operator==(Flags other) const { return _flags == other._flags; }
136 
137  bool operator!=(Flags other) const { return _flags != other._flags; }
138 
139 private:
140  uint64_t _flags = 0;
141 };
142 
143 inline Flags operator+(Flag f1, Flag f2) { return Flags(f1) + f2; }
144 
145 namespace detail {
146 
147 struct State {
148  std::optional<ID> id;
149  std::optional<ID> cxx;
150  std::optional<ID> resolved_id;
152 };
153 
154 #include <hilti/autogen/__type.h>
155 } // namespace detail
156 
157 } // namespace type
158 
159 class Type : public type::detail::Type {
160 public:
161  using type::detail::Type::Type;
162 
163  std::optional<ID> resolvedID() const { return _state().resolved_id; }
164 
165  void setCxxID(ID id) { _state().cxx = std::move(id); }
166  void setTypeID(ID id) { _state().id = std::move(id); }
167  void addFlag(type::Flag f) { _state().flags += f; }
168 
170  bool hasFlag(type::Flag f) const { return _state().flags.has(f); }
172  type::Flags flags() const { return _state().flags; }
174  bool _isConstant() const { return _state().flags.has(type::Flag::Constant); }
176  std::optional<ID> typeID() const { return _state().id; }
178  std::optional<ID> cxxID() const { return _state().cxx; }
180  const type::detail::State& _state() const { return _state_; }
182  type::detail::State& _state() { return _state_; }
184  bool pruneWalk() const { return hasFlag(type::Flag::PruneWalk); }
185 };
186 
188 inline Node to_node(Type t) { return Node(std::move(t)); }
189 
191 inline std::ostream& operator<<(std::ostream& out, Type t) { return out << to_node(std::move(t)); }
192 
198 class TypeBase : public NodeBase, public hilti::trait::isType {
199 public:
200  using NodeBase::NodeBase;
201 };
202 
203 namespace type {
204 namespace detail {
205 extern void applyPruneWalk(hilti::Type& t);
206 } // namespace detail
207 
208 inline Type pruneWalk(Type t) {
209  detail::applyPruneWalk(t);
210  return t;
211 }
212 
220 inline hilti::Type addFlags(const Type& t, const type::Flags& flags) {
221  auto x = Type(t);
222  x._state().flags += flags;
223  return x;
224 }
225 
233 inline hilti::Type removeFlags(const Type& t, const type::Flags& flags) {
234  auto x = Type(t);
235  x._state().flags -= flags;
236  return x;
237 }
238 
246 inline hilti::Type setCxxID(const Type& t, ID id) {
247  auto x = Type(t);
248  x._state().cxx = std::move(id);
249  return x;
250 }
251 
259 inline hilti::Type setTypeID(const Type& t, ID id) {
260  auto x = Type(t);
261  x._state().id = std::move(id);
262  return x;
263 }
264 
269 class Wildcard {};
270 
272 inline bool isAllocable(const Type& t) { return t._isAllocable(); }
273 
275 inline bool isDereferencable(const Type& t) { return t._isDereferencable(); }
276 
278 inline bool isIterable(const Type& t) { return t._isIterable(); }
279 
281 inline bool isIterator(const Type& t) { return t._isIterator(); }
282 
284 inline bool isParameterized(const Type& t) { return t._isParameterized(); }
285 
287 inline bool isReferenceType(const Type& t) { return t._isReferenceType(); }
288 
290 inline bool isMutable(const Type& t) { return t._isMutable(); }
291 
293 inline bool isRuntimeNonTrivial(const Type& t) { return t._isRuntimeNonTrivial(); }
294 
296 inline bool isView(const Type& t) { return t._isView(); }
297 
299 inline bool isViewable(const Type& t) { return t._isViewable(); }
300 
302 inline bool takesArguments(const Type& t) { return t._takesArguments(); }
303 
311 inline bool isConstant(const Type& t) {
312  return t.flags().has(type::Flag::Constant) || (! isMutable(t) && ! t.flags().has(type::Flag::NonConstant));
313 }
314 
316 inline auto constant(Type t) {
317  t._state().flags -= type::Flag::NonConstant;
318  t._state().flags += type::Flag::Constant;
319  return t;
320 }
321 
326 inline auto nonConstant(Type t, bool force = false) {
327  t._state().flags -= type::Flag::Constant;
328 
329  if ( force )
330  t._state().flags += type::Flag::NonConstant;
331 
332  return t;
333 }
334 
335 namespace detail {
336 // Internal backends for the `isResolved()`.
337 extern bool isResolved(const hilti::Type& t, ResolvedState* rstate);
338 
339 inline bool isResolved(const std::optional<hilti::Type>& t, ResolvedState* rstate) {
340  return t.has_value() ? isResolved(*t, rstate) : true;
341 }
342 
343 inline bool isResolved(const std::optional<const hilti::Type>& t, ResolvedState* rstate) {
344  return t.has_value() ? isResolved(*t, rstate) : true;
345 }
346 } // namespace detail
347 
349 extern bool isResolved(const Type& t);
350 
352 inline bool isResolved(const std::optional<Type>& t) { return t.has_value() ? isResolved(*t) : true; }
353 
355 inline bool isResolved(const std::optional<const Type>& t) { return t.has_value() ? isResolved(*t) : true; }
356 
358 inline bool sameExceptForConstness(const Type& t1, const Type& t2) {
359  if ( &t1 == &t2 )
360  return true;
361 
362  if ( t1.typeID() && t2.typeID() )
363  return *t1.typeID() == *t2.typeID();
364 
365  if ( t1.cxxID() && t2.cxxID() )
366  return *t1.cxxID() == *t2.cxxID();
367 
368  return t1.isEqual(t2) || t2.isEqual(t1);
369 }
370 
371 } // namespace type
372 
373 inline bool operator==(const Type& t1, const Type& t2) {
374  if ( &t1 == &t2 )
375  return true;
376 
377  if ( type::isMutable(t1) || type::isMutable(t2) ) {
378  if ( type::isConstant(t1) && ! type::isConstant(t2) )
379  return false;
380 
381  if ( type::isConstant(t2) && ! type::isConstant(t1) )
382  return false;
383  }
384 
385  if ( t1.typeID() && t2.typeID() )
386  return *t1.typeID() == *t2.typeID();
387 
388  if ( t1.cxxID() && t2.cxxID() )
389  return *t1.cxxID() == *t2.cxxID();
390 
391  // Type comparision is not fully symmetric, it's good enough
392  // if one type believes it matches the other one.
393  return t1.isEqual(t2) || t2.isEqual(t1);
394 }
395 
396 inline bool operator!=(const Type& t1, const Type& t2) { return ! (t1 == t2); }
397 
399 template<typename T, typename std::enable_if_t<std::is_base_of<trait::isType, T>::value>* = nullptr>
400 inline Node to_node(T t) {
401  return Node(Type(std::move(t)));
402 }
403 
404 } // namespace hilti
Definition: type.h:147
Definition: type.h:17
type::Flags flags() const
Definition: type.h:172
Definition: type.h:36
type::detail::State & _state()
Definition: type.h:182
Definition: type.h:37
std::optional< ID > cxxID() const
Definition: type.h:178
Definition: type.h:159
std::optional< ID > typeID() const
Definition: type.h:176
Definition: type.h:41
Definition: type.h:35
Definition: parameter.h:47
const type::detail::State & _state() const
Definition: type.h:180
Definition: type.h:73
bool has(Flag f) const
Definition: type.h:82
Definition: type.h:198
Definition: type.h:42
Definition: node.h:113
Definition: type.h:33
Definition: type.h:269
Definition: node.h:22
bool pruneWalk() const
Definition: type.h:184
bool hasFlag(type::Flag f) const
Definition: type.h:170
Definition: elements.cc:17
Definition: id.h:18
bool _isConstant() const
Definition: type.h:174
Definition: node.h:358