souffle
2.0.2-371-g6315b36
|
Go to the documentation of this file.
42 #include <unordered_set>
47 using namespace analysis;
49 class TypeDeclarationChecker {
51 TypeDeclarationChecker(TranslationUnit& tu) : tu(tu){};
88 std::unordered_set<const Atom*> negatedAtoms;
91 void visitNegation(
const Negation& neg)
override;
95 void visitAtom(
const Atom& atom)
override;
96 void visitVariable(
const Variable& var)
override;
99 void visitNilConstant(
const NilConstant& constant)
override;
100 void visitRecordInit(
const RecordInit& rec)
override;
101 void visitBranchInit(
const BranchInit& adt)
override;
106 void visitAggregator(
const Aggregator& aggregator)
override;
111 auto errorsBeforeDeclarationsCheck = report.
getNumErrors();
116 if (report.
getNumErrors() == errorsBeforeDeclarationsCheck) {
124 if (typeEnv.isPrimitiveType(
sub)) {
129 if (subtype ==
nullptr) {
131 type.getQualifiedName()),
133 }
else if (!isA<ast::UnionType>(subtype) && !isA<ast::SubsetType>(subtype)) {
141 if (typeEnvAnalysis.
isCyclic(
type.getQualifiedName())) {
142 report.
addError(
"Infinite descent in the definition of type " +
toString(
type.getQualifiedName()),
149 if (!isA<ast::UnionType>(
type)) {
153 const auto& name =
type->getQualifiedName();
158 if (predefinedTypesInUnion.size() > 1) {
160 tfm::format(
"Union type %s is defined over {%s} (multiple primitive types in union)",
161 name,
join(predefinedTypesInUnion,
", ")),
168 auto&& fields =
type.getFields();
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(),
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());
193 for (
auto* branch :
type.getBranches()) {
194 for (
auto* field : branch->getFields()) {
195 if (!typeEnv.isType(field->getTypeName())) {
197 field->getTypeName(), branch->getConstructor()),
205 if (typeEnvAnalysis.
isCyclic(astType.getQualifiedName())) {
207 tfm::format(
"Infinite descent in the definition of type %s", astType.getQualifiedName()),
208 astType.getSrcLoc());
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());
219 auto& rootType = typeEnv.getType(astType.getBaseType());
221 if (isA<analysis::UnionType>(rootType)) {
223 astType.getQualifiedName(), rootType.getName()),
224 astType.getSrcLoc());
227 if (isA<analysis::RecordType>(rootType)) {
229 astType.getQualifiedName(), rootType.getName()),
230 astType.getSrcLoc());
237 if (typeEnv.isPrimitiveType(
type->getQualifiedName())) {
238 report.
addError(
"Redefinition of the predefined type",
type->getSrcLoc());
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));
251 fatal(
"unsupported type construct: %s",
typeid(
type).name());
256 std::map<std::string, std::vector<SrcLocation>> branchToLocation;
258 for (auto* branch : type.getBranches()) {
259 branchToLocation[branch->getConstructor()].push_back(branch->getSrcLoc());
263 for (
auto& branchLocs : branchToLocation) {
264 auto& branch = branchLocs.first;
265 auto& locs = branchLocs.second;
268 if (locs.size() == 1)
continue;
270 auto primaryDiagnostic =
271 DiagnosticMessage(
tfm::format(
"Branch %s is defined multiple times", branch));
273 std::vector<DiagnosticMessage> branchDeclarations;
274 for (
auto& loc : locs) {
275 branchDeclarations.push_back(DiagnosticMessage(
tfm::format(
"Branch %s defined", branch), loc));
290 auto arguments = atom.getArguments();
291 if (attributes.size() != arguments.size()) {
295 for (
size_t i = 0;
i < attributes.size(); ++
i) {
296 auto& typeName = attributes[
i]->getTypeName();
304 if (argTypes.isAll() || argTypes.empty()) {
313 bool validAttribute =
all_of(argTypes, [&attributeType](
const analysis::Type&
type) {
316 if (isA<ConstantType>(
type))
return true;
317 return isA<analysis::RecordType>(
type) && !isA<analysis::SubsetType>(
type);
321 auto primaryDiagnostic =
322 DiagnosticMessage(
"Atom's argument type is not a subtype of its declared type",
323 arguments[
i]->getSrcLoc());
325 auto declaredTypeInfo =
326 DiagnosticMessage(
tfm::format(
"The argument's declared type is %s", typeName),
327 attributes[
i]->getSrcLoc());
330 {std::move(declaredTypeInfo)}));
336 bool validAttribute =
all_of(argTypes, [&](
const analysis::Type&
type) {
338 return isSubtypeOf(attributeType, constantType) && isSubtypeOf(type, constantType);
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());
350 {std::move(declaredTypeInfo)}));
358 report.
addError(
"Unable to deduce type for variable " + var.getName(), var.getSrcLoc());
400 report.
addError(
"Nil constant used as a non-record", constant.getSrcLoc());
414 auto& recordType = *as<analysis::RecordType>(*
types.begin());
416 if (recordType.getFields().size() != rec.
getArguments().size()) {
431 auto& sumType = *as<analysis::AlgebraicDataType>(*
types.begin());
433 auto& argsDeclaredTypes = sumType.getBranchTypes(adt.getConstructor());
434 auto args = adt.getArguments();
436 if (argsDeclaredTypes.size() != args.size()) {
441 for (
size_t i = 0;
i < args.size(); ++
i) {
443 bool correctType =
all_of(
447 report.
addError(
"Branch argument's type doesn't match its declared type", args[
i]->getSrcLoc());
455 tfm::format(
"Type cast to the undeclared type \"%s\"", cast.getType()), cast.getSrcLoc());
462 if (castTypes.isAll() || castTypes.size() != 1) {
463 report.
addError(
"Unable to deduce type of the argument (cast)", cast.getSrcLoc());
468 if (argTypes.isAll() || castTypes.size() != 1 || argTypes.isAll() || argTypes.size() != 1) {
475 auto args = fun.getArguments();
477 report.
addError(
"invalid overload (arity mismatch)", fun.getSrcLoc());
481 "unexpected type analysis result");
498 if (!
isOfKind(resultType, returnType)) {
499 switch (returnType) {
501 report.
addError(
"Non-numeric use for numeric functor", fun.getSrcLoc());
504 report.
addError(
"Non-unsigned use for unsigned functor", fun.getSrcLoc());
507 report.
addError(
"Non-float use for float functor", fun.getSrcLoc());
510 report.
addError(
"Non-symbolic use for symbolic functor", fun.getSrcLoc());
518 for (
auto arg : fun.getArguments()) {
523 report.
addError(
"Non-numeric argument for functor", arg->getSrcLoc());
526 report.
addError(
"Non-symbolic argument for functor", arg->getSrcLoc());
529 report.
addError(
"Non-unsigned argument for functor", arg->getSrcLoc());
532 report.
addError(
"Non-float argument for functor", arg->getSrcLoc());
544 auto left = constraint.getLHS();
545 auto right = constraint.getRHS();
553 if (leftTypes.empty() || rightTypes.empty() || leftTypes.isAll() || rightTypes.isAll())
return;
555 assert((leftTypes.size() == 1) && (rightTypes.size() == 1));
563 report.
addError(
"Cannot compare different types", constraint.getSrcLoc());
565 auto checkTyAttr = [&](
Argument const& side) {
566 auto opMatchesType =
any_of(opTypesAttrs,
569 if (!opMatchesType) {
570 std::stringstream
ss;
571 ss <<
"Constraint requires an operand of type "
572 <<
join(opTypesAttrs,
" or ", [&](
auto& out,
auto& typeAttr) {
599 if (!
isOfKind(aggregatorType, opType)) {
600 report.
addError(
"Couldn't assign types to the aggregator", aggregator.getSrcLoc());
bool isOfKind(const Type &type, TypeAttribute kind)
Check if the type is of a kind corresponding to the TypeAttribute.
const std::set< QualifiedName > & getPrimitiveTypesInUnion(const QualifiedName &identifier) const
NumericConstant::Type getInferredType(const NumericConstant *nc) const
The generic base type of all AstVisitors realizing the dispatching of visitor calls.
bool areEquivalentTypes(const Type &a, const Type &b)
Determine if two types are equivalent.
std::shared_ptr< Constraint< Var > > sub(const Var &a, const Var &b, const std::string &symbol="⊑")
A generic factory for constraints of the form.
const Type & getType(const QualifiedName &) const
std::vector< Own< ast::Type > > types
TypeSet const & getTypes(const Argument *argument) const
Get the computed types for the given argument.
IntrinsicFunctors getValidIntrinsicFunctorOverloads(const IntrinsicFunctor &inf) const
– Functor-related methods –
bool isType(const QualifiedName &) const
Defines the nil constant.
bool isCyclic(const QualifiedName &identifier) const
A type being a subset of another type.
std::vector< Clause * > getClauses() const
Return clauses.
A union type combining a list of types into a new, aggregated type.
An abstract base class for types to be covered within a type environment.
User-Defined functor class.
A variable to be utilized within constraints to be handled by the constraint solver.
bool hasValidTypeInfo(const Argument *argument) const
A collection to represent sets of types.
A record type combining a list of fields into a new, aggregated type.
An abstract class for arguments.
const std::string & toString(const std::string &str)
A generic function converting strings into strings (trivial case).
The program class consists of relations, clauses and types.
const_iterator begin() const
Allows to iterate over the types contained in this set (only if not universal)
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...
ErrorReport & getErrorReport()
Return error report.
Defines a type cast class for expressions.
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...
Negation of an atom negated atom.
Intrinsic Functor class for functors are in-built.
bool any_of(const Container &c, UnaryPredicate p)
A generic test checking whether any elements within a container satisfy a certain predicate.
TypeAttribute getReturnType(const Functor *functor) const
Return return type of functor.
A type environment is a set of types.
Translation unit class for the translation pipeline.
bool isValidFunctorOpArity(std::string_view symbol, size_t arity)
void addError(const std::string &message, SrcLocation location)
Adds an error with the given message and location.
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-...
const TypeSet & getConstantTypes() const
std::vector< Argument * > getArguments() const
Get arguments.
std::vector< TypeAttribute > getBinaryConstraintTypes(const BinaryConstraintOp op)
Get type binary constraint operates on.
std::vector< Type * > getTypes() const
Return types.
const TypeEnvironment & getTypeEnvironment() const
unsigned getNumErrors() const
TypeAttribute getTypeAttributeAggregate(const AggregateOp op)
Get return type of the aggregate.
Analysis * getAnalysis() const
get analysis: analysis is generated on the fly if not present
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.
static MainConfig & config()
TypeAttribute getArgType(const Functor *functor, const size_t idx) const
Return argument type of functor.
bool all_of(const Container &c, UnaryPredicate p)
A generic test checking whether all elements within a container satisfy a certain predicate.
Defines the aggregator class.
Atom * getAtom() const
Get negated atom.
void fatal(const char *format, const Args &... args)
Initialization of ADT instance.
const Relation * getAtomRelation(const Atom *atom, const Program *program)
Returns the relation referenced by the given atom.
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-...
const SrcLocation & getSrcLoc() const
Return source location of the Node.
void addDiagnostic(const Diagnostic &diagnostic)
Qualified Name class defines fully/partially qualified names to identify objects in components.
Program & getProgram() const
Return the program.
BinaryConstraintOp getOverloadedOperator(const BinaryConstraint *bc) const
Combination of types using sums and products.
bool isOrderedBinaryConstraintOp(const BinaryConstraintOp op)
Determines whether arguments of constraint are orderable.
bool hasInvalidType(const NumericConstant *nc) const
Defines a record initialization class.
class souffle::profile::Tui ss