GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 500 580 86.2 %
Date: 2021-08-01 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
232731
  ScopedBool(bool& value) :
57
232731
    d_value(value) {
58
59
232731
    Debug("gc") << ">> setting ScopedBool\n";
60
232731
    d_value = true;
61
232731
  }
62
63
465462
  ~ScopedBool() {
64
232731
    Debug("gc") << "<< clearing ScopedBool\n";
65
232731
    d_value = false;
66
232731
  }
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
31408452
  NVReclaim(NodeValue*& deletionField) :
77
31408452
    d_deletionField(deletionField) {
78
79
31408452
    Debug("gc") << ">> setting NVRECLAIM field\n";
80
31408452
  }
81
82
62816904
  ~NVReclaim() {
83
31408452
    Debug("gc") << "<< clearing NVRECLAIM field\n";
84
31408452
    d_deletionField = NULL;
85
31408452
  }
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
7955
NodeManager::NodeManager()
98
7955
    : d_skManager(new SkolemManager),
99
7955
      d_bvManager(new BoundVarManager),
100
      next_id(0),
101
7955
      d_attrManager(new expr::attr::AttributeManager()),
102
      d_nodeUnderDeletion(nullptr),
103
      d_inReclaimZombies(false),
104
      d_abstractValueCount(0),
105
31820
      d_skolemCounter(0)
106
{
107
7955
  init();
108
7955
}
109
110
207535
bool NodeManager::isNAryKind(Kind k)
111
{
112
207535
  return kind::metakind::getMaxArityForKind(k) == expr::NodeValue::MAX_CHILDREN;
113
}
114
115
20507183
TypeNode NodeManager::booleanType()
116
{
117
20507183
  return mkTypeConst<TypeConstant>(BOOLEAN_TYPE);
118
}
119
120
4796448
TypeNode NodeManager::integerType()
121
{
122
4796448
  return mkTypeConst<TypeConstant>(INTEGER_TYPE);
123
}
124
125
4896750
TypeNode NodeManager::realType()
126
{
127
4896750
  return mkTypeConst<TypeConstant>(REAL_TYPE);
128
}
129
130
139390
TypeNode NodeManager::stringType()
131
{
132
139390
  return mkTypeConst<TypeConstant>(STRING_TYPE);
133
}
134
135
36358
TypeNode NodeManager::regExpType()
136
{
137
36358
  return mkTypeConst<TypeConstant>(REGEXP_TYPE);
138
}
139
140
9534
TypeNode NodeManager::roundingModeType()
141
{
142
9534
  return mkTypeConst<TypeConstant>(ROUNDINGMODE_TYPE);
143
}
144
145
196309
TypeNode NodeManager::boundVarListType()
146
{
147
196309
  return mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE);
148
}
149
150
10503
TypeNode NodeManager::instPatternType()
151
{
152
10503
  return mkTypeConst<TypeConstant>(INST_PATTERN_TYPE);
153
}
154
155
23855
TypeNode NodeManager::instPatternListType()
156
{
157
23855
  return mkTypeConst<TypeConstant>(INST_PATTERN_LIST_TYPE);
158
}
159
160
7477
TypeNode NodeManager::builtinOperatorType()
161
{
162
7477
  return mkTypeConst<TypeConstant>(BUILTIN_OPERATOR_TYPE);
163
}
164
165
507632
TypeNode NodeManager::mkBitVectorType(unsigned size)
166
{
167
507632
  return mkTypeConst<BitVectorSize>(BitVectorSize(size));
168
}
169
170
1065808
TypeNode NodeManager::sExprType()
171
{
172
1065808
  return mkTypeConst<TypeConstant>(SEXPR_TYPE);
173
}
174
175
6547
TypeNode NodeManager::mkFloatingPointType(unsigned exp, unsigned sig)
176
{
177
6547
  return mkTypeConst<FloatingPointSize>(FloatingPointSize(exp, sig));
178
}
179
180
4026
TypeNode NodeManager::mkFloatingPointType(FloatingPointSize fs)
181
{
182
4026
  return mkTypeConst<FloatingPointSize>(fs);
183
}
184
185
7955
void NodeManager::init() {
186
  // `mkConst()` indirectly needs the correct NodeManager in scope because we
187
  // call `NodeValue::inc()` which uses `NodeManager::curentNM()`
188
15910
  NodeManagerScope nms(this);
189
190
7955
  poolInsert( &expr::NodeValue::null() );
191
192
2601285
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
193
2593330
    Kind k = Kind(i);
194
195
2593330
    if(hasOperator(k)) {
196
2163760
      d_operators[i] = mkConst(Kind(k));
197
    }
198
  }
199
7955
}
200
201
15910
NodeManager::~NodeManager() {
202
  // have to ensure "this" is the current NodeManager during
203
  // destruction of operators, because they get GCed.
204
205
15910
  NodeManagerScope nms(this);
206
207
  // Destroy skolem and bound var manager before cleaning up attributes and
208
  // zombies
209
7955
  d_skManager = nullptr;
210
7955
  d_bvManager = nullptr;
211
212
  {
213
15910
    ScopedBool dontGC(d_inReclaimZombies);
214
    // hopefully by this point all SmtEngines have been deleted
215
    // already, along with all their attributes
216
7955
    d_attrManager->deleteAllAttributes();
217
  }
218
219
2601285
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
220
2593330
    d_operators[i] = Node::null();
221
  }
222
223
7955
  d_unique_vars.clear();
224
225
15910
  TypeNode dummy;
226
7955
  d_tt_cache.d_children.clear();
227
7955
  d_tt_cache.d_data = dummy;
228
7955
  d_rt_cache.d_children.clear();
229
7955
  d_rt_cache.d_data = dummy;
230
231
  // clear the datatypes
232
7955
  d_dtypes.clear();
233
234
7955
  Assert(!d_attrManager->inGarbageCollection());
235
236
15910
  std::vector<NodeValue*> order = TopologicalSort(d_maxedOut);
237
7955
  d_maxedOut.clear();
238
239
451891
  while (!d_zombies.empty() || !order.empty()) {
240
221968
    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
221961
      reclaimZombies();
253
    }
254
  }
255
256
7955
  poolRemove( &expr::NodeValue::null() );
257
258
7955
  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
7955
  delete d_attrManager;
274
7955
  d_attrManager = NULL;
275
7955
}
276
277
4510785
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
4510785
  Assert(index < d_dtypes.size());
282
4510785
  return *d_dtypes[index];
283
}
284
285
224776
void NodeManager::reclaimZombies() {
286
  // FIXME multithreading
287
224776
  Assert(!d_attrManager->inGarbageCollection());
288
289
224776
  Debug("gc") << "reclaiming " << d_zombies.size() << " zombie(s)!\n";
290
291
  // during reclamation, reclaimZombies() is never supposed to be called
292
224776
  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
449552
  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
449552
  vector<NodeValue*> zombies;
313
224776
  zombies.reserve(d_zombies.size());
314
224776
  remove_copy_if(d_zombies.begin(),
315
                 d_zombies.end(),
316
                 back_inserter(zombies),
317
224776
                 NodeValueReferenceCountNonZero());
318
224776
  d_zombies.clear();
319
320
#ifdef _LIBCPP_VERSION
321
  NodeValue* last = NULL;
322
#endif
323
31633228
  for(vector<NodeValue*>::iterator i = zombies.begin();
324
31633228
      i != zombies.end();
325
      ++i) {
326
31408452
    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
31408452
    if(nv->d_rc == 0) {
338
31408452
      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
31408452
      kind::MetaKind mk = nv->getMetaKind();
347
31408452
      if(mk != kind::metakind::VARIABLE && mk != kind::metakind::NULLARY_OPERATOR) {
348
30359753
        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
62816904
      NVReclaim rc(d_nodeUnderDeletion);
355
31408452
      d_nodeUnderDeletion = nv;
356
357
      // remove attributes
358
      { // notify listeners of deleted node
359
62816904
        TNode n;
360
31408452
        n.d_nv = nv;
361
31408452
        nv->d_rc = 1; // so that TNode doesn't assert-fail
362
56058430
        for (NodeManagerListener* listener : d_listeners)
363
        {
364
24649978
          listener->nmNotifyDeleteNode(n);
365
        }
366
        // this would mean that one of the listeners stowed away
367
        // a reference to this node!
368
31408452
        Assert(nv->d_rc == 1);
369
      }
370
31408452
      nv->d_rc = 0;
371
31408452
      d_attrManager->deleteAllAttributes(nv);
372
373
      // decr ref counts of children
374
31408452
      nv->decrRefCounts();
375
31408452
      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
2736261
        kind::metakind::deleteNodeValueConstant(nv);
384
      }
385
31408452
      free(nv);
386
    }
387
  }
388
224776
}/* NodeManager::reclaimZombies() */
389
390
7959
std::vector<NodeValue*> NodeManager::TopologicalSort(
391
    const std::vector<NodeValue*>& roots) {
392
7959
  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
15918
  std::vector<std::pair<bool, NodeValue*> > stack;
396
  // Nodes that have been visited in both pre- and postorder
397
15918
  NodeValueIDSet visited;
398
15918
  const NodeValueIDSet root_set(roots.begin(), roots.end());
399
400
7972
  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
7959
  Assert(order.size() == roots.size());
432
15918
  return order;
433
} /* NodeManager::TopologicalSort() */
434
435
751949415
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
1503898830
  NodeManagerScope nms(this);
445
446
751949415
  TypeNode typeNode;
447
751949415
  bool hasType = getAttribute(n, TypeAttr(), typeNode);
448
751949415
  bool needsCheck = check && !getAttribute(n, TypeCheckedAttr());
449
450
451
751949415
  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
751949415
  bool doTypeCheck = false;
456
#else
457
  bool doTypeCheck = true;
458
#endif
459
751949415
  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
751949415
  } else if( !hasType || needsCheck ) {
493
    /* We can compute the type top-down, without worrying about
494
       deep recursion. */
495
27991268
    Assert(check || n.getMetaKind() != kind::metakind::NULLARY_OPERATOR);
496
27991268
    typeNode = TypeChecker::computeType(this, n, check);
497
  }
498
499
  /* The type should be have been computed and stored. */
500
751948960
  Assert(hasAttribute(n, TypeAttr()));
501
  /* The check should have happened, if we asked for it. */
502
751948960
  Assert(!check || getAttribute(n, TypeCheckedAttr()));
503
504
751948960
  Debug("getType") << "type of " << &n << " " <<  n << " is " << typeNode << endl;
505
1503897920
  return typeNode;
506
}
507
508
165289
Node NodeManager::mkSkolem(const std::string& prefix, const TypeNode& type, const std::string& comment, int flags) {
509
165289
  Node n = NodeBuilder(this, kind::SKOLEM);
510
165289
  setAttribute(n, TypeAttr(), type);
511
165289
  setAttribute(n, TypeCheckedAttr(), true);
512
165289
  if((flags & SKOLEM_EXACT_NAME) == 0) {
513
166310
    stringstream name;
514
83155
    name << prefix << '_' << ++d_skolemCounter;
515
83155
    setAttribute(n, expr::VarNameAttr(), name.str());
516
  } else {
517
82134
    setAttribute(n, expr::VarNameAttr(), prefix);
518
  }
519
165289
  if((flags & SKOLEM_NO_NOTIFY) == 0) {
520
266735
    for(vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
521
180346
      (*i)->nmNotifyNewSkolem(n, comment, (flags & SKOLEM_IS_GLOBAL) == SKOLEM_IS_GLOBAL);
522
    }
523
  }
524
165289
  return n;
525
}
526
527
407
TypeNode NodeManager::mkBagType(TypeNode elementType)
528
{
529
407
  CheckArgument(
530
407
      !elementType.isNull(), elementType, "unexpected NULL element type");
531
407
  Debug("bags") << "making bags type " << elementType << std::endl;
532
407
  return mkTypeNode(kind::BAG_TYPE, elementType);
533
}
534
535
944
TypeNode NodeManager::mkSequenceType(TypeNode elementType)
536
{
537
944
  CheckArgument(
538
944
      !elementType.isNull(), elementType, "unexpected NULL element type");
539
944
  return mkTypeNode(kind::SEQUENCE_TYPE, elementType);
540
}
541
542
2245
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
4490
  std::vector<DType> datatypes;
547
2245
  datatypes.push_back(datatype);
548
4490
  std::vector<TypeNode> result = mkMutualDatatypeTypes(datatypes, flags);
549
2245
  Assert(result.size() == 1);
550
4490
  return result.front();
551
}
552
553
2245
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
554
    const std::vector<DType>& datatypes, uint32_t flags)
555
{
556
4490
  std::set<TypeNode> unresolvedTypes;
557
4490
  return mkMutualDatatypeTypes(datatypes, unresolvedTypes, flags);
558
}
559
560
4136
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
561
    const std::vector<DType>& datatypes,
562
    const std::set<TypeNode>& unresolvedTypes,
563
    uint32_t flags)
564
{
565
8272
  NodeManagerScope nms(this);
566
8272
  std::map<std::string, TypeNode> nameResolutions;
567
4136
  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
9585
  for (const DType& dt : datatypes)
575
  {
576
5449
    uint32_t index = d_dtypes.size();
577
5449
    d_dtypes.push_back(std::unique_ptr<DType>(new DType(dt)));
578
5449
    DType* dtp = d_dtypes.back().get();
579
10898
    TypeNode typeNode;
580
5449
    if (dtp->getNumParameters() == 0)
581
    {
582
5378
      typeNode = mkTypeConst(DatatypeIndexConstant(index));
583
    }
584
    else
585
    {
586
142
      TypeNode cons = mkTypeConst(DatatypeIndexConstant(index));
587
142
      std::vector<TypeNode> params;
588
71
      params.push_back(cons);
589
164
      for (uint32_t ip = 0; ip < dtp->getNumParameters(); ++ip)
590
      {
591
93
        params.push_back(dtp->getParameter(ip));
592
      }
593
594
71
      typeNode = mkTypeNode(kind::PARAMETRIC_DATATYPE, params);
595
    }
596
5449
    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
5449
    nameResolutions.insert(std::make_pair(dtp->getName(), typeNode));
602
5449
    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
8272
  std::vector<TypeNode> paramTypes;
615
8272
  std::vector<TypeNode> paramReplacements;
616
8272
  std::vector<TypeNode> placeholders;  // to hold the "unresolved placeholders"
617
8272
  std::vector<TypeNode> replacements;  // to hold our final, resolved types
618
7332
  for (const TypeNode& ut : unresolvedTypes)
619
  {
620
6392
    std::string name = ut.getAttribute(expr::VarNameAttr());
621
    std::map<std::string, TypeNode>::const_iterator resolver =
622
3196
        nameResolutions.find(name);
623
3196
    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
3196
    if (ut.isSort())
633
    {
634
3143
      placeholders.push_back(ut);
635
3143
      replacements.push_back((*resolver).second);
636
    }
637
    else
638
    {
639
53
      Assert(ut.isSortConstructor());
640
53
      paramTypes.push_back(ut);
641
53
      paramReplacements.push_back((*resolver).second);
642
    }
643
  }
644
645
  // Lastly, perform the final resolutions and checks.
646
9585
  for (const TypeNode& ut : dtts)
647
  {
648
5449
    const DType& dt = ut.getDType();
649
5449
    if (!dt.isResolved())
650
    {
651
5449
      const_cast<DType&>(dt).resolve(nameResolutions,
652
                                     placeholders,
653
                                     replacements,
654
                                     paramTypes,
655
                                     paramReplacements);
656
    }
657
    // Check the datatype has been resolved properly.
658
20771
    for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
659
    {
660
15322
      const DTypeConstructor& c = dt[i];
661
30644
      TypeNode testerType CVC5_UNUSED = c.getTester().getType();
662
15322
      Assert(c.isResolved() && testerType.isTester() && testerType[0] == ut)
663
          << "malformed tester in datatype post-resolution";
664
30644
      TypeNode ctorType CVC5_UNUSED = c.getConstructor().getType();
665
15322
      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
30756
      for (size_t j = 0, nargs = c.getNumArgs(); j < nargs; j++)
671
      {
672
15434
        const DTypeSelector& a = c[j];
673
30868
        TypeNode selectorType = a.getType();
674
15434
        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
15434
        if (selectorType.getRangeType().isFunctionLike())
681
        {
682
          throw Exception("cannot put function-like things in datatypes");
683
        }
684
      }
685
    }
686
  }
687
688
9699
  for (NodeManagerListener* nml : d_listeners)
689
  {
690
5563
    nml->nmNotifyNewDatatypes(dtts, flags);
691
  }
692
693
8272
  return dtts;
694
}
695
696
15322
TypeNode NodeManager::mkConstructorType(const std::vector<TypeNode>& args,
697
                                        TypeNode range)
698
{
699
30644
  std::vector<TypeNode> sorts = args;
700
15322
  sorts.push_back(range);
701
30644
  return mkTypeNode(kind::CONSTRUCTOR_TYPE, sorts);
702
}
703
704
17456
TypeNode NodeManager::mkSelectorType(TypeNode domain, TypeNode range)
705
{
706
17456
  CheckArgument(
707
17456
      domain.isDatatype(), domain, "cannot create non-datatype selector type");
708
17456
  return mkTypeNode(kind::SELECTOR_TYPE, domain, range);
709
}
710
711
15322
TypeNode NodeManager::mkTesterType(TypeNode domain)
712
{
713
15322
  CheckArgument(
714
15322
      domain.isDatatype(), domain, "cannot create non-datatype tester");
715
15322
  return mkTypeNode(kind::TESTER_TYPE, domain);
716
}
717
718
15434
TypeNode NodeManager::mkDatatypeUpdateType(TypeNode domain, TypeNode range)
719
{
720
15434
  CheckArgument(
721
15434
      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
15434
  return mkTypeNode(kind::UPDATER_TYPE, domain, range);
725
}
726
727
30217
TypeNode NodeManager::TupleTypeCache::getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index ) {
728
30217
  if( index==types.size() ){
729
11123
    if( d_data.isNull() ){
730
4166
      std::stringstream sst;
731
2083
      sst << "__cvc5_tuple";
732
3128
      for (unsigned i = 0; i < types.size(); ++ i) {
733
1045
        sst << "_" << types[i];
734
      }
735
4166
      DType dt(sst.str());
736
2083
      dt.setTuple();
737
4166
      std::stringstream ssc;
738
2083
      ssc << sst.str() << "_ctor";
739
      std::shared_ptr<DTypeConstructor> c =
740
4166
          std::make_shared<DTypeConstructor>(ssc.str());
741
3128
      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
2083
      dt.addConstructor(c);
747
2083
      d_data = nm->mkDatatypeType(dt);
748
2083
      Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
749
    }
750
11123
    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
55156
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& sorts)
787
{
788
55156
  Assert(sorts.size() >= 2);
789
55156
  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
5333
TypeNode NodeManager::mkFunctionType(const TypeNode& domain,
802
                                     const TypeNode& range)
803
{
804
10666
  std::vector<TypeNode> sorts;
805
5333
  sorts.push_back(domain);
806
5333
  sorts.push_back(range);
807
10666
  return mkFunctionType(sorts);
808
}
809
810
42707
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& argTypes,
811
                                     const TypeNode& range)
812
{
813
42707
  Assert(argTypes.size() >= 1);
814
85414
  std::vector<TypeNode> sorts(argTypes);
815
42707
  sorts.push_back(range);
816
85414
  return mkFunctionType(sorts);
817
}
818
819
11123
TypeNode NodeManager::mkTupleType(const std::vector<TypeNode>& types) {
820
22246
  std::vector< TypeNode > ts;
821
11123
  Debug("tuprec-debug") << "Make tuple type : ";
822
30217
  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
11123
  Debug("tuprec-debug") << std::endl;
828
22246
  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
2
size_t NodeManager::poolSize() const{
849
2
  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
7810
TypeNode NodeManager::mkSort(const std::string& name, uint32_t flags) {
864
15620
  NodeBuilder nb(this, kind::SORT_TYPE);
865
15620
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
866
7810
  nb << sortTag;
867
7810
  TypeNode tn = nb.constructTypeNode();
868
7810
  setAttribute(tn, expr::VarNameAttr(), name);
869
18942
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
870
11132
    (*i)->nmNotifyNewSort(tn, flags);
871
  }
872
15620
  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
94
TypeNode NodeManager::mkSortConstructor(const std::string& name,
902
                                        size_t arity,
903
                                        uint32_t flags)
904
{
905
94
  Assert(arity > 0);
906
188
  NodeBuilder nb(this, kind::SORT_TYPE);
907
188
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
908
94
  nb << sortTag;
909
94
  TypeNode type = nb.constructTypeNode();
910
94
  setAttribute(type, expr::VarNameAttr(), name);
911
94
  setAttribute(type, expr::SortArityAttr(), arity);
912
194
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
913
100
    (*i)->nmNotifyNewSortConstructor(type, flags);
914
  }
915
188
  return type;
916
}
917
918
180451
Node NodeManager::mkVar(const std::string& name, const TypeNode& type)
919
{
920
180451
  Node n = NodeBuilder(this, kind::VARIABLE);
921
180451
  setAttribute(n, TypeAttr(), type);
922
180451
  setAttribute(n, TypeCheckedAttr(), true);
923
180451
  setAttribute(n, expr::VarNameAttr(), name);
924
385475
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
925
205024
    (*i)->nmNotifyNewVar(n);
926
  }
927
180451
  return n;
928
}
929
930
611294
Node NodeManager::mkBoundVar(const std::string& name, const TypeNode& type) {
931
611294
  Node n = mkBoundVar(type);
932
611294
  setAttribute(n, expr::VarNameAttr(), name);
933
611294
  return n;
934
}
935
936
3163
Node NodeManager::getBoundVarListForFunctionType( TypeNode tn ) {
937
3163
  Assert(tn.isFunction());
938
3163
  Node bvl = tn.getAttribute(LambdaBoundVarListAttr());
939
3163
  if( bvl.isNull() ){
940
362
    std::vector< Node > vars;
941
441
    for( unsigned i=0; i<tn.getNumChildren()-1; i++ ){
942
260
      vars.push_back(mkBoundVar(tn[i]));
943
    }
944
181
    bvl = mkNode(kind::BOUND_VAR_LIST, vars);
945
181
    Trace("functions") << "Make standard bound var list " << bvl << " for " << tn << std::endl;
946
181
    tn.setAttribute(LambdaBoundVarListAttr(),bvl);
947
  }
948
3163
  return bvl;
949
}
950
951
1066377
Node NodeManager::mkAssociative(Kind kind, const std::vector<Node>& children)
952
{
953
1066377
  AlwaysAssert(kind::isAssociative(kind)) << "Illegal kind in mkAssociative";
954
955
1066377
  const unsigned int max = kind::metakind::getMaxArityForKind(kind);
956
1066377
  size_t numChildren = children.size();
957
958
  /* If the number of children is within bounds, then there's nothing to do. */
959
1066377
  if (numChildren <= max)
960
  {
961
1066377
    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
708
Node NodeManager::mkLeftAssociative(Kind kind,
1005
                                    const std::vector<Node>& children)
1006
{
1007
708
  Node n = children[0];
1008
5139
  for (size_t i = 1, size = children.size(); i < size; i++)
1009
  {
1010
4431
    n = mkNode(kind, n, children[i]);
1011
  }
1012
708
  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
768
Node NodeManager::mkChain(Kind kind, const std::vector<Node>& children)
1027
{
1028
768
  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
1536
  std::vector<Node> cchildren;
1035
3949
  for (size_t i = 0, nargsmo = children.size() - 1; i < nargsmo; i++)
1036
  {
1037
3181
    cchildren.push_back(mkNode(kind, children[i], children[i + 1]));
1038
  }
1039
768
  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
630224
Node NodeManager::mkBoundVar(const TypeNode& type) {
1054
630224
  Node n = NodeBuilder(this, kind::BOUND_VARIABLE);
1055
630224
  setAttribute(n, TypeAttr(), type);
1056
630224
  setAttribute(n, TypeCheckedAttr(), true);
1057
630224
  return n;
1058
}
1059
1060
58803
Node NodeManager::mkInstConstant(const TypeNode& type) {
1061
58803
  Node n = NodeBuilder(this, kind::INST_CONSTANT);
1062
58803
  n.setAttribute(TypeAttr(), type);
1063
58803
  n.setAttribute(TypeCheckedAttr(), true);
1064
58803
  return n;
1065
}
1066
1067
841
Node NodeManager::mkBooleanTermVariable() {
1068
841
  Node n = NodeBuilder(this, kind::BOOLEAN_TERM_VARIABLE);
1069
841
  n.setAttribute(TypeAttr(), booleanType());
1070
841
  n.setAttribute(TypeCheckedAttr(), true);
1071
841
  return n;
1072
}
1073
1074
7436
Node NodeManager::mkNullaryOperator(const TypeNode& type, Kind k) {
1075
7436
  std::map< TypeNode, Node >::iterator it = d_unique_vars[k].find( type );
1076
7436
  if( it==d_unique_vars[k].end() ){
1077
10092
    Node n = NodeBuilder(this, k).constructNode();
1078
5046
    setAttribute(n, TypeAttr(), type);
1079
    //setAttribute(n, TypeCheckedAttr(), true);
1080
5046
    d_unique_vars[k][type] = n;
1081
5046
    Assert(n.getMetaKind() == kind::metakind::NULLARY_OPERATOR);
1082
5046
    return n;
1083
  }else{
1084
2390
    return it->second;
1085
  }
1086
}
1087
1088
8860
Node NodeManager::mkSingleton(const TypeNode& t, const TNode n)
1089
{
1090
17720
  Assert(n.getType().isSubtypeOf(t))
1091
8860
      << "Invalid operands for mkSingleton. The type '" << n.getType()
1092
8860
      << "' of node '" << n << "' is not a subtype of '" << t << "'."
1093
      << std::endl;
1094
17720
  Node op = mkConst(SingletonOp(t));
1095
8860
  Node singleton = mkNode(kind::SINGLETON, op, n);
1096
17720
  return singleton;
1097
}
1098
1099
322
Node NodeManager::mkBag(const TypeNode& t, const TNode n, const TNode m)
1100
{
1101
644
  Assert(n.getType().isSubtypeOf(t))
1102
322
      << "Invalid operands for mkBag. The type '" << n.getType()
1103
322
      << "' of node '" << n << "' is not a subtype of '" << t << "'."
1104
      << std::endl;
1105
644
  Node op = mkConst(MakeBagOp(t));
1106
322
  Node bag = mkNode(kind::MK_BAG, op, n, m);
1107
644
  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
47993524
bool NodeManager::safeToReclaimZombies() const{
1118
  // FIXME multithreading
1119
47993524
  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
98
Kind NodeManager::getKindForFunction(TNode fun)
1131
{
1132
196
  TypeNode tn = fun.getType();
1133
98
  if (tn.isFunction())
1134
  {
1135
11
    return kind::APPLY_UF;
1136
  }
1137
87
  else if (tn.isConstructor())
1138
  {
1139
22
    return kind::APPLY_CONSTRUCTOR;
1140
  }
1141
65
  else if (tn.isSelector())
1142
  {
1143
39
    return kind::APPLY_SELECTOR;
1144
  }
1145
26
  else if (tn.isTester())
1146
  {
1147
26
    return kind::APPLY_TESTER;
1148
  }
1149
  return kind::UNDEFINED_KIND;
1150
}
1151
1152
2416
Node NodeManager::mkNode(Kind kind, std::initializer_list<TNode> children)
1153
{
1154
4832
  NodeBuilder nb(this, kind);
1155
2416
  nb.append(children.begin(), children.end());
1156
4832
  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
29280
}  // namespace cvc5