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