souffle
2.0.2-371-g6315b36
|
Go to the documentation of this file.
24 return sub(a,
b,
"<:");
39 TypeSet& assignment = assignments[variable];
41 if (assignment.
isAll()) {
46 TypeSet newAssignment;
47 for (
const Type& t : assignment) {
52 if (assignment == newAssignment) {
55 assignment = newAssignment;
59 void print(std::ostream& out)
const override {
60 out << variable <<
" <: " <<
type.getName();
64 return std::make_shared<C>(variable,
type);
74 struct C :
public Constraint<TypeVar> {
82 TypeSet& assigments = assigment[var];
85 if (assigments.
isAll()) {
90 TypeSet newAssigments;
91 for (
const Type&
type : assigments) {
92 bool existsSuperTypeInValues =
94 if (existsSuperTypeInValues) {
95 newAssigments.insert(
type);
99 if (newAssigments == assigments) {
102 assigments = newAssigments;
106 void print(std::ostream& out)
const override {
107 out <<
"∃ t ∈ " << values <<
": " << var <<
" <: t";
111 return std::make_shared<C>(var, values);
115 while (
auto subset =
dynamic_cast<const SubsetType*
>(
type)) {
116 type = &subset->getBaseType();
118 assert((isA<ConstantType>(
type) || isA<RecordType>(
type)) &&
119 "Root must be a constant type or a record type");
135 TypeSet& assigmentsLeft = assigment[left];
136 TypeSet& assigmentsRight = assigment[right];
147 if (!assigmentsLeft.
isAll()) {
148 for (
const Type&
type : assigmentsLeft) {
149 if (isA<SubsetType>(
type) || isA<ConstantType>(
type)) {
155 if (!assigmentsRight.
isAll()) {
156 for (
const Type&
type : assigmentsRight) {
157 if (isA<SubsetType>(
type) || isA<ConstantType>(
type)) {
167 if (assigmentsLeft.isAll() && assigmentsRight.isAll()) {
172 if (assigmentsLeft.isAll()) {
173 assigmentsLeft = baseTypesRight;
176 if (assigmentsRight.isAll()) {
177 assigmentsRight = baseTypesLeft;
184 for (
const Type&
type : assigmentsLeft) {
185 bool isSubtypeOfCommonBaseType =
any_of(baseTypes.
begin(), baseTypes.
end(),
186 [&
type](
const Type& baseType) { return isSubtypeOf(type, baseType); });
187 if (isSubtypeOfCommonBaseType) {
188 resultLeft.insert(
type);
192 for (
const Type&
type : assigmentsRight) {
193 bool isSubtypeOfCommonBaseType =
any_of(baseTypes.
begin(), baseTypes.
end(),
194 [&
type](
const Type& baseType) { return isSubtypeOf(type, baseType); });
195 if (isSubtypeOfCommonBaseType) {
196 resultRight.insert(
type);
201 if (resultLeft == assigmentsLeft && resultRight == assigmentsRight) {
204 assigmentsLeft = resultLeft;
205 assigmentsRight = resultRight;
209 void print(std::ostream& out)
const override {
210 out <<
"∃ t : (" << left <<
" <: t)"
212 <<
"(" << right <<
" <: t)"
213 <<
" where t is a base type";
217 return std::make_shared<C>(left, right);
227 TypeVar result, std::vector<TypeVar> args,
bool subtypeResult) {
228 struct C :
public Constraint<TypeVar> {
230 mutable bool nonMonotonicUpdate =
false;
235 std::vector<TypeVar> args;
239 std::vector<TypeVar> args,
bool subtypeResult)
240 : typeEnv(typeEnv), overloads(
std::move(overloads)), result(
std::move(result)),
241 args(
std::move(args)), subtypeResult(subtypeResult) {}
250 auto& curr = assigment[var];
254 overloads =
filterNot(std::move(overloads), [&](
const IntrinsicFunctorInfo& x) ->
bool {
255 if (!x.variadic && args.size() != x.params.size())
return true;
257 for (
size_t i = 0;
i < args.size(); ++
i) {
258 if (!possible(x.params[x.variadic ? 0 :
i], args[
i]))
return true;
261 return !possible(x.result, result);
264 bool changed =
false;
265 auto newResult = [&]() -> std::optional<TypeSet> {
266 if (0 == overloads.size())
return TypeSet();
267 if (1 < overloads.size())
return {};
269 auto& overload = overloads.front().get();
275 for (
size_t i = 0;
i < args.size(); ++
i) {
276 auto argTy = overload.params[overload.variadic ? 0 :
i];
277 auto& currArg = assigment[args[
i]];
278 auto newArg = subtypesOf(currArg, argTy);
279 changed |= currArg != newArg;
281 currArg = std::move(newArg);
285 if (nonMonotonicUpdate || subtypeResult) {
286 return subtypesOf(assigment[result], overload.result);
288 nonMonotonicUpdate =
true;
294 auto& curr = assigment[result];
295 changed |= curr != *newResult;
297 curr = std::move(*newResult);
303 void print(std::ostream& out)
const override {
305 out <<
"∃ t : " << result <<
" <: t where t is a base type";
309 return std::make_shared<C>(
310 typeEnv, std::move(overloads), std::move(result), std::move(args), subtypeResult);
317 const TypeVar& elementVariable,
const TypeVar& recordVariable,
size_t index) {
318 struct C :
public Constraint<TypeVar> {
324 : elementVariable(
std::move(elementVariable)), recordVariable(
std::move(recordVariable)),
329 const TypeSet& recordTypes = assignment[recordVariable];
332 if (recordTypes.
isAll()) {
337 TypeSet newElementTypes;
338 TypeSet newRecordTypes;
340 for (
const Type&
type : recordTypes) {
346 const auto& typeAsRecord = *as<RecordType>(
type);
349 if (typeAsRecord.getFields().size() <= index) {
354 newRecordTypes.insert(
type);
357 newElementTypes.insert(*typeAsRecord.getFields()[index]);
364 bool changed =
false;
365 if (newRecordTypes != recordTypes) {
366 assignment[recordVariable] = newRecordTypes;
370 if (assignment[elementVariable] != newElementTypes) {
371 assignment[elementVariable] = newElementTypes;
378 void print(std::ostream& out)
const override {
379 out << elementVariable <<
" <: " << recordVariable <<
"::" << index;
383 return std::make_shared<C>(elementVariable, recordVariable, index);
387 iterateOverAtom(atom, [&](
const Argument& argument,
const Type& attributeType) {
388 if (isA<RecordType>(attributeType)) {
412 sinks.insert(cur.getAtom());
487 auto functorVar =
getVar(fun);
489 auto intrFun = as<IntrinsicFunctor>(fun);
491 auto argVars =
map(intrFun->getArguments(), [&](
auto&& x) { return getVar(x); });
504 for (
auto&& var : argVars)
530 for (
size_t i = 0;
i < arguments.size(); ++
i) {
541 auto& typeName = typeCast.
getType();
552 if (isA<Constant>(value)) {
558 auto arguments = record.getArguments();
559 for (
size_t i = 0;
i < arguments.size(); ++
i) {
567 if (correspondingType ==
nullptr) {
572 assert(isA<AlgebraicDataType>(correspondingType));
578 auto branchTypes = as<AlgebraicDataType>(correspondingType)->getBranchTypes(adt.
getConstructor());
581 if (branchTypes.size() != branchArgs.size()) {
587 for (
size_t i = 0;
i < branchArgs.size(); ++
i) {
588 auto argVar =
getVar(branchArgs[
i]);
603 if (
auto expr = agg.getTargetExpression()) {
610 const Atom& atom, std::function<
void(
const Argument&,
const Type&)>
map) {
617 auto atts =
rel->getAttributes();
618 auto args = atom.getArguments();
619 if (atts.size() != args.size()) {
623 for (
size_t i = 0;
i < atts.size();
i++) {
624 const auto& typeName = atts[
i]->getTypeName();
632 sinks.insert(clause.getHead());
bool isOfKind(const Type &type, TypeAttribute kind)
Check if the type is of a kind corresponding to the TypeAttribute.
static TypeConstraint hasSuperTypeInSet(const TypeVar &var, TypeSet values)
A constraint factory ensuring that all the types associated to the variable are subtypes of some type...
TypeVar getVar(const Argument &arg)
A utility function mapping an Argument to its associated analysis variable.
void visitTypeCast(const ast::TypeCast &typeCast) override
std::vector< A > filterNot(std::vector< A > xs, F &&f)
Filter a vector to exclude certain elements.
AggregateOp getPolymorphicOperator(const Aggregator *agg) const
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 std::optional< Type > & getFixedType() const
bool canBeParsedAsRamFloat(const std::string &string)
Can a string be parsed as RamFloat.
const Type & getType(const QualifiedName &) const
void insert(const Type &type)
Adds the given type to this set.
static TypeSet intersection(const TypeSet &left, const TypeSet &right)
Calculate intersection of two TypeSet.
A variable type to be utilized by AST constraint analysis.
const_iterator end() const
Allows to iterate over the types contained in this set (only if not universal)
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.
const QualifiedName & getType() const
Return cast type.
auto map(const std::vector< A > &xs, F &&f)
Applies a function to each element of a vector and returns the results.
void visitFunctor(const Functor &fun) override
static const Type & getBaseType(const Type *type)
const std::string & getConstant() const
Get string representation of Constant.
bool isType(const QualifiedName &) const
An abstract base class for types to be covered within a type environment.
@ ORD
Unary Functor Operators.
bool hasValidTypeInfo(const Argument *argument) const
A collection to represent sets of types.
void visitCounter(const Counter &counter) override
std::vector< std::reference_wrapper< const IntrinsicFunctorInfo > > IntrinsicFunctors
TypeSet getGreatestCommonSubtypes(const Type &a, const Type &b)
Computes the greatest common sub types of the two given types.
An abstract class for arguments.
TypeAttribute getFunctorReturnType(const Functor *functor) const
A generic base class for constraints on variables.
const TypeAnalysis & typeAnalysis
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...
void visitBinaryConstraint(const BinaryConstraint &rel) override
void visitSink(const Atom &atom)
const std::string & getConstructor() const
Defines a type cast class for expressions.
const TypeEnvironment & typeEnv
TypeAttribute getTypeAttribute(const Type &type)
void addConstraint(const constraint_type &constraint)
Adds another constraint to the internally maintained list of constraints.
void visitStringConstant(const StringConstant &cnst) override
bool any_of(const Container &c, UnaryPredicate p)
A generic test checking whether any elements within a container satisfy a certain predicate.
A type environment is a set of types.
std::shared_ptr< Constraint< TypeVar > > TypeConstraint
The definition of the type of constraint to be utilized in the type analysis.
const Type & getConstantType(TypeAttribute type) const
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-...
static TypeConstraint isSubtypeOfComponent(const TypeVar &elementVariable, const TypeVar &recordVariable, size_t index)
Constraint on record type and its elements.
bool canBeParsedAsRamUnsigned(const std::string &string)
Can a string be parsed as RamUnsigned.
const TypeSet & getConstantTypes() const
static TypeConstraint satisfiesOverload(const TypeEnvironment &typeEnv, IntrinsicFunctors overloads, TypeVar result, std::vector< TypeVar > args, bool subtypeResult)
Given a set of overloads, wait the list of candidates to reduce to one and then apply its constraints...
std::vector< Argument * > getArguments() const
Get arguments.
static TypeConstraint subtypesOfTheSameBaseType(const TypeVar &left, const TypeVar &right)
Ensure that types of left and right have the same base types.
bool isAll() const
Universality check.
std::set< const Atom * > sinks
const TypeSet & getConstantNumericTypes() const
TypeAttribute getFunctorArgType(const Functor *functor, const size_t idx) const
TypeSet filter(TypeSet whenAll, F &&f) const
IntrinsicFunctors functorBuiltIn(FunctorOp op)
l j a showGridBackground &&c b raw series this eventEmitter b
Argument * getValue() const
Return value.
void visitNegation(const Negation &cur) override
bool canBeParsedAsRamSigned(const std::string &string)
Can a string be parsed as RamSigned.
void visitNumericConstant(const NumericConstant &constant) override
const std::map< const NumericConstant *, NumericConstant::Type > & getNumericConstantTypes() const
const SumTypeBranchesAnalysis & sumTypesBranches
void collectConstraints(const Clause &clause) override
Visitors.
void visitBranchInit(const BranchInit &adt) override
Initialization of ADT instance.
const Relation * getAtomRelation(const Atom *atom, const Program *program)
Returns the relation referenced by the given atom.
void visitAggregator(const Aggregator &agg) override
bool isInfixFunctorOp(std::string_view symbol)
Determines whether a functor should be written using infix notation (e.g.
void iterateOverAtom(const Atom &atom, std::function< void(const Argument &, const Type &)> map)
Utility function.
void rel(size_t limit, bool showLimit=true)
const Type * getType(const std::string &branch) const
A type can be nullptr in case of a malformed program.
void visitRecordInit(const RecordInit &record) override
ConstraintAnalysisVar< type_lattice > TypeVar
The definition of the type of variable to be utilized in the type analysis.
void visitAtom(const Atom &atom) override