souffle  2.0.2-371-g6315b36
TypeChecker.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2020, The Souffle Developers. 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 TypeChecker.cpp
12  *
13  * Implementation of the type checker pass.
14  *
15  ***********************************************************************/
16 
18 #include "ast/Aggregator.h"
19 #include "ast/AlgebraicDataType.h"
20 #include "ast/Argument.h"
21 #include "ast/Atom.h"
22 #include "ast/Attribute.h"
23 #include "ast/BinaryConstraint.h"
24 #include "ast/BranchDeclaration.h"
25 #include "ast/BranchInit.h"
26 #include "ast/Clause.h"
27 #include "ast/Constant.h"
28 #include "ast/Counter.h"
29 #include "ast/Functor.h"
30 #include "ast/IntrinsicFunctor.h"
31 #include "ast/analysis/Functor.h"
33 #include "ast/analysis/Type.h"
36 #include "ast/utility/Utils.h"
37 #include "ast/utility/Visitor.h"
39 #include <map>
40 #include <sstream>
41 #include <string>
42 #include <unordered_set>
43 #include <utility>
44 #include <vector>
45 namespace souffle::ast::transform {
46 
47 using namespace analysis;
48 
49 class TypeDeclarationChecker {
50 public:
51  TypeDeclarationChecker(TranslationUnit& tu) : tu(tu){};
52  void run();
53 
54 private:
56  ErrorReport& report = tu.getErrorReport();
57  const Program& program = tu.getProgram();
58  const TypeEnvironmentAnalysis& typeEnvAnalysis = *tu.getAnalysis<TypeEnvironmentAnalysis>();
59  const TypeEnvironment& typeEnv = typeEnvAnalysis.getTypeEnvironment();
60 
61  void checkRecordType(const ast::RecordType& type);
62  void checkSubsetType(const ast::SubsetType& type);
63  void checkUnionType(const ast::UnionType& type);
64  void checkADT(const ast::AlgebraicDataType& type);
65 };
66 
67 class TypeCheckerImpl : Visitor<void> {
68 public:
69  TypeCheckerImpl(TranslationUnit& tu) : tu(tu){};
70 
71  /** Analyse types, clause by clause */
72  void run() {
73  const Program& program = tu.getProgram();
74  for (auto* clause : program.getClauses()) {
75  visitDepthFirstPreOrder(*clause, *this);
76  }
77  }
78 
79 private:
80  TranslationUnit& tu;
81  ErrorReport& report = tu.getErrorReport();
82  const TypeAnalysis& typeAnalysis = *tu.getAnalysis<TypeAnalysis>();
83  const TypeEnvironment& typeEnv = tu.getAnalysis<TypeEnvironmentAnalysis>()->getTypeEnvironment();
84  const FunctorAnalysis& functorAnalysis = *tu.getAnalysis<FunctorAnalysis>();
86  const Program& program = tu.getProgram();
87 
88  std::unordered_set<const Atom*> negatedAtoms;
89 
90  /** Collect negated atoms */
91  void visitNegation(const Negation& neg) override;
92 
93  /* Type checks */
94  /** Check if declared types of the relation match deduced types. */
95  void visitAtom(const Atom& atom) override;
96  void visitVariable(const Variable& var) override;
97  void visitStringConstant(const StringConstant& constant) override;
98  void visitNumericConstant(const NumericConstant& constant) override;
99  void visitNilConstant(const NilConstant& constant) override;
100  void visitRecordInit(const RecordInit& rec) override;
101  void visitBranchInit(const BranchInit& adt) override;
102  void visitTypeCast(const ast::TypeCast& cast) override;
103  void visitIntrinsicFunctor(const IntrinsicFunctor& fun) override;
104  void visitUserDefinedFunctor(const UserDefinedFunctor& fun) override;
105  void visitBinaryConstraint(const BinaryConstraint& constraint) override;
106  void visitAggregator(const Aggregator& aggregator) override;
107 };
108 
110  auto& report = tu.getErrorReport();
111  auto errorsBeforeDeclarationsCheck = report.getNumErrors();
112 
113  TypeDeclarationChecker{tu}.run();
114 
115  // Run type checker only if type declarations are valid.
116  if (report.getNumErrors() == errorsBeforeDeclarationsCheck) {
117  TypeCheckerImpl{tu}.run();
118  }
119 }
120 
122  // check presence of all the element types and that all element types are based off a primitive
123  for (const QualifiedName& sub : type.getTypes()) {
124  if (typeEnv.isPrimitiveType(sub)) {
125  continue;
126  }
127  const ast::Type* subtype = getIf(
128  program.getTypes(), [&](const ast::Type* type) { return type->getQualifiedName() == sub; });
129  if (subtype == nullptr) {
130  report.addError(tfm::format("Undefined type %s in definition of union type %s", sub,
131  type.getQualifiedName()),
132  type.getSrcLoc());
133  } else if (!isA<ast::UnionType>(subtype) && !isA<ast::SubsetType>(subtype)) {
134  report.addError(tfm::format("Union type %s contains the non-primitive type %s",
135  type.getQualifiedName(), sub),
136  type.getSrcLoc());
137  }
138  }
139 
140  // Check if the union is recursive.
141  if (typeEnvAnalysis.isCyclic(type.getQualifiedName())) {
142  report.addError("Infinite descent in the definition of type " + toString(type.getQualifiedName()),
143  type.getSrcLoc());
144  }
145 
146  /* check that union types do not mix different primitive types */
147  for (const auto* type : program.getTypes()) {
148  // We are only interested in unions here.
149  if (!isA<ast::UnionType>(type)) {
150  continue;
151  }
152 
153  const auto& name = type->getQualifiedName();
154 
155  const auto& predefinedTypesInUnion = typeEnvAnalysis.getPrimitiveTypesInUnion(name);
156 
157  // Report error (if size == 0, then the union is cyclic)
158  if (predefinedTypesInUnion.size() > 1) {
159  report.addError(
160  tfm::format("Union type %s is defined over {%s} (multiple primitive types in union)",
161  name, join(predefinedTypesInUnion, ", ")),
162  type->getSrcLoc());
163  }
164  }
165 }
166 
167 void TypeDeclarationChecker::checkRecordType(const ast::RecordType& type) {
168  auto&& fields = type.getFields();
169  // check proper definition of all field types
170  for (auto&& field : fields) {
171  if (!typeEnv.isType(field->getTypeName())) {
172  report.addError(tfm::format("Undefined type %s in definition of field %s", field->getTypeName(),
173  field->getName()),
174  field->getSrcLoc());
175  }
176  }
177 
178  // check that field names are unique
179  for (std::size_t i = 0; i < fields.size(); i++) {
180  auto&& cur_name = fields[i]->getName();
181  for (std::size_t j = 0; j < i; j++) {
182  if (fields[j]->getName() == cur_name) {
183  report.addError(tfm::format("Doubly defined field name %s in definition of type %s", cur_name,
184  type.getQualifiedName()),
185  fields[i]->getSrcLoc());
186  }
187  }
188  }
189 }
190 
191 void TypeDeclarationChecker::checkADT(const ast::AlgebraicDataType& type) {
192  // check if all branches contain properly defined types.
193  for (auto* branch : type.getBranches()) {
194  for (auto* field : branch->getFields()) {
195  if (!typeEnv.isType(field->getTypeName())) {
196  report.addError(tfm::format("Undefined type %s in definition of branch %s",
197  field->getTypeName(), branch->getConstructor()),
198  field->getSrcLoc());
199  }
200  }
201  }
202 }
203 
204 void TypeDeclarationChecker::checkSubsetType(const ast::SubsetType& astType) {
205  if (typeEnvAnalysis.isCyclic(astType.getQualifiedName())) {
206  report.addError(
207  tfm::format("Infinite descent in the definition of type %s", astType.getQualifiedName()),
208  astType.getSrcLoc());
209  return;
210  }
211 
212  if (!typeEnv.isType(astType.getBaseType())) {
213  report.addError(tfm::format("Undefined base type %s in definition of type %s", astType.getBaseType(),
214  astType.getQualifiedName()),
215  astType.getSrcLoc());
216  return;
217  }
218 
219  auto& rootType = typeEnv.getType(astType.getBaseType());
220 
221  if (isA<analysis::UnionType>(rootType)) {
222  report.addError(tfm::format("Subset type %s can't be derived from union %s",
223  astType.getQualifiedName(), rootType.getName()),
224  astType.getSrcLoc());
225  }
226 
227  if (isA<analysis::RecordType>(rootType)) {
228  report.addError(tfm::format("Subset type %s can't be derived from record type %s",
229  astType.getQualifiedName(), rootType.getName()),
230  astType.getSrcLoc());
231  }
232 }
233 
235  // The redefinitions of types is checked by checkNamespaces in SemanticChecker
236  for (auto* type : program.getTypes()) {
237  if (typeEnv.isPrimitiveType(type->getQualifiedName())) {
238  report.addError("Redefinition of the predefined type", type->getSrcLoc());
239  continue;
240  }
241 
242  if (isA<ast::UnionType>(type)) {
243  checkUnionType(*as<ast::UnionType>(type));
244  } else if (isA<ast::RecordType>(type)) {
245  checkRecordType(*as<ast::RecordType>(type));
246  } else if (isA<ast::SubsetType>(type)) {
247  checkSubsetType(*as<ast::SubsetType>(type));
248  } else if (isA<ast::AlgebraicDataType>(type)) {
249  checkADT(*as<ast::AlgebraicDataType>(type));
250  } else {
251  fatal("unsupported type construct: %s", typeid(type).name());
252  }
253  }
254 
255  // Check if all the branch names are unique in sum types.
256  std::map<std::string, std::vector<SrcLocation>> branchToLocation;
257  visitDepthFirst(program.getTypes(), [&](const ast::AlgebraicDataType& type) {
258  for (auto* branch : type.getBranches()) {
259  branchToLocation[branch->getConstructor()].push_back(branch->getSrcLoc());
260  }
261  });
262 
263  for (auto& branchLocs : branchToLocation) {
264  auto& branch = branchLocs.first;
265  auto& locs = branchLocs.second;
266 
267  // If a branch is used only once, then everything is fine.
268  if (locs.size() == 1) continue;
269 
270  auto primaryDiagnostic =
271  DiagnosticMessage(tfm::format("Branch %s is defined multiple times", branch));
272 
273  std::vector<DiagnosticMessage> branchDeclarations;
274  for (auto& loc : locs) {
275  branchDeclarations.push_back(DiagnosticMessage(tfm::format("Branch %s defined", branch), loc));
276  }
277 
278  report.addDiagnostic(Diagnostic(
279  Diagnostic::Type::ERROR, std::move(primaryDiagnostic), std::move(branchDeclarations)));
280  }
281 }
282 
283 void TypeCheckerImpl::visitAtom(const Atom& atom) {
284  auto relation = getAtomRelation(&atom, &program);
285  if (relation == nullptr) {
286  return; // error unrelated to types.
287  }
288 
289  auto attributes = relation->getAttributes();
290  auto arguments = atom.getArguments();
291  if (attributes.size() != arguments.size()) {
292  return; // error in input program
293  }
294 
295  for (size_t i = 0; i < attributes.size(); ++i) {
296  auto& typeName = attributes[i]->getTypeName();
297  if (!typeEnv.isType(typeName)) {
298  continue;
299  }
300 
301  auto argTypes = typeAnalysis.getTypes(arguments[i]);
302  auto& attributeType = typeEnv.getType(typeName);
303 
304  if (argTypes.isAll() || argTypes.empty()) {
305  continue; // This will be reported later.
306  }
307 
308  // We consider two cases: negated and not negated atoms.
309  // Negated atom have to agree in kind, non-negated atom need to follow source/sink rules.
310  if (negatedAtoms.count(&atom) == 0) {
311  // Attribute and argument type agree if, argument type is a subtype of declared type
312  // or is of the appropriate constant type or the (constant) record type.
313  bool validAttribute = all_of(argTypes, [&attributeType](const analysis::Type& type) {
314  if (isSubtypeOf(type, attributeType)) return true;
315  if (!isSubtypeOf(attributeType, type)) return false;
316  if (isA<ConstantType>(type)) return true;
317  return isA<analysis::RecordType>(type) && !isA<analysis::SubsetType>(type);
318  });
319 
320  if (!validAttribute && !Global::config().has("legacy")) {
321  auto primaryDiagnostic =
322  DiagnosticMessage("Atom's argument type is not a subtype of its declared type",
323  arguments[i]->getSrcLoc());
324 
325  auto declaredTypeInfo =
326  DiagnosticMessage(tfm::format("The argument's declared type is %s", typeName),
327  attributes[i]->getSrcLoc());
328 
329  report.addDiagnostic(Diagnostic(Diagnostic::Type::ERROR, std::move(primaryDiagnostic),
330  {std::move(declaredTypeInfo)}));
331  }
332  } else { // negation case.
333  // Declared attribute and deduced type agree if:
334  // They are the same type, or
335  // They are derived from the same constant type.
336  bool validAttribute = all_of(argTypes, [&](const analysis::Type& type) {
337  return type == attributeType || any_of(typeEnv.getConstantTypes(), [&](auto& constantType) {
338  return isSubtypeOf(attributeType, constantType) && isSubtypeOf(type, constantType);
339  });
340  });
341 
342  if (!validAttribute) {
343  auto primaryDiagnostic =
344  DiagnosticMessage("The kind of atom's argument doesn't match the declared type kind",
345  arguments[i]->getSrcLoc());
346  auto declaredTypeInfo =
347  DiagnosticMessage(tfm::format("The argument's declared type is %s", typeName),
348  attributes[i]->getSrcLoc());
349  report.addDiagnostic(Diagnostic(Diagnostic::Type::ERROR, std::move(primaryDiagnostic),
350  {std::move(declaredTypeInfo)}));
351  }
352  }
353  }
354 }
355 
356 void TypeCheckerImpl::visitVariable(const ast::Variable& var) {
357  if (typeAnalysis.getTypes(&var).empty()) {
358  report.addError("Unable to deduce type for variable " + var.getName(), var.getSrcLoc());
359  }
360 }
361 
363  TypeSet types = typeAnalysis.getTypes(&constant);
365  report.addError("Symbol constant (type mismatch)", constant.getSrcLoc());
366  }
367 }
368 
370  TypeSet types = typeAnalysis.getTypes(&constant);
371 
372  // No type could be assigned.
373  if (polyAnalysis.hasInvalidType(&constant)) {
374  report.addError("Ambiguous constant (unable to deduce type)", constant.getSrcLoc());
375  return;
376  }
377 
378  switch (polyAnalysis.getInferredType(&constant)) {
381  report.addError("Number constant (type mismatch)", constant.getSrcLoc());
382  }
383  break;
386  report.addError("Unsigned constant (type mismatch)", constant.getSrcLoc());
387  }
388  break;
391  report.addError("Float constant (type mismatch)", constant.getSrcLoc());
392  }
393  break;
394  }
395 }
396 
397 void TypeCheckerImpl::visitNilConstant(const NilConstant& constant) {
398  TypeSet types = typeAnalysis.getTypes(&constant);
400  report.addError("Nil constant used as a non-record", constant.getSrcLoc());
401  return;
402  }
403 }
404 
407 
408  if (!isOfKind(types, TypeAttribute::Record) || types.size() != 1) {
409  report.addError("Ambiguous record", rec.getSrcLoc());
410  return;
411  }
412 
413  // At this point we know that there is exactly one type in set, so we can take it.
414  auto& recordType = *as<analysis::RecordType>(*types.begin());
415 
416  if (recordType.getFields().size() != rec.getArguments().size()) {
417  report.addError("Wrong number of arguments given to record", rec.getSrcLoc());
418  return;
419  }
420 }
421 
422 void TypeCheckerImpl::visitBranchInit(const BranchInit& adt) {
423  TypeSet types = typeAnalysis.getTypes(&adt);
424 
425  if (!isOfKind(types, TypeAttribute::ADT) || types.isAll() || types.size() != 1) {
426  report.addError("Ambiguous branch", adt.getSrcLoc());
427  return;
428  }
429 
430  // We know now that the set "types" is a singleton
431  auto& sumType = *as<analysis::AlgebraicDataType>(*types.begin());
432 
433  auto& argsDeclaredTypes = sumType.getBranchTypes(adt.getConstructor());
434  auto args = adt.getArguments();
435 
436  if (argsDeclaredTypes.size() != args.size()) {
437  // Invalid branchInit arity, handled by checkBranchInits.
438  return;
439  }
440 
441  for (size_t i = 0; i < args.size(); ++i) {
442  auto argTypes = typeAnalysis.getTypes(args[i]);
443  bool correctType = all_of(
444  argTypes, [&](const analysis::Type& t) { return isSubtypeOf(t, *argsDeclaredTypes[i]); });
445  if (!correctType) {
446  // TODO (darth_tytus): Give better error
447  report.addError("Branch argument's type doesn't match its declared type", args[i]->getSrcLoc());
448  }
449  }
450 }
451 
452 void TypeCheckerImpl::visitTypeCast(const ast::TypeCast& cast) {
453  if (!typeEnv.isType(cast.getType())) {
455  tfm::format("Type cast to the undeclared type \"%s\"", cast.getType()), cast.getSrcLoc());
456  return;
457  }
458 
459  auto& castTypes = typeAnalysis.getTypes(&cast);
460  auto& argTypes = typeAnalysis.getTypes(cast.getValue());
461 
462  if (castTypes.isAll() || castTypes.size() != 1) {
463  report.addError("Unable to deduce type of the argument (cast)", cast.getSrcLoc());
464  return;
465  }
466 
467  // This should be reported elsewhere
468  if (argTypes.isAll() || castTypes.size() != 1 || argTypes.isAll() || argTypes.size() != 1) {
469  return;
470  }
471 }
472 
473 void TypeCheckerImpl::visitIntrinsicFunctor(const IntrinsicFunctor& fun) {
474  if (!typeAnalysis.hasValidTypeInfo(&fun)) {
475  auto args = fun.getArguments();
476  if (!isValidFunctorOpArity(fun.getBaseFunctionOp(), args.size())) {
477  report.addError("invalid overload (arity mismatch)", fun.getSrcLoc());
478  return;
479  }
480  assert(typeAnalysis.getValidIntrinsicFunctorOverloads(fun).empty() &&
481  "unexpected type analysis result");
482  report.addError("no valid overloads", fun.getSrcLoc());
483  }
484 }
485 
486 void TypeCheckerImpl::visitUserDefinedFunctor(const UserDefinedFunctor& fun) {
487  // check type of result
488  const TypeSet& resultType = typeAnalysis.getTypes(&fun);
489 
490  TypeAttribute returnType;
491  try {
492  returnType = functorAnalysis.getReturnType(&fun);
493  } catch (...) {
494  report.addError("Undeclared user functor", fun.getSrcLoc());
495  return;
496  }
497 
498  if (!isOfKind(resultType, returnType)) {
499  switch (returnType) {
501  report.addError("Non-numeric use for numeric functor", fun.getSrcLoc());
502  break;
504  report.addError("Non-unsigned use for unsigned functor", fun.getSrcLoc());
505  break;
507  report.addError("Non-float use for float functor", fun.getSrcLoc());
508  break;
510  report.addError("Non-symbolic use for symbolic functor", fun.getSrcLoc());
511  break;
512  case TypeAttribute::Record: fatal("Invalid return type");
513  case TypeAttribute::ADT: fatal("Invalid return type");
514  }
515  }
516 
517  size_t i = 0;
518  for (auto arg : fun.getArguments()) {
519  TypeAttribute argType = functorAnalysis.getArgType(&fun, i);
520  if (!isOfKind(typeAnalysis.getTypes(arg), argType)) {
521  switch (argType) {
523  report.addError("Non-numeric argument for functor", arg->getSrcLoc());
524  break;
526  report.addError("Non-symbolic argument for functor", arg->getSrcLoc());
527  break;
529  report.addError("Non-unsigned argument for functor", arg->getSrcLoc());
530  break;
532  report.addError("Non-float argument for functor", arg->getSrcLoc());
533  break;
534  case TypeAttribute::Record: fatal("Invalid argument type");
535  case TypeAttribute::ADT: fatal("Invalid argument type");
536  }
537  }
538  ++i;
539  }
540 }
541 
542 void TypeCheckerImpl::visitBinaryConstraint(const BinaryConstraint& constraint) {
543  auto op = polyAnalysis.getOverloadedOperator(&constraint);
544  auto left = constraint.getLHS();
545  auto right = constraint.getRHS();
546  auto opTypesAttrs = getBinaryConstraintTypes(op);
547 
548  auto leftTypes = typeAnalysis.getTypes(left);
549  auto rightTypes = typeAnalysis.getTypes(right);
550 
551  // Skip checks if either side is `Bottom` b/c it just adds noise.
552  // The unable-to-deduce-type checker will point out the issue.
553  if (leftTypes.empty() || rightTypes.empty() || leftTypes.isAll() || rightTypes.isAll()) return;
554 
555  assert((leftTypes.size() == 1) && (rightTypes.size() == 1));
556 
557  // Extract types from singleton sets.
558  auto& leftType = *typeAnalysis.getTypes(left).begin();
559  auto& rightType = *typeAnalysis.getTypes(right).begin();
560 
561  // give them a slightly nicer error
562  if (isOrderedBinaryConstraintOp(op) && !areEquivalentTypes(leftType, rightType)) {
563  report.addError("Cannot compare different types", constraint.getSrcLoc());
564  } else {
565  auto checkTyAttr = [&](Argument const& side) {
566  auto opMatchesType = any_of(opTypesAttrs,
567  [&](auto& typeAttr) { return isOfKind(typeAnalysis.getTypes(&side), typeAttr); });
568 
569  if (!opMatchesType) {
570  std::stringstream ss;
571  ss << "Constraint requires an operand of type "
572  << join(opTypesAttrs, " or ", [&](auto& out, auto& typeAttr) {
573  switch (typeAttr) {
574  case TypeAttribute::Signed: out << "`number`"; break;
575  case TypeAttribute::Symbol: out << "`symbol`"; break;
576  case TypeAttribute::Unsigned: out << "`unsigned`"; break;
577  case TypeAttribute::Float: out << "`float`"; break;
578  case TypeAttribute::Record: out << "a record"; break;
579  case TypeAttribute::ADT: out << "a sum"; break;
580  }
581  });
582  report.addError(ss.str(), side.getSrcLoc());
583  }
584  };
585 
586  checkTyAttr(*left);
587  checkTyAttr(*right);
588  }
589 }
590 
591 void TypeCheckerImpl::visitAggregator(const Aggregator& aggregator) {
592  auto op = polyAnalysis.getOverloadedOperator(&aggregator);
593 
594  auto aggregatorType = typeAnalysis.getTypes(&aggregator);
595 
597 
598  // Check if operation type and return type agree.
599  if (!isOfKind(aggregatorType, opType)) {
600  report.addError("Couldn't assign types to the aggregator", aggregator.getSrcLoc());
601  }
602 }
603 
604 void TypeCheckerImpl::visitNegation(const Negation& neg) {
605  negatedAtoms.insert(neg.getAtom());
606 }
607 
608 } // namespace souffle::ast::transform
souffle::ast::transform::TypeDeclarationChecker::checkSubsetType
void checkSubsetType(const ast::SubsetType &type)
Definition: TypeChecker.cpp:210
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::ast::transform::TypeCheckerImpl::visitVariable
void visitVariable(const Variable &var) override
Definition: TypeChecker.cpp:362
souffle::TypeAttribute::Record
@ Record
souffle::ast::analysis::TypeEnvironmentAnalysis::getPrimitiveTypesInUnion
const std::set< QualifiedName > & getPrimitiveTypesInUnion(const QualifiedName &identifier) const
Definition: TypeEnvironment.h:58
souffle::ast::analysis::TypeSet::empty
bool empty() const
Definition: TypeSystem.h:267
Functor.h
souffle::ast::analysis::PolymorphicObjectsAnalysis::getInferredType
NumericConstant::Type getInferredType(const NumericConstant *nc) const
Definition: PolymorphicObjects.cpp:40
souffle::ast::transform::TypeCheckerImpl::program
const Program & program
Definition: TypeChecker.cpp:92
souffle::ast::Visitor
The generic base type of all AstVisitors realizing the dispatching of visitor calls.
Definition: Visitor.h:87
souffle::ast::transform::TypeCheckerImpl::visitNegation
void visitNegation(const Negation &neg) override
Collect negated atoms.
Definition: TypeChecker.cpp:610
souffle::ast::transform::TypeCheckerImpl::typeAnalysis
const TypeAnalysis & typeAnalysis
Definition: TypeChecker.cpp:88
TypeAttribute
Type attribute class.
souffle::ast::transform::TypeCheckerImpl::visitAtom
void visitAtom(const Atom &atom) override
Check if declared types of the relation match deduced types.
Definition: TypeChecker.cpp:289
souffle::ast::analysis::FunctorAnalysis
Definition: Functor.h:39
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::sub
std::shared_ptr< Constraint< Var > > sub(const Var &a, const Var &b, const std::string &symbol="⊑")
A generic factory for constraints of the form.
Definition: ConstraintSystem.h:228
souffle::ast::analysis::TypeEnvironment::getType
const Type & getType(const QualifiedName &) const
Definition: TypeSystem.cpp:81
souffle::ast::analysis::PolymorphicObjectsAnalysis
Definition: PolymorphicObjects.h:39
souffle::TypeAttribute::Symbol
@ Symbol
relation
Relation & relation
Definition: Reader.h:130
types
std::vector< Own< ast::Type > > types
Definition: ComponentInstantiation.cpp:64
souffle::ast::analysis::TypeAnalysis::getTypes
TypeSet const & getTypes(const Argument *argument) const
Get the computed types for the given argument.
Definition: Type.h:56
souffle::ast::analysis::TypeAnalysis::getValidIntrinsicFunctorOverloads
IntrinsicFunctors getValidIntrinsicFunctorOverloads(const IntrinsicFunctor &inf) const
– Functor-related methods –
Definition: Type.cpp:216
souffle::ast::analysis::TypeEnvironment::isType
bool isType(const QualifiedName &) const
Definition: TypeSystem.cpp:73
souffle::ast::NilConstant
Defines the nil constant.
Definition: NilConstant.h:36
souffle::ast::analysis::TypeEnvironmentAnalysis::isCyclic
bool isCyclic(const QualifiedName &identifier) const
Definition: TypeEnvironment.h:62
souffle::ast::analysis::SubsetType
A type being a subset of another type.
Definition: TypeSystem.h:108
souffle::ast::Program::getClauses
std::vector< Clause * > getClauses() const
Return clauses.
Definition: Program.h:65
souffle::ast::transform::TypeDeclarationChecker::run
void run()
Definition: TypeChecker.cpp:240
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
souffle::ast::UserDefinedFunctor
User-Defined functor class.
Definition: UserDefinedFunctor.h:46
souffle::ast::analysis::Variable
A variable to be utilized within constraints to be handled by the constraint solver.
Definition: ConstraintSystem.h:41
souffle::ast::transform::TypeCheckerImpl::visitAggregator
void visitAggregator(const Aggregator &aggregator) override
Definition: TypeChecker.cpp:597
souffle::ast::transform::TypeCheckerImpl
Definition: TypeChecker.cpp:73
souffle::ast::transform::TypeCheckerImpl::negatedAtoms
std::unordered_set< const Atom * > negatedAtoms
Definition: TypeChecker.cpp:94
IntrinsicFunctor.h
souffle::ast::transform::TypeCheckerImpl::visitNilConstant
void visitNilConstant(const NilConstant &constant) override
Definition: TypeChecker.cpp:403
souffle::ast::Atom
An atom class.
Definition: Atom.h:51
souffle::ast::analysis::TypeAnalysis::hasValidTypeInfo
bool hasValidTypeInfo(const Argument *argument) const
Definition: Type.cpp:255
souffle::ast::analysis::TypeSet
A collection to represent sets of types.
Definition: TypeSystem.h:249
j
var j
Definition: htmlJsChartistMin.h:15
Utils.h
souffle::ast::analysis::RecordType
A record type combining a list of fields into a new, aggregated type.
Definition: TypeSystem.h:170
souffle::TypeAttribute::Signed
@ Signed
souffle::ast::NumericConstant::Type::Int
@ Int
Constant.h
souffle::ast::Argument
An abstract class for arguments.
Definition: Argument.h:33
Attribute.h
souffle::ast::transform::TypeCheckerImpl::visitIntrinsicFunctor
void visitIntrinsicFunctor(const IntrinsicFunctor &fun) override
Definition: TypeChecker.cpp:479
souffle::ast::analysis::TypeEnvironmentAnalysis
Definition: TypeEnvironment.h:38
souffle::toString
const std::string & toString(const std::string &str)
A generic function converting strings into strings (trivial case).
Definition: StringUtil.h:234
Argument.h
souffle::ast::Program
The program class consists of relations, clauses and types.
Definition: Program.h:52
souffle::ast::transform::TypeCheckerImpl::visitStringConstant
void visitStringConstant(const StringConstant &constant) override
Definition: TypeChecker.cpp:368
souffle::ast::analysis::TypeSet::begin
const_iterator begin() const
Allows to iterate over the types contained in this set (only if not universal)
Definition: TypeSystem.h:343
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::TranslationUnit::getErrorReport
ErrorReport & getErrorReport()
Return error report.
Definition: TranslationUnit.h:90
i
size_t i
Definition: json11.h:663
souffle::ast::TypeCast
Defines a type cast class for expressions.
Definition: TypeCast.h:46
souffle::ast::transform::TypeCheckerImpl::visitBranchInit
void visitBranchInit(const BranchInit &adt) override
Definition: TypeChecker.cpp:428
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
souffle::ast::Negation
Negation of an atom negated atom.
Definition: Negation.h:50
StringUtil.h
souffle::ast::IntrinsicFunctor
Intrinsic Functor class for functors are in-built.
Definition: IntrinsicFunctor.h:47
Atom.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
TypeChecker.h
souffle::ast::analysis::FunctorAnalysis::getReturnType
TypeAttribute getReturnType(const Functor *functor) const
Return return type of functor.
Definition: Functor.cpp:40
souffle::ast::analysis::TypeEnvironment
A type environment is a set of types.
Definition: TypeSystem.h:401
souffle::ast::TranslationUnit
Translation unit class for the translation pipeline.
Definition: TranslationUnit.h:51
souffle::ast::transform::TypeDeclarationChecker::checkUnionType
void checkUnionType(const ast::UnionType &type)
Definition: TypeChecker.cpp:127
souffle::isValidFunctorOpArity
bool isValidFunctorOpArity(std::string_view symbol, size_t arity)
Definition: FunctorOps.cpp:240
PolymorphicObjects.h
souffle::ErrorReport::addError
void addError(const std::string &message, SrcLocation location)
Adds an error with the given message and location.
Definition: ErrorReport.h:173
souffle::ast::transform::TypeChecker::verify
void verify(TranslationUnit &translationUnit)
Definition: TypeChecker.cpp:115
souffle::Diagnostic::Type::ERROR
@ ERROR
souffle::ast::visitDepthFirstPreOrder
void visitDepthFirstPreOrder(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the ast rooted by the given node recursively in a depth-...
Definition: Visitor.h:235
souffle::ast::transform::TypeCheckerImpl::visitUserDefinedFunctor
void visitUserDefinedFunctor(const UserDefinedFunctor &fun) override
Definition: TypeChecker.cpp:492
souffle::ast::transform
Definition: Program.h:45
souffle::ast::analysis::TypeEnvironment::getConstantTypes
const TypeSet & getConstantTypes() const
Definition: TypeSystem.h:448
BranchInit.h
souffle::ast::Term::getArguments
std::vector< Argument * > getArguments() const
Get arguments.
Definition: Term.h:56
souffle::ast::transform::TypeCheckerImpl::visitNumericConstant
void visitNumericConstant(const NumericConstant &constant) override
Definition: TypeChecker.cpp:375
souffle::getBinaryConstraintTypes
std::vector< TypeAttribute > getBinaryConstraintTypes(const BinaryConstraintOp op)
Get type binary constraint operates on.
Definition: BinaryConstraintOps.h:439
souffle::ast::transform::TypeDeclarationChecker::checkRecordType
void checkRecordType(const ast::RecordType &type)
Definition: TypeChecker.cpp:173
souffle::TypeAttribute::ADT
@ ADT
souffle::ast::Program::getTypes
std::vector< Type * > getTypes() const
Return types.
Definition: Program.h:55
souffle::ast::analysis::TypeEnvironmentAnalysis::getTypeEnvironment
const TypeEnvironment & getTypeEnvironment() const
Definition: TypeEnvironment.h:54
souffle::ErrorReport::getNumErrors
unsigned getNumErrors() const
Definition: ErrorReport.h:158
souffle::getTypeAttributeAggregate
TypeAttribute getTypeAttributeAggregate(const AggregateOp op)
Get return type of the aggregate.
Definition: AggregateOp.h:96
souffle::ast::TranslationUnit::getAnalysis
Analysis * getAnalysis() const
get analysis: analysis is generated on the fly if not present
Definition: TranslationUnit.h:60
souffle::ast::BinaryConstraint
Binary constraint class.
Definition: BinaryConstraint.h:53
Aggregator.h
souffle::getIf
C::value_type getIf(const C &container, std::function< bool(const typename C::value_type)> pred)
Returns the first element in a container that satisfies a given predicate, nullptr otherwise.
Definition: ContainerUtil.h:101
souffle::Global::config
static MainConfig & config()
Definition: Global.h:141
souffle::ast::analysis::FunctorAnalysis::getArgType
TypeAttribute getArgType(const Functor *functor, const size_t idx) const
Return argument type of functor.
Definition: Functor.cpp:49
souffle::ast::transform::TypeCheckerImpl::functorAnalysis
const FunctorAnalysis & functorAnalysis
Definition: TypeChecker.cpp:90
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::Aggregator
Defines the aggregator class.
Definition: Aggregator.h:53
souffle::ast::transform::TypeCheckerImpl::visitRecordInit
void visitRecordInit(const RecordInit &rec) override
Definition: TypeChecker.cpp:411
Functor.h
souffle::ast::Negation::getAtom
Atom * getAtom() const
Get negated atom.
Definition: Negation.h:55
souffle::ast::transform::TypeDeclarationChecker::checkADT
void checkADT(const ast::AlgebraicDataType &type)
Definition: TypeChecker.cpp:197
souffle::ast::NumericConstant::Type::Uint
@ Uint
souffle::fatal
void fatal(const char *format, const Args &... args)
Definition: MiscUtil.h:198
Visitor.h
Clause.h
Type.h
souffle::ast::transform::TypeCheckerImpl::report
ErrorReport & report
Definition: TypeChecker.cpp:87
souffle::ast::transform::TypeCheckerImpl::polyAnalysis
const PolymorphicObjectsAnalysis & polyAnalysis
Definition: TypeChecker.cpp:91
souffle::ast::transform::TypeCheckerImpl::visitTypeCast
void visitTypeCast(const ast::TypeCast &cast) override
Definition: TypeChecker.cpp:458
souffle::ast::BranchInit
Initialization of ADT instance.
Definition: BranchInit.h:49
souffle::ast::transform::TypeDeclarationChecker
Definition: TypeChecker.cpp:55
souffle::ast::analysis::TypeAnalysis
Definition: Type.h:45
Counter.h
souffle::ast::getAtomRelation
const Relation * getAtomRelation(const Atom *atom, const Program *program)
Returns the relation referenced by the given atom.
Definition: Utils.cpp:129
BinaryConstraint.h
souffle::ast::transform::TypeCheckerImpl::visitBinaryConstraint
void visitBinaryConstraint(const BinaryConstraint &constraint) override
Definition: TypeChecker.cpp:548
souffle::ast::visitDepthFirst
void visitDepthFirst(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the ast rooted by the given node recursively in a depth-...
Definition: Visitor.h:273
AlgebraicDataType.h
souffle::ast::Node::getSrcLoc
const SrcLocation & getSrcLoc() const
Return source location of the Node.
Definition: Node.h:46
souffle::ErrorReport::addDiagnostic
void addDiagnostic(const Diagnostic &diagnostic)
Definition: ErrorReport.h:186
souffle::ast::NumericConstant::Type::Float
@ Float
souffle::ast::NumericConstant
Numeric Constant.
Definition: NumericConstant.h:43
souffle::TypeAttribute::Float
@ Float
souffle::ast::QualifiedName
Qualified Name class defines fully/partially qualified names to identify objects in components.
Definition: QualifiedName.h:39
TypeEnvironment.h
souffle::ErrorReport
Definition: ErrorReport.h:152
souffle::ast::TranslationUnit::getProgram
Program & getProgram() const
Return the program.
Definition: TranslationUnit.h:84
souffle::ast::transform::TypeCheckerImpl::typeEnv
const TypeEnvironment & typeEnv
Definition: TypeChecker.cpp:89
souffle::ast::analysis::PolymorphicObjectsAnalysis::getOverloadedOperator
BinaryConstraintOp getOverloadedOperator(const BinaryConstraint *bc) const
Definition: PolymorphicObjects.cpp:48
souffle::ast::StringConstant
String constant class.
Definition: StringConstant.h:37
souffle::ast::AlgebraicDataType
Combination of types using sums and products.
Definition: AlgebraicDataType.h:55
souffle::isOrderedBinaryConstraintOp
bool isOrderedBinaryConstraintOp(const BinaryConstraintOp op)
Determines whether arguments of constraint are orderable.
Definition: BinaryConstraintOps.h:389
souffle::ast::analysis::PolymorphicObjectsAnalysis::hasInvalidType
bool hasInvalidType(const NumericConstant *nc) const
Definition: PolymorphicObjects.cpp:44
souffle::ast::RecordInit
Defines a record initialization class.
Definition: RecordInit.h:42
BranchDeclaration.h
std::type
ElementType type
Definition: span.h:640
TypeSystem.h
souffle::profile::ss
class souffle::profile::Tui ss
Definition: Tui.h:336