GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 497 582 85.4 %
Date: 2021-05-24 Branches: 649 1772 36.6 %

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