GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/dtype.cpp Lines: 415 479 86.6 %
Date: 2021-09-16 Branches: 718 2004 35.8 %

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 class representing a datatype definition.
14
 */
15
#include "expr/dtype.h"
16
17
#include <sstream>
18
19
#include "expr/dtype_cons.h"
20
#include "expr/node_algorithm.h"
21
#include "expr/skolem_manager.h"
22
#include "expr/type_matcher.h"
23
#include "util/rational.h"
24
25
using namespace cvc5::kind;
26
27
namespace cvc5 {
28
29
4224
DType::DType(std::string name, bool isCo)
30
    : d_name(name),
31
      d_params(),
32
      d_isCo(isCo),
33
      d_isTuple(false),
34
      d_isRecord(false),
35
      d_constructors(),
36
      d_resolved(false),
37
      d_self(),
38
      d_involvesExt(false),
39
      d_involvesUt(false),
40
      d_sygusAllowConst(false),
41
      d_sygusAllowAll(false),
42
8448
      d_card(CardinalityUnknown()),
43
      d_wellFounded(0),
44
12672
      d_nestedRecursion(0)
45
{
46
4224
}
47
48
1435
DType::DType(std::string name, const std::vector<TypeNode>& params, bool isCo)
49
    : d_name(name),
50
      d_params(params),
51
      d_isCo(isCo),
52
      d_isTuple(false),
53
      d_isRecord(false),
54
      d_constructors(),
55
      d_resolved(false),
56
      d_self(),
57
      d_involvesExt(false),
58
      d_involvesUt(false),
59
      d_sygusAllowConst(false),
60
      d_sygusAllowAll(false),
61
2870
      d_card(CardinalityUnknown()),
62
      d_wellFounded(0),
63
4305
      d_nestedRecursion(0)
64
{
65
1435
}
66
67
26789
DType::~DType() {}
68
69
1040392
std::string DType::getName() const { return d_name; }
70
9301716
size_t DType::getNumConstructors() const { return d_constructors.size(); }
71
72
1857111
bool DType::isParametric() const { return d_params.size() > 0; }
73
11800
size_t DType::getNumParameters() const { return d_params.size(); }
74
6239
TypeNode DType::getParameter(size_t i) const
75
{
76
6239
  Assert(isParametric());
77
6239
  Assert(i < d_params.size());
78
6239
  return d_params[i];
79
}
80
81
2408
std::vector<TypeNode> DType::getParameters() const
82
{
83
2408
  Assert(isParametric());
84
2408
  return d_params;
85
}
86
87
772512
bool DType::isCodatatype() const { return d_isCo; }
88
89
1927360
bool DType::isSygus() const { return !d_sygusType.isNull(); }
90
91
98558
bool DType::isTuple() const { return d_isTuple; }
92
93
417
bool DType::isRecord() const { return d_isRecord; }
94
95
1045403
bool DType::isResolved() const { return d_resolved; }
96
97
11416
const DType& DType::datatypeOf(Node item)
98
{
99
22832
  TypeNode t = item.getType();
100
11416
  switch (t.getKind())
101
  {
102
11416
    case CONSTRUCTOR_TYPE: return t[t.getNumChildren() - 1].getDType();
103
    case SELECTOR_TYPE:
104
    case TESTER_TYPE:
105
    case UPDATER_TYPE: return t[0].getDType();
106
    default:
107
      Unhandled() << "arg must be a datatype constructor, selector, or tester";
108
  }
109
}
110
111
3579148
size_t DType::indexOf(Node item)
112
{
113
3579148
  Assert(item.getType().isConstructor() || item.getType().isTester()
114
         || item.getType().isSelector() || item.getType().isUpdater());
115
3579148
  return indexOfInternal(item);
116
}
117
118
3579148
size_t DType::indexOfInternal(Node item)
119
{
120
3579148
  if (item.getKind() == APPLY_TYPE_ASCRIPTION)
121
  {
122
7084
    return indexOf(item[0]);
123
  }
124
3572064
  Assert(item.hasAttribute(DTypeIndexAttr()));
125
3572064
  return item.getAttribute(DTypeIndexAttr());
126
}
127
128
4570
size_t DType::cindexOf(Node item)
129
{
130
4570
  Assert(item.getType().isSelector() || item.getType().isUpdater());
131
4570
  return cindexOfInternal(item);
132
}
133
4570
size_t DType::cindexOfInternal(Node item)
134
{
135
4570
  if (item.getKind() == APPLY_TYPE_ASCRIPTION)
136
  {
137
    return cindexOf(item[0]);
138
  }
139
4570
  Assert(item.hasAttribute(DTypeConsIndexAttr()));
140
4570
  return item.getAttribute(DTypeConsIndexAttr());
141
}
142
143
5649
bool DType::resolve(const std::map<std::string, TypeNode>& resolutions,
144
                    const std::vector<TypeNode>& placeholders,
145
                    const std::vector<TypeNode>& replacements,
146
                    const std::vector<TypeNode>& paramTypes,
147
                    const std::vector<TypeNode>& paramReplacements)
148
{
149
5649
  Trace("datatypes-init") << "DType::resolve: " << std::endl;
150
5649
  Assert(!d_resolved);
151
5649
  Assert(resolutions.find(d_name) != resolutions.end());
152
5649
  Assert(placeholders.size() == replacements.size());
153
5649
  Assert(paramTypes.size() == paramReplacements.size());
154
5649
  Assert(getNumConstructors() > 0);
155
11298
  TypeNode self = (*resolutions.find(d_name)).second;
156
5649
  Assert(&self.getDType() == this);
157
5649
  d_resolved = true;
158
5649
  size_t index = 0;
159
22221
  for (std::shared_ptr<DTypeConstructor> ctor : d_constructors)
160
  {
161
16572
    Trace("datatypes-init") << "DType::resolve ctor " << std::endl;
162
16572
    if (!ctor->resolve(self,
163
                       resolutions,
164
                       placeholders,
165
                       replacements,
166
                       paramTypes,
167
                       paramReplacements,
168
                       index))
169
    {
170
      return false;
171
    }
172
16572
    ctor->d_constructor.setAttribute(DTypeIndexAttr(), index);
173
16572
    ctor->d_tester.setAttribute(DTypeIndexAttr(), index++);
174
16572
    Assert(ctor->isResolved());
175
16572
    Trace("datatypes-init") << "DType::resolve ctor finished" << std::endl;
176
  }
177
5649
  d_self = self;
178
179
5649
  d_involvesExt = false;
180
5649
  d_involvesUt = false;
181
22221
  for (const std::shared_ptr<DTypeConstructor>& ctor : d_constructors)
182
  {
183
16572
    if (ctor->involvesExternalType())
184
    {
185
1555
      d_involvesExt = true;
186
    }
187
16572
    if (ctor->involvesUninterpretedType())
188
    {
189
8405
      d_involvesUt = true;
190
    }
191
  }
192
193
5649
  if (isSygus())
194
  {
195
    // all datatype constructors should be sygus and have sygus operators whose
196
    // free variables are subsets of sygus bound var list.
197
3836
    std::unordered_set<Node> svs;
198
5315
    for (const Node& sv : d_sygusBvl)
199
    {
200
3397
      svs.insert(sv);
201
    }
202
13278
    for (size_t i = 0, ncons = d_constructors.size(); i < ncons; i++)
203
    {
204
22720
      Node sop = d_constructors[i]->getSygusOp();
205
11360
      Assert(!sop.isNull())
206
          << "Sygus datatype contains a non-sygus constructor";
207
22720
      std::unordered_set<Node> fvs;
208
11360
      expr::getFreeVariables(sop, fvs);
209
12796
      for (const Node& v : fvs)
210
      {
211
1436
        if (svs.find(v) == svs.end())
212
        {
213
          // return false, indicating we should abort, since this datatype is
214
          // not well formed.
215
          return false;
216
        }
217
      }
218
    }
219
  }
220
5649
  Trace("datatypes-init") << "DType::resolve: finished" << std::endl;
221
5649
  return true;
222
}
223
224
16572
void DType::addConstructor(std::shared_ptr<DTypeConstructor> c)
225
{
226
16572
  Assert(!d_resolved);
227
16572
  d_constructors.push_back(c);
228
16572
}
229
230
11331
void DType::addSygusConstructor(Node op,
231
                                const std::string& cname,
232
                                const std::vector<TypeNode>& cargs,
233
                                int weight)
234
{
235
  // avoid name clashes
236
22662
  std::stringstream ss;
237
11331
  ss << getName() << "_" << getNumConstructors() << "_" << cname;
238
22662
  std::string name = ss.str();
239
11331
  unsigned cweight = weight >= 0 ? weight : (cargs.empty() ? 0 : 1);
240
  std::shared_ptr<DTypeConstructor> c =
241
22662
      std::make_shared<DTypeConstructor>(name, cweight);
242
11331
  c->setSygus(op);
243
24057
  for (size_t j = 0, nargs = cargs.size(); j < nargs; j++)
244
  {
245
25452
    std::stringstream sname;
246
12726
    sname << name << "_" << j;
247
12726
    c->addArg(sname.str(), cargs[j]);
248
  }
249
11331
  addConstructor(c);
250
11331
}
251
252
1918
void DType::setSygus(TypeNode st, Node bvl, bool allowConst, bool allowAll)
253
{
254
1918
  Assert(!d_resolved);
255
  // We can be in a case where the only rule specified was
256
  // (Constant T), in which case we have not yet added a constructor. We
257
  // ensure an arbitrary constant is added in this case. We additionally
258
  // add a constant if the grammar has only non-nullary constructors, since this
259
  // ensures the datatype is well-founded (see 3423).
260
  // Notice we only want to do this for sygus datatypes that are user-provided.
261
  // At the moment, the condition !allow_all implies the grammar is
262
  // user-provided and hence may require a default constant.
263
  // For the SyGuS API, we could consider requiring the user to explicitly add
264
  // the "any constant" constructor with a call instead of passing a flag. This
265
  // would make the block of code unnecessary.
266
1918
  if (allowConst && !allowAll)
267
  {
268
    // if I don't already have a constant (0-ary constructor)
269
35
    bool hasConstant = false;
270
59
    for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++)
271
    {
272
30
      if ((*this)[i].getNumArgs() == 0)
273
      {
274
6
        hasConstant = true;
275
6
        break;
276
      }
277
    }
278
35
    if (!hasConstant)
279
    {
280
      // add an arbitrary one
281
58
      Node op = st.mkGroundTerm();
282
      // use same naming convention as SygusDatatype
283
58
      std::stringstream ss;
284
29
      ss << getName() << "_" << getNumConstructors() << "_" << op;
285
      // it has zero weight
286
      std::shared_ptr<DTypeConstructor> c =
287
58
          std::make_shared<DTypeConstructor>(ss.str(), 0);
288
29
      c->setSygus(op);
289
29
      addConstructor(c);
290
    }
291
  }
292
293
1918
  d_sygusType = st;
294
1918
  d_sygusBvl = bvl;
295
1918
  d_sygusAllowConst = allowConst || allowAll;
296
1918
  d_sygusAllowAll = allowAll;
297
1918
}
298
299
2118
void DType::setTuple()
300
{
301
2118
  Assert(!d_resolved);
302
2118
  d_isTuple = true;
303
2118
}
304
305
74
void DType::setRecord()
306
{
307
74
  Assert(!d_resolved);
308
74
  d_isRecord = true;
309
74
}
310
311
3199
Cardinality DType::getCardinality(TypeNode t) const
312
{
313
3199
  Trace("datatypes-init") << "DType::getCardinality " << std::endl;
314
3199
  Assert(isResolved());
315
3199
  Assert(t.isDatatype() && t.getDType().getTypeNode() == d_self);
316
6398
  std::vector<TypeNode> processing;
317
3199
  computeCardinality(t, processing);
318
6398
  return d_card;
319
}
320
321
22
Cardinality DType::getCardinality() const
322
{
323
22
  Assert(!isParametric());
324
22
  return getCardinality(d_self);
325
}
326
327
7692
Cardinality DType::computeCardinality(TypeNode t,
328
                                      std::vector<TypeNode>& processing) const
329
{
330
7692
  Trace("datatypes-init") << "DType::computeCardinality " << std::endl;
331
7692
  Assert(isResolved());
332
23076
  if (std::find(processing.begin(), processing.end(), d_self)
333
23076
      != processing.end())
334
  {
335
292
    d_card = Cardinality::INTEGERS;
336
292
    return d_card;
337
  }
338
7400
  processing.push_back(d_self);
339
14800
  Cardinality c = 0;
340
21451
  for (std::shared_ptr<DTypeConstructor> ctor : d_constructors)
341
  {
342
14051
    c += ctor->computeCardinality(t, processing);
343
  }
344
7400
  d_card = c;
345
7400
  processing.pop_back();
346
7400
  return d_card;
347
}
348
349
191943
bool DType::isRecursiveSingleton(TypeNode t) const
350
{
351
191943
  Trace("datatypes-init") << "DType::isRecursiveSingleton " << std::endl;
352
191943
  Assert(isResolved());
353
191943
  Assert(t.isDatatype() && t.getDType().getTypeNode() == d_self);
354
191943
  if (d_cardRecSingleton.find(t) != d_cardRecSingleton.end())
355
  {
356
190432
    return d_cardRecSingleton[t] == 1;
357
  }
358
1511
  if (isCodatatype())
359
  {
360
17
    Assert(d_cardUAssume[t].empty());
361
34
    std::vector<TypeNode> processing;
362
17
    if (computeCardinalityRecSingleton(t, processing, d_cardUAssume[t]))
363
    {
364
3
      d_cardRecSingleton[t] = 1;
365
3
      if (Trace.isOn("dt-card"))
366
      {
367
        Trace("dt-card") << "DType " << getName()
368
                         << " is recursive singleton, dependent upon "
369
                         << d_cardUAssume[t].size()
370
                         << " uninterpreted sorts: " << std::endl;
371
        for (size_t i = 0; i < d_cardUAssume[t].size(); i++)
372
        {
373
          Trace("dt-card") << "  " << d_cardUAssume[t][i] << std::endl;
374
        }
375
        Trace("dt-card") << std::endl;
376
      }
377
    }
378
    else
379
    {
380
14
      d_cardRecSingleton[t] = -1;
381
    }
382
  }
383
  else
384
  {
385
1494
    d_cardRecSingleton[t] = -1;
386
  }
387
1511
  return d_cardRecSingleton[t] == 1;
388
}
389
390
bool DType::isRecursiveSingleton() const
391
{
392
  Assert(!isParametric());
393
  return isRecursiveSingleton(d_self);
394
}
395
396
4
unsigned DType::getNumRecursiveSingletonArgTypes(TypeNode t) const
397
{
398
4
  Assert(d_cardRecSingleton.find(t) != d_cardRecSingleton.end());
399
4
  Assert(isRecursiveSingleton(t));
400
4
  return d_cardUAssume[t].size();
401
}
402
403
unsigned DType::getNumRecursiveSingletonArgTypes() const
404
{
405
  Assert(!isParametric());
406
  return getNumRecursiveSingletonArgTypes(d_self);
407
}
408
409
TypeNode DType::getRecursiveSingletonArgType(TypeNode t, size_t i) const
410
{
411
  Assert(d_cardRecSingleton.find(t) != d_cardRecSingleton.end());
412
  Assert(isRecursiveSingleton(t));
413
  return d_cardUAssume[t][i];
414
}
415
416
TypeNode DType::getRecursiveSingletonArgType(size_t i) const
417
{
418
  Assert(!isParametric());
419
  return getRecursiveSingletonArgType(d_self, i);
420
}
421
422
22
bool DType::computeCardinalityRecSingleton(
423
    TypeNode t,
424
    std::vector<TypeNode>& processing,
425
    std::vector<TypeNode>& u_assume) const
426
{
427
44
  Trace("datatypes-init") << "DType::computeCardinalityRecSingleton "
428
22
                          << std::endl;
429
66
  if (std::find(processing.begin(), processing.end(), d_self)
430
66
      != processing.end())
431
  {
432
3
    return true;
433
  }
434
19
  if (d_cardRecSingleton[t] == 0)
435
  {
436
    // if not yet computed
437
19
    if (d_constructors.size() != 1)
438
    {
439
14
      return false;
440
    }
441
5
    bool success = false;
442
5
    processing.push_back(d_self);
443
8
    for (size_t i = 0, nargs = d_constructors[0]->getNumArgs(); i < nargs; i++)
444
    {
445
8
      TypeNode tc = d_constructors[0]->getArgType(i);
446
      // if it is an uninterpreted sort, then we depend on it having cardinality
447
      // one
448
5
      if (tc.isSort())
449
      {
450
        if (std::find(u_assume.begin(), u_assume.end(), tc) == u_assume.end())
451
        {
452
          u_assume.push_back(tc);
453
        }
454
        // if it is a datatype, recurse
455
      }
456
5
      else if (tc.isDatatype())
457
      {
458
5
        const DType& dt = tc.getDType();
459
5
        if (!dt.computeCardinalityRecSingleton(t, processing, u_assume))
460
        {
461
2
          return false;
462
        }
463
        else
464
        {
465
3
          success = true;
466
        }
467
        // if it is a builtin type, it must have cardinality one
468
      }
469
      else if (!tc.getCardinality().isOne())
470
      {
471
        return false;
472
      }
473
    }
474
3
    processing.pop_back();
475
3
    return success;
476
  }
477
  else if (d_cardRecSingleton[t] == -1)
478
  {
479
    return false;
480
  }
481
  for (size_t i = 0, csize = d_cardUAssume[t].size(); i < csize; i++)
482
  {
483
    if (std::find(u_assume.begin(), u_assume.end(), d_cardUAssume[t][i])
484
        == u_assume.end())
485
    {
486
      u_assume.push_back(d_cardUAssume[t][i]);
487
    }
488
  }
489
  return true;
490
}
491
492
156887
CardinalityClass DType::getCardinalityClass(TypeNode t) const
493
{
494
156887
  Trace("datatypes-init") << "DType::isFinite " << std::endl;
495
156887
  Assert(isResolved());
496
156887
  Assert(t.isDatatype() && t.getDType().getTypeNode() == d_self);
497
498
  // is this already in the cache ?
499
156887
  std::map<TypeNode, CardinalityClass>::const_iterator it = d_cardClass.find(t);
500
156887
  if (it != d_cardClass.end())
501
  {
502
154295
    return it->second;
503
  }
504
  // it is the max cardinality class of a constructor, with base case ONE
505
  // if we have one constructor and FINITE otherwise.
506
2592
  CardinalityClass c = d_constructors.size() == 1 ? CardinalityClass::ONE
507
2592
                                                  : CardinalityClass::FINITE;
508
12300
  for (std::shared_ptr<DTypeConstructor> ctor : d_constructors)
509
  {
510
9708
    CardinalityClass cc = ctor->getCardinalityClass(t);
511
9708
    c = maxCardinalityClass(c, cc);
512
  }
513
2592
  d_cardClass[t] = c;
514
2592
  return c;
515
}
516
14
CardinalityClass DType::getCardinalityClass() const
517
{
518
14
  Assert(isResolved() && !isParametric());
519
14
  return getCardinalityClass(d_self);
520
}
521
522
22
bool DType::isFinite(TypeNode t, bool fmfEnabled) const
523
{
524
22
  return isCardinalityClassFinite(getCardinalityClass(t), fmfEnabled);
525
}
526
527
22
bool DType::isFinite(bool fmfEnabled) const
528
{
529
22
  return isFinite(d_self, fmfEnabled);
530
}
531
532
75923
bool DType::isWellFounded() const
533
{
534
75923
  Assert(isResolved());
535
75923
  if (d_wellFounded != 0)
536
  {
537
    // already computed
538
72616
    return d_wellFounded == 1;
539
  }
540
3307
  Trace("datatypes-init") << "DType::isWellFounded " << getName() << std::endl;
541
6614
  std::vector<TypeNode> processing;
542
3307
  if (!computeWellFounded(processing))
543
  {
544
    // not well-founded since no ground term can be constructed
545
4
    Trace("datatypes-init") << "DType::isWellFounded: false for " << getName()
546
2
                            << " due to no ground terms." << std::endl;
547
2
    d_wellFounded = -1;
548
2
    return false;
549
  }
550
6610
  Trace("datatypes-init") << "DType::isWellFounded: true for " << getName()
551
3305
                          << std::endl;
552
3305
  d_wellFounded = 1;
553
3305
  return true;
554
}
555
556
6432
bool DType::computeWellFounded(std::vector<TypeNode>& processing) const
557
{
558
6432
  Trace("datatypes-init") << "DType::computeWellFounded " << std::endl;
559
6432
  Assert(isResolved());
560
19296
  if (std::find(processing.begin(), processing.end(), d_self)
561
19296
      != processing.end())
562
  {
563
1054
    return d_isCo;
564
  }
565
5378
  processing.push_back(d_self);
566
6478
  for (std::shared_ptr<DTypeConstructor> ctor : d_constructors)
567
  {
568
6412
    if (ctor->computeWellFounded(processing))
569
    {
570
5312
      processing.pop_back();
571
5312
      return true;
572
    }
573
    else
574
    {
575
2200
      Trace("dt-wf") << "Constructor " << ctor->getName()
576
1100
                     << " is not well-founded." << std::endl;
577
    }
578
  }
579
66
  processing.pop_back();
580
132
  Trace("dt-wf") << "DType " << getName() << " is not well-founded."
581
66
                 << std::endl;
582
66
  return false;
583
}
584
585
114589
Node DType::mkGroundTerm(TypeNode t) const
586
{
587
114589
  Trace("datatypes-init") << "DType::mkGroundTerm of type " << t << std::endl;
588
114589
  Assert(isResolved());
589
114589
  return mkGroundTermInternal(t, false);
590
}
591
592
119884
Node DType::mkGroundValue(TypeNode t) const
593
{
594
119884
  Assert(isResolved());
595
119884
  Trace("datatypes-init") << "DType::mkGroundValue of type " << t << std::endl;
596
119884
  Node v = mkGroundTermInternal(t, true);
597
119884
  return v;
598
}
599
600
234473
Node DType::mkGroundTermInternal(TypeNode t, bool isValue) const
601
{
602
468946
  Trace("datatypes-init") << "DType::mkGroundTerm of type " << t
603
234473
                          << ", isValue = " << isValue << std::endl;
604
  // is this already in the cache ?
605
234473
  std::map<TypeNode, Node>& cache = isValue ? d_groundValue : d_groundTerm;
606
234473
  std::map<TypeNode, Node>::iterator it = cache.find(t);
607
234473
  if (it != cache.end())
608
  {
609
466312
    Trace("datatypes-init")
610
233156
        << "\nin cache: " << d_self << " => " << it->second << std::endl;
611
233156
    return it->second;
612
  }
613
2634
  std::vector<TypeNode> processing;
614
2634
  Node groundTerm = computeGroundTerm(t, processing, isValue);
615
1317
  if (!groundTerm.isNull())
616
  {
617
    // we found a ground-term-constructing constructor!
618
1307
    cache[t] = groundTerm;
619
2614
    Trace("datatypes-init")
620
1307
        << "constructed: " << getName() << " => " << groundTerm << std::endl;
621
  }
622
  // if ground term is null, we are not well-founded
623
2634
  Trace("datatypes-init") << "DType::mkGroundTerm for " << t
624
1317
                          << ", isValue=" << isValue << " returns "
625
1317
                          << groundTerm << std::endl;
626
1317
  return groundTerm;
627
}
628
629
12390
void DType::getAlienSubfieldTypes(std::unordered_set<TypeNode>& types,
630
                                  std::map<TypeNode, bool>& processed,
631
                                  bool isAlienPos) const
632
{
633
12390
  std::map<TypeNode, bool>::iterator it = processed.find(d_self);
634
12390
  if (it != processed.end())
635
  {
636
9178
    if (it->second || (!isAlienPos && !it->second))
637
    {
638
      // already processed as an alien subfield type, or already processed
639
      // as a non-alien subfield type and isAlienPos is false.
640
9160
      return;
641
    }
642
  }
643
3230
  processed[d_self] = isAlienPos;
644
14728
  for (std::shared_ptr<DTypeConstructor> ctor : d_constructors)
645
  {
646
23982
    for (unsigned j = 0, nargs = ctor->getNumArgs(); j < nargs; ++j)
647
    {
648
24929
      TypeNode tn = ctor->getArgType(j);
649
12484
      if (tn.isDatatype())
650
      {
651
        // special case for datatypes, we must recurse to collect subfield types
652
10361
        if (!isAlienPos)
653
        {
654
          // since we aren't adding it to types below, we add its alien
655
          // subfield types here.
656
10331
          const DType& dt = tn.getDType();
657
10331
          dt.getAlienSubfieldTypes(types, processed, false);
658
        }
659
10361
        if (tn.isParametricDatatype() && !isAlienPos)
660
        {
661
          // (instantiated) parametric datatypes have an AST structure:
662
          //  (PARAMETRIC_DATATYPE D T1 ... Tn)
663
          // where D is the uninstantiated datatype type.  We should not view D
664
          // as an alien subfield type of tn. Thus, we need a special case here
665
          // which ignores the first child, when isAlienPos is false.
666
80
          for (unsigned i = 1, nchild = tn.getNumChildren(); i < nchild; i++)
667
          {
668
41
            expr::getComponentTypes(tn[i], types);
669
          }
670
39
          continue;
671
        }
672
      }
673
      // we are in a case where tn is not a datatype, we add all (alien)
674
      // component types to types below.
675
12445
      bool hasTn = types.find(tn) != types.end();
676
24890
      Trace("datatypes-init")
677
12445
          << "Collect subfield types " << tn << ", hasTn=" << hasTn
678
12445
          << ", isAlienPos=" << isAlienPos << std::endl;
679
12445
      expr::getComponentTypes(tn, types);
680
12445
      if (!isAlienPos && !hasTn)
681
      {
682
        // the top-level type is added by getComponentTypes, so remove it if it
683
        // was not already listed in types
684
12366
        Assert(types.find(tn) != types.end());
685
12366
        types.erase(tn);
686
      }
687
    }
688
  }
689
  // Now, go back and add all alien subfield types from datatypes if
690
  // not done so already. This is because getComponentTypes does not
691
  // recurse into subfield types of datatypes.
692
3552
  for (const TypeNode& sstn : types)
693
  {
694
322
    if (sstn.isDatatype())
695
    {
696
180
      const DType& dt = sstn.getDType();
697
180
      dt.getAlienSubfieldTypes(types, processed, true);
698
    }
699
  }
700
}
701
702
74283
bool DType::hasNestedRecursion() const
703
{
704
74283
  if (d_nestedRecursion != 0)
705
  {
706
72404
    return d_nestedRecursion == 1;
707
  }
708
3758
  Trace("datatypes-init") << "Compute simply recursive for " << getName()
709
1879
                          << std::endl;
710
  // get the alien subfield types of this datatype
711
3758
  std::unordered_set<TypeNode> types;
712
3758
  std::map<TypeNode, bool> processed;
713
1879
  getAlienSubfieldTypes(types, processed, false);
714
1879
  if (Trace.isOn("datatypes-init"))
715
  {
716
    Trace("datatypes-init") << "Alien subfield types: " << std::endl;
717
    for (const TypeNode& t : types)
718
    {
719
      Trace("datatypes-init") << "- " << t << std::endl;
720
    }
721
  }
722
  // does types contain self?
723
1879
  if (types.find(d_self) != types.end())
724
  {
725
26
    Trace("datatypes-init")
726
26
        << "DType::hasNestedRecursion: true for " << getName()
727
13
        << " due to alien subfield type" << std::endl;
728
    // has nested recursion since it has itself as an alien subfield type.
729
13
    d_nestedRecursion = 1;
730
13
    return true;
731
  }
732
  // If it is parametric, this type may match with an alien subfield type (e.g.
733
  // we may have a field (T Int) for parametric datatype (T x) where x
734
  // is a type parameter). Thus, we check whether the self type matches any
735
  // alien subfield type using the TypeMatcher utility.
736
1866
  if (isParametric())
737
  {
738
65
    for (const TypeNode& t : types)
739
    {
740
62
      TypeMatcher m(d_self);
741
31
      Trace("datatypes-init") << "  " << t << std::endl;
742
31
      if (m.doMatching(d_self, t))
743
      {
744
        Trace("datatypes-init")
745
            << "DType::hasNestedRecursion: true for " << getName()
746
            << " due to parametric strict component type, " << d_self
747
            << " matching " << t << std::endl;
748
        d_nestedRecursion = 1;
749
        return true;
750
      }
751
    }
752
  }
753
3732
  Trace("datatypes-init") << "DType::hasNestedRecursion: false for "
754
1866
                          << getName() << std::endl;
755
1866
  d_nestedRecursion = -1;
756
1866
  return false;
757
}
758
759
2938
Node getSubtermWithType(Node e, TypeNode t, bool isTop)
760
{
761
2938
  if (!isTop && e.getType() == t)
762
  {
763
2
    return e;
764
  }
765
4057
  for (const Node& ei : e)
766
  {
767
2245
    Node se = getSubtermWithType(ei, t, false);
768
1124
    if (!se.isNull())
769
    {
770
3
      return se;
771
    }
772
  }
773
2933
  return Node();
774
}
775
776
1916
Node DType::computeGroundTerm(TypeNode t,
777
                              std::vector<TypeNode>& processing,
778
                              bool isValue) const
779
{
780
1916
  if (std::find(processing.begin(), processing.end(), t) != processing.end())
781
  {
782
180
    Trace("datatypes-init")
783
90
        << "...already processing " << t << " " << d_self << std::endl;
784
90
    return Node();
785
  }
786
1826
  processing.push_back(t);
787
1826
  std::map<TypeNode, Node>& gtCache = isValue ? d_groundValue : d_groundTerm;
788
2251
  for (unsigned r = 0; r < 2; r++)
789
  {
790
2331
    for (std::shared_ptr<DTypeConstructor> ctor : d_constructors)
791
    {
792
      // do nullary constructors first
793
3162
      if ((ctor->getNumArgs() == 0) != (r == 0))
794
      {
795
1256
        continue;
796
      }
797
3812
      Trace("datatypes-init") << "Try constructing for " << ctor->getName()
798
3812
                              << ", processing = " << processing.size()
799
1906
                              << ", isValue=" << isValue << std::endl;
800
1998
      Node e = ctor->computeGroundTerm(t, processing, gtCache, isValue);
801
1906
      if (!e.isNull())
802
      {
803
        // must check subterms for the same type to avoid infinite loops in
804
        // type enumeration
805
3628
        Node se = getSubtermWithType(e, t, true);
806
1814
        if (!se.isNull())
807
        {
808
2
          Trace("datatypes-init") << "Take subterm " << se << std::endl;
809
2
          e = se;
810
        }
811
1814
        processing.pop_back();
812
1814
        return e;
813
      }
814
      else
815
      {
816
92
        Trace("datatypes-init") << "...failed." << std::endl;
817
      }
818
    }
819
  }
820
12
  processing.pop_back();
821
12
  return Node();
822
}
823
824
355326
TypeNode DType::getTypeNode() const
825
{
826
355326
  Assert(isResolved());
827
355326
  Assert(!d_self.isNull());
828
355326
  return d_self;
829
}
830
831
8
TypeNode DType::getTypeNode(const std::vector<TypeNode>& params) const
832
{
833
8
  Assert(isResolved());
834
8
  Assert(!d_self.isNull() && d_self.isParametricDatatype());
835
8
  return d_self.instantiateParametricDatatype(params);
836
}
837
838
5839414
const DTypeConstructor& DType::operator[](size_t index) const
839
{
840
5839414
  Assert(index < getNumConstructors());
841
5839414
  return *d_constructors[index];
842
}
843
844
1375
Node DType::getSharedSelector(TypeNode dtt, TypeNode t, size_t index) const
845
{
846
1375
  Assert(isResolved());
847
  std::map<TypeNode, std::map<TypeNode, std::map<unsigned, Node> > >::iterator
848
1375
      itd = d_sharedSel.find(dtt);
849
1375
  if (itd != d_sharedSel.end())
850
  {
851
    std::map<TypeNode, std::map<unsigned, Node> >::iterator its =
852
1088
        itd->second.find(t);
853
1088
    if (its != itd->second.end())
854
    {
855
877
      std::map<unsigned, Node>::iterator it = its->second.find(index);
856
877
      if (it != its->second.end())
857
      {
858
620
        return it->second;
859
      }
860
    }
861
  }
862
  // make the shared selector
863
1510
  Node s;
864
755
  NodeManager* nm = NodeManager::currentNM();
865
1510
  std::stringstream ss;
866
755
  ss << "sel_" << index;
867
755
  SkolemManager* sm = nm->getSkolemManager();
868
1510
  TypeNode stype = nm->mkSelectorType(dtt, t);
869
1510
  Node nindex = nm->mkConst(Rational(index));
870
755
  s = sm->mkSkolemFunction(SkolemFunId::SHARED_SELECTOR,
871
                           stype,
872
                           nindex,
873
                           NodeManager::SKOLEM_NO_NOTIFY);
874
755
  d_sharedSel[dtt][t][index] = s;
875
1510
  Trace("dt-shared-sel") << "Made " << s << " of type " << dtt << " -> " << t
876
755
                         << std::endl;
877
755
  return s;
878
}
879
880
626735
TypeNode DType::getSygusType() const { return d_sygusType; }
881
882
105337
Node DType::getSygusVarList() const { return d_sygusBvl; }
883
884
1292
bool DType::getSygusAllowConst() const { return d_sygusAllowConst; }
885
886
1257
bool DType::getSygusAllowAll() const { return d_sygusAllowAll; }
887
888
bool DType::involvesExternalType() const { return d_involvesExt; }
889
890
9950
bool DType::involvesUninterpretedType() const { return d_involvesUt; }
891
892
484
const std::vector<std::shared_ptr<DTypeConstructor> >& DType::getConstructors()
893
    const
894
{
895
484
  return d_constructors;
896
}
897
898
std::unordered_set<TypeNode> DType::getSubfieldTypes() const
899
{
900
  std::unordered_set<TypeNode> subFieldTypes;
901
  for (std::shared_ptr<DTypeConstructor> ctor : d_constructors)
902
  {
903
    for (size_t i = 0, nargs = ctor->getNumArgs(); i < nargs; i++)
904
    {
905
      subFieldTypes.insert(ctor->getArgType(i));
906
    }
907
  }
908
  return subFieldTypes;
909
}
910
911
20
std::ostream& operator<<(std::ostream& os, const DType& dt)
912
{
913
  // can only output datatypes in the cvc5 native language
914
40
  language::SetLanguage::Scope ls(os, Language::LANG_CVC);
915
20
  dt.toStream(os);
916
40
  return os;
917
}
918
919
20
void DType::toStream(std::ostream& out) const
920
{
921
20
  out << "DATATYPE " << getName();
922
20
  if (isParametric())
923
  {
924
    out << '[';
925
    for (size_t i = 0, nparams = getNumParameters(); i < nparams; ++i)
926
    {
927
      if (i > 0)
928
      {
929
        out << ',';
930
      }
931
      out << getParameter(i);
932
    }
933
    out << ']';
934
  }
935
20
  out << " = " << std::endl;
936
20
  bool firstTime = true;
937
58
  for (std::shared_ptr<DTypeConstructor> ctor : d_constructors)
938
  {
939
38
    if (!firstTime)
940
    {
941
20
      out << " | ";
942
    }
943
38
    firstTime = false;
944
38
    out << *ctor;
945
  }
946
20
  out << " END;" << std::endl;
947
20
}
948
949
DTypeIndexConstant::DTypeIndexConstant(size_t index) : d_index(index) {}
950
std::ostream& operator<<(std::ostream& out, const DTypeIndexConstant& dic)
951
{
952
  return out << "index_" << dic.getIndex();
953
}
954
955
29577
}  // namespace cvc5