GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 501 581 86.2 %
Date: 2021-09-29 Branches: 654 1764 37.1 %

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