souffle  2.0.2-371-g6315b36
ComponentChecker.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 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 ComponentChecker.cpp
12  *
13  * Implementation of the component semantic checker pass.
14  *
15  ***********************************************************************/
16 
18 #include "RelationTag.h"
19 #include "ast/Component.h"
20 #include "ast/ComponentInit.h"
21 #include "ast/ComponentType.h"
22 #include "ast/Program.h"
23 #include "ast/QualifiedName.h"
24 #include "ast/Relation.h"
25 #include "ast/TranslationUnit.h"
26 #include "ast/Type.h"
28 #include "parser/SrcLocation.h"
29 #include "reports/ErrorReport.h"
31 #include <functional>
32 #include <map>
33 #include <set>
34 #include <utility>
35 #include <vector>
36 
37 namespace souffle::ast::transform {
38 
39 using namespace analysis;
40 
41 bool ComponentChecker::transform(TranslationUnit& translationUnit) {
42  Program& program = translationUnit.getProgram();
43  ComponentLookupAnalysis& componentLookup = *translationUnit.getAnalysis<ComponentLookupAnalysis>();
44  ErrorReport& report = translationUnit.getErrorReport();
45  checkComponents(report, program, componentLookup);
46  checkComponentNamespaces(report, program);
47  return false;
48 }
49 
51  const Component* enclosingComponent, const ComponentLookupAnalysis& componentLookup,
52  const std::string& name, const SrcLocation& loc, const TypeBinding& binding) {
53  const QualifiedName& forwarded = binding.find(name);
54  if (!forwarded.empty()) {
55  // for forwarded types we do not check anything, because we do not know
56  // what the actual type will be
57  return nullptr;
58  }
59 
60  const Component* c = componentLookup.getComponent(enclosingComponent, name, binding);
61  if (c == nullptr) {
62  report.addError("Referencing undefined component " + name, loc);
63  return nullptr;
64  }
65 
66  return c;
67 }
68 
69 void ComponentChecker::checkComponentReference(ErrorReport& report, const Component* enclosingComponent,
70  const ComponentLookupAnalysis& componentLookup, const ast::ComponentType& type,
71  const SrcLocation& loc, const TypeBinding& binding) {
72  // check whether targeted component exists
73  const Component* c = checkComponentNameReference(
74  report, enclosingComponent, componentLookup, type.getName(), loc, binding);
75  if (c == nullptr) {
76  return;
77  }
78 
79  // check number of type parameters
80  if (c->getComponentType()->getTypeParameters().size() != type.getTypeParameters().size()) {
81  report.addError("Invalid number of type parameters for component " + type.getName(), loc);
82  }
83 }
84 
85 void ComponentChecker::checkComponentInit(ErrorReport& report, const Component* enclosingComponent,
86  const ComponentLookupAnalysis& componentLookup, const ComponentInit& init,
87  const TypeBinding& binding) {
88  checkComponentReference(
89  report, enclosingComponent, componentLookup, *init.getComponentType(), init.getSrcLoc(), binding);
90 
91  // Note: actual parameters can be atomic types like number, or anything declared with .type
92  // The original semantic check permitted any identifier (existing or non-existing) to be actual parameter
93  // In order to maintain the compatibility, we do not check the actual parameters
94 
95  // check the actual parameters:
96  // const auto& actualParams = init.getComponentType().getTypeParameters();
97  // for (const auto& param : actualParams) {
98  // checkComponentNameReference(report, scope, param, init.getSrcLoc(), binding);
99  //}
100 }
101 
102 void ComponentChecker::checkComponent(ErrorReport& report, const Component* enclosingComponent,
103  const ComponentLookupAnalysis& componentLookup, const Component& component,
104  const TypeBinding& binding) {
105  // -- inheritance --
106 
107  // Update type binding:
108  // Since we are not compiling, i.e. creating concrete instance of the
109  // components with type parameters, we are only interested in whether
110  // component references refer to existing components or some type parameter.
111  // Type parameter for us here is unknown type that will be bound at the template
112  // instantiation time.
113  auto parentTypeParameters = component.getComponentType()->getTypeParameters();
114  std::vector<QualifiedName> actualParams(parentTypeParameters.size(), "<type parameter>");
115  TypeBinding activeBinding = binding.extend(parentTypeParameters, actualParams);
116 
117  // check parents of component
118  for (const auto& cur : component.getBaseComponents()) {
119  checkComponentReference(
120  report, enclosingComponent, componentLookup, *cur, component.getSrcLoc(), activeBinding);
121 
122  // Note: type parameters can also be atomic types like number, or anything defined through .type
123  // The original semantic check permitted any identifier (existing or non-existing) to be actual
124  // parameter
125  // In order to maintain the compatibility, we do not check the actual parameters
126 
127  // for (const std::string& param : cur.getTypeParameters()) {
128  // checkComponentNameReference(report, scope, param, component.getSrcLoc(), activeBinding);
129  //}
130  }
131 
132  // get all parents
133  std::set<const Component*> parents;
134  std::function<void(const Component&)> collectParents = [&](const Component& cur) {
135  for (const auto& base : cur.getBaseComponents()) {
136  auto c = componentLookup.getComponent(enclosingComponent, base->getName(), binding);
137  if (c == nullptr) {
138  continue;
139  }
140  if (parents.insert(c).second) {
141  collectParents(*c);
142  }
143  }
144  };
145  collectParents(component);
146 
147  // check overrides
148  for (const Relation* relation : component.getRelations()) {
149  if (component.getOverridden().count(relation->getQualifiedName().getQualifiers()[0]) != 0u) {
150  report.addError("Override of non-inherited relation " +
151  relation->getQualifiedName().getQualifiers()[0] + " in component " +
152  component.getComponentType()->getName(),
153  component.getSrcLoc());
154  }
155  }
156  for (const Component* parent : parents) {
157  for (const Relation* relation : parent->getRelations()) {
158  if ((component.getOverridden().count(relation->getQualifiedName().getQualifiers()[0]) != 0u) &&
159  !relation->hasQualifier(RelationQualifier::OVERRIDABLE)) {
160  report.addError("Override of non-overridable relation " +
161  relation->getQualifiedName().getQualifiers()[0] + " in component " +
162  component.getComponentType()->getName(),
163  component.getSrcLoc());
164  }
165  }
166  }
167 
168  // check for a cycle
169  if (parents.find(&component) != parents.end()) {
170  report.addError(
171  "Invalid cycle in inheritance for component " + component.getComponentType()->getName(),
172  component.getSrcLoc());
173  }
174 
175  // -- nested components --
176 
177  // check nested components
178  for (const auto& cur : component.getComponents()) {
179  checkComponent(report, &component, componentLookup, *cur, activeBinding);
180  }
181 
182  // check nested instantiations
183  for (const auto& cur : component.getInstantiations()) {
184  checkComponentInit(report, &component, componentLookup, *cur, activeBinding);
185  }
186 }
187 
189  ErrorReport& report, const Program& program, const ComponentLookupAnalysis& componentLookup) {
190  for (Component* cur : program.getComponents()) {
191  checkComponent(report, nullptr, componentLookup, *cur, TypeBinding());
192  }
193 
194  for (ComponentInit* cur : program.getComponentInstantiations()) {
195  checkComponentInit(report, nullptr, componentLookup, *cur, TypeBinding());
196  }
197 }
198 
199 // Check that component names are disjoint from type and relation names.
200 void ComponentChecker::checkComponentNamespaces(ErrorReport& report, const Program& program) {
201  std::map<std::string, SrcLocation> names;
202 
203  // Type and relation name error reporting performed by the SemanticChecker instead
204 
205  // Find all names and report redeclarations as we go.
206  for (const auto& type : program.getTypes()) {
207  const std::string name = toString(type->getQualifiedName());
208  if (names.count(name) == 0u) {
209  names[name] = type->getSrcLoc();
210  }
211  }
212 
213  for (const auto& rel : program.getRelations()) {
214  const std::string name = toString(rel->getQualifiedName());
215  if (names.count(name) == 0u) {
216  names[name] = rel->getSrcLoc();
217  }
218  }
219 
220  // Note: Nested component and instance names are not obtained.
221  for (const auto& comp : program.getComponents()) {
222  const std::string name = toString(comp->getComponentType()->getName());
223  if (names.count(name) != 0u) {
224  report.addError("Name clash on component " + name, comp->getSrcLoc());
225  } else {
226  names[name] = comp->getSrcLoc();
227  }
228  }
229 
230  for (const auto& inst : program.getComponentInstantiations()) {
231  const std::string name = toString(inst->getInstanceName());
232  if (names.count(name) != 0u) {
233  report.addError("Name clash on instantiation " + name, inst->getSrcLoc());
234  } else {
235  names[name] = inst->getSrcLoc();
236  }
237  }
238 }
239 } // namespace souffle::ast::transform
souffle::ast::transform::ComponentChecker::checkComponents
static void checkComponents(ErrorReport &report, const Program &program, const analysis::ComponentLookupAnalysis &componentLookup)
Definition: ComponentChecker.cpp:194
souffle::ast::Program::getComponents
std::vector< Component * > getComponents() const
Return components.
Definition: Program.h:114
TranslationUnit.h
souffle::ast::transform::ComponentChecker::checkComponentNameReference
static const Component * checkComponentNameReference(ErrorReport &report, const Component *enclosingComponent, const analysis::ComponentLookupAnalysis &componentLookup, const std::string &name, const SrcLocation &loc, const analysis::TypeBinding &binding)
Definition: ComponentChecker.cpp:56
souffle::ast::analysis::ComponentLookupAnalysis::getComponent
const Component * getComponent(const Component *scope, const std::string &name, const TypeBinding &activeBinding) const
Performs a lookup operation for a component with the given name within the addressed scope.
Definition: ComponentLookup.cpp:48
souffle::ast::transform::ComponentChecker::checkComponent
static void checkComponent(ErrorReport &report, const Component *enclosingComponent, const analysis::ComponentLookupAnalysis &componentLookup, const Component &component, const analysis::TypeBinding &binding)
Definition: ComponentChecker.cpp:108
souffle::RelationQualifier::OVERRIDABLE
@ OVERRIDABLE
SrcLocation.h
Component.h
souffle::ast::transform::ComponentChecker::checkComponentInit
static void checkComponentInit(ErrorReport &report, const Component *enclosingComponent, const analysis::ComponentLookupAnalysis &componentLookup, const ComponentInit &init, const analysis::TypeBinding &binding)
Definition: ComponentChecker.cpp:91
souffle::ast::analysis::TypeBinding::extend
TypeBinding extend(const std::vector< QualifiedName > &formalParams, const std::vector< QualifiedName > &actualParams) const
Definition: ComponentLookup.h:55
relation
Relation & relation
Definition: Reader.h:130
souffle::ast::ComponentInit
Component initialization class.
Definition: ComponentInit.h:47
base
T & base
Definition: Reader.h:60
ComponentInit.h
Relation.h
souffle::ast::Component::getOverridden
const std::set< std::string > & getOverridden() const
Get override.
Definition: Component.h:151
souffle::ast::Component::getRelations
std::vector< Relation * > getRelations() const
Get relations.
Definition: Component.h:101
souffle::ast::Component::getBaseComponents
const std::vector< ComponentType * > getBaseComponents() const
Get base components.
Definition: Component.h:71
souffle::ast::ComponentType::getTypeParameters
const std::vector< QualifiedName > & getTypeParameters() const
Return component type parameters.
Definition: ComponentType.h:61
souffle::ast::ComponentType
Component type of a component.
Definition: ComponentType.h:45
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::ComponentChecker::transform
bool transform(TranslationUnit &translationUnit) override
Definition: ComponentChecker.cpp:47
souffle::ast::Program
The program class consists of relations, clauses and types.
Definition: Program.h:52
souffle::ast::QualifiedName::empty
bool empty() const
check for emptiness
Definition: QualifiedName.h:61
RelationTag.h
souffle::ast::Component::getComponentType
const ComponentType * getComponentType() const
Get component type.
Definition: Component.h:61
souffle::ast::transform::ComponentChecker::checkComponentReference
static void checkComponentReference(ErrorReport &report, const Component *enclosingComponent, const analysis::ComponentLookupAnalysis &componentLookup, const ast::ComponentType &type, const SrcLocation &loc, const analysis::TypeBinding &binding)
Definition: ComponentChecker.cpp:75
StringUtil.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
ComponentLookup.h
souffle::ast::transform
Definition: Program.h:45
souffle::ast::Program::getRelations
std::vector< Relation * > getRelations() const
Return relations.
Definition: Program.h:60
Type.h
ComponentType.h
souffle::ast::analysis::TypeBinding
Class that encapsulates std::map of types binding that comes from .init c = Comp<MyType> Type binding...
Definition: ComponentLookup.h:37
souffle::ast::Component
Component class.
Definition: Component.h:58
souffle::ast::Component::getInstantiations
std::vector< ComponentInit * > getInstantiations() const
Get instantiation.
Definition: Component.h:141
souffle::ast::Program::getTypes
std::vector< Type * > getTypes() const
Return types.
Definition: Program.h:55
QualifiedName.h
Program.h
souffle::ast::transform::ComponentChecker::checkComponentNamespaces
static void checkComponentNamespaces(ErrorReport &report, const Program &program)
Definition: ComponentChecker.cpp:206
souffle::SrcLocation
A class describing a range in an input file.
Definition: SrcLocation.h:32
souffle::ast::Program::getComponentInstantiations
std::vector< ComponentInit * > getComponentInstantiations() const
Return component instantiation.
Definition: Program.h:119
ComponentChecker.h
souffle::ast::analysis::TypeBinding::find
const QualifiedName & find(const QualifiedName &name) const
Returns binding for given name or empty string if such binding does not exist.
Definition: ComponentLookup.h:46
souffle::ast::Node::getSrcLoc
const SrcLocation & getSrcLoc() const
Return source location of the Node.
Definition: Node.h:46
souffle::ast::QualifiedName
Qualified Name class defines fully/partially qualified names to identify objects in components.
Definition: QualifiedName.h:39
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
souffle::ErrorReport
Definition: ErrorReport.h:152
souffle::ast::Component::getComponents
std::vector< Component * > getComponents() const
Get components.
Definition: Component.h:131
ErrorReport.h
souffle::ast::ComponentType::getName
const std::string & getName() const
Return component name.
Definition: ComponentType.h:51
std::type
ElementType type
Definition: span.h:640
souffle::ast::analysis::ComponentLookupAnalysis
Definition: ComponentLookup.h:78