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 <utility>
7 
8 #include <hilti/ast/id.h>
9 #include <hilti/ast/node.h>
10 #include <hilti/base/type_erase.h>
11 
12 namespace hilti {
13 
14 namespace trait {
16 class isType : public isNode {};
17 } // namespace trait
18 
19 namespace type {
20 
21 namespace trait {
22 class hasDynamicType {};
23 class isAllocable {};
25 class isIterable {};
26 class isIterator {};
27 class isMutable {};
28 class isOnHeap {};
29 class isParameterized {};
30 class isReferenceType {};
32 class isView {};
33 class isViewable {};
35 } // namespace trait
36 
38 enum class Flag {
40  Constant = (1U << 0U),
41 
46  NoInheritScope = (1U << 1U),
47 };
48 
54 class Flags {
55 public:
56  Flags() = default;
57  Flags(Flag f) : _flags(static_cast<uint64_t>(f)) {}
58  Flags(const Flags&) = default;
59  Flags(Flags&&) noexcept = default;
60  ~Flags() = default;
61 
63  bool has(Flag f) const { return _flags & static_cast<uint64_t>(f); }
64 
66  void set(type::Flag flag, bool set = true) {
67  if ( set )
68  _flags |= static_cast<uint64_t>(flag);
69  else
70  _flags &= ~static_cast<uint64_t>(flag);
71  }
72 
73  Flags operator+(Flag f) {
74  auto x = Flags(*this);
75  x.set(f);
76  return x;
77  }
78 
79  Flags operator+(const Flags& other) const {
80  auto x = Flags();
81  x._flags = _flags | other._flags;
82  return x;
83  }
84 
85  Flags& operator+=(Flag f) {
86  set(f);
87  return *this;
88  }
89  Flags& operator+=(const Flags& other) {
90  _flags |= other._flags;
91  return *this;
92  }
93 
94  Flags operator-(const Flags& other) const {
95  auto x = Flags();
96  x._flags = _flags & ~other._flags;
97  return x;
98  }
99 
100  Flags& operator-=(Flag f) {
101  set(f, false);
102  return *this;
103  }
104  Flags& operator-=(const Flags& other) {
105  _flags &= ~other._flags;
106  return *this;
107  }
108 
109  Flags& operator=(Flag f) {
110  set(f);
111  return *this;
112  }
113  Flags& operator=(const Flags&) = default;
114  Flags& operator=(Flags&&) noexcept = default;
115 
116  bool operator==(Flags other) const { return _flags == other._flags; }
117 
118  bool operator!=(Flags other) const { return _flags != other._flags; }
119 
120 private:
121  uint64_t _flags = 0;
122 };
123 
124 inline Flags operator+(Flag f1, Flag f2) { return Flags(f1) + f2; }
125 
126 namespace detail {
127 
128 struct State {
129  std::optional<ID> id;
130  std::optional<ID> cxx;
132 };
133 
134 #include <hilti/autogen/__type.h>
135 
137 inline Node to_node(Type t) { return Node(std::move(t)); }
138 
140 inline std::ostream& operator<<(std::ostream& out, Type t) { return out << to_node(std::move(t)); }
141 
142 } // namespace detail
143 } // namespace type
144 
145 using Type = type::detail::Type;
146 
152 class TypeBase : public NodeBase, public hilti::trait::isType {
153 public:
154  using NodeBase::NodeBase;
155 
157  bool hasFlag(type::Flag f) const { return _state().flags.has(f); }
159  type::Flags flags() const { return _state().flags; }
161  bool _isConstant() const { return _state().flags.has(type::Flag::Constant); }
163  std::optional<ID> typeID() const { return _state().id; }
165  std::optional<ID> cxxID() const { return _state().cxx; }
167  const type::detail::State& _state() const { return _state_; }
169  type::detail::State& _state() { return _state_; }
170 
171 private:
172  type::detail::State _state_;
173 };
174 
175 namespace type {
176 
184 inline hilti::Type addFlags(const Type& t, const type::Flags& flags) {
185  auto x = t._clone();
186  x._state().flags += flags;
187  return x;
188 }
189 
197 inline hilti::Type removeFlags(const Type& t, const type::Flags& flags) {
198  auto x = t._clone();
199  x._state().flags -= flags;
200  return x;
201 }
202 
213 inline hilti::Type setConstant(const Type& t, bool const_) {
214  auto x = t._clone();
215  x._state().flags.set(type::Flag::Constant, const_);
216  return x;
217 }
218 
226 inline hilti::Type setCxxID(const Type& t, ID id) {
227  auto x = t._clone();
228  x._state().cxx = std::move(id);
229  return x;
230 }
231 
239 inline hilti::Type setTypeID(const Type& t, ID id) {
240  auto x = t._clone();
241  x._state().id = std::move(id);
242  return x;
243 }
244 
249 class Wildcard {};
250 
257 inline Type effectiveType(Type t) { return t._hasDynamicType() ? t.effectiveType() : std::move(t); }
258 
263 inline std::optional<Type> effectiveOptionalType(std::optional<Type> t) {
264  if ( t )
265  return effectiveType(*t);
266 
267  return {};
268 }
269 
271 inline bool isAllocable(const Type& t) { return effectiveType(t)._isAllocable(); }
272 
274 inline bool isDereferencable(const Type& t) { return effectiveType(t)._isDereferencable(); }
275 
277 inline bool isIterable(const Type& t) { return effectiveType(t)._isIterable(); }
278 
280 inline bool isIterator(const Type& t) { return effectiveType(t)._isIterator(); }
281 
283 inline bool isParameterized(const Type& t) { return effectiveType(t)._isParameterized(); }
284 
286 inline bool isReferenceType(const Type& t) { return effectiveType(t)._isReferenceType(); }
287 
289 inline bool isMutable(const Type& t) { return effectiveType(t)._isMutable(); }
290 
292 inline bool isRuntimeNonTrivial(const Type& t) { return effectiveType(t)._isRuntimeNonTrivial(); }
293 
295 inline bool isView(const Type& t) { return effectiveType(t)._isView(); }
296 
298 inline bool isViewable(const Type& t) { return effectiveType(t)._isViewable(); }
299 
301 inline bool isOnHeap(const Type& t) { return effectiveType(t)._isOnHeap(); }
302 
310 inline bool isConstant(const Type& t) { return effectiveType(t).flags().has(type::Flag::Constant); }
311 
313 inline auto constant(const Type& t) { return setConstant(t, true); }
314 
316 inline auto nonConstant(const Type& t) { return setConstant(t, false); }
317 
319 inline auto transferConstness(const Type& t, const Type& from) { return setConstant(t, isConstant(from)); }
320 
321 namespace detail {
322 inline bool operator==(const Type& t1, const Type& t2) {
323  if ( &t1 == &t2 )
324  return true;
325 
326  if ( type::isConstant(t1) != type::isConstant(t2) )
327  return false;
328 
329  if ( t1.cxxID() && t2.cxxID() )
330  return t1.cxxID() == t2.cxxID();
331 
332  if ( (t1.flags() - type::Flag::Constant) != (t2.flags() - type::Flag::Constant) )
333  return false;
334 
335  // Type comparision is not fully symmetric, it's good enough
336  // if one type believes it matches the other one.
337  return t1.isEqual(t2) || t2.isEqual(t1);
338 }
339 
340 inline bool operator!=(const Type& t1, const Type& t2) { return ! (t1 == t2); }
341 
342 } // namespace detail
343 
348 inline bool isConstCompatible(const Type& src, const Type& dst) {
349  if ( type::isConstant(dst) )
350  return true;
351 
352  return ! type::isConstant(src);
353 }
354 
356 inline bool sameExceptForConstness(const Type& t1, const Type& t2) { return t1.isEqual(t2) || t2.isEqual(t1); }
357 
358 } // namespace type
359 
361 template<typename T, typename std::enable_if_t<std::is_base_of<trait::isType, T>::value>* = nullptr>
362 inline Node to_node(T t) {
363  return Node(Type(std::move(t)));
364 }
365 
366 } // namespace hilti
Definition: type.h:128
std::optional< ID > cxxID() const
Definition: type.h:165
Definition: type.h:16
Definition: type.h:26
type::Flags flags() const
Definition: type.h:159
bool hasFlag(type::Flag f) const
Definition: type.h:157
Definition: type.h:27
const type::detail::State & _state() const
Definition: type.h:167
Definition: type.h:32
type::detail::State & _state()
Definition: type.h:169
Definition: type.h:25
Definition: type.h:54
std::optional< ID > typeID() const
Definition: type.h:163
bool has(Flag f) const
Definition: type.h:63
Definition: type.h:152
Definition: type.h:33
Definition: node.h:97
Definition: type.h:23
Definition: type.h:249
Definition: node.h:19
Definition: elements.cc:17
Definition: id.h:18
bool _isConstant() const
Definition: type.h:161
Definition: type.h:28
Definition: node.h:318