GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 500 580 86.2 %
Date: 2021-09-09 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
232520
  ScopedBool(bool& value) :
57
232520
    d_value(value) {
58
59
232520
    Debug("gc") << ">> setting ScopedBool\n";
60
232520
    d_value = true;
61
232520
  }
62
63
465040
  ~ScopedBool() {
64
232520
    Debug("gc") << "<< clearing ScopedBool\n";
65
232520
    d_value = false;
66
232520
  }
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
30576863
  NVReclaim(NodeValue*& deletionField) :
77
30576863
    d_deletionField(deletionField) {
78
79
30576863
    Debug("gc") << ">> setting NVRECLAIM field\n";
80
30576863
  }
81
82
61153726
  ~NVReclaim() {
83
30576863
    Debug("gc") << "<< clearing NVRECLAIM field\n";
84
30576863
    d_deletionField = NULL;
85
30576863
  }
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
10644
NodeManager::NodeManager()
98
10644
    : d_skManager(new SkolemManager),
99
10644
      d_bvManager(new BoundVarManager),
100
      next_id(0),
101
10644
      d_attrManager(new expr::attr::AttributeManager()),
102
      d_nodeUnderDeletion(nullptr),
103
      d_inReclaimZombies(false),
104
      d_abstractValueCount(0),
105
42576
      d_skolemCounter(0)
106
{
107
10644
  init();
108
10644
}
109
110
215350
bool NodeManager::isNAryKind(Kind k)
111
{
112
215350
  return kind::metakind::getMaxArityForKind(k) == expr::NodeValue::MAX_CHILDREN;
113
}
114
115
19714041
TypeNode NodeManager::booleanType()
116
{
117
19714041
  return mkTypeConst<TypeConstant>(BOOLEAN_TYPE);
118
}
119
120
4725292
TypeNode NodeManager::integerType()
121
{
122
4725292
  return mkTypeConst<TypeConstant>(INTEGER_TYPE);
123
}
124
125
4839026
TypeNode NodeManager::realType()
126
{
127
4839026
  return mkTypeConst<TypeConstant>(REAL_TYPE);
128
}
129
130
157954
TypeNode NodeManager::stringType()
131
{
132
157954
  return mkTypeConst<TypeConstant>(STRING_TYPE);
133
}
134
135
36877
TypeNode NodeManager::regExpType()
136
{
137
36877
  return mkTypeConst<TypeConstant>(REGEXP_TYPE);
138
}
139
140
9738
TypeNode NodeManager::roundingModeType()
141
{
142
9738
  return mkTypeConst<TypeConstant>(ROUNDINGMODE_TYPE);
143
}
144
145
198254
TypeNode NodeManager::boundVarListType()
146
{
147
198254
  return mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE);
148
}
149
150
10344
TypeNode NodeManager::instPatternType()
151
{
152
10344
  return mkTypeConst<TypeConstant>(INST_PATTERN_TYPE);
153
}
154
155
23851
TypeNode NodeManager::instPatternListType()
156
{
157
23851
  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
474275
TypeNode NodeManager::mkBitVectorType(unsigned size)
166
{
167
474275
  return mkTypeConst<BitVectorSize>(BitVectorSize(size));
168
}
169
170
1169317
TypeNode NodeManager::sExprType()
171
{
172
1169317
  return mkTypeConst<TypeConstant>(SEXPR_TYPE);
173
}
174
175
6683
TypeNode NodeManager::mkFloatingPointType(unsigned exp, unsigned sig)
176
{
177
6683
  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
10644
void NodeManager::init() {
186
  // `mkConst()` indirectly needs the correct NodeManager in scope because we
187
  // call `NodeValue::inc()` which uses `NodeManager::curentNM()`
188
21288
  NodeManagerScope nms(this);
189
190
10644
  poolInsert( &expr::NodeValue::null() );
191
192
3491232
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
193
3480588
    Kind k = Kind(i);
194
195
3480588
    if(hasOperator(k)) {
196
2905812
      d_operators[i] = mkConst(Kind(k));
197
    }
198
  }
199
10644
}
200
201
16006
NodeManager::~NodeManager() {
202
  // have to ensure "this" is the current NodeManager during
203
  // destruction of operators, because they get GCed.
204
205
16006
  NodeManagerScope nms(this);
206
207
  // Destroy skolem and bound var manager before cleaning up attributes and
208
  // zombies
209
8003
  d_skManager = nullptr;
210
8003
  d_bvManager = nullptr;
211
212
  {
213
16006
    ScopedBool dontGC(d_inReclaimZombies);
214
    // hopefully by this point all SmtEngines have been deleted
215
    // already, along with all their attributes
216
8003
    d_attrManager->deleteAllAttributes();
217
  }
218
219
2624984
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
220
2616981
    d_operators[i] = Node::null();
221
  }
222
223
8003
  d_unique_vars.clear();
224
225
16006
  TypeNode dummy;
226
8003
  d_tt_cache.d_children.clear();
227
8003
  d_tt_cache.d_data = dummy;
228
8003
  d_rt_cache.d_children.clear();
229
8003
  d_rt_cache.d_data = dummy;
230
231
  // clear the datatypes
232
8003
  d_dtypes.clear();
233
234
8003
  Assert(!d_attrManager->inGarbageCollection());
235
236
16006
  std::vector<NodeValue*> order = TopologicalSort(d_maxedOut);
237
8003
  d_maxedOut.clear();
238
239
451671
  while (!d_zombies.empty() || !order.empty()) {
240
221834
    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
221827
      reclaimZombies();
253
    }
254
  }
255
256
8003
  poolRemove( &expr::NodeValue::null() );
257
258
8003
  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
8003
  delete d_attrManager;
274
8003
  d_attrManager = NULL;
275
8003
}
276
277
4277522
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
4277522
  Assert(index < d_dtypes.size());
282
4277522
  return *d_dtypes[index];
283
}
284
285
224517
void NodeManager::reclaimZombies() {
286
  // FIXME multithreading
287
224517
  Assert(!d_attrManager->inGarbageCollection());
288
289
224517
  Debug("gc") << "reclaiming " << d_zombies.size() << " zombie(s)!\n";
290
291
  // during reclamation, reclaimZombies() is never supposed to be called
292
224517
  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
449034
  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
449034
  vector<NodeValue*> zombies;
313
224517
  zombies.reserve(d_zombies.size());
314
224517
  remove_copy_if(d_zombies.begin(),
315
                 d_zombies.end(),
316
                 back_inserter(zombies),
317
224517
                 NodeValueReferenceCountNonZero());
318
224517
  d_zombies.clear();
319
320
#ifdef _LIBCPP_VERSION
321
  NodeValue* last = NULL;
322
#endif
323
30801380
  for(vector<NodeValue*>::iterator i = zombies.begin();
324
30801380
      i != zombies.end();
325
      ++i) {
326
30576863
    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
30576863
    if(nv->d_rc == 0) {
338
30576863
      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
30576863
      kind::MetaKind mk = nv->getMetaKind();
347
30576863
      if(mk != kind::metakind::VARIABLE && mk != kind::metakind::NULLARY_OPERATOR) {
348
29449354
        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
61153726
      NVReclaim rc(d_nodeUnderDeletion);
355
30576863
      d_nodeUnderDeletion = nv;
356
357
      // remove attributes
358
      { // notify listeners of deleted node
359
61153726
        TNode n;
360
30576863
        n.d_nv = nv;
361
30576863
        nv->d_rc = 1; // so that TNode doesn't assert-fail
362
53876082
        for (NodeManagerListener* listener : d_listeners)
363
        {
364
23299219
          listener->nmNotifyDeleteNode(n);
365
        }
366
        // this would mean that one of the listeners stowed away
367
        // a reference to this node!
368
30576863
        Assert(nv->d_rc == 1);
369
      }
370
30576863
      nv->d_rc = 0;
371
30576863
      d_attrManager->deleteAllAttributes(nv);
372
373
      // decr ref counts of children
374
30576863
      nv->decrRefCounts();
375
30576863
      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
2756482
        kind::metakind::deleteNodeValueConstant(nv);
384
      }
385
30576863
      free(nv);
386
    }
387
  }
388
224517
}/* NodeManager::reclaimZombies() */
389
390
8007
std::vector<NodeValue*> NodeManager::TopologicalSort(
391
    const std::vector<NodeValue*>& roots) {
392
8007
  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
16014
  std::vector<std::pair<bool, NodeValue*> > stack;
396
  // Nodes that have been visited in both pre- and postorder
397
16014
  NodeValueIDSet visited;
398
16014
  const NodeValueIDSet root_set(roots.begin(), roots.end());
399
400
8020
  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
8007
  Assert(order.size() == roots.size());
432
16014
  return order;
433
} /* NodeManager::TopologicalSort() */
434
435
742841511
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
1485683022
  NodeManagerScope nms(this);
445
446
742841511
  TypeNode typeNode;
447
742841511
  bool hasType = getAttribute(n, TypeAttr(), typeNode);
448
742841511
  bool needsCheck = check && !getAttribute(n, TypeCheckedAttr());
449
450
451
742841511
  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
742841511
  bool doTypeCheck = false;
456
#else
457
  bool doTypeCheck = true;
458
#endif
459
742841511
  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
742841511
  } else if( !hasType || needsCheck ) {
493
    /* We can compute the type top-down, without worrying about
494
       deep recursion. */
495
27056522
    Assert(check || n.getMetaKind() != kind::metakind::NULLARY_OPERATOR);
496
27056522
    typeNode = TypeChecker::computeType(this, n, check);
497
  }
498
499
  /* The type should be have been computed and stored. */
500
742841050
  Assert(hasAttribute(n, TypeAttr()));
501
  /* The check should have happened, if we asked for it. */
502
742841050
  Assert(!check || getAttribute(n, TypeCheckedAttr()));
503
504
742841050
  Debug("getType") << "type of " << &n << " " <<  n << " is " << typeNode << endl;
505
1485682100
  return typeNode;
506
}
507
508
166057
Node NodeManager::mkSkolem(const std::string& prefix, const TypeNode& type, const std::string& comment, int flags) {
509
166057
  Node n = NodeBuilder(this, kind::SKOLEM);
510
166057
  setAttribute(n, TypeAttr(), type);
511
166057
  setAttribute(n, TypeCheckedAttr(), true);
512
166057
  if((flags & SKOLEM_EXACT_NAME) == 0) {
513
163818
    stringstream name;
514
81909
    name << prefix << '_' << ++d_skolemCounter;
515
81909
    setAttribute(n, expr::VarNameAttr(), name.str());
516
  } else {
517
84148
    setAttribute(n, expr::VarNameAttr(), prefix);
518
  }
519
166057
  if((flags & SKOLEM_NO_NOTIFY) == 0) {
520
261250
    for(vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
521
176077
      (*i)->nmNotifyNewSkolem(n, comment, (flags & SKOLEM_IS_GLOBAL) == SKOLEM_IS_GLOBAL);
522
    }
523
  }
524
166057
  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
2281
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
4562
  std::vector<DType> datatypes;
547
2281
  datatypes.push_back(datatype);
548
4562
  std::vector<TypeNode> result = mkMutualDatatypeTypes(datatypes, flags);
549
2281
  Assert(result.size() == 1);
550
4562
  return result.front();
551
}
552
553
2281
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
554
    const std::vector<DType>& datatypes, uint32_t flags)
555
{
556
4562
  std::set<TypeNode> unresolvedTypes;
557
4562
  return mkMutualDatatypeTypes(datatypes, unresolvedTypes, flags);
558
}
559
560
4208
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
561
    const std::vector<DType>& datatypes,
562
    const std::set<TypeNode>& unresolvedTypes,
563
    uint32_t flags)
564
{
565
8416
  NodeManagerScope nms(this);
566
8416
  std::map<std::string, TypeNode> nameResolutions;
567
4208
  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
9745
  for (const DType& dt : datatypes)
575
  {
576
5537
    uint32_t index = d_dtypes.size();
577
5537
    d_dtypes.push_back(std::unique_ptr<DType>(new DType(dt)));
578
5537
    DType* dtp = d_dtypes.back().get();
579
11074
    TypeNode typeNode;
580
5537
    if (dtp->getNumParameters() == 0)
581
    {
582
5463
      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
5537
    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
5537
    nameResolutions.insert(std::make_pair(dtp->getName(), typeNode));
602
5537
    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
8416
  std::vector<TypeNode> paramTypes;
615
8416
  std::vector<TypeNode> paramReplacements;
616
8416
  std::vector<TypeNode> placeholders;  // to hold the "unresolved placeholders"
617
8416
  std::vector<TypeNode> replacements;  // to hold our final, resolved types
618
7456
  for (const TypeNode& ut : unresolvedTypes)
619
  {
620
6496
    std::string name = ut.getAttribute(expr::VarNameAttr());
621
    std::map<std::string, TypeNode>::const_iterator resolver =
622
3248
        nameResolutions.find(name);
623
3248
    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
3248
    if (ut.isSort())
633
    {
634
3192
      placeholders.push_back(ut);
635
3192
      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
9745
  for (const TypeNode& ut : dtts)
647
  {
648
5537
    const DType& dt = ut.getDType();
649
5537
    if (!dt.isResolved())
650
    {
651
5537
      const_cast<DType&>(dt).resolve(nameResolutions,
652
                                     placeholders,
653
                                     replacements,
654
                                     paramTypes,
655
                                     paramReplacements);
656
    }
657
    // Check the datatype has been resolved properly.
658
21243
    for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
659
    {
660
15706
      const DTypeConstructor& c = dt[i];
661
31412
      TypeNode testerType CVC5_UNUSED = c.getTester().getType();
662
15706
      Assert(c.isResolved() && testerType.isTester() && testerType[0] == ut)
663
          << "malformed tester in datatype post-resolution";
664
31412
      TypeNode ctorType CVC5_UNUSED = c.getConstructor().getType();
665
15706
      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
31533
      for (size_t j = 0, nargs = c.getNumArgs(); j < nargs; j++)
671
      {
672
15827
        const DTypeSelector& a = c[j];
673
31654
        TypeNode selectorType = a.getType();
674
15827
        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
15827
        if (selectorType.getRangeType().isFunctionLike())
681
        {
682
          throw Exception("cannot put function-like things in datatypes");
683
        }
684
      }
685
    }
686
  }
687
688
9874
  for (NodeManagerListener* nml : d_listeners)
689
  {
690
5666
    nml->nmNotifyNewDatatypes(dtts, flags);
691
  }
692
693
8416
  return dtts;
694
}
695
696
15706
TypeNode NodeManager::mkConstructorType(const std::vector<TypeNode>& args,
697
                                        TypeNode range)
698
{
699
31412
  std::vector<TypeNode> sorts = args;
700
15706
  sorts.push_back(range);
701
31412
  return mkTypeNode(kind::CONSTRUCTOR_TYPE, sorts);
702
}
703
704
17886
TypeNode NodeManager::mkSelectorType(TypeNode domain, TypeNode range)
705
{
706
17886
  CheckArgument(
707
17886
      domain.isDatatype(), domain, "cannot create non-datatype selector type");
708
17886
  return mkTypeNode(kind::SELECTOR_TYPE, domain, range);
709
}
710
711
15706
TypeNode NodeManager::mkTesterType(TypeNode domain)
712
{
713
15706
  CheckArgument(
714
15706
      domain.isDatatype(), domain, "cannot create non-datatype tester");
715
15706
  return mkTypeNode(kind::TESTER_TYPE, domain);
716
}
717
718
15827
TypeNode NodeManager::mkDatatypeUpdateType(TypeNode domain, TypeNode range)
719
{
720
15827
  CheckArgument(
721
15827
      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
15827
  return mkTypeNode(kind::UPDATER_TYPE, domain, range);
725
}
726
727
30251
TypeNode NodeManager::TupleTypeCache::getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index ) {
728
30251
  if( index==types.size() ){
729
11157
    if( d_data.isNull() ){
730
4234
      std::stringstream sst;
731
2117
      sst << "__cvc5_tuple";
732
3162
      for (unsigned i = 0; i < types.size(); ++ i) {
733
1045
        sst << "_" << types[i];
734
      }
735
4234
      DType dt(sst.str());
736
2117
      dt.setTuple();
737
4234
      std::stringstream ssc;
738
2117
      ssc << sst.str() << "_ctor";
739
      std::shared_ptr<DTypeConstructor> c =
740
4234
          std::make_shared<DTypeConstructor>(ssc.str());
741
3162
      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
2117
      dt.addConstructor(c);
747
2117
      d_data = nm->mkDatatypeType(dt);
748
2117
      Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
749
    }
750
11157
    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
55758
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& sorts)
787
{
788
55758
  Assert(sorts.size() >= 2);
789
55758
  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
5744
TypeNode NodeManager::mkFunctionType(const TypeNode& domain,
802
                                     const TypeNode& range)
803
{
804
11488
  std::vector<TypeNode> sorts;
805
5744
  sorts.push_back(domain);
806
5744
  sorts.push_back(range);
807
11488
  return mkFunctionType(sorts);
808
}
809
810
42887
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& argTypes,
811
                                     const TypeNode& range)
812
{
813
42887
  Assert(argTypes.size() >= 1);
814
85774
  std::vector<TypeNode> sorts(argTypes);
815
42887
  sorts.push_back(range);
816
85774
  return mkFunctionType(sorts);
817
}
818
819
11157
TypeNode NodeManager::mkTupleType(const std::vector<TypeNode>& types) {
820
22314
  std::vector< TypeNode > ts;
821
11157
  Debug("tuprec-debug") << "Make tuple type : ";
822
30251
  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
11157
  Debug("tuprec-debug") << std::endl;
828
22314
  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
7875
TypeNode NodeManager::mkSort(const std::string& name, uint32_t flags) {
864
15750
  NodeBuilder nb(this, kind::SORT_TYPE);
865
15750
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
866
7875
  nb << sortTag;
867
7875
  TypeNode tn = nb.constructTypeNode();
868
7875
  setAttribute(tn, expr::VarNameAttr(), name);
869
19121
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
870
11246
    (*i)->nmNotifyNewSort(tn, flags);
871
  }
872
15750
  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
177700
Node NodeManager::mkVar(const std::string& name, const TypeNode& type)
919
{
920
177700
  Node n = NodeBuilder(this, kind::VARIABLE);
921
177700
  setAttribute(n, TypeAttr(), type);
922
177700
  setAttribute(n, TypeCheckedAttr(), true);
923
177700
  setAttribute(n, expr::VarNameAttr(), name);
924
379980
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
925
202280
    (*i)->nmNotifyNewVar(n);
926
  }
927
177700
  return n;
928
}
929
930
687335
Node NodeManager::mkBoundVar(const std::string& name, const TypeNode& type) {
931
687335
  Node n = mkBoundVar(type);
932
687335
  setAttribute(n, expr::VarNameAttr(), name);
933
687335
  return n;
934
}
935
936
3106
Node NodeManager::getBoundVarListForFunctionType( TypeNode tn ) {
937
3106
  Assert(tn.isFunction());
938
3106
  Node bvl = tn.getAttribute(LambdaBoundVarListAttr());
939
3106
  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
3106
  return bvl;
949
}
950
951
1049029
Node NodeManager::mkAssociative(Kind kind, const std::vector<Node>& children)
952
{
953
1049029
  AlwaysAssert(kind::isAssociative(kind)) << "Illegal kind in mkAssociative";
954
955
1049029
  const unsigned int max = kind::metakind::getMaxArityForKind(kind);
956
1049029
  size_t numChildren = children.size();
957
958
  /* If the number of children is within bounds, then there's nothing to do. */
959
1049029
  if (numChildren <= max)
960
  {
961
1049029
    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
710423
Node NodeManager::mkBoundVar(const TypeNode& type) {
1054
710423
  Node n = NodeBuilder(this, kind::BOUND_VARIABLE);
1055
710423
  setAttribute(n, TypeAttr(), type);
1056
710423
  setAttribute(n, TypeCheckedAttr(), true);
1057
710423
  return n;
1058
}
1059
1060
59367
Node NodeManager::mkInstConstant(const TypeNode& type) {
1061
59367
  Node n = NodeBuilder(this, kind::INST_CONSTANT);
1062
59367
  n.setAttribute(TypeAttr(), type);
1063
59367
  n.setAttribute(TypeCheckedAttr(), true);
1064
59367
  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
7264
Node NodeManager::mkNullaryOperator(const TypeNode& type, Kind k) {
1075
7264
  std::map< TypeNode, Node >::iterator it = d_unique_vars[k].find( type );
1076
7264
  if( it==d_unique_vars[k].end() ){
1077
10280
    Node n = NodeBuilder(this, k).constructNode();
1078
5140
    setAttribute(n, TypeAttr(), type);
1079
    //setAttribute(n, TypeCheckedAttr(), true);
1080
5140
    d_unique_vars[k][type] = n;
1081
5140
    Assert(n.getMetaKind() == kind::metakind::NULLARY_OPERATOR);
1082
5140
    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
48645041
bool NodeManager::safeToReclaimZombies() const{
1118
  // FIXME multithreading
1119
48645041
  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
132
Kind NodeManager::getKindForFunction(TNode fun)
1131
{
1132
264
  TypeNode tn = fun.getType();
1133
132
  if (tn.isFunction())
1134
  {
1135
10
    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
29505
}  // namespace cvc5