GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_manager.cpp Lines: 501 581 86.2 %
Date: 2021-09-18 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
228318
  ScopedBool(bool& value) :
55
228318
    d_value(value) {
56
57
228318
    Debug("gc") << ">> setting ScopedBool\n";
58
228318
    d_value = true;
59
228318
  }
60
61
456636
  ~ScopedBool() {
62
228318
    Debug("gc") << "<< clearing ScopedBool\n";
63
228318
    d_value = false;
64
228318
  }
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
31231066
  NVReclaim(NodeValue*& deletionField) :
75
31231066
    d_deletionField(deletionField) {
76
77
31231066
    Debug("gc") << ">> setting NVRECLAIM field\n";
78
31231066
  }
79
80
62462132
  ~NVReclaim() {
81
31231066
    Debug("gc") << "<< clearing NVRECLAIM field\n";
82
31231066
    d_deletionField = NULL;
83
31231066
  }
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
9858
NodeManager::NodeManager()
96
9858
    : d_skManager(new SkolemManager),
97
9858
      d_bvManager(new BoundVarManager),
98
      d_initialized(false),
99
      next_id(0),
100
9858
      d_attrManager(new expr::attr::AttributeManager()),
101
      d_nodeUnderDeletion(nullptr),
102
      d_inReclaimZombies(false),
103
      d_abstractValueCount(0),
104
39432
      d_skolemCounter(0)
105
{
106
9858
}
107
108
36445665681
NodeManager* NodeManager::currentNM()
109
{
110
36445665681
  thread_local static NodeManager nm;
111
36445665681
  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
19934872
TypeNode NodeManager::booleanType()
120
{
121
19934872
  return mkTypeConst<TypeConstant>(BOOLEAN_TYPE);
122
}
123
124
4715249
TypeNode NodeManager::integerType()
125
{
126
4715249
  return mkTypeConst<TypeConstant>(INTEGER_TYPE);
127
}
128
129
4816639
TypeNode NodeManager::realType()
130
{
131
4816639
  return mkTypeConst<TypeConstant>(REAL_TYPE);
132
}
133
134
157355
TypeNode NodeManager::stringType()
135
{
136
157355
  return mkTypeConst<TypeConstant>(STRING_TYPE);
137
}
138
139
34729
TypeNode NodeManager::regExpType()
140
{
141
34729
  return mkTypeConst<TypeConstant>(REGEXP_TYPE);
142
}
143
144
9524
TypeNode NodeManager::roundingModeType()
145
{
146
9524
  return mkTypeConst<TypeConstant>(ROUNDINGMODE_TYPE);
147
}
148
149
198196
TypeNode NodeManager::boundVarListType()
150
{
151
198196
  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
7562
TypeNode NodeManager::builtinOperatorType()
165
{
166
7562
  return mkTypeConst<TypeConstant>(BUILTIN_OPERATOR_TYPE);
167
}
168
169
469623
TypeNode NodeManager::mkBitVectorType(unsigned size)
170
{
171
469623
  return mkTypeConst<BitVectorSize>(BitVectorSize(size));
172
}
173
174
1170268
TypeNode NodeManager::sExprType()
175
{
176
1170268
  return mkTypeConst<TypeConstant>(SEXPR_TYPE);
177
}
178
179
6687
TypeNode NodeManager::mkFloatingPointType(unsigned exp, unsigned sig)
180
{
181
6687
  return mkTypeConst<FloatingPointSize>(FloatingPointSize(exp, sig));
182
}
183
184
4224
TypeNode NodeManager::mkFloatingPointType(FloatingPointSize fs)
185
{
186
4224
  return mkTypeConst<FloatingPointSize>(fs);
187
}
188
189
10674
void NodeManager::init() {
190
10674
  if (d_initialized)
191
  {
192
963
    return;
193
  }
194
9711
  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
9711
  poolInsert( &expr::NodeValue::null() );
200
201
3185208
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
202
3175497
    Kind k = Kind(i);
203
204
3175497
    if(hasOperator(k)) {
205
2651103
      d_operators[i] = mkConst(Kind(k));
206
    }
207
  }
208
}
209
210
19716
NodeManager::~NodeManager() {
211
  // Destroy skolem and bound var manager before cleaning up attributes and
212
  // zombies
213
9858
  d_skManager = nullptr;
214
9858
  d_bvManager = nullptr;
215
216
  {
217
19716
    ScopedBool dontGC(d_inReclaimZombies);
218
    // hopefully by this point all SmtEngines have been deleted
219
    // already, along with all their attributes
220
9858
    d_attrManager->deleteAllAttributes();
221
  }
222
223
3233424
  for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
224
3223566
    d_operators[i] = Node::null();
225
  }
226
227
9858
  d_unique_vars.clear();
228
229
19716
  TypeNode dummy;
230
9858
  d_tt_cache.d_children.clear();
231
9858
  d_tt_cache.d_data = dummy;
232
9858
  d_rt_cache.d_children.clear();
233
9858
  d_rt_cache.d_data = dummy;
234
235
  // clear the datatypes
236
9858
  d_dtypes.clear();
237
238
9858
  Assert(!d_attrManager->inGarbageCollection());
239
240
19716
  std::vector<NodeValue*> order = TopologicalSort(d_maxedOut);
241
9858
  d_maxedOut.clear();
242
243
441242
  while (!d_zombies.empty() || !order.empty()) {
244
215692
    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
215685
      reclaimZombies();
257
    }
258
  }
259
260
9858
  if (d_initialized)
261
  {
262
9711
    poolRemove(&expr::NodeValue::null());
263
  }
264
265
9858
  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
9858
  delete d_attrManager;
281
9858
  d_attrManager = NULL;
282
9858
}
283
284
4341375
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
4341375
  Assert(index < d_dtypes.size());
289
4341375
  return *d_dtypes[index];
290
}
291
292
218460
void NodeManager::reclaimZombies() {
293
  // FIXME multithreading
294
218460
  Assert(!d_attrManager->inGarbageCollection());
295
296
218460
  Debug("gc") << "reclaiming " << d_zombies.size() << " zombie(s)!\n";
297
298
  // during reclamation, reclaimZombies() is never supposed to be called
299
218460
  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
436920
  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
436920
  vector<NodeValue*> zombies;
320
218460
  zombies.reserve(d_zombies.size());
321
218460
  remove_copy_if(d_zombies.begin(),
322
                 d_zombies.end(),
323
                 back_inserter(zombies),
324
218460
                 NodeValueReferenceCountNonZero());
325
218460
  d_zombies.clear();
326
327
#ifdef _LIBCPP_VERSION
328
  NodeValue* last = NULL;
329
#endif
330
31449526
  for(vector<NodeValue*>::iterator i = zombies.begin();
331
31449526
      i != zombies.end();
332
      ++i) {
333
31231066
    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
31231066
    if(nv->d_rc == 0) {
345
31231066
      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
31231066
      kind::MetaKind mk = nv->getMetaKind();
354
31231066
      if(mk != kind::metakind::VARIABLE && mk != kind::metakind::NULLARY_OPERATOR) {
355
30100030
        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
62462132
      NVReclaim rc(d_nodeUnderDeletion);
362
31231066
      d_nodeUnderDeletion = nv;
363
364
      // remove attributes
365
      { // notify listeners of deleted node
366
62462132
        TNode n;
367
31231066
        n.d_nv = nv;
368
31231066
        nv->d_rc = 1; // so that TNode doesn't assert-fail
369
55762649
        for (NodeManagerListener* listener : d_listeners)
370
        {
371
24531583
          listener->nmNotifyDeleteNode(n);
372
        }
373
        // this would mean that one of the listeners stowed away
374
        // a reference to this node!
375
31231066
        Assert(nv->d_rc == 1);
376
      }
377
31231066
      nv->d_rc = 0;
378
31231066
      d_attrManager->deleteAllAttributes(nv);
379
380
      // decr ref counts of children
381
31231066
      nv->decrRefCounts();
382
31231066
      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
3206384
        kind::metakind::deleteNodeValueConstant(nv);
391
      }
392
31231066
      free(nv);
393
    }
394
  }
395
218460
}/* NodeManager::reclaimZombies() */
396
397
9862
std::vector<NodeValue*> NodeManager::TopologicalSort(
398
    const std::vector<NodeValue*>& roots) {
399
9862
  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
19724
  std::vector<std::pair<bool, NodeValue*> > stack;
403
  // Nodes that have been visited in both pre- and postorder
404
19724
  NodeValueIDSet visited;
405
19724
  const NodeValueIDSet root_set(roots.begin(), roots.end());
406
407
9875
  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
9862
  Assert(order.size() == roots.size());
439
19724
  return order;
440
} /* NodeManager::TopologicalSort() */
441
442
743889979
TypeNode NodeManager::getType(TNode n, bool check)
443
{
444
743889979
  TypeNode typeNode;
445
743889979
  bool hasType = getAttribute(n, TypeAttr(), typeNode);
446
743889979
  bool needsCheck = check && !getAttribute(n, TypeCheckedAttr());
447
448
449
743889979
  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
743889979
  bool doTypeCheck = false;
454
#else
455
  bool doTypeCheck = true;
456
#endif
457
743889979
  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
743889979
  } else if( !hasType || needsCheck ) {
491
    /* We can compute the type top-down, without worrying about
492
       deep recursion. */
493
27250151
    Assert(check || n.getMetaKind() != kind::metakind::NULLARY_OPERATOR);
494
27250151
    typeNode = TypeChecker::computeType(this, n, check);
495
  }
496
497
  /* The type should be have been computed and stored. */
498
743889518
  Assert(hasAttribute(n, TypeAttr()));
499
  /* The check should have happened, if we asked for it. */
500
743889518
  Assert(!check || getAttribute(n, TypeCheckedAttr()));
501
502
743889518
  Debug("getType") << "type of " << &n << " " <<  n << " is " << typeNode << endl;
503
743889518
  return typeNode;
504
}
505
506
169178
Node NodeManager::mkSkolem(const std::string& prefix, const TypeNode& type, const std::string& comment, int flags) {
507
169178
  Node n = NodeBuilder(this, kind::SKOLEM);
508
169178
  setAttribute(n, TypeAttr(), type);
509
169178
  setAttribute(n, TypeCheckedAttr(), true);
510
169178
  if((flags & SKOLEM_EXACT_NAME) == 0) {
511
161418
    stringstream name;
512
80709
    name << prefix << '_' << ++d_skolemCounter;
513
80709
    setAttribute(n, expr::VarNameAttr(), name.str());
514
  } else {
515
88469
    setAttribute(n, expr::VarNameAttr(), prefix);
516
  }
517
169178
  if((flags & SKOLEM_NO_NOTIFY) == 0) {
518
261088
    for(vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
519
175814
      (*i)->nmNotifyNewSkolem(n, comment, (flags & SKOLEM_IS_GLOBAL) == SKOLEM_IS_GLOBAL);
520
    }
521
  }
522
169178
  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
2225
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
4450
  std::vector<DType> datatypes;
545
2225
  datatypes.push_back(datatype);
546
4450
  std::vector<TypeNode> result = mkMutualDatatypeTypes(datatypes, flags);
547
2225
  Assert(result.size() == 1);
548
4450
  return result.front();
549
}
550
551
2225
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
552
    const std::vector<DType>& datatypes, uint32_t flags)
553
{
554
4450
  std::set<TypeNode> unresolvedTypes;
555
4450
  return mkMutualDatatypeTypes(datatypes, unresolvedTypes, flags);
556
}
557
558
4208
std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
559
    const std::vector<DType>& datatypes,
560
    const std::set<TypeNode>& unresolvedTypes,
561
    uint32_t flags)
562
{
563
8416
  std::map<std::string, TypeNode> nameResolutions;
564
4208
  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
9800
  for (const DType& dt : datatypes)
572
  {
573
5592
    uint32_t index = d_dtypes.size();
574
5592
    d_dtypes.push_back(std::unique_ptr<DType>(new DType(dt)));
575
5592
    DType* dtp = d_dtypes.back().get();
576
11184
    TypeNode typeNode;
577
5592
    if (dtp->getNumParameters() == 0)
578
    {
579
5518
      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
5592
    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
5592
    nameResolutions.insert(std::make_pair(dtp->getName(), typeNode));
599
5592
    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
8416
  std::vector<TypeNode> paramTypes;
612
8416
  std::vector<TypeNode> paramReplacements;
613
8416
  std::vector<TypeNode> placeholders;  // to hold the "unresolved placeholders"
614
8416
  std::vector<TypeNode> replacements;  // to hold our final, resolved types
615
7567
  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
9800
  for (const TypeNode& ut : dtts)
644
  {
645
5592
    const DType& dt = ut.getDType();
646
5592
    if (!dt.isResolved())
647
    {
648
5592
      const_cast<DType&>(dt).resolve(nameResolutions,
649
                                     placeholders,
650
                                     replacements,
651
                                     paramTypes,
652
                                     paramReplacements);
653
    }
654
    // Check the datatype has been resolved properly.
655
22107
    for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
656
    {
657
16515
      const DTypeConstructor& c = dt[i];
658
33030
      TypeNode testerType CVC5_UNUSED = c.getTester().getType();
659
16515
      Assert(c.isResolved() && testerType.isTester() && testerType[0] == ut)
660
          << "malformed tester in datatype post-resolution";
661
33030
      TypeNode ctorType CVC5_UNUSED = c.getConstructor().getType();
662
16515
      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
33244
      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
9932
  for (NodeManagerListener* nml : d_listeners)
686
  {
687
5724
    nml->nmNotifyNewDatatypes(dtts, flags);
688
  }
689
690
8416
  return dtts;
691
}
692
693
16515
TypeNode NodeManager::mkConstructorType(const std::vector<TypeNode>& args,
694
                                        TypeNode range)
695
{
696
33030
  std::vector<TypeNode> sorts = args;
697
16515
  sorts.push_back(range);
698
33030
  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
16515
TypeNode NodeManager::mkTesterType(TypeNode domain)
709
{
710
16515
  CheckArgument(
711
16515
      domain.isDatatype(), domain, "cannot create non-datatype tester");
712
16515
  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
30252
TypeNode NodeManager::TupleTypeCache::getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index ) {
725
30252
  if( index==types.size() ){
726
11158
    if( d_data.isNull() ){
727
4138
      std::stringstream sst;
728
2069
      sst << "__cvc5_tuple";
729
3104
      for (unsigned i = 0; i < types.size(); ++ i) {
730
1035
        sst << "_" << types[i];
731
      }
732
4138
      DType dt(sst.str());
733
2069
      dt.setTuple();
734
4138
      std::stringstream ssc;
735
2069
      ssc << sst.str() << "_ctor";
736
      std::shared_ptr<DTypeConstructor> c =
737
4138
          std::make_shared<DTypeConstructor>(ssc.str());
738
3104
      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
2069
      dt.addConstructor(c);
744
2069
      d_data = nm->mkDatatypeType(dt);
745
2069
      Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
746
    }
747
11158
    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
55534
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& sorts)
784
{
785
55534
  Assert(sorts.size() >= 2);
786
55534
  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
42978
TypeNode NodeManager::mkFunctionType(const std::vector<TypeNode>& argTypes,
808
                                     const TypeNode& range)
809
{
810
42978
  Assert(argTypes.size() >= 1);
811
85956
  std::vector<TypeNode> sorts(argTypes);
812
42978
  sorts.push_back(range);
813
85956
  return mkFunctionType(sorts);
814
}
815
816
11158
TypeNode NodeManager::mkTupleType(const std::vector<TypeNode>& types) {
817
22316
  std::vector< TypeNode > ts;
818
11158
  Debug("tuprec-debug") << "Make tuple type : ";
819
30252
  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
11158
  Debug("tuprec-debug") << std::endl;
825
22316
  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
7986
TypeNode NodeManager::mkSort(const std::string& name, uint32_t flags) {
861
15972
  NodeBuilder nb(this, kind::SORT_TYPE);
862
15972
  Node sortTag = NodeBuilder(this, kind::SORT_TAG);
863
7986
  nb << sortTag;
864
7986
  TypeNode tn = nb.constructTypeNode();
865
7986
  setAttribute(tn, expr::VarNameAttr(), name);
866
19456
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
867
11470
    (*i)->nmNotifyNewSort(tn, flags);
868
  }
869
15972
  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
177711
Node NodeManager::mkVar(const std::string& name, const TypeNode& type)
916
{
917
177711
  Node n = NodeBuilder(this, kind::VARIABLE);
918
177711
  setAttribute(n, TypeAttr(), type);
919
177711
  setAttribute(n, TypeCheckedAttr(), true);
920
177711
  setAttribute(n, expr::VarNameAttr(), name);
921
380041
  for(std::vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
922
202330
    (*i)->nmNotifyNewVar(n);
923
  }
924
177711
  return n;
925
}
926
927
687526
Node NodeManager::mkBoundVar(const std::string& name, const TypeNode& type) {
928
687526
  Node n = mkBoundVar(type);
929
687526
  setAttribute(n, expr::VarNameAttr(), name);
930
687526
  return n;
931
}
932
933
3239
Node NodeManager::getBoundVarListForFunctionType( TypeNode tn ) {
934
3239
  Assert(tn.isFunction());
935
3239
  Node bvl = tn.getAttribute(LambdaBoundVarListAttr());
936
3239
  if( bvl.isNull() ){
937
366
    std::vector< Node > vars;
938
444
    for( unsigned i=0; i<tn.getNumChildren()-1; i++ ){
939
261
      vars.push_back(mkBoundVar(tn[i]));
940
    }
941
183
    bvl = mkNode(kind::BOUND_VAR_LIST, vars);
942
183
    Trace("functions") << "Make standard bound var list " << bvl << " for " << tn << std::endl;
943
183
    tn.setAttribute(LambdaBoundVarListAttr(),bvl);
944
  }
945
3239
  return bvl;
946
}
947
948
1049114
Node NodeManager::mkAssociative(Kind kind, const std::vector<Node>& children)
949
{
950
1049114
  AlwaysAssert(kind::isAssociative(kind)) << "Illegal kind in mkAssociative";
951
952
1049114
  const unsigned int max = kind::metakind::getMaxArityForKind(kind);
953
1049114
  size_t numChildren = children.size();
954
955
  /* If the number of children is within bounds, then there's nothing to do. */
956
1049114
  if (numChildren <= max)
957
  {
958
1049114
    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
710648
Node NodeManager::mkBoundVar(const TypeNode& type) {
1051
710648
  Node n = NodeBuilder(this, kind::BOUND_VARIABLE);
1052
710648
  setAttribute(n, TypeAttr(), type);
1053
710648
  setAttribute(n, TypeCheckedAttr(), true);
1054
710648
  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
7271
Node NodeManager::mkNullaryOperator(const TypeNode& type, Kind k) {
1072
7271
  std::map< TypeNode, Node >::iterator it = d_unique_vars[k].find( type );
1073
7271
  if( it==d_unique_vars[k].end() ){
1074
10020
    Node n = NodeBuilder(this, k).constructNode();
1075
5010
    setAttribute(n, TypeAttr(), type);
1076
    //setAttribute(n, TypeCheckedAttr(), true);
1077
5010
    d_unique_vars[k][type] = n;
1078
5010
    Assert(n.getMetaKind() == kind::metakind::NULLARY_OPERATOR);
1079
5010
    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
49518834
bool NodeManager::safeToReclaimZombies() const{
1115
  // FIXME multithreading
1116
49518834
  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
29574
}  // namespace cvc5