souffle  2.0.2-371-g6315b36
Public Member Functions | Data Fields | Private Member Functions | Private Attributes
souffle::ast::transform::SemanticCheckerImpl Struct Reference
Collaboration diagram for souffle::ast::transform::SemanticCheckerImpl:
Collaboration graph

Public Member Functions

 SemanticCheckerImpl (TranslationUnit &tu)
 

Data Fields

TranslationUnittu
 

Private Member Functions

void checkAggregator (const Aggregator &aggregator)
 
void checkArgument (const Argument &arg)
 
void checkAtom (const Atom &atom)
 
void checkBranchInits ()
 check if all the branches refer to the existing types. More...
 
void checkClause (const Clause &clause)
 
void checkComplexRule (std::set< const Clause * > multiRule)
 
void checkConstant (const Argument &argument)
 
void checkFact (const Clause &fact)
 
void checkInlining ()
 
void checkIO ()
 
void checkLiteral (const Literal &literal)
 
void checkNamespaces ()
 
void checkRelation (const Relation &relation)
 
void checkRelationDeclaration (const Relation &relation)
 
void checkWitnessProblem ()
 
bool isDependent (const Clause &agg1, const Clause &agg2)
 agg1, agg2 are clauses which contain no head, and consist of a single literal that contains an aggregate. More...
 

Private Attributes

const IOTypeAnalysisioTypes = *tu.getAnalysis<IOTypeAnalysis>()
 
const PrecedenceGraphAnalysisprecedenceGraph = *tu.getAnalysis<PrecedenceGraphAnalysis>()
 
const Programprogram = tu.getProgram()
 
const RecursiveClausesAnalysisrecursiveClauses = *tu.getAnalysis<RecursiveClausesAnalysis>()
 
ErrorReportreport = tu.getErrorReport()
 
const SCCGraphAnalysissccGraph = *tu.getAnalysis<SCCGraphAnalysis>()
 
const SumTypeBranchesAnalysissumTypesBranches = *tu.getAnalysis<SumTypeBranchesAnalysis>()
 
const TypeEnvironmenttypeEnv = tu.getAnalysis<TypeEnvironmentAnalysis>()->getTypeEnvironment()
 

Detailed Description

Definition at line 108 of file SemanticChecker.cpp.

Constructor & Destructor Documentation

◆ SemanticCheckerImpl()

souffle::ast::transform::SemanticCheckerImpl::SemanticCheckerImpl ( TranslationUnit tu)

Definition at line 149 of file SemanticChecker.cpp.

150  {
151  // mute all relations
152  for (Relation* rel : program.getRelations()) {
153  rel->addQualifier(RelationQualifier::SUPPRESSED);
154  }
155  } else {
156  // mute only the given relations (if they exist)
157  for (auto& relname : suppressedRelations) {
158  const std::vector<std::string> comps = splitString(relname, '.');
159  if (!comps.empty()) {
160  // generate the relation identifier
161  QualifiedName relid(comps[0]);
162  for (size_t i = 1; i < comps.size(); i++) {
163  relid.append(comps[i]);
164  }
165 
166  // update suppressed qualifier if the relation is found
167  if (Relation* rel = getRelation(program, relid)) {
168  rel->addQualifier(RelationQualifier::SUPPRESSED);
169  }
170  }
171  }
172  }
173  }
174 
176 
177  // check rules
178  for (auto* rel : program.getRelations()) {
179  checkRelation(*rel);
180  }
181  for (auto* clause : program.getClauses()) {
182  checkClause(*clause);
183  }
184 
185  // Group clauses that stem from a single complex rule
186  // with multiple headers/disjunction etc. The grouping
187  // is performed via their source-location.
188  std::map<SrcLocation, std::set<const Clause*>> multiRuleMap;
189  for (auto* clause : program.getClauses()) {
190  // collect clauses of a multi rule, i.e., they have the same source locator
191  multiRuleMap[clause->getSrcLoc()].insert(clause);
192  }
193 
194  // check complex rule
195  for (const auto& multiRule : multiRuleMap) {
196  checkComplexRule(multiRule.second);
197  }
198 
199  checkNamespaces();
200  checkIO();
202  checkInlining();
203 
204  // Run grounded terms checker
205  GroundedTermsChecker().verify(tu);
206 
207  // Check types
208  TypeChecker().verify(tu);
209 
210  // - stratification --
211  // check for cyclic dependencies
212  for (Relation* cur : program.getRelations()) {
213  size_t scc = sccGraph.getSCC(cur);
214  if (sccGraph.isRecursive(scc)) {
215  for (const Relation* cyclicRelation : sccGraph.getInternalRelations(scc)) {
216  // Negations and aggregations need to be stratified
217  const Literal* foundLiteral = nullptr;
218  bool hasNegation = hasClauseWithNegatedRelation(cyclicRelation, cur, &program, foundLiteral);
219  if (hasNegation ||
220  hasClauseWithAggregatedRelation(cyclicRelation, cur, &program, foundLiteral)) {
221  auto const& relSet = sccGraph.getInternalRelations(scc);
222  std::set<const Relation*, NameComparison> sortedRelSet(relSet.begin(), relSet.end());
223  // Negations and aggregations need to be stratified
224  std::string relationsListStr = toString(join(sortedRelSet, ",",
225  [](std::ostream& out, const Relation* r) { out << r->getQualifiedName(); }));
226  std::vector<DiagnosticMessage> messages;
227  messages.push_back(DiagnosticMessage(
228  "Relation " + toString(cur->getQualifiedName()), cur->getSrcLoc()));
229  std::string negOrAgg = hasNegation ? "negation" : "aggregation";
230  messages.push_back(
231  DiagnosticMessage("has cyclic " + negOrAgg, foundLiteral->getSrcLoc()));
233  DiagnosticMessage("Unable to stratify relation(s) {" + relationsListStr + "}"),
234  messages));
235  break;
236  }
237  }
238  }
239  }
240 }
241 
242 void SemanticCheckerImpl::checkAtom(const Atom& atom) {
243  // check existence of relation
244  auto* r = getRelation(program, atom.getQualifiedName());
245  if (r == nullptr) {
246  report.addError("Undefined relation " + toString(atom.getQualifiedName()), atom.getSrcLoc());

References souffle::ast::Program::getRelations(), program, rel(), and souffle::SUPPRESSED.

Here is the call graph for this function:

Member Function Documentation

◆ checkAggregator()

void souffle::ast::transform::SemanticCheckerImpl::checkAggregator ( const Aggregator aggregator)
private

Definition at line 375 of file SemanticChecker.cpp.

375  {
376  if (candidateAggregate != aggregator) {
377  return;
378  }
379  // Get the literal containing the aggregator and put it into a dummy clause
380  // so we can get information about groundedness
381  dummyClauseAggregator.addToBody(souffle::clone(&parentLiteral));
382  });
383  });
384 
385  visitDepthFirst(program, [&](const Literal& parentLiteral) {
386  visitDepthFirst(parentLiteral, [&](const Aggregator& /* otherAggregate */) {
387  // Create the other aggregate's dummy clause
388  Clause dummyClauseOther;
389  dummyClauseOther.addToBody(souffle::clone(&parentLiteral));
390  // Check dependency between the aggregator and this one
391  if (isDependent(dummyClauseAggregator, dummyClauseOther) &&
392  isDependent(dummyClauseOther, dummyClauseAggregator)) {
393  report.addError("Mutually dependent aggregate", aggregator.getSrcLoc());
394  }
395  });
396  });
397 
398  for (Literal* literal : aggregator.getBodyLiterals()) {
399  checkLiteral(*literal);
400  }
401 }
402 
403 void SemanticCheckerImpl::checkArgument(const Argument& arg) {
404  if (const auto* agg = dynamic_cast<const Aggregator*>(&arg)) {
405  checkAggregator(*agg);
406  } else if (const auto* func = dynamic_cast<const Functor*>(&arg)) {
407  for (auto arg : func->getArguments()) {

References souffle::clone().

Here is the call graph for this function:

◆ checkArgument()

void souffle::ast::transform::SemanticCheckerImpl::checkArgument ( const Argument arg)
private

Definition at line 409 of file SemanticChecker.cpp.

413  {
414 
415 /**
416  * Check if the argument can be statically evaluated
417  * and thus in particular, if it should be allowed to appear as argument in facts.

◆ checkAtom()

void souffle::ast::transform::SemanticCheckerImpl::checkAtom ( const Atom atom)
private

Definition at line 248 of file SemanticChecker.cpp.

250  {
252  "Mismatching arity of relation " + toString(atom.getQualifiedName()), atom.getSrcLoc());
253  }
254 
255  for (const Argument* arg : atom.getArguments()) {
256  checkArgument(*arg);
257  }
258 }
259 
261  visitDepthFirst(program.getClauses(), [&](const BranchInit& adt) {
262  auto* type = sumTypesBranches.getType(adt.getConstructor());
263  if (type == nullptr) {
264  report.addError("Undeclared branch", adt.getSrcLoc());

◆ checkBranchInits()

void souffle::ast::transform::SemanticCheckerImpl::checkBranchInits ( )
private

check if all the branches refer to the existing types.

Definition at line 266 of file SemanticChecker.cpp.

271  {
272  report.addError(tfm::format("Invalid arity, the declared arity of %s is %s", adt.getConstructor(),
273  declaredArity),
274  adt.getSrcLoc());
275  return;
276  }
277  });
278 }
279 
280 namespace {
281 
282 /**
283  * Get unnamed variables except those that appear inside aggregates.
284  */

References souffle::ErrorReport::addError(), tinyformat::format(), and report.

Here is the call graph for this function:

◆ checkClause()

void souffle::ast::transform::SemanticCheckerImpl::checkClause ( const Clause clause)
private

Definition at line 470 of file SemanticChecker.cpp.

474  : clause.getBodyLiterals()) {
475  checkLiteral(*lit);
476  }
477 
478  // check facts
479  if (isFact(clause)) {
480  checkFact(clause);
481  }
482 
483  // check whether named unnamed variables of the form _<ident>
484  // are only used once in a clause; if not, warnings will be
485  // issued.
486  std::map<std::string, int> var_count;
487  std::map<std::string, const ast::Variable*> var_pos;
488  visitDepthFirst(clause, [&](const ast::Variable& var) {
489  var_count[var.getName()]++;
490  var_pos[var.getName()] = &var;
491  });
492  for (const auto& cur : var_count) {
493  int numAppearances = cur.second;
494  const auto& varName = cur.first;
495  const auto& varLocation = var_pos[varName]->getSrcLoc();
496  if (varName[0] == '_') {
497  assert(varName.size() > 1 && "named variable should not be a single underscore");
498  if (numAppearances > 1) {
499  report.addWarning("Variable " + varName + " marked as singleton but occurs more than once",
500  varLocation);
501  }
502  }
503  }
504 
505  // check execution plan
506  if (clause.getExecutionPlan() != nullptr) {
507  auto numAtoms = getBodyLiterals<Atom>(clause).size();
508  for (const auto& cur : clause.getExecutionPlan()->getOrders()) {
509  bool isComplete = true;
510  auto order = cur.second->getOrder();
511  for (unsigned i = 1; i <= order.size(); i++) {
512  if (!contains(order, i)) {
513  isComplete = false;
514  break;
515  }
516  }
517  if (order.size() != numAtoms || !isComplete) {
518  report.addError("Invalid execution order in plan", cur.second->getSrcLoc());
519  }
520  }
521  }
522 
523  // check auto-increment
524  if (recursiveClauses.recursive(&clause)) {
525  visitDepthFirst(clause, [&](const Counter& ctr) {
526  report.addError("Auto-increment functor in a recursive rule", ctr.getSrcLoc());
527  });
528  }
529 }
530 
531 void SemanticCheckerImpl::checkComplexRule(std::set<const Clause*> multiRule) {
532  std::map<std::string, int> var_count;
533  std::map<std::string, const ast::Variable*> var_pos;
534 
535  // Count the variable occurrence for the body of a

◆ checkComplexRule()

void souffle::ast::transform::SemanticCheckerImpl::checkComplexRule ( std::set< const Clause * >  multiRule)
private

Definition at line 537 of file SemanticChecker.cpp.

539  : (*multiRule.begin())->getBodyLiterals()) {
540  visitDepthFirst(*literal, [&](const ast::Variable& var) {
541  var_count[var.getName()]++;
542  var_pos[var.getName()] = &var;
543  });
544  }
545 
546  // Count variable occurrence for each head separately
547  for (auto clause : multiRule) {
548  visitDepthFirst(*(clause->getHead()), [&](const ast::Variable& var) {
549  var_count[var.getName()]++;
550  var_pos[var.getName()] = &var;
551  });
552  }
553 
554  // Check that a variables occurs more than once
555  for (const auto& cur : var_count) {
556  int numAppearances = cur.second;
557  const auto& varName = cur.first;
558  const auto& varLocation = var_pos[varName]->getSrcLoc();
559  if (varName[0] != '_' && numAppearances == 1) {
560  report.addWarning("Variable " + varName + " only occurs once", varLocation);
561  }
562  }
563 }
564 
566  const auto& attributes = relation.getAttributes();
567  assert(attributes.size() == relation.getArity() && "mismatching attribute size and arity");
568 
569  for (size_t i = 0; i < relation.getArity(); i++) {

References souffle::ast::visitDepthFirst().

Here is the call graph for this function:

◆ checkConstant()

void souffle::ast::transform::SemanticCheckerImpl::checkConstant ( const Argument argument)
private

◆ checkFact()

void souffle::ast::transform::SemanticCheckerImpl::checkFact ( const Clause fact)
private

Definition at line 449 of file SemanticChecker.cpp.

452  {
453  return; // checked by clause
454  }
455 
456  // facts must only contain constants
457  for (auto* arg : head->getArguments()) {
458  if (!isConstantArgument(arg)) {
459  report.addError("Argument in fact is not constant", arg->getSrcLoc());
460  }
461  }
462 }
463 
464 void SemanticCheckerImpl::checkClause(const Clause& clause) {
465  // check head atom
466  checkAtom(*clause.getHead());
467 
468  // Check for absence of underscores in head

◆ checkInlining()

void souffle::ast::transform::SemanticCheckerImpl::checkInlining ( )
private

Definition at line 791 of file SemanticChecker.cpp.

791  {
792  inlinedRelations.insert(relation);
793  if (ioTypes.isIO(relation)) {
795  "IO relation " + toString(relation->getQualifiedName()) + " cannot be inlined",
796  relation->getSrcLoc());
797  }
798  }
799  }
800 
801  // Check 1:
802  // Let G' be the subgraph of the precedence graph G containing only those nodes
803  // which are marked with the inline directive.
804  // If G' contains a cycle, then inlining cannot be performed.
805 
806  RelationSet unvisited; // nodes that have not been visited yet
807  RelationSet visiting; // nodes that we are currently visiting
808  RelationSet visited; // nodes that have been completely explored
809 
810  // All nodes are initially unvisited
811  for (const Relation* rel : inlinedRelations) {
812  unvisited.insert(rel);
813  }
814 
815  // Remember the parent node of each visited node to construct the found cycle
816  std::map<const Relation*, const Relation*> origins;
817 
818  std::vector<QualifiedName> result =
819  findInlineCycle(precedenceGraph, origins, nullptr, unvisited, visiting, visited);
820 
821  // If the result contains anything, then a cycle was found
822  if (!result.empty()) {
823  Relation* cycleOrigin = getRelation(program, result[result.size() - 1]);
824 
825  // Construct the string representation of the cycle
826  std::stringstream cycle;
827  cycle << "{" << cycleOrigin->getQualifiedName();
828 
829  // Print it backwards to preserve the initial cycle order
830  for (int i = result.size() - 2; i >= 0; i--) {
831  cycle << ", " << result[i];
832  }
833 
834  cycle << "}";
835 
837  "Cannot inline cyclically dependent relations " + cycle.str(), cycleOrigin->getSrcLoc());
838  }
839 
840  // Check 2:
841  // Cannot use the counter argument ('$') in inlined relations
842 
843  // Check if an inlined literal ever takes in a $
844  visitDepthFirst(program, [&](const Atom& atom) {
845  Relation* associatedRelation = getRelation(program, atom.getQualifiedName());
846  if (associatedRelation != nullptr && isInline(associatedRelation)) {
847  visitDepthFirst(atom, [&](const Argument& arg) {
848  if (isA<Counter>(&arg)) {
850  "Cannot inline literal containing a counter argument '$'", arg.getSrcLoc());
851  }
852  });
853  }
854  });
855 
856  // Check if an inlined clause ever contains a $
857  for (const Relation* rel : inlinedRelations) {
858  for (Clause* clause : getClauses(program, *rel)) {
859  visitDepthFirst(*clause, [&](const Argument& arg) {
860  if (isA<Counter>(&arg)) {
862  "Cannot inline clause containing a counter argument '$'", arg.getSrcLoc());
863  }
864  });
865  }
866  }
867 
868  // Check 3:
869  // Suppose the relation b is marked with the inline directive, but appears negated
870  // in a clause. Then, if b introduces a new variable in its body, we cannot inline
871  // the relation b.
872 
873  // Find all relations with the inline declarative that introduce new variables in their bodies
874  RelationSet nonNegatableRelations;
875  for (const Relation* rel : inlinedRelations) {
876  bool foundNonNegatable = false;
877  for (const Clause* clause : getClauses(program, *rel)) {
878  // Get the variables in the head
879  std::set<std::string> headVariables;
880  visitDepthFirst(*clause->getHead(),
881  [&](const ast::Variable& var) { headVariables.insert(var.getName()); });
882 
883  // Get the variables in the body
884  std::set<std::string> bodyVariables;
885  visitDepthFirst(clause->getBodyLiterals(),
886  [&](const ast::Variable& var) { bodyVariables.insert(var.getName()); });
887 
888  // Check if all body variables are in the head
889  // Do this separately to the above so only one error is printed per variable
890  for (const std::string& var : bodyVariables) {
891  if (headVariables.find(var) == headVariables.end()) {
892  nonNegatableRelations.insert(rel);
893  foundNonNegatable = true;
894  break;
895  }
896  }
897 
898  if (foundNonNegatable) {
899  break;
900  }
901  }
902  }
903 
904  // Check that these relations never appear negated
905  visitDepthFirst(program, [&](const Negation& neg) {
906  Relation* associatedRelation = getRelation(program, neg.getAtom()->getQualifiedName());
907  if (associatedRelation != nullptr &&
908  nonNegatableRelations.find(associatedRelation) != nonNegatableRelations.end()) {
910  "Cannot inline negated relation which may introduce new variables", neg.getSrcLoc());
911  }
912  });
913 
914  // Check 4:
915  // Don't support inlining atoms within aggregators at this point.
916 
917  // Reasoning: Suppose we have an aggregator like `max X: a(X)`, where `a` is inlined to `a1` and `a2`.
918  // Then, `max X: a(X)` will become `max( max X: a1(X), max X: a2(X) )`. Suppose further that a(X) has
919  // values X where it is true, while a2(X) does not. Then, the produced argument
920  // `max( max X: a1(X), max X: a2(X) )` will not return anything (as one of its arguments fails), while
921  // `max X: a(X)` will.
922  // Can work around this with emptiness checks (e.g. `!a1(_), ... ; !a2(_), ... ; ...`)
923 
924  // This corner case prevents generalising aggregator inlining with the current set up.
925 
926  visitDepthFirst(program, [&](const Aggregator& aggr) {
927  visitDepthFirst(aggr, [&](const Atom& subatom) {
928  const Relation* rel = getRelation(program, subatom.getQualifiedName());
929  if (rel != nullptr && isInline(rel)) {
930  report.addError("Cannot inline relations that appear in aggregator", subatom.getSrcLoc());
931  }
932  });
933  });
934 
935  // Check 5:
936  // Suppose a relation `a` is inlined, appears negated in a clause, and contains a
937  // (possibly nested) unnamed variable in its arguments. Then, the atom can't be
938  // inlined, as unnamed variables are named during inlining (since they may appear
939  // multiple times in an inlined-clause's body) => ungroundedness!
940 
941  // Exception: It's fine if the unnamed variable appears in a nested aggregator, as
942  // the entire aggregator will automatically be grounded.
943 
944  // TODO (azreika): special case where all rules defined for `a` use the
945  // underscored-argument exactly once: can workaround by remapping the variable
946  // back to an underscore - involves changes to the actual inlining algo, though
947 
948  // Returns the pair (isValid, lastSrcLoc) where:
949  // - isValid is true if and only if the node contains an invalid underscore, and
950  // - lastSrcLoc is the source location of the last visited node
951  std::function<std::pair<bool, SrcLocation>(const Node*)> checkInvalidUnderscore = [&](const Node* node) {
952  if (isA<UnnamedVariable>(node)) {
953  // Found an invalid underscore
954  return std::make_pair(true, node->getSrcLoc());
955  } else if (isA<Aggregator>(node)) {
956  // Don't care about underscores within aggregators
957  return std::make_pair(false, node->getSrcLoc());
958  }
959 
960  // Check if any children nodes use invalid underscores
961  for (const Node* child : node->getChildNodes()) {
962  std::pair<bool, SrcLocation> childStatus = checkInvalidUnderscore(child);
963  if (childStatus.first) {
964  // Found an invalid underscore
965  return childStatus;
966  }
967  }
968 
969  return std::make_pair(false, node->getSrcLoc());
970  };
971 
972  // Perform the check
973  visitDepthFirst(program, [&](const Negation& negation) {
974  const Atom* associatedAtom = negation.getAtom();
975  const Relation* associatedRelation = getRelation(program, associatedAtom->getQualifiedName());
976  if (associatedRelation != nullptr && isInline(associatedRelation)) {
977  std::pair<bool, SrcLocation> atomStatus = checkInvalidUnderscore(associatedAtom);
978  if (atomStatus.first) {
980  "Cannot inline negated atom containing an unnamed variable unless the variable is "
981  "within an aggregator",
982  atomStatus.second);
983  }
984  }
985  });
986 }
987 
988 // Check that type and relation names are disjoint sets.
990  std::map<std::string, SrcLocation> names;
991 
992  // Find all names and report redeclarations as we go.

References souffle::ErrorReport::addError(), relation, and souffle::toString().

Here is the call graph for this function:

◆ checkIO()

void souffle::ast::transform::SemanticCheckerImpl::checkIO ( )
private

Definition at line 623 of file SemanticChecker.cpp.

625  : program.getDirectives()) {
626  checkIO(directive);
627  }
628 }
629 
630 /**
631  * A witness is considered "invalid" if it is trying to export a witness
632  * out of a count, sum, or mean aggregate.
633  *
634  * However we need to be careful: Sometimes a witness variables occurs within the body

◆ checkLiteral()

void souffle::ast::transform::SemanticCheckerImpl::checkLiteral ( const Literal literal)
private

Definition at line 309 of file SemanticChecker.cpp.

309  {
310  checkAtom(*neg->getAtom());
311  }
312 
313  if (const auto* constraint = as<BinaryConstraint>(literal)) {
314  checkArgument(*constraint->getLHS());
315  checkArgument(*constraint->getRHS());
316 
317  std::set<const UnnamedVariable*> unnamedInRecord;
318  visitDepthFirst(*constraint, [&](const RecordInit& record) {
319  for (auto* arg : record.getArguments()) {
320  if (auto* unnamed = as<UnnamedVariable>(arg)) {
321  unnamedInRecord.insert(unnamed);
322  }
323  }
324  });
325 
326  // Don't worry about underscores if either side is an aggregate (because of witness exporting)
327  if (isA<Aggregator>(*constraint->getLHS()) || isA<Aggregator>(*constraint->getRHS())) {
328  return;
329  }
330  // Check if constraint contains unnamed variables.
331  for (auto* unnamed : getUnnamedVariables(*constraint)) {
332  if (!contains(unnamedInRecord, unnamed)) {
333  report.addError("Underscore in binary relation", unnamed->getSrcLoc());
334  }
335  }
336  }
337 }
338 
339 /**
340  * agg1, agg2 are clauses which contain no head, and consist of a single literal
341  * that contains an aggregate.
342  * agg1 is dependent on agg2 if agg1 contains a variable which is grounded by agg2, and not by agg1.
343  */

◆ checkNamespaces()

void souffle::ast::transform::SemanticCheckerImpl::checkNamespaces ( )
private

Definition at line 995 of file SemanticChecker.cpp.

995  {
996  report.addError("Name clash on type " + name, type->getSrcLoc());
997  } else {
998  names[name] = type->getSrcLoc();
999  }
1000  }
1001 
1002  for (const auto& rel : program.getRelations()) {
1003  const std::string name = toString(rel->getQualifiedName());
1004  if (names.count(name) != 0u) {
1005  report.addError("Name clash on relation " + name, rel->getSrcLoc());
1006  } else {
1007  names[name] = rel->getSrcLoc();
1008  }
1009  }
1010 }
1011 
1012 } // namespace souffle::ast::transform

References souffle::ErrorReport::addError().

Here is the call graph for this function:

◆ checkRelation()

void souffle::ast::transform::SemanticCheckerImpl::checkRelation ( const Relation relation)
private

Definition at line 595 of file SemanticChecker.cpp.

599  {
601  "Equivalence relation " + toString(relation.getQualifiedName()) + " is not binary",
602  relation.getSrcLoc());
603  }
604  }
605 
606  // start with declaration
608 
609  // check whether this relation is empty
610  if (getClauses(program, relation).empty() && !ioTypes.isInput(&relation) &&
611  !relation.hasQualifier(RelationQualifier::SUPPRESSED)) {
612  report.addWarning("No rules/facts defined for relation " + toString(relation.getQualifiedName()),
613  relation.getSrcLoc());
614  }
615 }
616 
618  auto checkIO = [&](const Directive* directive) {
619  auto* r = getRelation(program, directive->getQualifiedName());
620  if (r == nullptr) {

◆ checkRelationDeclaration()

void souffle::ast::transform::SemanticCheckerImpl::checkRelationDeclaration ( const Relation relation)
private

Definition at line 571 of file SemanticChecker.cpp.

573  { return type->getQualifiedName() == typeName; });
574 
575  /* check whether type exists */
576  if (!typeEnv.isPrimitiveType(typeName) && nullptr == existingType) {
577  report.addError(tfm::format("Undefined type in attribute %s", *attr), attr->getSrcLoc());
578  }
579 
580  /* check whether name occurs more than once */
581  for (size_t j = 0; j < i; j++) {
582  if (attr->getName() == attributes[j]->getName()) {
583  report.addError(tfm::format("Doubly defined attribute name %s", *attr), attr->getSrcLoc());
584  }
585  }
586  }
587 }
588 
589 void SemanticCheckerImpl::checkRelation(const Relation& relation) {
590  if (relation.getRepresentation() == RelationRepresentation::EQREL) {
591  if (relation.getArity() == 2) {
592  const auto& attributes = relation.getAttributes();
593  assert(attributes.size() == 2 && "mismatching attribute size and arity");

◆ checkWitnessProblem()

void souffle::ast::transform::SemanticCheckerImpl::checkWitnessProblem ( )
private

Definition at line 692 of file SemanticChecker.cpp.

692  : usesInvalidWitness(tu, clause, agg)) {
694  "Witness problem: argument grounded by an aggregator's inner scope is used "
695  "ungrounded in "
696  "outer scope in a count/sum/mean aggregate",
697  invalidArgument);
698  }
699  });
700  });
701 }
702 
703 /**
704  * Find a cycle consisting entirely of inlined relations.
705  * If no cycle exists, then an empty vector is returned.
706  */
707 std::vector<QualifiedName> findInlineCycle(const PrecedenceGraphAnalysis& precedenceGraph,

References souffle::ErrorReport::addError().

Here is the call graph for this function:

◆ isDependent()

bool souffle::ast::transform::SemanticCheckerImpl::isDependent ( const Clause agg1,
const Clause agg2 
)
private

agg1, agg2 are clauses which contain no head, and consist of a single literal that contains an aggregate.

agg1 is dependent on agg2 if agg1 contains a variable which is grounded by agg2, and not by agg1.

Definition at line 350 of file SemanticChecker.cpp.

353  {
354  if (var == searchVar) {
355  matchingVarPtr = &var;
356  return;
357  }
358  });
359  // If the variable occurs in both clauses (a match was found)
360  if (matchingVarPtr != nullptr) {
361  if (!groundedInAgg1[&searchVar] && groundedInAgg2[matchingVarPtr]) {
362  dependent = true;
363  }
364  }
365  });
366  return dependent;
367 }
368 
369 void SemanticCheckerImpl::checkAggregator(const Aggregator& aggregator) {
370  auto& report = tu.getErrorReport();
371  const Program& program = tu.getProgram();
372  Clause dummyClauseAggregator;
373 

Field Documentation

◆ ioTypes

const IOTypeAnalysis& souffle::ast::transform::SemanticCheckerImpl::ioTypes = *tu.getAnalysis<IOTypeAnalysis>()
private

Definition at line 113 of file SemanticChecker.cpp.

◆ precedenceGraph

const PrecedenceGraphAnalysis& souffle::ast::transform::SemanticCheckerImpl::precedenceGraph = *tu.getAnalysis<PrecedenceGraphAnalysis>()
private

Definition at line 114 of file SemanticChecker.cpp.

◆ program

const Program& souffle::ast::transform::SemanticCheckerImpl::program = tu.getProgram()
private

Definition at line 120 of file SemanticChecker.cpp.

Referenced by SemanticCheckerImpl().

◆ recursiveClauses

const RecursiveClausesAnalysis& souffle::ast::transform::SemanticCheckerImpl::recursiveClauses = *tu.getAnalysis<RecursiveClausesAnalysis>()
private

Definition at line 115 of file SemanticChecker.cpp.

◆ report

ErrorReport& souffle::ast::transform::SemanticCheckerImpl::report = tu.getErrorReport()
private

Definition at line 121 of file SemanticChecker.cpp.

Referenced by checkBranchInits().

◆ sccGraph

const SCCGraphAnalysis& souffle::ast::transform::SemanticCheckerImpl::sccGraph = *tu.getAnalysis<SCCGraphAnalysis>()
private

Definition at line 116 of file SemanticChecker.cpp.

◆ sumTypesBranches

const SumTypeBranchesAnalysis& souffle::ast::transform::SemanticCheckerImpl::sumTypesBranches = *tu.getAnalysis<SumTypeBranchesAnalysis>()
private

Definition at line 117 of file SemanticChecker.cpp.

◆ tu

TranslationUnit& souffle::ast::transform::SemanticCheckerImpl::tu

Definition at line 109 of file SemanticChecker.cpp.

◆ typeEnv

const TypeEnvironment& souffle::ast::transform::SemanticCheckerImpl::typeEnv = tu.getAnalysis<TypeEnvironmentAnalysis>()->getTypeEnvironment()
private

Definition at line 119 of file SemanticChecker.cpp.


The documentation for this struct was generated from the following file:
souffle::ast::transform::SemanticCheckerImpl::checkWitnessProblem
void checkWitnessProblem()
Definition: SemanticChecker.cpp:692
souffle::ast::transform::SemanticCheckerImpl::checkNamespaces
void checkNamespaces()
Definition: SemanticChecker.cpp:995
souffle::ast::transform::SemanticCheckerImpl::report
ErrorReport & report
Definition: SemanticChecker.cpp:121
souffle::RelationQualifier::SUPPRESSED
@ SUPPRESSED
tinyformat::format
void format(std::ostream &out, const char *fmt)
Definition: tinyformat.h:1089
souffle::RelationRepresentation::EQREL
@ EQREL
souffle::contains
bool contains(const C &container, const typename C::value_type &element)
A utility to check generically whether a given element is contained in a given container.
Definition: ContainerUtil.h:75
souffle::ast::analysis::IOTypeAnalysis::isIO
bool isIO(const Relation *relation) const
Definition: IOType.h:73
souffle::ast::transform::SemanticCheckerImpl::checkInlining
void checkInlining()
Definition: SemanticChecker.cpp:791
souffle::ast::analysis::SCCGraphAnalysis::getSCC
size_t getSCC(const Relation *rel) const
Get the SCC of the given relation.
Definition: SCCGraph.h:64
relation
Relation & relation
Definition: Reader.h:130
souffle::ast::transform::SemanticCheckerImpl::checkArgument
void checkArgument(const Argument &arg)
Definition: SemanticChecker.cpp:409
souffle::ast::isFact
bool isFact(const Clause &clause)
Returns whether the given clause is a fact.
Definition: Utils.cpp:214
souffle::ast::Program::getClauses
std::vector< Clause * > getClauses() const
Return clauses.
Definition: Program.h:65
souffle::ast::transform::SemanticCheckerImpl::program
const Program & program
Definition: SemanticChecker.cpp:120
souffle::ast::transform::SemanticCheckerImpl::checkRelation
void checkRelation(const Relation &relation)
Definition: SemanticChecker.cpp:595
j
var j
Definition: htmlJsChartistMin.h:15
souffle::ast::transform::SemanticCheckerImpl::isDependent
bool isDependent(const Clause &agg1, const Clause &agg2)
agg1, agg2 are clauses which contain no head, and consist of a single literal that contains an aggreg...
Definition: SemanticChecker.cpp:350
souffle::ast::transform::SemanticCheckerImpl::checkClause
void checkClause(const Clause &clause)
Definition: SemanticChecker.cpp:470
souffle::ast::hasClauseWithNegatedRelation
bool hasClauseWithNegatedRelation(const Relation *relation, const Relation *negRelation, const Program *program, const Literal *&foundLiteral)
Returns whether the given relation has any clauses which contain a negation of a specific relation.
Definition: Utils.cpp:171
souffle::toString
const std::string & toString(const std::string &str)
A generic function converting strings into strings (trivial case).
Definition: StringUtil.h:234
souffle::ast::transform::findInlineCycle
std::vector< QualifiedName > findInlineCycle(const PrecedenceGraphAnalysis &precedenceGraph, std::map< const Relation *, const Relation * > &origins, const Relation *current, RelationSet &unvisited, RelationSet &visiting, RelationSet &visited)
Find a cycle consisting entirely of inlined relations.
Definition: SemanticChecker.cpp:713
souffle::ast::transform::SemanticCheckerImpl::recursiveClauses
const RecursiveClausesAnalysis & recursiveClauses
Definition: SemanticChecker.cpp:115
souffle::ast::hasClauseWithAggregatedRelation
bool hasClauseWithAggregatedRelation(const Relation *relation, const Relation *aggRelation, const Program *program, const Literal *&foundLiteral)
Returns whether the given relation has any clauses which contain an aggregation over of a specific re...
Definition: Utils.cpp:184
souffle::clone
auto clone(const std::vector< A * > &xs)
Definition: ContainerUtil.h:172
souffle::ast::transform::SemanticCheckerImpl::checkLiteral
void checkLiteral(const Literal &literal)
Definition: SemanticChecker.cpp:309
souffle::ast::TranslationUnit::getErrorReport
ErrorReport & getErrorReport()
Return error report.
Definition: TranslationUnit.h:90
i
size_t i
Definition: json11.h:663
souffle::ast::analysis::SCCGraphAnalysis::isRecursive
bool isRecursive(const size_t scc) const
Return if the given SCC is recursive.
Definition: SCCGraph.h:201
souffle::ast::getRelation
Relation * getRelation(const Program &program, const QualifiedName &name)
Returns the relation with the given name in the program.
Definition: Utils.cpp:101
souffle::ast::transform::SemanticCheckerImpl::sccGraph
const SCCGraphAnalysis & sccGraph
Definition: SemanticChecker.cpp:116
souffle::ast::getBodyLiterals
std::vector< T * > getBodyLiterals(const C &clause)
Returns literals of a particular type in the body of a clause.
Definition: Utils.h:87
souffle::ast::transform::SemanticCheckerImpl::checkBranchInits
void checkBranchInits()
check if all the branches refer to the existing types.
Definition: SemanticChecker.cpp:266
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::transform::SemanticCheckerImpl::precedenceGraph
const PrecedenceGraphAnalysis & precedenceGraph
Definition: SemanticChecker.cpp:114
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::RelationSet
std::set< const Relation *, NameComparison > RelationSet
Relation set.
Definition: Relation.h:180
souffle::ast::transform::SemanticCheckerImpl::checkFact
void checkFact(const Clause &fact)
Definition: SemanticChecker.cpp:449
souffle::Diagnostic::Type::ERROR
@ ERROR
souffle::ast::transform::SemanticCheckerImpl::checkIO
void checkIO()
Definition: SemanticChecker.cpp:623
souffle::ast::Program::getRelations
std::vector< Relation * > getRelations() const
Return relations.
Definition: Program.h:60
souffle::ast::analysis::IOTypeAnalysis::isInput
bool isInput(const Relation *relation) const
Definition: IOType.h:49
souffle::ast::getClauses
std::vector< Clause * > getClauses(const Program &program, const QualifiedName &relationName)
Returns a vector of clauses in the program describing the relation with the given name.
Definition: Utils.cpp:77
souffle::ast::Program::getDirectives
std::vector< Directive * > getDirectives() const
Return relation directives.
Definition: Program.h:75
souffle::ast::transform::SemanticCheckerImpl::checkAggregator
void checkAggregator(const Aggregator &aggregator)
Definition: SemanticChecker.cpp:375
souffle::ast::transform::usesInvalidWitness
static const std::vector< SrcLocation > usesInvalidWitness(TranslationUnit &tu, const Clause &clause, const Aggregator &aggregate)
A witness is considered "invalid" if it is trying to export a witness out of a count,...
Definition: SemanticChecker.cpp:647
souffle::ast::transform::SemanticCheckerImpl::typeEnv
const TypeEnvironment & typeEnv
Definition: SemanticChecker.cpp:119
souffle::ast::transform::SemanticCheckerImpl::checkRelationDeclaration
void checkRelationDeclaration(const Relation &relation)
Definition: SemanticChecker.cpp:571
souffle::ast::transform::SemanticCheckerImpl::tu
TranslationUnit & tu
Definition: SemanticChecker.cpp:109
souffle::splitString
std::vector< std::string > splitString(const std::string &str, char delimiter)
Splits a string given a delimiter.
Definition: StringUtil.h:321
souffle::ErrorReport::addWarning
void addWarning(const std::string &message, SrcLocation location)
Adds a warning with the given message and location.
Definition: ErrorReport.h:179
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
souffle::ast::analysis::RecursiveClausesAnalysis::recursive
bool recursive(const Clause *clause) const
Definition: RecursiveClauses.h:54
souffle::ErrorReport::addDiagnostic
void addDiagnostic(const Diagnostic &diagnostic)
Definition: ErrorReport.h:186
souffle::ast::transform::SemanticCheckerImpl::checkComplexRule
void checkComplexRule(std::set< const Clause * > multiRule)
Definition: SemanticChecker.cpp:537
souffle::ast::transform::SemanticCheckerImpl::checkAtom
void checkAtom(const Atom &atom)
Definition: SemanticChecker.cpp:248
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
souffle::ast::TranslationUnit::getProgram
Program & getProgram() const
Return the program.
Definition: TranslationUnit.h:84
souffle::ast::transform::SemanticCheckerImpl::ioTypes
const IOTypeAnalysis & ioTypes
Definition: SemanticChecker.cpp:113
souffle::ast::analysis::SCCGraphAnalysis::getInternalRelations
const std::set< const Relation * > & getInternalRelations(const size_t scc) const
Get all internal relations of a given SCC.
Definition: SCCGraph.h:105
souffle::ast::analysis::TypeEnvironment::isPrimitiveType
bool isPrimitiveType(const QualifiedName &identifier) const
Definition: TypeSystem.h:437
std::type
ElementType type
Definition: span.h:640