GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 501 581 86.2 %
Date: 2021-09-21 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
229286
  ScopedBool(bool& value) :
55
229286
    d_value(value) {
56
57
229286
    Debug("gc") << ">> setting ScopedBool\n";
58
229286
    d_value = true;
59
229286
  }
60
61
458572
  ~ScopedBool() {
62
229286
    Debug("gc") << "<< clearing ScopedBool\n";
63
229286
    d_value = false;
64
229286
  }
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
31323593
  NVReclaim(NodeValue*& deletionField) :
75
31323593
    d_deletionField(deletionField) {
76
77
31323593
    Debug("gc") << ">> setting NVRECLAIM field\n";
78
31323593
  }
79
80
62647186
  ~NVReclaim() {
81
31323593
    Debug("gc") << "<< clearing NVRECLAIM field\n";
82
31323593
    d_deletionField = NULL;
83
31323593
  }
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
9863
NodeManager::NodeManager()
96
9863
    : d_skManager(new SkolemManager),
97
9863
      d_bvManager(new BoundVarManager),
98
      d_initialized(false),
99
      next_id(0),
100
9863
      d_attrManager(new expr::attr::AttributeManager()),
101
      d_nodeUnderDeletion(nullptr),
102
      d_inReclaimZombies(false),
103
      d_abstractValueCount(0),
104
39452
      d_skolemCounter(0)
105
{
106
9863
}
107
108
36485922112
NodeManager* NodeManager::currentNM()
109
{
110
36485922112
  thread_local static NodeManager nm;
111
36485922112
  return &nm;
112
}
113
114
215836
bool NodeManager::isNAryKind(Kind k)
115
{
116
215836
  return kind::metakind::getMaxArityForKind(k) == expr::NodeValue::MAX_CHILDREN;
117
}
118
119
20000480
TypeNode NodeManager::booleanType()
120
{
121
20000480
  return mkTypeConst<TypeConstant>(BOOLEAN_TYPE);
122
}
123
124
4715920
TypeNode NodeManager::integerType()
125
{
126
4715920
  return mkTypeConst<TypeConstant>(INTEGER_TYPE);
127
}
128
129
4821551
TypeNode NodeManager::realType()
130
{
131
4821551
  return mkTypeConst<TypeConstant>(REAL_TYPE);
132
}
133
134
157369
TypeNode NodeManager::stringType()
135
{
136
157369
  return mkTypeConst<TypeConstant>(STRING_TYPE);
137
}
138
139
34742
TypeNode NodeManager::regExpType()
140
{
141
34742
  return mkTypeConst<TypeConstant>(REGEXP_TYPE);
142
}
143
144
9542
TypeNode NodeManager::roundingModeType()
145
{
146
9542
  return mkTypeConst<TypeConstant>(ROUNDINGMODE_TYPE);
147
}
148
149
198278
TypeNode NodeManager::boundVarListType()
150
{
151
198278
  return mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE);
152
}
153
154
10346
TypeNode NodeManager::instPatternType()
155
{
156
10346
  return mkTypeConst<TypeConstant>(INST_PATTERN_TYPE);
157
}
158
159
23854
TypeNode NodeManager::instPatternListType()
160
{
161
23854
  return mkTypeConst<TypeConstant>(INST_PATTERN_LIST_TYPE);
162
}
163
164
7565
TypeNode NodeManager::builtinOperatorType()
165
{
166
7565
  return mkTypeConst<TypeConstant>(BUILTIN_OPERATOR_TYPE);
167
}
168
169
483608
TypeNode NodeManager::mkBitVectorType(unsigned size)
170
{
171
483608
  return mkTypeConst<BitVectorSize>(BitVectorSize(size));
172
}
173
174
1170268
TypeNode NodeManager::sExprType()
175
{
176
1170268
  return mkTypeConst<TypeConstant>(SEXPR_TYPE);
177
}
178
179
6702
TypeNode NodeManager::mkFloatingPointType(unsigned exp, unsigned sig)
180
{
181
6702
  return mkTypeConst<FloatingPointSize>(FloatingPointSize(exp, sig));
182
}
183
184
5361
TypeNode NodeManager::mkFloatingPointType(FloatingPointSize fs)
185
{
186
5361
  return mkTypeConst<FloatingPointSize>(fs);
187
}
188
189
10679
void NodeManager::init() {
190
10679
  if (d_initialized)
191
  {
192
963
    return;
193
  }
194
9716
  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
9716
  poolInsert( &expr::NodeValue::null() );
200
201
3186848
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
202
3177132
    Kind k = Kind(i);
203
204
3177132
    if(hasOperator(k)) {
205
2652468
      d_operators[i] = mkConst(Kind(k));
206
    }
207
  }
208
}
209
210
19726
NodeManager::~NodeManager() {
211
  // Destroy skolem and bound var manager before cleaning up attributes and
212
  // zombies
213
9863
  d_skManager = nullptr;
214
9863
  d_bvManager = nullptr;
215
216
  {
217
19726
    ScopedBool dontGC(d_inReclaimZombies);
218
    // hopefully by this point all SmtEngines have been deleted
219
    // already, along with all their attributes
220
9863
    d_attrManager->deleteAllAttributes();
221
  }
222
223
3235064
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
224
3225201
    d_operators[i] = Node::null();
225
  }
226
227
9863
  d_unique_vars.clear();
228
229
19726
  TypeNode dummy;
230
9863
  d_tt_cache.d_children.clear();
231
9863
  d_tt_cache.d_data = dummy;
232
9863
  d_rt_cache.d_children.clear();
233
9863
  d_rt_cache.d_data = dummy;
234
235
  // clear the datatypes
236
9863
  d_dtypes.clear();
237
238
9863
  Assert(!d_attrManager->inGarbageCollection());
239
240
19726
  std::vector<NodeValue*> order = TopologicalSort(d_maxedOut);
241
9863
  d_maxedOut.clear();
242
243
443159
  while (!d_zombies.empty() || !order.empty()) {
244
216648
    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
216641
      reclaimZombies();
257
    }
258
  }
259
260
9863
  if (d_initialized)
261
  {
262
9716
    poolRemove(&expr::NodeValue::null());
263
  }
264
265
9863
  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
9863
  delete d_attrManager;
281
9863
  d_attrManager = NULL;
282
9863
}
283
284
4341327
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
4341327
  Assert(index < d_dtypes.size());
289
4341327
  return *d_dtypes[index];
290
}
291
292
219423
void NodeManager::reclaimZombies() {
293
  // FIXME multithreading
294
219423
  Assert(!d_attrManager->inGarbageCollection());
295
296
219423
  Debug("gc") << "reclaiming " << d_zombies.size() << " zombie(s)!\n";
297
298
  // during reclamation, reclaimZombies() is never supposed to be called
299
219423
  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
438846
  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
438846
  vector<NodeValue*> zombies;
320
219423
  zombies.reserve(d_zombies.size());
321
219423
  remove_copy_if(d_zombies.begin(),
322
                 d_zombies.end(),
323
                 back_inserter(zombies),
324
219423
                 NodeValueReferenceCountNonZero());
325
219423
  d_zombies.clear();
326
327
#ifdef _LIBCPP_VERSION
328
  NodeValue* last = NULL;
329
#endif
330
31543016
  for(vector<NodeValue*>::iterator i = zombies.begin();
331
31543016
      i != zombies.end();
332
      ++i) {
333
31323593
    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
31323593
    if(nv->d_rc == 0) {
345
31323593
      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
31323593
      kind::MetaKind mk = nv->getMetaKind();
354
31323593
      if(mk != kind::metakind::VARIABLE && mk != kind::metakind::NULLARY_OPERATOR) {
355
30192477
        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
62647186
      NVReclaim rc(d_nodeUnderDeletion);
362
31323593
      d_nodeUnderDeletion = nv;
363
364
      // remove attributes
365
      { // notify listeners of deleted node
366
62647186
        TNode n;
367
31323593
        n.d_nv = nv;
368
31323593
        nv->d_rc = 1; // so that TNode doesn't assert-fail
369
55885121
        for (NodeManagerListener* listener : d_listeners)
370
        {
371
24561528
          listener->nmNotifyDeleteNode(n);
372
        }
373
        // this would mean that one of the listeners stowed away
374
        // a reference to this node!
375
31323593
        Assert(nv->d_rc == 1);
376
      }
377
31323593
      nv->d_rc = 0;
378
31323593
      d_attrManager->deleteAllAttributes(nv);
379
380
      // decr ref counts of children
381
31323593
      nv->decrRefCounts();
382
31323593
      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
3209016
        kind::metakind::deleteNodeValueConstant(nv);
391
      }
392
31323593
      free(nv);
393
    }
394
  }
395
219423
}/* NodeManager::reclaimZombies() */
396
397
9867
std::vector<NodeValue*> NodeManager::TopologicalSort(
398
    const std::vector<NodeValue*>& roots) {
399
9867
  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
19734
  std::vector<std::pair<bool, NodeValue*> > stack;
403
  // Nodes that have been visited in both pre- and postorder
404
19734
  NodeValueIDSet visited;
405
19734
  const NodeValueIDSet root_set(roots.begin(), roots.end());
406
407
9880
  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
9867
  Assert(order.size() == roots.size());
439
19734
  return order;
440
} /* NodeManager::TopologicalSort() */
441
442
745928822
TypeNode NodeManager::getType(TNode n, bool check)
443
{
444
745928822
  TypeNode typeNode;
445
745928822
  bool hasType = getAttribute(n, TypeAttr(), typeNode);
446
745928822
  bool needsCheck = check && !getAttribute(n, TypeCheckedAttr());
447
448
449
745928822
  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
745928822
  bool doTypeCheck = false;
454
#else
455
  bool doTypeCheck = true;
456
#endif
457
745928822
  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
745928822
  } else if( !hasType || needsCheck ) {
491
    /* We can compute the type top-down, without worrying about
492
       deep recursion. */
493
27341146
    Assert(check || n.getMetaKind() != kind::metakind::NULLARY_OPERATOR);
494
27341146
    typeNode = TypeChecker::computeType(this, n, check);
495
  }
496
497
  /* The type should be have been computed and stored. */
498
745928361
  Assert(hasAttribute(n, TypeAttr()));
499
  /* The check should have happened, if we asked for it. */
500
745928361
  Assert(!check || getAttribute(n, TypeCheckedAttr()));
501
502
745928361
  Debug("getType") << "type of " << &n << " " <<  n << " is " << typeNode << endl;
503
745928361
  return typeNode;
504
}
505
506
169197
Node NodeManager::mkSkolem(const std::string& prefix, const TypeNode& type, const std::string& comment, int flags) {
507
169197
  Node n = NodeBuilder(this, kind::SKOLEM);
508
169197
  setAttribute(n, TypeAttr(), type);
509
169197
  setAttribute(n, TypeCheckedAttr(), true);
510
169197
  if((flags & SKOLEM_EXACT_NAME) == 0) {
511
161458
    stringstream name;
512
80729
    name << prefix << '_' << ++d_skolemCounter;
513
80729
    setAttribute(n, expr::VarNameAttr(), name.str());
514
  } else {
515
88468
    setAttribute(n, expr::VarNameAttr(), prefix);
516
  }
517
169197
  if((flags & SKOLEM_NO_NOTIFY) == 0) {
518
261138
    for(vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
519
175847
      (*i)->nmNotifyNewSkolem(n, comment, (flags & SKOLEM_IS_GLOBAL) == SKOLEM_IS_GLOBAL);
520
    }
521
  }
522
169197
  return n;
523
}
524
525
398
TypeNode NodeManager::mkBagType(TypeNode elementType)
526
{
527
398
  CheckArgument(
528
398
      !elementType.isNull(), elementType, "unexpected NULL element type");
529
398
  Debug("bags") << "making bags type " << elementType << std::endl;
530
398
  return mkTypeNode(kind::BAG_TYPE, elementType);
531
}
532
533
935
TypeNode NodeManager::mkSequenceType(TypeNode elementType)
534
{
535
935
  CheckArgument(
536
935
      !elementType.isNull(), elementType, "unexpected NULL element type");
537
935
  return mkTypeNode(kind::SEQUENCE_TYPE, elementType);
538
}
539
540
2226
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
4452
  std::vector<DType> datatypes;
545
2226
  datatypes.push_back(datatype);
546
4452
  std::vector<TypeNode> result = mkMutualDatatypeTypes(datatypes, flags);
547
2226
  Assert(result.size() == 1);
548
4452
  return result.front();
549
}
550
551
2226
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
552
    const std::vector<DType>& datatypes, uint32_t flags)
553
{
554
4452
  std::set<TypeNode> unresolvedTypes;
555
4452
  return mkMutualDatatypeTypes(datatypes, unresolvedTypes, flags);
556
}
557
558
4209
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
559
    const std::vector<DType>& datatypes,
560
    const std::set<TypeNode>& unresolvedTypes,
561
    uint32_t flags)
562
{
563
8418
  std::map<std::string, TypeNode> nameResolutions;
564
4209
  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
9802
  for (const DType& dt : datatypes)
572
  {
573
5593
    uint32_t index = d_dtypes.size();
574
5593
    d_dtypes.push_back(std::unique_ptr<DType>(new DType(dt)));
575
5593
    DType* dtp = d_dtypes.back().get();
576
11186
    TypeNode typeNode;
577
5593
    if (dtp->getNumParameters() == 0)
578
    {
579
5519
      typeNode = mkTypeConst(DatatypeIndexConstant(index));
580
    }
581
    else
582
    {
583
148
      TypeNode cons = mkTypeConst(DatatypeIndexConstant(index));
584
148
      std::vector<TypeNode> params;
585
74
      params.push_back(cons);
586
170
      for (uint32_t ip = 0; ip < dtp->getNumParameters(); ++ip)
587
      {
588
96
        params.push_back(dtp->getParameter(ip));
589
      }
590
591
74
      typeNode = mkTypeNode(kind::PARAMETRIC_DATATYPE, params);
592
    }
593
5593
    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
5593
    nameResolutions.insert(std::make_pair(dtp->getName(), typeNode));
599
5593
    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
8418
  std::vector<TypeNode> paramTypes;
612
8418
  std::vector<TypeNode> paramReplacements;
613
8418
  std::vector<TypeNode> placeholders;  // to hold the "unresolved placeholders"
614
8418
  std::vector<TypeNode> replacements;  // to hold our final, resolved types
615
7568
  for (const TypeNode& ut : unresolvedTypes)
616
  {
617
6718
    std::string name = ut.getAttribute(expr::VarNameAttr());
618
    std::map<std::string, TypeNode>::const_iterator resolver =
619
3359
        nameResolutions.find(name);
620
3359
    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
3359
    if (ut.isSort())
630
    {
631
3303
      placeholders.push_back(ut);
632
3303
      replacements.push_back((*resolver).second);
633
    }
634
    else
635
    {
636
56
      Assert(ut.isSortConstructor());
637
56
      paramTypes.push_back(ut);
638
56
      paramReplacements.push_back((*resolver).second);
639
    }
640
  }
641
642
  // Lastly, perform the final resolutions and checks.
643
9802
  for (const TypeNode& ut : dtts)
644
  {
645
5593
    const DType& dt = ut.getDType();
646
5593
    if (!dt.isResolved())
647
    {
648
5593
      const_cast<DType&>(dt).resolve(nameResolutions,
649
                                     placeholders,
650
                                     replacements,
651
                                     paramTypes,
652
                                     paramReplacements);
653
    }
654
    // Check the datatype has been resolved properly.
655
22109
    for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
656
    {
657
16516
      const DTypeConstructor& c = dt[i];
658
33032
      TypeNode testerType CVC5_UNUSED = c.getTester().getType();
659
16516
      Assert(c.isResolved() && testerType.isTester() && testerType[0] == ut)
660
          << "malformed tester in datatype post-resolution";
661
33032
      TypeNode ctorType CVC5_UNUSED = c.getConstructor().getType();
662
16516
      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
33245
      for (size_t j = 0, nargs = c.getNumArgs(); j < nargs; j++)
668
      {
669
16729
        const DTypeSelector& a = c[j];
670
33458
        TypeNode selectorType = a.getType();
671
16729
        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
16729
        if (selectorType.getRangeType().isFunctionLike())
678
        {
679
          throw Exception("cannot put function-like things in datatypes");
680
        }
681
      }
682
    }
683
  }
684
685
9934
  for (NodeManagerListener* nml : d_listeners)
686
  {
687
5725
    nml->nmNotifyNewDatatypes(dtts, flags);
688
  }
689
690
8418
  return dtts;
691
}
692
693
16516
TypeNode NodeManager::mkConstructorType(const std::vector<TypeNode>& args,
694
                                        TypeNode range)
695
{
696
33032
  std::vector<TypeNode> sorts = args;
697
16516
  sorts.push_back(range);
698
33032
  return mkTypeNode(kind::CONSTRUCTOR_TYPE, sorts);
699
}
700
701
17484
TypeNode NodeManager::mkSelectorType(TypeNode domain, TypeNode range)
702
{
703
17484
  CheckArgument(
704
17484
      domain.isDatatype(), domain, "cannot create non-datatype selector type");
705
17484
  return mkTypeNode(kind::SELECTOR_TYPE, domain, range);
706
}
707
708
16516
TypeNode NodeManager::mkTesterType(TypeNode domain)
709
{
710
16516
  CheckArgument(
711
16516
      domain.isDatatype(), domain, "cannot create non-datatype tester");
712
16516
  return mkTypeNode(kind::TESTER_TYPE, domain);
713
}
714
715
16729
TypeNode NodeManager::mkDatatypeUpdateType(TypeNode domain, TypeNode range)
716
{
717
16729
  CheckArgument(
718
16729
      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
16729
  return mkTypeNode(kind::UPDATER_TYPE, domain, range);
722
}
723
724
30253
TypeNode NodeManager::TupleTypeCache::getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index ) {
725
30253
  if( index==types.size() ){
726
11159
    if( d_data.isNull() ){
727
4140
      std::stringstream sst;
728
2070
      sst << "__cvc5_tuple";
729
3105
      for (unsigned i = 0; i < types.size(); ++ i) {
730
1035
        sst << "_" << types[i];
731
      }
732
4140
      DType dt(sst.str());
733
2070
      dt.setTuple();
734
4140
      std::stringstream ssc;
735
2070
      ssc << sst.str() << "_ctor";
736
      std::shared_ptr<DTypeConstructor> c =
737
4140
          std::make_shared<DTypeConstructor>(ssc.str());
738
3105
      for (unsigned i = 0; i < types.size(); ++ i) {
739
2070
        std::stringstream ss;
740
1035
        ss << sst.str() << "_stor_" << i;
741
1035
        c->addArg(ss.str().c_str(), types[i]);
742
      }
743
2070
      dt.addConstructor(c);
744
2070
      d_data = nm->mkDatatypeType(dt);
745
2070
      Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
746
    }
747
11159
    return d_data;
748
  }else{
749
19094
    return d_children[types[index]].getTupleType( nm, types, index+1 );
750
  }
751
}
752
753
367
TypeNode NodeManager::RecTypeCache::getRecordType( NodeManager * nm, const Record& rec, unsigned index ) {
754
367
  if (index == rec.size())
755
  {
756
141
    if( d_data.isNull() ){
757
132
      std::stringstream sst;
758
66
      sst << "__cvc5_record";
759
176
      for (const std::pair<std::string, TypeNode>& i : rec)
760
      {
761
110
        sst << "_" << i.first << "_" << i.second;
762
      }
763
132
      DType dt(sst.str());
764
66
      dt.setRecord();
765
132
      std::stringstream ssc;
766
66
      ssc << sst.str() << "_ctor";
767
      std::shared_ptr<DTypeConstructor> c =
768
132
          std::make_shared<DTypeConstructor>(ssc.str());
769
176
      for (const std::pair<std::string, TypeNode>& i : rec)
770
      {
771
110
        c->addArg(i.first, i.second);
772
      }
773
66
      dt.addConstructor(c);
774
66
      d_data = nm->mkDatatypeType(dt);
775
66
      Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
776
    }
777
141
    return d_data;
778
  }
779
226
  return d_children[rec[index].second][rec[index].first].getRecordType(
780
226
      nm, rec, index + 1);
781
}
782
783
55568
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& sorts)
784
{
785
55568
  Assert(sorts.size() >= 2);
786
55568
  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
5429
TypeNode NodeManager::mkFunctionType(const TypeNode& domain,
799
                                     const TypeNode& range)
800
{
801
10858
  std::vector<TypeNode> sorts;
802
5429
  sorts.push_back(domain);
803
5429
  sorts.push_back(range);
804
10858
  return mkFunctionType(sorts);
805
}
806
807
43019
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& argTypes,
808
                                     const TypeNode& range)
809
{
810
43019
  Assert(argTypes.size() >= 1);
811
86038
  std::vector<TypeNode> sorts(argTypes);
812
43019
  sorts.push_back(range);
813
86038
  return mkFunctionType(sorts);
814
}
815
816
11159
TypeNode NodeManager::mkTupleType(const std::vector<TypeNode>& types) {
817
22318
  std::vector< TypeNode > ts;
818
11159
  Debug("tuprec-debug") << "Make tuple type : ";
819
30253
  for (unsigned i = 0; i < types.size(); ++ i) {
820
19094
    CheckArgument(!types[i].isFunctionLike(), types, "cannot put function-like types in tuples");
821
19094
    ts.push_back( types[i] );
822
19094
    Debug("tuprec-debug") << types[i] << " ";
823
  }
824
11159
  Debug("tuprec-debug") << std::endl;
825
22318
  return d_tt_cache.getTupleType( this, ts );
826
}
827
828
141
TypeNode NodeManager::mkRecordType(const Record& rec) {
829
141
  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
7987
TypeNode NodeManager::mkSort(const std::string& name, uint32_t flags) {
861
15974
  NodeBuilder nb(this, kind::SORT_TYPE);
862
15974
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
863
7987
  nb << sortTag;
864
7987
  TypeNode tn = nb.constructTypeNode();
865
7987
  setAttribute(tn, expr::VarNameAttr(), name);
866
19459
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
867
11472
    (*i)->nmNotifyNewSort(tn, flags);
868
  }
869
15974
  return tn;
870
}
871
872
485
TypeNode NodeManager::mkSort(TypeNode constructor,
873
                                    const std::vector<TypeNode>& children,
874
                                    uint32_t flags) {
875
485
  Assert(constructor.getKind() == kind::SORT_TYPE
876
         && constructor.getNumChildren() == 0)
877
      << "expected a sort constructor";
878
485
  Assert(children.size() > 0) << "expected non-zero # of children";
879
485
  Assert(hasAttribute(constructor.d_nv, expr::SortArityAttr())
880
         && hasAttribute(constructor.d_nv, expr::VarNameAttr()))
881
      << "expected a sort constructor";
882
970
  std::string name = getAttribute(constructor.d_nv, expr::VarNameAttr());
883
485
  Assert(getAttribute(constructor.d_nv, expr::SortArityAttr())
884
         == children.size())
885
      << "arity mismatch in application of sort constructor";
886
970
  NodeBuilder nb(this, kind::SORT_TYPE);
887
970
  Node sortTag = Node(constructor.d_nv->d_children[0]);
888
485
  nb << sortTag;
889
485
  nb.append(children);
890
485
  TypeNode type = nb.constructTypeNode();
891
485
  setAttribute(type, expr::VarNameAttr(), name);
892
1114
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
893
629
    (*i)->nmNotifyInstantiateSortConstructor(constructor, type, flags);
894
  }
895
970
  return type;
896
}
897
898
97
TypeNode NodeManager::mkSortConstructor(const std::string& name,
899
                                        size_t arity,
900
                                        uint32_t flags)
901
{
902
97
  Assert(arity > 0);
903
194
  NodeBuilder nb(this, kind::SORT_TYPE);
904
194
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
905
97
  nb << sortTag;
906
97
  TypeNode type = nb.constructTypeNode();
907
97
  setAttribute(type, expr::VarNameAttr(), name);
908
97
  setAttribute(type, expr::SortArityAttr(), arity);
909
200
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
910
103
    (*i)->nmNotifyNewSortConstructor(type, flags);
911
  }
912
194
  return type;
913
}
914
915
177728
Node NodeManager::mkVar(const std::string& name, const TypeNode& type)
916
{
917
177728
  Node n = NodeBuilder(this, kind::VARIABLE);
918
177728
  setAttribute(n, TypeAttr(), type);
919
177728
  setAttribute(n, TypeCheckedAttr(), true);
920
177728
  setAttribute(n, expr::VarNameAttr(), name);
921
380083
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
922
202355
    (*i)->nmNotifyNewVar(n);
923
  }
924
177728
  return n;
925
}
926
927
687579
Node NodeManager::mkBoundVar(const std::string& name, const TypeNode& type) {
928
687579
  Node n = mkBoundVar(type);
929
687579
  setAttribute(n, expr::VarNameAttr(), name);
930
687579
  return n;
931
}
932
933
3221
Node NodeManager::getBoundVarListForFunctionType( TypeNode tn ) {
934
3221
  Assert(tn.isFunction());
935
3221
  Node bvl = tn.getAttribute(LambdaBoundVarListAttr());
936
3221
  if( bvl.isNull() ){
937
358
    std::vector< Node > vars;
938
434
    for( unsigned i=0; i<tn.getNumChildren()-1; i++ ){
939
255
      vars.push_back(mkBoundVar(tn[i]));
940
    }
941
179
    bvl = mkNode(kind::BOUND_VAR_LIST, vars);
942
179
    Trace("functions") << "Make standard bound var list " << bvl << " for " << tn << std::endl;
943
179
    tn.setAttribute(LambdaBoundVarListAttr(),bvl);
944
  }
945
3221
  return bvl;
946
}
947
948
1049120
Node NodeManager::mkAssociative(Kind kind, const std::vector<Node>& children)
949
{
950
1049120
  AlwaysAssert(kind::isAssociative(kind)) << "Illegal kind in mkAssociative";
951
952
1049120
  const unsigned int max = kind::metakind::getMaxArityForKind(kind);
953
1049120
  size_t numChildren = children.size();
954
955
  /* If the number of children is within bounds, then there's nothing to do. */
956
1049120
  if (numChildren <= max)
957
  {
958
1049120
    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
712
Node NodeManager::mkLeftAssociative(Kind kind,
1002
                                    const std::vector<Node>& children)
1003
{
1004
712
  Node n = children[0];
1005
5156
  for (size_t i = 1, size = children.size(); i < size; i++)
1006
  {
1007
4444
    n = mkNode(kind, n, children[i]);
1008
  }
1009
712
  return n;
1010
}
1011
1012
6
Node NodeManager::mkRightAssociative(Kind kind,
1013
                                     const std::vector<Node>& children)
1014
{
1015
6
  Node n = children[children.size() - 1];
1016
18
  for (size_t i = children.size() - 1; i > 0;)
1017
  {
1018
12
    n = mkNode(kind, children[--i], n);
1019
  }
1020
6
  return n;
1021
}
1022
1023
769
Node NodeManager::mkChain(Kind kind, const std::vector<Node>& children)
1024
{
1025
769
  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
1538
  std::vector<Node> cchildren;
1032
3952
  for (size_t i = 0, nargsmo = children.size() - 1; i < nargsmo; i++)
1033
  {
1034
3183
    cchildren.push_back(mkNode(kind, children[i], children[i + 1]));
1035
  }
1036
769
  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
710688
Node NodeManager::mkBoundVar(const TypeNode& type) {
1051
710688
  Node n = NodeBuilder(this, kind::BOUND_VARIABLE);
1052
710688
  setAttribute(n, TypeAttr(), type);
1053
710688
  setAttribute(n, TypeCheckedAttr(), true);
1054
710688
  return n;
1055
}
1056
1057
59458
Node NodeManager::mkInstConstant(const TypeNode& type) {
1058
59458
  Node n = NodeBuilder(this, kind::INST_CONSTANT);
1059
59458
  n.setAttribute(TypeAttr(), type);
1060
59458
  n.setAttribute(TypeCheckedAttr(), true);
1061
59458
  return n;
1062
}
1063
1064
838
Node NodeManager::mkBooleanTermVariable() {
1065
838
  Node n = NodeBuilder(this, kind::BOOLEAN_TERM_VARIABLE);
1066
838
  n.setAttribute(TypeAttr(), booleanType());
1067
838
  n.setAttribute(TypeCheckedAttr(), true);
1068
838
  return n;
1069
}
1070
1071
7274
Node NodeManager::mkNullaryOperator(const TypeNode& type, Kind k) {
1072
7274
  std::map< TypeNode, Node >::iterator it = d_unique_vars[k].find( type );
1073
7274
  if( it==d_unique_vars[k].end() ){
1074
10026
    Node n = NodeBuilder(this, k).constructNode();
1075
5013
    setAttribute(n, TypeAttr(), type);
1076
    //setAttribute(n, TypeCheckedAttr(), true);
1077
5013
    d_unique_vars[k][type] = n;
1078
5013
    Assert(n.getMetaKind() == kind::metakind::NULLARY_OPERATOR);
1079
5013
    return n;
1080
  }else{
1081
2261
    return it->second;
1082
  }
1083
}
1084
1085
8922
Node NodeManager::mkSingleton(const TypeNode& t, const TNode n)
1086
{
1087
17844
  Assert(n.getType().isSubtypeOf(t))
1088
8922
      << "Invalid operands for mkSingleton. The type '" << n.getType()
1089
8922
      << "' of node '" << n << "' is not a subtype of '" << t << "'."
1090
      << std::endl;
1091
17844
  Node op = mkConst(SingletonOp(t));
1092
8922
  Node singleton = mkNode(kind::SINGLETON, op, n);
1093
17844
  return singleton;
1094
}
1095
1096
336
Node NodeManager::mkBag(const TypeNode& t, const TNode n, const TNode m)
1097
{
1098
672
  Assert(n.getType().isSubtypeOf(t))
1099
336
      << "Invalid operands for mkBag. The type '" << n.getType()
1100
336
      << "' of node '" << n << "' is not a subtype of '" << t << "'."
1101
      << std::endl;
1102
672
  Node op = mkConst(MakeBagOp(t));
1103
336
  Node bag = mkNode(kind::MK_BAG, op, n, m);
1104
672
  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
49655942
bool NodeManager::safeToReclaimZombies() const{
1115
  // FIXME multithreading
1116
49655942
  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
2556
Node NodeManager::mkNode(Kind kind, std::initializer_list<TNode> children)
1150
{
1151
5112
  NodeBuilder nb(this, kind);
1152
2556
  nb.append(children.begin(), children.end());
1153
5112
  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
29589
}  // namespace cvc5