souffle  2.0.2-371-g6315b36
TypeSystem.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file TypeSystem.cpp
12  *
13  * Covers basic operations constituting Souffle's type system.
14  *
15  ***********************************************************************/
16 
18 #include "ast/Type.h"
23 #include <cassert>
24 #include <initializer_list>
25 
26 namespace souffle::ast::analysis {
27 
28 void SubsetType::print(std::ostream& out) const {
29  out << tfm::format("%s <: %s", getName(), baseType.getName());
30 }
31 
32 void UnionType::print(std::ostream& out) const {
33  out << tfm::format("%s = %s", getName(),
34  join(elementTypes, " | ", [](std::ostream& out, const Type* type) { out << type->getName(); }));
35 }
36 
37 void RecordType::print(std::ostream& out) const {
38  out << tfm::format("%s = (%s)", getName(),
39  join(fields, ", ",
40  [&](std::ostream& out, const Type* fieldType) { out << fieldType->getName(); }));
41 }
42 
44  auto& signedConstant = createType<ConstantType>("__numberConstant");
45  auto& floatConstant = createType<ConstantType>("__floatConstant");
46  auto& symbolConstant = createType<ConstantType>("__symbolConstant");
47  auto& unsignedConstant = createType<ConstantType>("__unsignedConstant");
48 
49  return TypeSet(signedConstant, floatConstant, symbolConstant, unsignedConstant);
50 }
51 
53 #define CREATE_PRIMITIVE(TYPE) \
54  auto& TYPE##Type = createType<PrimitiveType>( \
55  #TYPE, static_cast<const ConstantType&>(getType("__" #TYPE "Constant")));
56 
57  CREATE_PRIMITIVE(number);
59  CREATE_PRIMITIVE(symbol);
60  CREATE_PRIMITIVE(unsigned);
61 
62  return TypeSet(numberType, floatType, symbolType, unsignedType);
63 
64 #undef CREATE_PRIMITIVE
65 }
66 
67 bool TypeEnvironment::isType(const QualifiedName& ident) const {
68  return types.find(ident) != types.end();
69 }
70 
71 bool TypeEnvironment::isType(const Type& type) const {
72  return this == &type.getTypeEnvironment();
73 }
74 
75 const Type& TypeEnvironment::getType(const QualifiedName& ident) const {
76  return *types.at(ident);
77 }
78 
79 const Type& TypeEnvironment::getType(const ast::Type& astTypeDeclaration) const {
80  return getType(astTypeDeclaration.getQualifiedName());
81 }
82 
83 /**
84  * A visitor for Types.
85  */
86 template <typename R>
87 struct TypeVisitor {
88  virtual ~TypeVisitor() = default;
89 
90  R operator()(const Type& type) const {
91  return visit(type);
92  }
93 
94 #define FORWARD(TYPE) \
95  if (auto* t = dynamic_cast<const TYPE##Type*>(&type)) return visit##TYPE##Type(*t);
96 
97  virtual R visit(const Type& type) const {
99  FORWARD(Subset);
100  FORWARD(Union);
101  FORWARD(Record);
102  FORWARD(AlgebraicData);
103 
104  fatal("Unsupported type encountered!");
105  }
106 #undef FORWARD
107 
108 #define VISIT(TYPE) \
109  virtual R visit##TYPE##Type(const TYPE##Type& type) const { \
110  return visitType(type); \
111  }
112 
113  VISIT(Constant)
114  VISIT(Subset)
115  VISIT(Union)
116  VISIT(Record)
117  VISIT(AlgebraicData)
118 
119  virtual R visitType(const Type& /*type*/) const {
120  return R();
121  }
122 
123 #undef VISIT
124 };
125 
126 /**
127  * A visitor for types visiting each type only once (effectively breaking
128  * recursive cycles).
129  */
130 template <typename R>
131 class VisitOnceTypeVisitor : public TypeVisitor<R> {
132 protected:
133  mutable std::map<const Type*, R> seen;
134 
135 public:
136  R visit(const Type& type) const override {
137  auto pos = seen.find(&type);
138  if (pos != seen.end()) {
139  return pos->second;
140  }
141  auto& res = seen[&type]; // mark as seen
143  }
144 };
145 
146 /**
147  * Determines whether the given type is a sub-type of the given root type.
148  */
149 bool isOfRootType(const Type& type, const Type& root) {
150  struct visitor : public VisitOnceTypeVisitor<bool> {
151  const Type& root;
152 
153  explicit visitor(const Type& root) : root(root) {}
154 
155  bool visitConstantType(const ConstantType& type) const override {
156  return type == root;
157  }
158  bool visitSubsetType(const SubsetType& type) const override {
159  return type == root || isOfRootType(type.getBaseType(), root);
160  }
161 
162  bool visitAlgebraicDataType(const AlgebraicDataType& type) const override {
163  return type == root;
164  }
165 
166  bool visitUnionType(const UnionType& type) const override {
167  return type == root ||
168  all_of(type.getElementTypes(), [&](const Type* cur) { return this->visit(*cur); });
169  }
170 
171  bool visitRecordType(const RecordType& type) const override {
172  return type == root;
173  }
174 
175  bool visitType(const Type& /*unused*/) const override {
176  return false;
177  }
178  };
179 
180  return visitor(root).visit(type);
181 }
182 
183 bool isOfKind(const Type& type, TypeAttribute kind) {
184  if (kind == TypeAttribute::Record) {
185  return isA<RecordType>(type);
186  } else if (kind == TypeAttribute::ADT) {
187  return isA<AlgebraicDataType>(type);
188  }
189 
190  return isOfRootType(type, type.getTypeEnvironment().getConstantType(kind));
191 }
192 
193 bool isOfKind(const TypeSet& typeSet, TypeAttribute kind) {
194  return !typeSet.empty() && !typeSet.isAll() &&
195  all_of(typeSet, [&](const Type& type) { return isOfKind(type, kind); });
196 }
197 
198 std::string getTypeQualifier(const Type& type) {
199  std::string kind = [&]() {
201  return "i";
202  } else if (isOfKind(type, TypeAttribute::Unsigned)) {
203  return "u";
205  return "f";
206  } else if (isOfKind(type, TypeAttribute::Symbol)) {
207  return "s";
208  } else if (isOfKind(type, TypeAttribute::Record)) {
209  return "r";
210  } else if (isOfKind(type, TypeAttribute::ADT)) {
211  return "+";
212  } else {
213  fatal("Unsupported kind");
214  }
215  }();
216 
217  return tfm::format("%s:%s", kind, type.getName());
218 }
219 
220 bool isSubtypeOf(const Type& a, const Type& b) {
221  assert(&a.getTypeEnvironment() == &b.getTypeEnvironment() &&
222  "Types must be in the same type environment");
223 
224  if (isOfRootType(a, b)) {
225  return true;
226  }
227 
228  if (isA<UnionType>(a)) {
229  return all_of(static_cast<const UnionType&>(a).getElementTypes(),
230  [&b](const Type* type) { return isSubtypeOf(*type, b); });
231  }
232 
233  if (isA<UnionType>(b)) {
234  return any_of(static_cast<const UnionType&>(b).getElementTypes(),
235  [&a](const Type* type) { return isSubtypeOf(a, *type); });
236  }
237 
238  return false;
239 }
240 
241 void TypeEnvironment::print(std::ostream& out) const {
242  out << "Types:\n";
243  for (const auto& cur : types) {
244  out << "\t" << *cur.second << "\n";
245  }
246 }
247 
248 TypeSet getGreatestCommonSubtypes(const Type& a, const Type& b) {
249  assert(&a.getTypeEnvironment() == &b.getTypeEnvironment() &&
250  "Types must be in the same type environment");
251 
252  if (isSubtypeOf(a, b)) {
253  return TypeSet(a);
254  }
255  if (isSubtypeOf(b, a)) {
256  return TypeSet(b);
257  }
258 
259  TypeSet res;
260  if (isA<UnionType>(a) && isA<UnionType>(b)) {
261  // collect common sub-types of union types
262  struct collector : public TypeVisitor<void> {
263  const Type& b;
264  TypeSet& res;
265  collector(const Type& b, TypeSet& res) : b(b), res(res) {}
266 
267  void visit(const Type& type) const override {
268  if (isSubtypeOf(type, b)) {
269  res.insert(type);
270  } else {
272  }
273  }
274  void visitUnionType(const UnionType& type) const override {
275  for (const auto& cur : type.getElementTypes()) {
276  visit(*cur);
277  }
278  }
279  };
280 
281  // collect all common sub-types
282  collector(b, res).visit(a);
283  }
284 
285  // otherwise there is no common super type
286  return res;
287 }
288 
289 TypeSet getGreatestCommonSubtypes(const TypeSet& set) {
290  // Edge cases.
291  if (set.empty() || set.isAll()) {
292  return TypeSet();
293  }
294 
295  TypeSet greatestCommonSubtypes;
296  greatestCommonSubtypes.insert(*set.begin());
297 
298  for (auto& type : set) {
299  greatestCommonSubtypes = getGreatestCommonSubtypes(TypeSet(type), greatestCommonSubtypes);
300  }
301 
302  return greatestCommonSubtypes;
303 }
304 
305 TypeSet getGreatestCommonSubtypes(const TypeSet& a, const TypeSet& b) {
306  // special cases
307  if (a.empty()) {
308  return a;
309  }
310  if (b.empty()) {
311  return b;
312  }
313 
314  if (a.isAll()) {
315  return b;
316  }
317  if (b.isAll()) {
318  return a;
319  }
320 
321  // compute pairwise greatest common sub types
322  TypeSet res;
323  for (const Type& x : a) {
324  for (const Type& y : b) {
325  res.insert(getGreatestCommonSubtypes(x, y));
326  }
327  }
328  return res;
329 }
330 
331 bool haveCommonSupertype(const Type& a, const Type& b) {
332  assert(&a.getTypeEnvironment() == &b.getTypeEnvironment() &&
333  "Types must be in the same type environment");
334 
335  if (a == b) {
336  return true;
337  }
338 
339  if (isSubtypeOf(a, b) || isSubtypeOf(b, a)) {
340  return true;
341  }
342 
343  return any_of(a.getTypeEnvironment().getTypes(),
344  [&](const Type& type) { return isSubtypeOf(a, type) && isSubtypeOf(b, type); });
345 }
346 
347 TypeAttribute getTypeAttribute(const Type& type) {
350  if (isOfKind(type, typeAttribute)) {
351  return typeAttribute;
352  }
353  }
354  fatal("Unknown type class");
355 }
356 
357 std::optional<TypeAttribute> getTypeAttribute(const TypeSet& type) {
360  if (isOfKind(type, typeAttribute)) {
361  return typeAttribute;
362  }
363  }
364  return {};
365 }
366 
367 bool areEquivalentTypes(const Type& a, const Type& b) {
368  return isSubtypeOf(a, b) && isSubtypeOf(b, a);
369 }
370 
371 bool isADTEnum(const AlgebraicDataType& type) {
372  return all_of(type.getBranches(), [](auto& branch) { return branch.types.empty(); });
373 }
374 
375 } // namespace souffle::ast::analysis
souffle::ast::analysis::isOfKind
bool isOfKind(const Type &type, TypeAttribute kind)
Check if the type is of a kind corresponding to the TypeAttribute.
Definition: TypeSystem.cpp:189
souffle::TypeAttribute::Record
@ Record
souffle::ast::analysis::TypeSet::empty
bool empty() const
Definition: TypeSystem.h:267
souffle::ast::analysis::TypeVisitor
A visitor for Types.
Definition: TypeSystem.cpp:93
TypeAttribute
Type attribute class.
souffle::ast::analysis::ConstantType
Representing the type assigned to a constant.
Definition: TypeSystem.h:99
souffle::ast::analysis::areEquivalentTypes
bool areEquivalentTypes(const Type &a, const Type &b)
Determine if two types are equivalent.
Definition: TypeSystem.cpp:373
tinyformat::format
void format(std::ostream &out, const char *fmt)
Definition: tinyformat.h:1089
souffle::ast::analysis::isADTEnum
bool isADTEnum(const AlgebraicDataType &type)
Determine if ADT is enumerations (are all constructors empty)
Definition: TypeSystem.cpp:377
souffle::ast::analysis::SubsetType::print
void print(std::ostream &out) const override
Definition: TypeSystem.cpp:34
souffle::ast::analysis::TypeEnvironment::getType
const Type & getType(const QualifiedName &) const
Definition: TypeSystem.cpp:81
souffle::ast::analysis::TypeSet::insert
void insert(const Type &type)
Adds the given type to this set.
Definition: TypeSystem.h:288
souffle::ast::analysis::TypeVisitor::visitType
virtual R visitType(const Type &) const
Definition: TypeSystem.cpp:125
souffle::ast::analysis::TypeEnvironment::print
void print(std::ostream &out) const
Definition: TypeSystem.cpp:247
VISIT
#define VISIT(TYPE)
Definition: TypeSystem.cpp:114
souffle::TypeAttribute::Symbol
@ Symbol
souffle::ast::analysis::Type::getTypeEnvironment
const TypeEnvironment & getTypeEnvironment() const
Definition: TypeSystem.h:61
souffle::ast::analysis::TypeEnvironment::isType
bool isType(const QualifiedName &) const
Definition: TypeSystem.cpp:73
souffle::ast::analysis::TypeEnvironment::initializePrimitiveTypes
TypeSet initializePrimitiveTypes()
Definition: TypeSystem.cpp:58
souffle::ast::analysis::SubsetType
A type being a subset of another type.
Definition: TypeSystem.h:108
souffle::ast::analysis::UnionType
A union type combining a list of types into a new, aggregated type.
Definition: TypeSystem.h:146
souffle::ast::analysis::Type
An abstract base class for types to be covered within a type environment.
Definition: TypeSystem.h:51
tinyformat.h
souffle::ast::analysis::haveCommonSupertype
bool haveCommonSupertype(const Type &a, const Type &b)
Determine if there exist a type t such that a <: t and b <: t.
Definition: TypeSystem.cpp:337
souffle::ast::analysis::TypeSet
A collection to represent sets of types.
Definition: TypeSystem.h:249
FORWARD
#define FORWARD(TYPE)
Definition: TypeSystem.cpp:100
souffle::TypeAttribute::Signed
@ Signed
souffle::ast::analysis::getGreatestCommonSubtypes
TypeSet getGreatestCommonSubtypes(const Type &a, const Type &b)
Computes the greatest common sub types of the two given types.
Definition: TypeSystem.cpp:254
souffle::ast::analysis::TypeVisitor::~TypeVisitor
virtual ~TypeVisitor()=default
souffle::ast::analysis::VisitOnceTypeVisitor
A visitor for types visiting each type only once (effectively breaking recursive cycles).
Definition: TypeSystem.cpp:137
souffle::ast::analysis::isSubtypeOf
static TypeConstraint isSubtypeOf(const TypeVar &a, const TypeVar &b)
A constraint factory ensuring that all the types associated to the variable a are subtypes of the var...
Definition: TypeConstraints.cpp:27
souffle::TypeAttribute::Unsigned
@ Unsigned
souffle::ast::analysis::isOfRootType
bool isOfRootType(const Type &type, const Type &root)
Determines whether the given type is a sub-type of the given root type.
Definition: TypeSystem.cpp:155
souffle::ast::analysis::getTypeAttribute
TypeAttribute getTypeAttribute(const Type &type)
Definition: TypeSystem.cpp:353
souffle::join
detail::joined_sequence< Iter, Printer > join(const Iter &a, const Iter &b, const std::string &sep, const Printer &p)
Creates an object to be forwarded to some output stream for printing sequences of elements interspers...
Definition: StreamUtil.h:175
StringUtil.h
souffle::any_of
bool any_of(const Container &c, UnaryPredicate p)
A generic test checking whether any elements within a container satisfy a certain predicate.
Definition: FunctionalUtil.h:124
souffle::ast::Constant
Abstract constant class.
Definition: Constant.h:38
Type.h
CREATE_PRIMITIVE
#define CREATE_PRIMITIVE(TYPE)
souffle::TypeAttribute::ADT
@ ADT
souffle::ast::analysis::TypeSet::isAll
bool isAll() const
Universality check.
Definition: TypeSystem.h:272
souffle::ast::analysis::UnionType::elementTypes
std::vector< const Type * > elementTypes
Definition: TypeSystem.h:160
souffle::ast::analysis::RecordType::fields
std::vector< const Type * > fields
Definition: TypeSystem.h:185
souffle::ast::analysis::Type::getName
const QualifiedName & getName() const
Definition: TypeSystem.h:57
souffle::ast::analysis::TypeEnvironment::types
std::map< QualifiedName, Own< Type > > types
The list of covered types.
Definition: TypeSystem.h:480
souffle::all_of
bool all_of(const Container &c, UnaryPredicate p)
A generic test checking whether all elements within a container satisfy a certain predicate.
Definition: FunctionalUtil.h:110
souffle::ast::analysis::SubsetType::baseType
const Type & baseType
Definition: TypeSystem.h:123
b
l j a showGridBackground &&c b raw series this eventEmitter b
Definition: htmlJsChartistMin.h:15
souffle::ast::analysis::TypeEnvironment::initializeConstantTypes
TypeSet initializeConstantTypes()
Definition: TypeSystem.cpp:49
StreamUtil.h
souffle::fatal
void fatal(const char *format, const Args &... args)
Definition: MiscUtil.h:198
souffle::ast::analysis
Definition: Aggregate.cpp:39
souffle::ast::analysis::getTypeQualifier
std::string getTypeQualifier(const Type &type)
Returns full type qualifier for a given type.
Definition: TypeSystem.cpp:204
FunctionalUtil.h
souffle::ast::analysis::UnionType::print
void print(std::ostream &out) const override
Definition: TypeSystem.cpp:38
souffle::TypeAttribute::Float
@ Float
souffle::ast::QualifiedName
Qualified Name class defines fully/partially qualified names to identify objects in components.
Definition: QualifiedName.h:39
souffle::ast::analysis::RecordType::print
void print(std::ostream &out) const override
Definition: TypeSystem.cpp:43
souffle::ast::analysis::VisitOnceTypeVisitor::seen
std::map< const Type *, R > seen
Definition: TypeSystem.cpp:139
souffle::ast::analysis::TypeVisitor::visit
virtual R visit(const Type &type) const
Definition: TypeSystem.cpp:103
std::type
ElementType type
Definition: span.h:640
souffle::ast::analysis::TypeVisitor::operator()
R operator()(const Type &type) const
Definition: TypeSystem.cpp:96
souffle::ast::analysis::VisitOnceTypeVisitor::visit
R visit(const Type &type) const override
Definition: TypeSystem.cpp:142
TypeSystem.h