| 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