GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 466 546 85.3 %
Date: 2021-11-07 Branches: 597 1672 35.7 %

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