summaryrefslogtreecommitdiff
path: root/src/expr/node_manager.cpp
diff options
context:
space:
mode:
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>2020-08-01 22:27:08 -0500
committerGitHub <noreply@github.com>2020-08-01 22:27:08 -0500
commit5be889668bfb52d6705c2dc37ec05c291c7c9445 (patch)
tree4edbfeabcd3f5cf034ffd8b99b01a539820a5a99 /src/expr/node_manager.cpp
parent230d27bad9b4cd49bad1164145cf83c9f04e9aca (diff)
Add methods for constructing datatype types from NodeManager (#4823)
This is work towards eliminating the Expr-level datatype. This PR implements the required methods for constructing datatype types from NodeManager. In particular, this PR copies the "mkMutualDatatypeTypes" methods and converts them to Node-level. The next PRs will be in preparation for using these methods instead of the Expr-level ones. It also adds a flag d_isRecord to DType, which is required for supporting record printing in the cvc printer, which will be updated in another PR. It also eliminates an interface for constructing constructor types via Expr-level DatatypeConstructor objects, which was unused.
Diffstat (limited to 'src/expr/node_manager.cpp')
-rw-r--r--src/expr/node_manager.cpp154
1 files changed, 130 insertions, 24 deletions
diff --git a/src/expr/node_manager.cpp b/src/expr/node_manager.cpp
index e9f56bf3f..c72de9564 100644
--- a/src/expr/node_manager.cpp
+++ b/src/expr/node_manager.cpp
@@ -149,6 +149,8 @@ NodeManager::~NodeManager() {
d_rt_cache.d_children.clear();
d_rt_cache.d_data = dummy;
+ d_registeredDTypes.clear();
+ // clear the datatypes
d_ownedDTypes.clear();
Assert(!d_attrManager->inGarbageCollection());
@@ -198,15 +200,15 @@ NodeManager::~NodeManager() {
size_t NodeManager::registerDatatype(std::shared_ptr<DType> dt)
{
- size_t sz = d_ownedDTypes.size();
- d_ownedDTypes.push_back(dt);
+ size_t sz = d_registeredDTypes.size();
+ d_registeredDTypes.push_back(dt);
return sz;
}
-const DType& NodeManager::getDTypeForIndex(unsigned index) const
+const DType& NodeManager::getDTypeForIndex(size_t index) const
{
- Assert(index < d_ownedDTypes.size());
- return *d_ownedDTypes[index];
+ Assert(index < d_registeredDTypes.size());
+ return *d_registeredDTypes[index];
}
void NodeManager::reclaimZombies() {
@@ -462,28 +464,132 @@ TypeNode NodeManager::mkSequenceType(TypeNode elementType)
return mkTypeNode(kind::SEQUENCE_TYPE, elementType);
}
-TypeNode NodeManager::mkConstructorType(const DatatypeConstructor& constructor,
- TypeNode range) {
- vector<TypeNode> sorts;
- Debug("datatypes") << "ctor name: " << constructor.getName() << endl;
- for(DatatypeConstructor::const_iterator i = constructor.begin();
- i != constructor.end();
- ++i) {
- TypeNode selectorType = *(*i).getSelector().getType().d_typeNode;
- Debug("datatypes") << selectorType << endl;
- TypeNode sort = selectorType[1];
+TypeNode NodeManager::mkDatatypeType(DType& datatype, uint32_t flags)
+{
+ // Not worth a special implementation; this doesn't need to be fast
+ // code anyway.
+ std::vector<DType> datatypes;
+ datatypes.push_back(datatype);
+ std::vector<TypeNode> result = mkMutualDatatypeTypes(datatypes, flags);
+ Assert(result.size() == 1);
+ return result.front();
+}
+
+std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
+ const std::vector<DType>& datatypes, uint32_t flags)
+{
+ std::set<TypeNode> unresolvedTypes;
+ return mkMutualDatatypeTypes(datatypes, unresolvedTypes, flags);
+}
- // should be guaranteed here already, but just in case
- Assert(!sort.isFunctionLike());
+std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
+ const std::vector<DType>& datatypes,
+ const std::set<TypeNode>& unresolvedTypes,
+ uint32_t flags)
+{
+ NodeManagerScope nms(this);
+ std::map<std::string, TypeNode> nameResolutions;
+ std::vector<TypeNode> dtts;
- Debug("datatypes") << "ctor sort: " << sort << endl;
- sorts.push_back(sort);
+ // have to build deep copy so that datatypes will live in this class
+ std::vector<std::shared_ptr<DType> > dt_copies;
+ for (const DType& dt : datatypes)
+ {
+ d_ownedDTypes.push_back(std::unique_ptr<DType>(new DType(dt)));
+ dt_copies.push_back(std::move(d_ownedDTypes.back()));
}
- Debug("datatypes") << "ctor range: " << range << endl;
- PrettyCheckArgument(!range.isFunctionLike(), range,
- "cannot create higher-order function types");
- sorts.push_back(range);
- return mkTypeNode(kind::CONSTRUCTOR_TYPE, sorts);
+
+ // First do some sanity checks, set up the final Type to be used for
+ // each datatype, and set up the "named resolutions" used to handle
+ // simple self- and mutual-recursion, for example in the definition
+ // "nat = succ(pred:nat) | zero", a named resolution can handle the
+ // pred selector.
+ for (const std::shared_ptr<DType>& dtc : dt_copies)
+ {
+ TypeNode typeNode;
+ // register datatype with the node manager
+ size_t index = registerDatatype(dtc);
+ if (dtc->getNumParameters() == 0)
+ {
+ typeNode = mkTypeConst(DatatypeIndexConstant(index));
+ }
+ else
+ {
+ TypeNode cons = mkTypeConst(DatatypeIndexConstant(index));
+ std::vector<TypeNode> params;
+ params.push_back(cons);
+ for (unsigned int ip = 0; ip < dtc->getNumParameters(); ++ip)
+ {
+ params.push_back(dtc->getParameter(ip));
+ }
+
+ typeNode = mkTypeNode(kind::PARAMETRIC_DATATYPE, params);
+ }
+ AlwaysAssert(nameResolutions.find(dtc->getName()) == nameResolutions.end())
+ << "cannot construct two datatypes at the same time "
+ "with the same name";
+ nameResolutions.insert(std::make_pair(dtc->getName(), typeNode));
+ dtts.push_back(typeNode);
+ }
+
+ // Second, set up the type substitution map for complex type
+ // resolution (e.g. if "list" is the type we're defining, and it has
+ // a selector of type "ARRAY INT OF list", this can't be taken care
+ // of using the named resolutions that we set up above. A
+ // preliminary array type was set up, and now needs to have "list"
+ // substituted in it for the correct type.
+ //
+ // @TODO get rid of named resolutions altogether and handle
+ // everything with these resolutions?
+ std::vector<TypeNode> paramTypes;
+ std::vector<TypeNode> paramReplacements;
+ std::vector<TypeNode> placeholders; // to hold the "unresolved placeholders"
+ std::vector<TypeNode> replacements; // to hold our final, resolved types
+ for (const TypeNode& ut : unresolvedTypes)
+ {
+ std::string name = ut.getAttribute(expr::VarNameAttr());
+ std::map<std::string, TypeNode>::const_iterator resolver =
+ nameResolutions.find(name);
+ AlwaysAssert(resolver != nameResolutions.end())
+ << "cannot resolve type " + name
+ + "; it's not among the datatypes being defined";
+ // We will instruct the Datatype to substitute "ut" (the
+ // unresolved SortType used as a placeholder in complex types)
+ // with "(*resolver).second" (the TypeNode we created in the
+ // first step, above).
+ if (ut.isSort())
+ {
+ placeholders.push_back(ut);
+ replacements.push_back((*resolver).second);
+ }
+ else
+ {
+ Assert(ut.isSortConstructor());
+ paramTypes.push_back(ut);
+ paramReplacements.push_back((*resolver).second);
+ }
+ }
+
+ // Lastly, perform the final resolutions and checks.
+ for (const TypeNode& ut : dtts)
+ {
+ const DType& dt = ut.getDType();
+ if (!dt.isResolved())
+ {
+ const_cast<DType&>(dt).resolve(nameResolutions,
+ placeholders,
+ replacements,
+ paramTypes,
+ paramReplacements);
+ }
+ }
+
+ for (NodeManagerListener* nml : d_listeners)
+ {
+ nml->nmNotifyNewDatatypes(dtts, flags);
+ }
+
+ return dtts;
}
TypeNode NodeManager::mkConstructorType(const std::vector<TypeNode>& args,
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback