Spicy
type.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <unordered_set>
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 class Type;
20 
21 namespace declaration {
22 class Parameter;
23 }
24 
25 namespace type {
26 
27 namespace function {
28 using Parameter = declaration::Parameter;
29 }
30 
31 namespace trait {
32 class isAllocable {};
34 class isIterable {};
35 class isIterator {};
36 class isMutable {};
37 class isParameterized {};
38 class isReferenceType {};
40 class isView {};
41 class isViewable {};
43 class takesArguments {};
44 } // namespace trait
45 
46 using ResolvedState = std::unordered_set<uintptr_t>;
47 
49 enum class Flag {
51  Constant = (1U << 0U),
52 
54  NonConstant = (1U << 1U),
55 
60  NoInheritScope = (1U << 2U),
61 
64  PruneWalk = (1U << 3U),
65 };
66 
72 class Flags {
73 public:
74  Flags() = default;
75  Flags(Flag f) : _flags(static_cast<uint64_t>(f)) {}
76  Flags(const Flags&) = default;
77  Flags(Flags&&) noexcept = default;
78  ~Flags() = default;
79 
81  bool has(Flag f) const { return _flags & static_cast<uint64_t>(f); }
82 
84  void set(type::Flag flag, bool set = true) {
85  if ( set )
86  _flags |= static_cast<uint64_t>(flag);
87  else
88  _flags &= ~static_cast<uint64_t>(flag);
89  }
90 
91  Flags operator+(Flag f) {
92  auto x = Flags(*this);
93  x.set(f);
94  return x;
95  }
96 
97  Flags operator+(const Flags& other) const {
98  auto x = Flags();
99  x._flags = _flags | other._flags;
100  return x;
101  }
102 
103  Flags& operator+=(Flag f) {
104  set(f);
105  return *this;
106  }
107  Flags& operator+=(const Flags& other) {
108  _flags |= other._flags;
109  return *this;
110  }
111 
112  Flags operator-(const Flags& other) const {
113  auto x = Flags();
114  x._flags = _flags & ~other._flags;
115  return x;
116  }
117 
118  Flags& operator-=(Flag f) {
119  set(f, false);
120  return *this;
121  }
122  Flags& operator-=(const Flags& other) {
123  _flags &= ~other._flags;
124  return *this;
125  }
126 
127  Flags& operator=(Flag f) {
128  set(f);
129  return *this;
130  }
131  Flags& operator=(const Flags&) = default;
132  Flags& operator=(Flags&&) noexcept = default;
133 
134  bool operator==(Flags other) const { return _flags == other._flags; }
135 
136  bool operator!=(Flags other) const { return _flags != other._flags; }
137 
138 private:
139  uint64_t _flags = 0;
140 };
141 
142 inline Flags operator+(Flag f1, Flag f2) { return Flags(f1) + f2; }
143 
144 namespace detail {
145 
146 struct State {
147  std::optional<ID> id;
148  std::optional<ID> cxx;
149  std::optional<ID> resolved_id;
151 };
152 
153 #include <hilti/autogen/__type.h>
154 } // namespace detail
155 
156 } // namespace type
157 
158 class Type : public type::detail::Type {
159 public:
160  using type::detail::Type::Type;
161 
162  std::optional<ID> resolvedID() const { return _state().resolved_id; }
163 
164  void setCxxID(ID id) { _state().cxx = std::move(id); }
165  void setTypeID(ID id) { _state().id = std::move(id); }
166  void addFlag(type::Flag f) { _state().flags += f; }
167 
169  bool hasFlag(type::Flag f) const { return _state().flags.has(f); }
171  const type::Flags& flags() const { return _state().flags; }
173  bool _isConstant() const { return _state().flags.has(type::Flag::Constant); }
175  const std::optional<ID>& typeID() const { return _state().id; }
177  const std::optional<ID>& cxxID() const { return _state().cxx; }
179  const type::detail::State& _state() const { return _state_; }
181  type::detail::State& _state() { return _state_; }
183  bool pruneWalk() const { return hasFlag(type::Flag::PruneWalk); }
184 };
185 
187 inline Node to_node(Type t) { return Node(std::move(t)); }
188 
190 inline std::ostream& operator<<(std::ostream& out, Type t) { return out << to_node(std::move(t)); }
191 
197 class TypeBase : public NodeBase, public hilti::trait::isType {
198 public:
199  using NodeBase::NodeBase;
200 };
201 
202 namespace type {
203 namespace detail {
204 extern void applyPruneWalk(hilti::Type& t);
205 } // namespace detail
206 
207 inline Type pruneWalk(Type t) {
208  detail::applyPruneWalk(t);
209  return t;
210 }
211 
219 inline hilti::Type addFlags(const Type& t, const type::Flags& flags) {
220  auto x = Type(t);
221  x._state().flags += flags;
222  return x;
223 }
224 
232 inline hilti::Type removeFlags(const Type& t, const type::Flags& flags) {
233  auto x = Type(t);
234  x._state().flags -= flags;
235  return x;
236 }
237 
245 inline hilti::Type setCxxID(const Type& t, ID id) {
246  auto x = Type(t);
247  x._state().cxx = std::move(id);
248  return x;
249 }
250 
258 inline hilti::Type setTypeID(const Type& t, ID id) {
259  auto x = Type(t);
260  x._state().id = std::move(id);
261  return x;
262 }
263 
268 class Wildcard {};
269 
271 inline bool isAllocable(const Type& t) { return t._isAllocable(); }
272 
274 inline bool isDereferenceable(const Type& t) { return t._isDereferenceable(); }
275 
277 inline bool isIterable(const Type& t) { return t._isIterable(); }
278 
280 inline bool isIterator(const Type& t) { return t._isIterator(); }
281 
283 inline bool isParameterized(const Type& t) { return t._isParameterized(); }
284 
286 inline bool isReferenceType(const Type& t) { return t._isReferenceType(); }
287 
289 inline bool isMutable(const Type& t) { return t._isMutable(); }
290 
292 inline bool isRuntimeNonTrivial(const Type& t) { return t._isRuntimeNonTrivial(); }
293 
295 inline bool isView(const Type& t) { return t._isView(); }
296 
298 inline bool isViewable(const Type& t) { return t._isViewable(); }
299 
301 inline bool takesArguments(const Type& t) { return t._takesArguments(); }
302 
310 inline bool isConstant(const Type& t) {
311  return t.flags().has(type::Flag::Constant) || (! isMutable(t) && ! t.flags().has(type::Flag::NonConstant));
312 }
313 
315 inline auto constant(Type t) {
316  t._state().flags -= type::Flag::NonConstant;
317  t._state().flags += type::Flag::Constant;
318  return t;
319 }
320 
325 inline auto nonConstant(Type t, bool force = false) {
326  t._state().flags -= type::Flag::Constant;
327 
328  if ( force )
329  t._state().flags += type::Flag::NonConstant;
330 
331  return t;
332 }
333 
334 namespace detail {
335 // Internal backends for the `isResolved()`.
336 extern bool isResolved(const hilti::Type& t, ResolvedState* rstate);
337 
338 inline bool isResolved(const std::optional<hilti::Type>& t, ResolvedState* rstate) {
339  return t.has_value() ? isResolved(*t, rstate) : true;
340 }
341 
342 inline bool isResolved(const std::optional<const hilti::Type>& t, ResolvedState* rstate) {
343  return t.has_value() ? isResolved(*t, rstate) : true;
344 }
345 } // namespace detail
346 
348 extern bool isResolved(const Type& t);
349 
351 inline bool isResolved(const std::optional<Type>& t) { return t.has_value() ? isResolved(*t) : true; }
352 
354 inline bool isResolved(const std::optional<const Type>& t) { return t.has_value() ? isResolved(*t) : true; }
355 
357 inline bool sameExceptForConstness(const Type& t1, const Type& t2) {
358  if ( &t1 == &t2 )
359  return true;
360 
361  if ( t1.typeID() && t2.typeID() )
362  return *t1.typeID() == *t2.typeID();
363 
364  if ( t1.cxxID() && t2.cxxID() )
365  return *t1.cxxID() == *t2.cxxID();
366 
367  return t1.isEqual(t2) || t2.isEqual(t1);
368 }
369 
370 } // namespace type
371 
372 inline bool operator==(const Type& t1, const Type& t2) {
373  if ( &t1 == &t2 )
374  return true;
375 
376  if ( type::isMutable(t1) || type::isMutable(t2) ) {
377  if ( type::isConstant(t1) && ! type::isConstant(t2) )
378  return false;
379 
380  if ( type::isConstant(t2) && ! type::isConstant(t1) )
381  return false;
382  }
383 
384  if ( t1.typeID() && t2.typeID() )
385  return *t1.typeID() == *t2.typeID();
386 
387  if ( t1.cxxID() && t2.cxxID() )
388  return *t1.cxxID() == *t2.cxxID();
389 
390  // Type comparison is not fully symmetric, it's good enough
391  // if one type believes it matches the other one.
392  return t1.isEqual(t2) || t2.isEqual(t1);
393 }
394 
395 inline bool operator!=(const Type& t1, const Type& t2) { return ! (t1 == t2); }
396 
398 template<typename T, typename std::enable_if_t<std::is_base_of<trait::isType, T>::value>* = nullptr>
399 inline Node to_node(T t) {
400  return Node(Type(std::move(t)));
401 }
402 
403 } // namespace hilti
Definition: type.h:146
const std::optional< ID > & typeID() const
Definition: type.h:175
Definition: type.h:16
Definition: type.h:35
type::detail::State & _state()
Definition: type.h:181
Definition: type.h:36
Definition: type.h:158
const std::optional< ID > & cxxID() const
Definition: type.h:177
Definition: type.h:40
Definition: type.h:34
Definition: parameter.h:46
const type::detail::State & _state() const
Definition: type.h:179
Definition: type.h:72
bool has(Flag f) const
Definition: type.h:81
Definition: type.h:197
Definition: type.h:41
Definition: node.h:111
Definition: type.h:32
Definition: type.h:268
Definition: node.h:21
bool pruneWalk() const
Definition: type.h:183
bool hasFlag(type::Flag f) const
Definition: type.h:169
Definition: elements.cc:17
const type::Flags & flags() const
Definition: type.h:171
Definition: id.h:18
bool _isConstant() const
Definition: type.h:173
Definition: node.h:359