GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 500 580 86.2 %
Date: 2021-08-16 Branches: 655 1772 37.0 %

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