GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 500 580 86.2 %
Date: 2021-09-10 Branches: 655 1772 37.0 %

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