GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 501 581 86.2 %
Date: 2021-09-22 Branches: 654 1764 37.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Tim King
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * A manager for Nodes.
14
 */
15
#include "expr/node_manager.h"
16
17
#include <algorithm>
18
#include <sstream>
19
#include <stack>
20
#include <utility>
21
22
#include "base/check.h"
23
#include "base/listener.h"
24
#include "expr/attribute.h"
25
#include "expr/bound_var_manager.h"
26
#include "expr/datatype_index.h"
27
#include "expr/dtype.h"
28
#include "expr/dtype_cons.h"
29
#include "expr/metakind.h"
30
#include "expr/node_manager_attributes.h"
31
#include "expr/skolem_manager.h"
32
#include "expr/type_checker.h"
33
#include "theory/bags/make_bag_op.h"
34
#include "theory/sets/singleton_op.h"
35
#include "util/abstract_value.h"
36
#include "util/bitvector.h"
37
#include "util/resource_manager.h"
38
39
using namespace std;
40
using namespace cvc5::expr;
41
42
namespace cvc5 {
43
44
namespace {
45
46
/**
47
 * This class sets it reference argument to true and ensures that it gets set
48
 * to false on destruction. This can be used to make sure a flag gets toggled
49
 * in a function even on exceptional exit (e.g., see reclaimZombies()).
50
 */
51
struct ScopedBool {
52
  bool& d_value;
53
54
229300
  ScopedBool(bool& value) :
55
229300
    d_value(value) {
56
57
229300
    Debug("gc") << ">> setting ScopedBool\n";
58
229300
    d_value = true;
59
229300
  }
60
61
458600
  ~ScopedBool() {
62
229300
    Debug("gc") << "<< clearing ScopedBool\n";
63
229300
    d_value = false;
64
229300
  }
65
};
66
67
/**
68
 * Similarly, ensure d_nodeUnderDeletion gets set to NULL even on
69
 * exceptional exit from NodeManager::reclaimZombies().
70
 */
71
struct NVReclaim {
72
  NodeValue*& d_deletionField;
73
74
31325070
  NVReclaim(NodeValue*& deletionField) :
75
31325070
    d_deletionField(deletionField) {
76
77
31325070
    Debug("gc") << ">> setting NVRECLAIM field\n";
78
31325070
  }
79
80
62650140
  ~NVReclaim() {
81
31325070
    Debug("gc") << "<< clearing NVRECLAIM field\n";
82
31325070
    d_deletionField = NULL;
83
31325070
  }
84
};
85
86
} // namespace
87
88
namespace attr {
89
  struct LambdaBoundVarListTag { };
90
  }  // namespace attr
91
92
// attribute that stores the canonical bound variable list for function types
93
typedef expr::Attribute<attr::LambdaBoundVarListTag, Node> LambdaBoundVarListAttr;
94
95
9866
NodeManager::NodeManager()
96
9866
    : d_skManager(new SkolemManager),
97
9866
      d_bvManager(new BoundVarManager),
98
      d_initialized(false),
99
      next_id(0),
100
9866
      d_attrManager(new expr::attr::AttributeManager()),
101
      d_nodeUnderDeletion(nullptr),
102
      d_inReclaimZombies(false),
103
      d_abstractValueCount(0),
104
39464
      d_skolemCounter(0)
105
{
106
9866
}
107
108
36487019522
NodeManager* NodeManager::currentNM()
109
{
110
36487019522
  thread_local static NodeManager nm;
111
36487019522
  return &nm;
112
}
113
114
215873
bool NodeManager::isNAryKind(Kind k)
115
{
116
215873
  return kind::metakind::getMaxArityForKind(k) == expr::NodeValue::MAX_CHILDREN;
117
}
118
119
20000834
TypeNode NodeManager::booleanType()
120
{
121
20000834
  return mkTypeConst<TypeConstant>(BOOLEAN_TYPE);
122
}
123
124
4715970
TypeNode NodeManager::integerType()
125
{
126
4715970
  return mkTypeConst<TypeConstant>(INTEGER_TYPE);
127
}
128
129
4821613
TypeNode NodeManager::realType()
130
{
131
4821613
  return mkTypeConst<TypeConstant>(REAL_TYPE);
132
}
133
134
157379
TypeNode NodeManager::stringType()
135
{
136
157379
  return mkTypeConst<TypeConstant>(STRING_TYPE);
137
}
138
139
34752
TypeNode NodeManager::regExpType()
140
{
141
34752
  return mkTypeConst<TypeConstant>(REGEXP_TYPE);
142
}
143
144
9554
TypeNode NodeManager::roundingModeType()
145
{
146
9554
  return mkTypeConst<TypeConstant>(ROUNDINGMODE_TYPE);
147
}
148
149
198278
TypeNode NodeManager::boundVarListType()
150
{
151
198278
  return mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE);
152
}
153
154
10346
TypeNode NodeManager::instPatternType()
155
{
156
10346
  return mkTypeConst<TypeConstant>(INST_PATTERN_TYPE);
157
}
158
159
23854
TypeNode NodeManager::instPatternListType()
160
{
161
23854
  return mkTypeConst<TypeConstant>(INST_PATTERN_LIST_TYPE);
162
}
163
164
7565
TypeNode NodeManager::builtinOperatorType()
165
{
166
7565
  return mkTypeConst<TypeConstant>(BUILTIN_OPERATOR_TYPE);
167
}
168
169
483608
TypeNode NodeManager::mkBitVectorType(unsigned size)
170
{
171
483608
  return mkTypeConst<BitVectorSize>(BitVectorSize(size));
172
}
173
174
1170274
TypeNode NodeManager::sExprType()
175
{
176
1170274
  return mkTypeConst<TypeConstant>(SEXPR_TYPE);
177
}
178
179
6710
TypeNode NodeManager::mkFloatingPointType(unsigned exp, unsigned sig)
180
{
181
6710
  return mkTypeConst<FloatingPointSize>(FloatingPointSize(exp, sig));
182
}
183
184
5361
TypeNode NodeManager::mkFloatingPointType(FloatingPointSize fs)
185
{
186
5361
  return mkTypeConst<FloatingPointSize>(fs);
187
}
188
189
10682
void NodeManager::init() {
190
10682
  if (d_initialized)
191
  {
192
963
    return;
193
  }
194
9719
  d_initialized = true;
195
196
  // Note: This code cannot be part of the constructor because it indirectly
197
  // calls `NodeManager::currentNM()`, which is where the `NodeManager` is
198
  // being constructed.
199
9719
  poolInsert( &expr::NodeValue::null() );
200
201
3187832
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
202
3178113
    Kind k = Kind(i);
203
204
3178113
    if(hasOperator(k)) {
205
2653287
      d_operators[i] = mkConst(Kind(k));
206
    }
207
  }
208
}
209
210
19732
NodeManager::~NodeManager() {
211
  // Destroy skolem and bound var manager before cleaning up attributes and
212
  // zombies
213
9866
  d_skManager = nullptr;
214
9866
  d_bvManager = nullptr;
215
216
  {
217
19732
    ScopedBool dontGC(d_inReclaimZombies);
218
    // hopefully by this point all SmtEngines have been deleted
219
    // already, along with all their attributes
220
9866
    d_attrManager->deleteAllAttributes();
221
  }
222
223
3236048
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
224
3226182
    d_operators[i] = Node::null();
225
  }
226
227
9866
  d_unique_vars.clear();
228
229
19732
  TypeNode dummy;
230
9866
  d_tt_cache.d_children.clear();
231
9866
  d_tt_cache.d_data = dummy;
232
9866
  d_rt_cache.d_children.clear();
233
9866
  d_rt_cache.d_data = dummy;
234
235
  // clear the datatypes
236
9866
  d_dtypes.clear();
237
238
9866
  Assert(!d_attrManager->inGarbageCollection());
239
240
19732
  std::vector<NodeValue*> order = TopologicalSort(d_maxedOut);
241
9866
  d_maxedOut.clear();
242
243
443184
  while (!d_zombies.empty() || !order.empty()) {
244
216659
    if (d_zombies.empty()) {
245
      // Delete the maxed out nodes in toplogical order once we know
246
      // there are no additional zombies, or other nodes to worry about.
247
7
      Assert(!order.empty());
248
      // We process these in reverse to reverse the topological order.
249
7
      NodeValue* greatest_maxed_out = order.back();
250
7
      order.pop_back();
251
7
      Assert(greatest_maxed_out->HasMaximizedReferenceCount());
252
7
      Debug("gc") << "Force zombify " << greatest_maxed_out << std::endl;
253
7
      greatest_maxed_out->d_rc = 0;
254
7
      markForDeletion(greatest_maxed_out);
255
    } else {
256
216652
      reclaimZombies();
257
    }
258
  }
259
260
9866
  if (d_initialized)
261
  {
262
9719
    poolRemove(&expr::NodeValue::null());
263
  }
264
265
9866
  if(Debug.isOn("gc:leaks")) {
266
    Debug("gc:leaks") << "still in pool:" << endl;
267
    for(NodeValuePool::const_iterator i = d_nodeValuePool.begin(),
268
          iend = d_nodeValuePool.end();
269
        i != iend;
270
        ++i) {
271
      Debug("gc:leaks") << "  " << *i
272
                        << " id=" << (*i)->d_id
273
                        << " rc=" << (*i)->d_rc
274
                        << " " << **i << endl;
275
    }
276
    Debug("gc:leaks") << ":end:" << endl;
277
  }
278
279
  // defensive coding, in case destruction-order issues pop up (they often do)
280
9866
  delete d_attrManager;
281
9866
  d_attrManager = NULL;
282
9866
}
283
284
4342076
const DType& NodeManager::getDTypeForIndex(size_t index) const
285
{
286
  // if this assertion fails, it is likely due to not managing datatypes
287
  // properly w.r.t. multiple NodeManagers.
288
4342076
  Assert(index < d_dtypes.size());
289
4342076
  return *d_dtypes[index];
290
}
291
292
219434
void NodeManager::reclaimZombies() {
293
  // FIXME multithreading
294
219434
  Assert(!d_attrManager->inGarbageCollection());
295
296
219434
  Debug("gc") << "reclaiming " << d_zombies.size() << " zombie(s)!\n";
297
298
  // during reclamation, reclaimZombies() is never supposed to be called
299
219434
  Assert(!d_inReclaimZombies)
300
      << "NodeManager::reclaimZombies() not re-entrant!";
301
302
  // whether exit is normal or exceptional, the Reclaim dtor is called
303
  // and ensures that d_inReclaimZombies is set back to false.
304
438868
  ScopedBool r(d_inReclaimZombies);
305
306
  // We copy the set away and clear the NodeManager's set of zombies.
307
  // This is because reclaimZombie() decrements the RC of the
308
  // NodeValue's children, which may (recursively) reclaim them.
309
  //
310
  // Let's say we're reclaiming zombie NodeValue "A" and its child "B"
311
  // then becomes a zombie (NodeManager::markForDeletion(B) is called).
312
  //
313
  // One way to handle B's zombification would be simply to put it
314
  // into d_zombies.  This is what we do.  However, if we were to
315
  // concurrently process d_zombies in the loop below, such addition
316
  // may be invisible to us (B is leaked) or even invalidate our
317
  // iterator, causing a crash.  So we need to copy the set away.
318
319
438868
  vector<NodeValue*> zombies;
320
219434
  zombies.reserve(d_zombies.size());
321
219434
  remove_copy_if(d_zombies.begin(),
322
                 d_zombies.end(),
323
                 back_inserter(zombies),
324
219434
                 NodeValueReferenceCountNonZero());
325
219434
  d_zombies.clear();
326
327
#ifdef _LIBCPP_VERSION
328
  NodeValue* last = NULL;
329
#endif
330
31544504
  for(vector<NodeValue*>::iterator i = zombies.begin();
331
31544504
      i != zombies.end();
332
      ++i) {
333
31325070
    NodeValue* nv = *i;
334
#ifdef _LIBCPP_VERSION
335
    // Work around an apparent bug in libc++'s hash_set<> which can
336
    // (very occasionally) have an element repeated.
337
    if(nv == last) {
338
      continue;
339
    }
340
    last = nv;
341
#endif
342
343
    // collect ONLY IF still zero
344
31325070
    if(nv->d_rc == 0) {
345
31325070
      if(Debug.isOn("gc")) {
346
        Debug("gc") << "deleting node value " << nv
347
                    << " [" << nv->d_id << "]: ";
348
        nv->printAst(Debug("gc"));
349
        Debug("gc") << endl;
350
      }
351
352
      // remove from the pool
353
31325070
      kind::MetaKind mk = nv->getMetaKind();
354
31325070
      if(mk != kind::metakind::VARIABLE && mk != kind::metakind::NULLARY_OPERATOR) {
355
30193913
        poolRemove(nv);
356
      }
357
358
      // whether exit is normal or exceptional, the NVReclaim dtor is
359
      // called and ensures that d_nodeUnderDeletion is set back to
360
      // NULL.
361
62650140
      NVReclaim rc(d_nodeUnderDeletion);
362
31325070
      d_nodeUnderDeletion = nv;
363
364
      // remove attributes
365
      { // notify listeners of deleted node
366
62650140
        TNode n;
367
31325070
        n.d_nv = nv;
368
31325070
        nv->d_rc = 1; // so that TNode doesn't assert-fail
369
55887082
        for (NodeManagerListener* listener : d_listeners)
370
        {
371
24562012
          listener->nmNotifyDeleteNode(n);
372
        }
373
        // this would mean that one of the listeners stowed away
374
        // a reference to this node!
375
31325070
        Assert(nv->d_rc == 1);
376
      }
377
31325070
      nv->d_rc = 0;
378
31325070
      d_attrManager->deleteAllAttributes(nv);
379
380
      // decr ref counts of children
381
31325070
      nv->decrRefCounts();
382
31325070
      if(mk == kind::metakind::CONSTANT) {
383
        // Destroy (call the destructor for) the C++ type representing
384
        // the constant in this NodeValue.  This is needed for
385
        // e.g. cvc5::Rational, since it has a gmp internal
386
        // representation that mallocs memory and should be cleaned
387
        // up.  (This won't delete a pointer value if used as a
388
        // constant, but then, you should probably use a smart-pointer
389
        // type for a constant payload.)
390
3209897
        kind::metakind::deleteNodeValueConstant(nv);
391
      }
392
31325070
      free(nv);
393
    }
394
  }
395
219434
}/* NodeManager::reclaimZombies() */
396
397
9870
std::vector<NodeValue*> NodeManager::TopologicalSort(
398
    const std::vector<NodeValue*>& roots) {
399
9870
  std::vector<NodeValue*> order;
400
  // The stack of nodes to visit. The Boolean value is false when visiting the
401
  // node in preorder and true when visiting it in postorder.
402
19740
  std::vector<std::pair<bool, NodeValue*> > stack;
403
  // Nodes that have been visited in both pre- and postorder
404
19740
  NodeValueIDSet visited;
405
19740
  const NodeValueIDSet root_set(roots.begin(), roots.end());
406
407
9883
  for (size_t index = 0; index < roots.size(); index++) {
408
13
    NodeValue* root = roots[index];
409
13
    if (visited.find(root) == visited.end()) {
410
42
      stack.push_back(std::make_pair(false, root));
411
    }
412
117
    while (!stack.empty()) {
413
52
      NodeValue* current = stack.back().second;
414
52
      const bool visited_children = stack.back().first;
415
104
      Debug("gc") << "Topological sort " << current << " " << visited_children
416
52
                  << std::endl;
417
52
      if (visited_children) {
418
21
        if (root_set.find(current) != root_set.end()) {
419
13
          order.push_back(current);
420
        }
421
21
        stack.pop_back();
422
      }
423
31
      else if (visited.find(current) == visited.end())
424
      {
425
21
        stack.back().first = true;
426
21
        visited.insert(current);
427
41
        for (unsigned i = 0; i < current->getNumChildren(); ++i) {
428
20
          expr::NodeValue* child = current->getChild(i);
429
20
          stack.push_back(std::make_pair(false, child));
430
        }
431
      }
432
      else
433
      {
434
10
        stack.pop_back();
435
      }
436
    }
437
  }
438
9870
  Assert(order.size() == roots.size());
439
19740
  return order;
440
} /* NodeManager::TopologicalSort() */
441
442
745950665
TypeNode NodeManager::getType(TNode n, bool check)
443
{
444
745950665
  TypeNode typeNode;
445
745950665
  bool hasType = getAttribute(n, TypeAttr(), typeNode);
446
745950665
  bool needsCheck = check && !getAttribute(n, TypeCheckedAttr());
447
448
449
745950665
  Debug("getType") << this << " getting type for " << &n << " " << n << ", check=" << check << ", needsCheck = " << needsCheck << ", hasType = " << hasType << endl;
450
451
#ifdef CVC5_DEBUG
452
  // already did type check eagerly upon creation in node builder
453
745950665
  bool doTypeCheck = false;
454
#else
455
  bool doTypeCheck = true;
456
#endif
457
745950665
  if (needsCheck && doTypeCheck)
458
  {
459
    /* Iterate and compute the children bottom up. This avoids stack
460
       overflows in computeType() when the Node graph is really deep,
461
       which should only affect us when we're type checking lazily. */
462
    stack<TNode> worklist;
463
    worklist.push(n);
464
465
    while( !worklist.empty() ) {
466
      TNode m = worklist.top();
467
468
      bool readyToCompute = true;
469
470
      for( TNode::iterator it = m.begin(), end = m.end();
471
           it != end;
472
           ++it ) {
473
        if( !hasAttribute(*it, TypeAttr())
474
            || (check && !getAttribute(*it, TypeCheckedAttr())) ) {
475
          readyToCompute = false;
476
          worklist.push(*it);
477
        }
478
      }
479
480
      if( readyToCompute ) {
481
        Assert(check || m.getMetaKind() != kind::metakind::NULLARY_OPERATOR);
482
        /* All the children have types, time to compute */
483
        typeNode = TypeChecker::computeType(this, m, check);
484
        worklist.pop();
485
      }
486
    } // end while
487
488
    /* Last type computed in loop should be the type of n */
489
    Assert(typeNode == getAttribute(n, TypeAttr()));
490
745950665
  } else if( !hasType || needsCheck ) {
491
    /* We can compute the type top-down, without worrying about
492
       deep recursion. */
493
27341724
    Assert(check || n.getMetaKind() != kind::metakind::NULLARY_OPERATOR);
494
27341724
    typeNode = TypeChecker::computeType(this, n, check);
495
  }
496
497
  /* The type should be have been computed and stored. */
498
745950204
  Assert(hasAttribute(n, TypeAttr()));
499
  /* The check should have happened, if we asked for it. */
500
745950204
  Assert(!check || getAttribute(n, TypeCheckedAttr()));
501
502
745950204
  Debug("getType") << "type of " << &n << " " <<  n << " is " << typeNode << endl;
503
745950204
  return typeNode;
504
}
505
506
169226
Node NodeManager::mkSkolem(const std::string& prefix, const TypeNode& type, const std::string& comment, int flags) {
507
169226
  Node n = NodeBuilder(this, kind::SKOLEM);
508
169226
  setAttribute(n, TypeAttr(), type);
509
169226
  setAttribute(n, TypeCheckedAttr(), true);
510
169226
  if((flags & SKOLEM_EXACT_NAME) == 0) {
511
161472
    stringstream name;
512
80736
    name << prefix << '_' << ++d_skolemCounter;
513
80736
    setAttribute(n, expr::VarNameAttr(), name.str());
514
  } else {
515
88490
    setAttribute(n, expr::VarNameAttr(), prefix);
516
  }
517
169226
  if((flags & SKOLEM_NO_NOTIFY) == 0) {
518
261156
    for(vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
519
175856
      (*i)->nmNotifyNewSkolem(n, comment, (flags & SKOLEM_IS_GLOBAL) == SKOLEM_IS_GLOBAL);
520
    }
521
  }
522
169226
  return n;
523
}
524
525
398
TypeNode NodeManager::mkBagType(TypeNode elementType)
526
{
527
398
  CheckArgument(
528
398
      !elementType.isNull(), elementType, "unexpected NULL element type");
529
398
  Debug("bags") << "making bags type " << elementType << std::endl;
530
398
  return mkTypeNode(kind::BAG_TYPE, elementType);
531
}
532
533
935
TypeNode NodeManager::mkSequenceType(TypeNode elementType)
534
{
535
935
  CheckArgument(
536
935
      !elementType.isNull(), elementType, "unexpected NULL element type");
537
935
  return mkTypeNode(kind::SEQUENCE_TYPE, elementType);
538
}
539
540
2230
TypeNode NodeManager::mkDatatypeType(DType& datatype, uint32_t flags)
541
{
542
  // Not worth a special implementation; this doesn't need to be fast
543
  // code anyway.
544
4460
  std::vector<DType> datatypes;
545
2230
  datatypes.push_back(datatype);
546
4460
  std::vector<TypeNode> result = mkMutualDatatypeTypes(datatypes, flags);
547
2230
  Assert(result.size() == 1);
548
4460
  return result.front();
549
}
550
551
2230
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
552
    const std::vector<DType>& datatypes, uint32_t flags)
553
{
554
4460
  std::set<TypeNode> unresolvedTypes;
555
4460
  return mkMutualDatatypeTypes(datatypes, unresolvedTypes, flags);
556
}
557
558
4213
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
559
    const std::vector<DType>& datatypes,
560
    const std::set<TypeNode>& unresolvedTypes,
561
    uint32_t flags)
562
{
563
8426
  std::map<std::string, TypeNode> nameResolutions;
564
4213
  std::vector<TypeNode> dtts;
565
566
  // First do some sanity checks, set up the final Type to be used for
567
  // each datatype, and set up the "named resolutions" used to handle
568
  // simple self- and mutual-recursion, for example in the definition
569
  // "nat = succ(pred:nat) | zero", a named resolution can handle the
570
  // pred selector.
571
9810
  for (const DType& dt : datatypes)
572
  {
573
5597
    uint32_t index = d_dtypes.size();
574
5597
    d_dtypes.push_back(std::unique_ptr<DType>(new DType(dt)));
575
5597
    DType* dtp = d_dtypes.back().get();
576
11194
    TypeNode typeNode;
577
5597
    if (dtp->getNumParameters() == 0)
578
    {
579
5523
      typeNode = mkTypeConst(DatatypeIndexConstant(index));
580
    }
581
    else
582
    {
583
148
      TypeNode cons = mkTypeConst(DatatypeIndexConstant(index));
584
148
      std::vector<TypeNode> params;
585
74
      params.push_back(cons);
586
170
      for (uint32_t ip = 0; ip < dtp->getNumParameters(); ++ip)
587
      {
588
96
        params.push_back(dtp->getParameter(ip));
589
      }
590
591
74
      typeNode = mkTypeNode(kind::PARAMETRIC_DATATYPE, params);
592
    }
593
5597
    if (nameResolutions.find(dtp->getName()) != nameResolutions.end())
594
    {
595
      throw Exception(
596
          "cannot construct two datatypes at the same time with the same name");
597
    }
598
5597
    nameResolutions.insert(std::make_pair(dtp->getName(), typeNode));
599
5597
    dtts.push_back(typeNode);
600
  }
601
602
  // Second, set up the type substitution map for complex type
603
  // resolution (e.g. if "list" is the type we're defining, and it has
604
  // a selector of type "ARRAY INT OF list", this can't be taken care
605
  // of using the named resolutions that we set up above.  A
606
  // preliminary array type was set up, and now needs to have "list"
607
  // substituted in it for the correct type.
608
  //
609
  // @TODO get rid of named resolutions altogether and handle
610
  // everything with these resolutions?
611
8426
  std::vector<TypeNode> paramTypes;
612
8426
  std::vector<TypeNode> paramReplacements;
613
8426
  std::vector<TypeNode> placeholders;  // to hold the "unresolved placeholders"
614
8426
  std::vector<TypeNode> replacements;  // to hold our final, resolved types
615
7572
  for (const TypeNode& ut : unresolvedTypes)
616
  {
617
6718
    std::string name = ut.getAttribute(expr::VarNameAttr());
618
    std::map<std::string, TypeNode>::const_iterator resolver =
619
3359
        nameResolutions.find(name);
620
3359
    if (resolver == nameResolutions.end())
621
    {
622
      throw Exception("cannot resolve type " + name
623
                      + "; it's not among the datatypes being defined");
624
    }
625
    // We will instruct the Datatype to substitute "ut" (the
626
    // unresolved SortType used as a placeholder in complex types)
627
    // with "(*resolver).second" (the TypeNode we created in the
628
    // first step, above).
629
3359
    if (ut.isSort())
630
    {
631
3303
      placeholders.push_back(ut);
632
3303
      replacements.push_back((*resolver).second);
633
    }
634
    else
635
    {
636
56
      Assert(ut.isSortConstructor());
637
56
      paramTypes.push_back(ut);
638
56
      paramReplacements.push_back((*resolver).second);
639
    }
640
  }
641
642
  // Lastly, perform the final resolutions and checks.
643
9810
  for (const TypeNode& ut : dtts)
644
  {
645
5597
    const DType& dt = ut.getDType();
646
5597
    if (!dt.isResolved())
647
    {
648
5597
      const_cast<DType&>(dt).resolve(nameResolutions,
649
                                     placeholders,
650
                                     replacements,
651
                                     paramTypes,
652
                                     paramReplacements);
653
    }
654
    // Check the datatype has been resolved properly.
655
22117
    for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
656
    {
657
16520
      const DTypeConstructor& c = dt[i];
658
33040
      TypeNode testerType CVC5_UNUSED = c.getTester().getType();
659
16520
      Assert(c.isResolved() && testerType.isTester() && testerType[0] == ut)
660
          << "malformed tester in datatype post-resolution";
661
33040
      TypeNode ctorType CVC5_UNUSED = c.getConstructor().getType();
662
16520
      Assert(ctorType.isConstructor()
663
            && ctorType.getNumChildren() == c.getNumArgs() + 1
664
            && ctorType.getRangeType() == ut)
665
          << "malformed constructor in datatype post-resolution";
666
      // for all selectors...
667
33253
      for (size_t j = 0, nargs = c.getNumArgs(); j < nargs; j++)
668
      {
669
16733
        const DTypeSelector& a = c[j];
670
33466
        TypeNode selectorType = a.getType();
671
16733
        Assert(a.isResolved() && selectorType.isSelector()
672
              && selectorType[0] == ut)
673
            << "malformed selector in datatype post-resolution";
674
        // This next one's a "hard" check, performed in non-debug builds
675
        // as well; the other ones should all be guaranteed by the
676
        // cvc5::DType class, but this actually needs to be checked.
677
16733
        if (selectorType.getRangeType().isFunctionLike())
678
        {
679
          throw Exception("cannot put function-like things in datatypes");
680
        }
681
      }
682
    }
683
  }
684
685
9942
  for (NodeManagerListener* nml : d_listeners)
686
  {
687
5729
    nml->nmNotifyNewDatatypes(dtts, flags);
688
  }
689
690
8426
  return dtts;
691
}
692
693
16520
TypeNode NodeManager::mkConstructorType(const std::vector<TypeNode>& args,
694
                                        TypeNode range)
695
{
696
33040
  std::vector<TypeNode> sorts = args;
697
16520
  sorts.push_back(range);
698
33040
  return mkTypeNode(kind::CONSTRUCTOR_TYPE, sorts);
699
}
700
701
17488
TypeNode NodeManager::mkSelectorType(TypeNode domain, TypeNode range)
702
{
703
17488
  CheckArgument(
704
17488
      domain.isDatatype(), domain, "cannot create non-datatype selector type");
705
17488
  return mkTypeNode(kind::SELECTOR_TYPE, domain, range);
706
}
707
708
16520
TypeNode NodeManager::mkTesterType(TypeNode domain)
709
{
710
16520
  CheckArgument(
711
16520
      domain.isDatatype(), domain, "cannot create non-datatype tester");
712
16520
  return mkTypeNode(kind::TESTER_TYPE, domain);
713
}
714
715
16733
TypeNode NodeManager::mkDatatypeUpdateType(TypeNode domain, TypeNode range)
716
{
717
16733
  CheckArgument(
718
16733
      domain.isDatatype(), domain, "cannot create non-datatype upater type");
719
  // It is a function type domain x range -> domain, we store only the
720
  // arguments
721
16733
  return mkTypeNode(kind::UPDATER_TYPE, domain, range);
722
}
723
724
30267
TypeNode NodeManager::TupleTypeCache::getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index ) {
725
30267
  if( index==types.size() ){
726
11165
    if( d_data.isNull() ){
727
4148
      std::stringstream sst;
728
2074
      sst << "__cvc5_tuple";
729
3113
      for (unsigned i = 0; i < types.size(); ++ i) {
730
1039
        sst << "_" << types[i];
731
      }
732
4148
      DType dt(sst.str());
733
2074
      dt.setTuple();
734
4148
      std::stringstream ssc;
735
2074
      ssc << sst.str() << "_ctor";
736
      std::shared_ptr<DTypeConstructor> c =
737
4148
          std::make_shared<DTypeConstructor>(ssc.str());
738
3113
      for (unsigned i = 0; i < types.size(); ++ i) {
739
2078
        std::stringstream ss;
740
1039
        ss << sst.str() << "_stor_" << i;
741
1039
        c->addArg(ss.str().c_str(), types[i]);
742
      }
743
2074
      dt.addConstructor(c);
744
2074
      d_data = nm->mkDatatypeType(dt);
745
2074
      Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
746
    }
747
11165
    return d_data;
748
  }else{
749
19102
    return d_children[types[index]].getTupleType( nm, types, index+1 );
750
  }
751
}
752
753
367
TypeNode NodeManager::RecTypeCache::getRecordType( NodeManager * nm, const Record& rec, unsigned index ) {
754
367
  if (index == rec.size())
755
  {
756
141
    if( d_data.isNull() ){
757
132
      std::stringstream sst;
758
66
      sst << "__cvc5_record";
759
176
      for (const std::pair<std::string, TypeNode>& i : rec)
760
      {
761
110
        sst << "_" << i.first << "_" << i.second;
762
      }
763
132
      DType dt(sst.str());
764
66
      dt.setRecord();
765
132
      std::stringstream ssc;
766
66
      ssc << sst.str() << "_ctor";
767
      std::shared_ptr<DTypeConstructor> c =
768
132
          std::make_shared<DTypeConstructor>(ssc.str());
769
176
      for (const std::pair<std::string, TypeNode>& i : rec)
770
      {
771
110
        c->addArg(i.first, i.second);
772
      }
773
66
      dt.addConstructor(c);
774
66
      d_data = nm->mkDatatypeType(dt);
775
66
      Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
776
    }
777
141
    return d_data;
778
  }
779
226
  return d_children[rec[index].second][rec[index].first].getRecordType(
780
226
      nm, rec, index + 1);
781
}
782
783
55574
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& sorts)
784
{
785
55574
  Assert(sorts.size() >= 2);
786
55574
  return mkTypeNode(kind::FUNCTION_TYPE, sorts);
787
}
788
789
39
TypeNode NodeManager::mkPredicateType(const std::vector<TypeNode>& sorts)
790
{
791
39
  Assert(sorts.size() >= 1);
792
78
  std::vector<TypeNode> sortNodes;
793
39
  sortNodes.insert(sortNodes.end(), sorts.begin(), sorts.end());
794
39
  sortNodes.push_back(booleanType());
795
78
  return mkFunctionType(sortNodes);
796
}
797
798
5435
TypeNode NodeManager::mkFunctionType(const TypeNode& domain,
799
                                     const TypeNode& range)
800
{
801
10870
  std::vector<TypeNode> sorts;
802
5435
  sorts.push_back(domain);
803
5435
  sorts.push_back(range);
804
10870
  return mkFunctionType(sorts);
805
}
806
807
43019
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& argTypes,
808
                                     const TypeNode& range)
809
{
810
43019
  Assert(argTypes.size() >= 1);
811
86038
  std::vector<TypeNode> sorts(argTypes);
812
43019
  sorts.push_back(range);
813
86038
  return mkFunctionType(sorts);
814
}
815
816
11165
TypeNode NodeManager::mkTupleType(const std::vector<TypeNode>& types) {
817
22330
  std::vector< TypeNode > ts;
818
11165
  Debug("tuprec-debug") << "Make tuple type : ";
819
30267
  for (unsigned i = 0; i < types.size(); ++ i) {
820
19102
    CheckArgument(!types[i].isFunctionLike(), types, "cannot put function-like types in tuples");
821
19102
    ts.push_back( types[i] );
822
19102
    Debug("tuprec-debug") << types[i] << " ";
823
  }
824
11165
  Debug("tuprec-debug") << std::endl;
825
22330
  return d_tt_cache.getTupleType( this, ts );
826
}
827
828
141
TypeNode NodeManager::mkRecordType(const Record& rec) {
829
141
  return d_rt_cache.getRecordType( this, rec );
830
}
831
832
void NodeManager::reclaimAllZombies(){
833
  reclaimZombiesUntil(0u);
834
}
835
836
/** Reclaim zombies while there are more than k nodes in the pool (if possible).*/
837
void NodeManager::reclaimZombiesUntil(uint32_t k){
838
  if(safeToReclaimZombies()){
839
    while(poolSize() >= k && !d_zombies.empty()){
840
      reclaimZombies();
841
    }
842
  }
843
}
844
845
1
size_t NodeManager::poolSize() const{
846
1
  return d_nodeValuePool.size();
847
}
848
849
14
TypeNode NodeManager::mkSort(uint32_t flags) {
850
28
  NodeBuilder nb(this, kind::SORT_TYPE);
851
28
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
852
14
  nb << sortTag;
853
14
  TypeNode tn = nb.constructTypeNode();
854
16
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
855
2
    (*i)->nmNotifyNewSort(tn, flags);
856
  }
857
28
  return tn;
858
}
859
860
7987
TypeNode NodeManager::mkSort(const std::string& name, uint32_t flags) {
861
15974
  NodeBuilder nb(this, kind::SORT_TYPE);
862
15974
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
863
7987
  nb << sortTag;
864
7987
  TypeNode tn = nb.constructTypeNode();
865
7987
  setAttribute(tn, expr::VarNameAttr(), name);
866
19459
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
867
11472
    (*i)->nmNotifyNewSort(tn, flags);
868
  }
869
15974
  return tn;
870
}
871
872
485
TypeNode NodeManager::mkSort(TypeNode constructor,
873
                                    const std::vector<TypeNode>& children,
874
                                    uint32_t flags) {
875
485
  Assert(constructor.getKind() == kind::SORT_TYPE
876
         && constructor.getNumChildren() == 0)
877
      << "expected a sort constructor";
878
485
  Assert(children.size() > 0) << "expected non-zero # of children";
879
485
  Assert(hasAttribute(constructor.d_nv, expr::SortArityAttr())
880
         && hasAttribute(constructor.d_nv, expr::VarNameAttr()))
881
      << "expected a sort constructor";
882
970
  std::string name = getAttribute(constructor.d_nv, expr::VarNameAttr());
883
485
  Assert(getAttribute(constructor.d_nv, expr::SortArityAttr())
884
         == children.size())
885
      << "arity mismatch in application of sort constructor";
886
970
  NodeBuilder nb(this, kind::SORT_TYPE);
887
970
  Node sortTag = Node(constructor.d_nv->d_children[0]);
888
485
  nb << sortTag;
889
485
  nb.append(children);
890
485
  TypeNode type = nb.constructTypeNode();
891
485
  setAttribute(type, expr::VarNameAttr(), name);
892
1114
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
893
629
    (*i)->nmNotifyInstantiateSortConstructor(constructor, type, flags);
894
  }
895
970
  return type;
896
}
897
898
97
TypeNode NodeManager::mkSortConstructor(const std::string& name,
899
                                        size_t arity,
900
                                        uint32_t flags)
901
{
902
97
  Assert(arity > 0);
903
194
  NodeBuilder nb(this, kind::SORT_TYPE);
904
194
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
905
97
  nb << sortTag;
906
97
  TypeNode type = nb.constructTypeNode();
907
97
  setAttribute(type, expr::VarNameAttr(), name);
908
97
  setAttribute(type, expr::SortArityAttr(), arity);
909
200
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
910
103
    (*i)->nmNotifyNewSortConstructor(type, flags);
911
  }
912
194
  return type;
913
}
914
915
177732
Node NodeManager::mkVar(const std::string& name, const TypeNode& type)
916
{
917
177732
  Node n = NodeBuilder(this, kind::VARIABLE);
918
177732
  setAttribute(n, TypeAttr(), type);
919
177732
  setAttribute(n, TypeCheckedAttr(), true);
920
177732
  setAttribute(n, expr::VarNameAttr(), name);
921
380091
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
922
202359
    (*i)->nmNotifyNewVar(n);
923
  }
924
177732
  return n;
925
}
926
927
687581
Node NodeManager::mkBoundVar(const std::string& name, const TypeNode& type) {
928
687581
  Node n = mkBoundVar(type);
929
687581
  setAttribute(n, expr::VarNameAttr(), name);
930
687581
  return n;
931
}
932
933
3221
Node NodeManager::getBoundVarListForFunctionType( TypeNode tn ) {
934
3221
  Assert(tn.isFunction());
935
3221
  Node bvl = tn.getAttribute(LambdaBoundVarListAttr());
936
3221
  if( bvl.isNull() ){
937
358
    std::vector< Node > vars;
938
434
    for( unsigned i=0; i<tn.getNumChildren()-1; i++ ){
939
255
      vars.push_back(mkBoundVar(tn[i]));
940
    }
941
179
    bvl = mkNode(kind::BOUND_VAR_LIST, vars);
942
179
    Trace("functions") << "Make standard bound var list " << bvl << " for " << tn << std::endl;
943
179
    tn.setAttribute(LambdaBoundVarListAttr(),bvl);
944
  }
945
3221
  return bvl;
946
}
947
948
1049120
Node NodeManager::mkAssociative(Kind kind, const std::vector<Node>& children)
949
{
950
1049120
  AlwaysAssert(kind::isAssociative(kind)) << "Illegal kind in mkAssociative";
951
952
1049120
  const unsigned int max = kind::metakind::getMaxArityForKind(kind);
953
1049120
  size_t numChildren = children.size();
954
955
  /* If the number of children is within bounds, then there's nothing to do. */
956
1049120
  if (numChildren <= max)
957
  {
958
1049120
    return mkNode(kind, children);
959
  }
960
  const unsigned int min = kind::metakind::getMinArityForKind(kind);
961
962
  std::vector<Node>::const_iterator it = children.begin();
963
  std::vector<Node>::const_iterator end = children.end();
964
965
  /* The new top-level children and the children of each sub node */
966
  std::vector<Node> newChildren;
967
  std::vector<Node> subChildren;
968
969
  while (it != end && numChildren > max)
970
  {
971
    /* Grab the next max children and make a node for them. */
972
    for (std::vector<Node>::const_iterator next = it + max; it != next;
973
         ++it, --numChildren)
974
    {
975
      subChildren.push_back(*it);
976
    }
977
    Node subNode = mkNode(kind, subChildren);
978
    newChildren.push_back(subNode);
979
980
    subChildren.clear();
981
  }
982
983
  // add the leftover children
984
  if (numChildren > 0)
985
  {
986
    for (; it != end; ++it)
987
    {
988
      newChildren.push_back(*it);
989
    }
990
  }
991
992
  /* It would be really weird if this happened (it would require
993
   * min > 2, for one thing), but let's make sure. */
994
  AlwaysAssert(newChildren.size() >= min)
995
      << "Too few new children in mkAssociative";
996
997
  // recurse
998
  return mkAssociative(kind, newChildren);
999
}
1000
1001
712
Node NodeManager::mkLeftAssociative(Kind kind,
1002
                                    const std::vector<Node>& children)
1003
{
1004
712
  Node n = children[0];
1005
5156
  for (size_t i = 1, size = children.size(); i < size; i++)
1006
  {
1007
4444
    n = mkNode(kind, n, children[i]);
1008
  }
1009
712
  return n;
1010
}
1011
1012
6
Node NodeManager::mkRightAssociative(Kind kind,
1013
                                     const std::vector<Node>& children)
1014
{
1015
6
  Node n = children[children.size() - 1];
1016
18
  for (size_t i = children.size() - 1; i > 0;)
1017
  {
1018
12
    n = mkNode(kind, children[--i], n);
1019
  }
1020
6
  return n;
1021
}
1022
1023
769
Node NodeManager::mkChain(Kind kind, const std::vector<Node>& children)
1024
{
1025
769
  if (children.size() == 2)
1026
  {
1027
    // if this is the case exactly 1 pair will be generated so the
1028
    // AND is not required
1029
    return mkNode(kind, children[0], children[1]);
1030
  }
1031
1538
  std::vector<Node> cchildren;
1032
3952
  for (size_t i = 0, nargsmo = children.size() - 1; i < nargsmo; i++)
1033
  {
1034
3183
    cchildren.push_back(mkNode(kind, children[i], children[i + 1]));
1035
  }
1036
769
  return mkNode(kind::AND, cchildren);
1037
}
1038
1039
127
Node NodeManager::mkVar(const TypeNode& type)
1040
{
1041
127
  Node n = NodeBuilder(this, kind::VARIABLE);
1042
127
  setAttribute(n, TypeAttr(), type);
1043
127
  setAttribute(n, TypeCheckedAttr(), true);
1044
252
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
1045
125
    (*i)->nmNotifyNewVar(n);
1046
  }
1047
127
  return n;
1048
}
1049
1050
710690
Node NodeManager::mkBoundVar(const TypeNode& type) {
1051
710690
  Node n = NodeBuilder(this, kind::BOUND_VARIABLE);
1052
710690
  setAttribute(n, TypeAttr(), type);
1053
710690
  setAttribute(n, TypeCheckedAttr(), true);
1054
710690
  return n;
1055
}
1056
1057
59458
Node NodeManager::mkInstConstant(const TypeNode& type) {
1058
59458
  Node n = NodeBuilder(this, kind::INST_CONSTANT);
1059
59458
  n.setAttribute(TypeAttr(), type);
1060
59458
  n.setAttribute(TypeCheckedAttr(), true);
1061
59458
  return n;
1062
}
1063
1064
838
Node NodeManager::mkBooleanTermVariable() {
1065
838
  Node n = NodeBuilder(this, kind::BOOLEAN_TERM_VARIABLE);
1066
838
  n.setAttribute(TypeAttr(), booleanType());
1067
838
  n.setAttribute(TypeCheckedAttr(), true);
1068
838
  return n;
1069
}
1070
1071
7280
Node NodeManager::mkNullaryOperator(const TypeNode& type, Kind k) {
1072
7280
  std::map< TypeNode, Node >::iterator it = d_unique_vars[k].find( type );
1073
7280
  if( it==d_unique_vars[k].end() ){
1074
10038
    Node n = NodeBuilder(this, k).constructNode();
1075
5019
    setAttribute(n, TypeAttr(), type);
1076
    //setAttribute(n, TypeCheckedAttr(), true);
1077
5019
    d_unique_vars[k][type] = n;
1078
5019
    Assert(n.getMetaKind() == kind::metakind::NULLARY_OPERATOR);
1079
5019
    return n;
1080
  }else{
1081
2261
    return it->second;
1082
  }
1083
}
1084
1085
8922
Node NodeManager::mkSingleton(const TypeNode& t, const TNode n)
1086
{
1087
17844
  Assert(n.getType().isSubtypeOf(t))
1088
8922
      << "Invalid operands for mkSingleton. The type '" << n.getType()
1089
8922
      << "' of node '" << n << "' is not a subtype of '" << t << "'."
1090
      << std::endl;
1091
17844
  Node op = mkConst(SingletonOp(t));
1092
8922
  Node singleton = mkNode(kind::SINGLETON, op, n);
1093
17844
  return singleton;
1094
}
1095
1096
336
Node NodeManager::mkBag(const TypeNode& t, const TNode n, const TNode m)
1097
{
1098
672
  Assert(n.getType().isSubtypeOf(t))
1099
336
      << "Invalid operands for mkBag. The type '" << n.getType()
1100
336
      << "' of node '" << n << "' is not a subtype of '" << t << "'."
1101
      << std::endl;
1102
672
  Node op = mkConst(MakeBagOp(t));
1103
336
  Node bag = mkNode(kind::MK_BAG, op, n, m);
1104
672
  return bag;
1105
}
1106
1107
8
Node NodeManager::mkAbstractValue(const TypeNode& type) {
1108
8
  Node n = mkConst(AbstractValue(++d_abstractValueCount));
1109
8
  n.setAttribute(TypeAttr(), type);
1110
8
  n.setAttribute(TypeCheckedAttr(), true);
1111
8
  return n;
1112
}
1113
1114
49658418
bool NodeManager::safeToReclaimZombies() const{
1115
  // FIXME multithreading
1116
49658418
  return !d_inReclaimZombies && !d_attrManager->inGarbageCollection();
1117
}
1118
1119
void NodeManager::deleteAttributes(const std::vector<const expr::attr::AttributeUniqueId*>& ids){
1120
  d_attrManager->deleteAttributes(ids);
1121
}
1122
1123
void NodeManager::debugHook(int debugFlag){
1124
  // For debugging purposes only, DO NOT CHECK IN ANY CODE!
1125
}
1126
1127
131
Kind NodeManager::getKindForFunction(TNode fun)
1128
{
1129
262
  TypeNode tn = fun.getType();
1130
131
  if (tn.isFunction())
1131
  {
1132
9
    return kind::APPLY_UF;
1133
  }
1134
122
  else if (tn.isConstructor())
1135
  {
1136
31
    return kind::APPLY_CONSTRUCTOR;
1137
  }
1138
91
  else if (tn.isSelector())
1139
  {
1140
57
    return kind::APPLY_SELECTOR;
1141
  }
1142
34
  else if (tn.isTester())
1143
  {
1144
34
    return kind::APPLY_TESTER;
1145
  }
1146
  return kind::UNDEFINED_KIND;
1147
}
1148
1149
2556
Node NodeManager::mkNode(Kind kind, std::initializer_list<TNode> children)
1150
{
1151
5112
  NodeBuilder nb(this, kind);
1152
2556
  nb.append(children.begin(), children.end());
1153
5112
  return nb.constructNode();
1154
}
1155
1156
Node NodeManager::mkNode(TNode opNode, std::initializer_list<TNode> children)
1157
{
1158
  NodeBuilder nb(this, operatorToKind(opNode));
1159
  if (opNode.getKind() != kind::BUILTIN)
1160
  {
1161
    nb << opNode;
1162
  }
1163
  nb.append(children.begin(), children.end());
1164
  return nb.constructNode();
1165
}
1166
1167
29598
}  // namespace cvc5