GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/datatypes/theory_datatypes_type_rules.cpp Lines: 218 280 77.9 %
Date: 2021-08-14 Branches: 447 1364 32.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
 * Typing and cardinality rules for the theory of datatypes.
14
 */
15
16
#include "theory/datatypes/theory_datatypes_type_rules.h"
17
18
#include <sstream>
19
20
#include "expr/ascription_type.h"
21
#include "expr/dtype.h"
22
#include "expr/dtype_cons.h"
23
#include "expr/type_matcher.h"
24
#include "theory/datatypes/theory_datatypes_utils.h"
25
#include "theory/datatypes/tuple_project_op.h"
26
#include "util/rational.h"
27
28
namespace cvc5 {
29
namespace theory {
30
namespace datatypes {
31
32
133312
TypeNode DatatypeConstructorTypeRule::computeType(NodeManager* nodeManager,
33
                                                  TNode n,
34
                                                  bool check)
35
{
36
133312
  Assert(n.getKind() == kind::APPLY_CONSTRUCTOR);
37
266624
  TypeNode consType = n.getOperator().getType(check);
38
266624
  TypeNode t = consType.getConstructorRangeType();
39
133312
  Assert(t.isDatatype());
40
133312
  TNode::iterator child_it = n.begin();
41
133312
  TNode::iterator child_it_end = n.end();
42
133312
  TypeNode::iterator tchild_it = consType.begin();
43
399534
  if ((t.isParametricDatatype() || check)
44
266624
      && n.getNumChildren() != consType.getNumChildren() - 1)
45
  {
46
    throw TypeCheckingExceptionPrivate(
47
5
        n, "number of arguments does not match the constructor type");
48
  }
49
133307
  if (t.isParametricDatatype())
50
  {
51
796
    Debug("typecheck-idt") << "typecheck parameterized datatype " << n
52
398
                           << std::endl;
53
796
    TypeMatcher m(t);
54
1650
    for (; child_it != child_it_end; ++child_it, ++tchild_it)
55
    {
56
1252
      TypeNode childType = (*child_it).getType(check);
57
626
      if (!m.doMatching(*tchild_it, childType))
58
      {
59
        throw TypeCheckingExceptionPrivate(
60
            n, "matching failed for parameterized constructor");
61
      }
62
    }
63
796
    std::vector<TypeNode> instTypes;
64
398
    m.getMatches(instTypes);
65
796
    TypeNode range = t.instantiateParametricDatatype(instTypes);
66
398
    Debug("typecheck-idt") << "Return " << range << std::endl;
67
398
    return range;
68
  }
69
  else
70
  {
71
132909
    if (check)
72
    {
73
265818
      Debug("typecheck-idt")
74
132909
          << "typecheck cons: " << n << " " << n.getNumChildren() << std::endl;
75
265818
      Debug("typecheck-idt") << "cons type: " << consType << " "
76
132909
                             << consType.getNumChildren() << std::endl;
77
641731
      for (; child_it != child_it_end; ++child_it, ++tchild_it)
78
      {
79
508822
        TypeNode childType = (*child_it).getType(check);
80
508822
        Debug("typecheck-idt") << "typecheck cons arg: " << childType << " "
81
254411
                               << (*tchild_it) << std::endl;
82
508822
        TypeNode argumentType = *tchild_it;
83
254411
        if (!childType.isSubtypeOf(argumentType))
84
        {
85
          std::stringstream ss;
86
          ss << "bad type for constructor argument:\n"
87
             << "child type:  " << childType << "\n"
88
             << "not subtype: " << argumentType << "\n"
89
             << "in term : " << n;
90
          throw TypeCheckingExceptionPrivate(n, ss.str());
91
        }
92
      }
93
    }
94
132909
    return consType.getConstructorRangeType();
95
  }
96
}
97
98
73513
bool DatatypeConstructorTypeRule::computeIsConst(NodeManager* nodeManager,
99
                                                 TNode n)
100
{
101
73513
  Assert(n.getKind() == kind::APPLY_CONSTRUCTOR);
102
147026
  NodeManagerScope nms(nodeManager);
103
134963
  for (TNode::const_iterator i = n.begin(); i != n.end(); ++i)
104
  {
105
106497
    if (!(*i).isConst())
106
    {
107
45047
      return false;
108
    }
109
  }
110
28466
  return true;
111
}
112
113
63882
TypeNode DatatypeSelectorTypeRule::computeType(NodeManager* nodeManager,
114
                                               TNode n,
115
                                               bool check)
116
{
117
63882
  Assert(n.getKind() == kind::APPLY_SELECTOR
118
         || n.getKind() == kind::APPLY_SELECTOR_TOTAL);
119
127764
  TypeNode selType = n.getOperator().getType(check);
120
127764
  TypeNode t = selType[0];
121
63882
  Assert(t.isDatatype());
122
63882
  if ((t.isParametricDatatype() || check) && n.getNumChildren() != 1)
123
  {
124
    throw TypeCheckingExceptionPrivate(
125
        n, "number of arguments does not match the selector type");
126
  }
127
63882
  if (t.isParametricDatatype())
128
  {
129
500
    Debug("typecheck-idt") << "typecheck parameterized sel: " << n << std::endl;
130
1000
    TypeMatcher m(t);
131
1000
    TypeNode childType = n[0].getType(check);
132
500
    if (!childType.isInstantiatedDatatype())
133
    {
134
      throw TypeCheckingExceptionPrivate(
135
          n, "Datatype type not fully instantiated");
136
    }
137
500
    if (!m.doMatching(selType[0], childType))
138
    {
139
      throw TypeCheckingExceptionPrivate(
140
          n, "matching failed for selector argument of parameterized datatype");
141
    }
142
1000
    std::vector<TypeNode> types, matches;
143
500
    m.getTypes(types);
144
500
    m.getMatches(matches);
145
1000
    TypeNode range = selType[1];
146
500
    range = range.substitute(
147
        types.begin(), types.end(), matches.begin(), matches.end());
148
500
    Debug("typecheck-idt") << "Return " << range << std::endl;
149
500
    return range;
150
  }
151
  else
152
  {
153
63382
    if (check)
154
    {
155
63382
      Debug("typecheck-idt") << "typecheck sel: " << n << std::endl;
156
63382
      Debug("typecheck-idt") << "sel type: " << selType << std::endl;
157
126764
      TypeNode childType = n[0].getType(check);
158
63382
      if (!selType[0].isComparableTo(childType))
159
      {
160
        Debug("typecheck-idt") << "ERROR: " << selType[0].getKind() << " "
161
                               << childType.getKind() << std::endl;
162
        throw TypeCheckingExceptionPrivate(n, "bad type for selector argument");
163
      }
164
    }
165
63382
    return selType[1];
166
  }
167
}
168
169
26015
TypeNode DatatypeTesterTypeRule::computeType(NodeManager* nodeManager,
170
                                             TNode n,
171
                                             bool check)
172
{
173
26015
  Assert(n.getKind() == kind::APPLY_TESTER);
174
26015
  if (check)
175
  {
176
26015
    if (n.getNumChildren() != 1)
177
    {
178
      throw TypeCheckingExceptionPrivate(
179
          n, "number of arguments does not match the tester type");
180
    }
181
52030
    TypeNode testType = n.getOperator().getType(check);
182
52030
    TypeNode childType = n[0].getType(check);
183
52030
    TypeNode t = testType[0];
184
26015
    Assert(t.isDatatype());
185
26015
    if (t.isParametricDatatype())
186
    {
187
226
      Debug("typecheck-idt")
188
113
          << "typecheck parameterized tester: " << n << std::endl;
189
226
      TypeMatcher m(t);
190
113
      if (!m.doMatching(testType[0], childType))
191
      {
192
        throw TypeCheckingExceptionPrivate(
193
            n, "matching failed for tester argument of parameterized datatype");
194
      }
195
    }
196
    else
197
    {
198
25902
      Debug("typecheck-idt") << "typecheck test: " << n << std::endl;
199
25902
      Debug("typecheck-idt") << "test type: " << testType << std::endl;
200
25902
      if (!testType[0].isComparableTo(childType))
201
      {
202
        throw TypeCheckingExceptionPrivate(n, "bad type for tester argument");
203
      }
204
    }
205
  }
206
26015
  return nodeManager->booleanType();
207
}
208
209
35
TypeNode DatatypeUpdateTypeRule::computeType(NodeManager* nodeManager,
210
                                             TNode n,
211
                                             bool check)
212
{
213
35
  Assert(n.getKind() == kind::APPLY_UPDATER);
214
70
  TypeNode updType = n.getOperator().getType(check);
215
35
  Assert(updType.getNumChildren() == 2);
216
35
  if (check)
217
  {
218
103
    for (size_t i = 0; i < 2; i++)
219
    {
220
140
      TypeNode childType = n[i].getType(check);
221
140
      TypeNode t = updType[i];
222
70
      if (t.isParametricDatatype())
223
      {
224
        Debug("typecheck-idt")
225
            << "typecheck parameterized update: " << n << std::endl;
226
        TypeMatcher m(t);
227
        if (!m.doMatching(t, childType))
228
        {
229
          throw TypeCheckingExceptionPrivate(
230
              n,
231
              "matching failed for update argument of parameterized datatype");
232
        }
233
      }
234
      else
235
      {
236
70
        Debug("typecheck-idt") << "typecheck update: " << n << std::endl;
237
70
        Debug("typecheck-idt") << "test type: " << updType << std::endl;
238
70
        if (!t.isComparableTo(childType))
239
        {
240
2
          throw TypeCheckingExceptionPrivate(n, "bad type for update argument");
241
        }
242
      }
243
    }
244
  }
245
  // type is the first argument
246
66
  return updType[0];
247
}
248
249
103
TypeNode DatatypeAscriptionTypeRule::computeType(NodeManager* nodeManager,
250
                                                 TNode n,
251
                                                 bool check)
252
{
253
103
  Debug("typecheck-idt") << "typechecking ascription: " << n << std::endl;
254
103
  Assert(n.getKind() == kind::APPLY_TYPE_ASCRIPTION);
255
103
  TypeNode t = n.getOperator().getConst<AscriptionType>().getType();
256
103
  if (check)
257
  {
258
206
    TypeNode childType = n[0].getType(check);
259
260
206
    TypeMatcher m;
261
103
    if (childType.getKind() == kind::CONSTRUCTOR_TYPE)
262
    {
263
95
      m.addTypesFromDatatype(childType.getConstructorRangeType());
264
    }
265
8
    else if (childType.getKind() == kind::DATATYPE_TYPE)
266
    {
267
      m.addTypesFromDatatype(childType);
268
    }
269
103
    if (!m.doMatching(childType, t))
270
    {
271
      throw TypeCheckingExceptionPrivate(n,
272
                                         "matching failed for type "
273
                                         "ascription argument of "
274
                                         "parameterized datatype");
275
    }
276
  }
277
103
  return t;
278
}
279
280
2
Cardinality ConstructorProperties::computeCardinality(TypeNode type)
281
{
282
  // Constructors aren't exactly functions, they're like
283
  // parameterized ground terms.  So the cardinality is more like
284
  // that of a tuple than that of a function.
285
2
  AssertArgument(type.isConstructor(), type);
286
2
  Cardinality c = 1;
287
2
  for (unsigned i = 0, i_end = type.getNumChildren(); i < i_end - 1; ++i)
288
  {
289
    c *= type[i].getCardinality();
290
  }
291
2
  return c;
292
}
293
294
11157
TypeNode DtSizeTypeRule::computeType(NodeManager* nodeManager,
295
                                     TNode n,
296
                                     bool check)
297
{
298
11157
  if (check)
299
  {
300
22314
    TypeNode t = n[0].getType(check);
301
11157
    if (!t.isDatatype())
302
    {
303
      throw TypeCheckingExceptionPrivate(
304
          n, "expecting datatype size term to have datatype argument.");
305
    }
306
  }
307
11157
  return nodeManager->integerType();
308
}
309
310
TypeNode DtBoundTypeRule::computeType(NodeManager* nodeManager,
311
                                      TNode n,
312
                                      bool check)
313
{
314
  if (check)
315
  {
316
    TypeNode t = n[0].getType(check);
317
    if (!t.isDatatype())
318
    {
319
      throw TypeCheckingExceptionPrivate(
320
          n, "expecting datatype bound term to have datatype argument.");
321
    }
322
    if (n[1].getKind() != kind::CONST_RATIONAL)
323
    {
324
      throw TypeCheckingExceptionPrivate(n,
325
                                         "datatype bound must be a constant");
326
    }
327
    if (n[1].getConst<Rational>().getNumerator().sgn() == -1)
328
    {
329
      throw TypeCheckingExceptionPrivate(n,
330
                                         "datatype bound must be non-negative");
331
    }
332
  }
333
  return nodeManager->booleanType();
334
}
335
336
474
TypeNode DtSygusBoundTypeRule::computeType(NodeManager* nodeManager,
337
                                           TNode n,
338
                                           bool check)
339
{
340
474
  if (check)
341
  {
342
474
    if (!n[0].getType().isDatatype())
343
    {
344
      throw TypeCheckingExceptionPrivate(
345
          n, "datatype sygus bound takes a datatype");
346
    }
347
474
    if (n[1].getKind() != kind::CONST_RATIONAL)
348
    {
349
      throw TypeCheckingExceptionPrivate(
350
          n, "datatype sygus bound must be a constant");
351
    }
352
474
    if (n[1].getConst<Rational>().getNumerator().sgn() == -1)
353
    {
354
      throw TypeCheckingExceptionPrivate(
355
          n, "datatype sygus bound must be non-negative");
356
    }
357
  }
358
474
  return nodeManager->booleanType();
359
}
360
361
90667
TypeNode DtSyguEvalTypeRule::computeType(NodeManager* nodeManager,
362
                                         TNode n,
363
                                         bool check)
364
{
365
181334
  TypeNode headType = n[0].getType(check);
366
90667
  if (!headType.isDatatype())
367
  {
368
    throw TypeCheckingExceptionPrivate(
369
        n, "datatype sygus eval takes a datatype head");
370
  }
371
90667
  const DType& dt = headType.getDType();
372
90667
  if (!dt.isSygus())
373
  {
374
    throw TypeCheckingExceptionPrivate(
375
        n, "datatype sygus eval must have a datatype head that is sygus");
376
  }
377
90667
  if (check)
378
  {
379
181334
    Node svl = dt.getSygusVarList();
380
90667
    if (svl.getNumChildren() + 1 != n.getNumChildren())
381
    {
382
      throw TypeCheckingExceptionPrivate(n,
383
                                         "wrong number of arguments to a "
384
                                         "datatype sygus evaluation "
385
                                         "function");
386
    }
387
629063
    for (unsigned i = 0, nvars = svl.getNumChildren(); i < nvars; i++)
388
    {
389
1076792
      TypeNode vtype = svl[i].getType(check);
390
1076792
      TypeNode atype = n[i + 1].getType(check);
391
538396
      if (!vtype.isComparableTo(atype))
392
      {
393
        throw TypeCheckingExceptionPrivate(
394
            n,
395
            "argument type mismatch in a datatype sygus evaluation function");
396
      }
397
    }
398
  }
399
181334
  return dt.getSygusType();
400
}
401
402
17
TypeNode MatchTypeRule::computeType(NodeManager* nodeManager,
403
                                    TNode n,
404
                                    bool check)
405
{
406
17
  Assert(n.getKind() == kind::MATCH);
407
408
17
  TypeNode retType;
409
410
34
  TypeNode headType = n[0].getType(check);
411
17
  if (!headType.isDatatype())
412
  {
413
    throw TypeCheckingExceptionPrivate(n, "expecting datatype head in match");
414
  }
415
17
  const DType& hdt = headType.getDType();
416
417
34
  std::unordered_set<unsigned> patIndices;
418
17
  bool patHasVariable = false;
419
  // the type of a match case list is the least common type of its cases
420
58
  for (unsigned i = 1, nchildren = n.getNumChildren(); i < nchildren; i++)
421
  {
422
82
    Node nc = n[i];
423
41
    if (check)
424
    {
425
41
      Kind nck = nc.getKind();
426
82
      std::unordered_set<Node> bvs;
427
41
      if (nck == kind::MATCH_BIND_CASE)
428
      {
429
39
        for (const Node& v : nc[0])
430
        {
431
25
          Assert(v.getKind() == kind::BOUND_VARIABLE);
432
25
          bvs.insert(v);
433
        }
434
      }
435
27
      else if (nck != kind::MATCH_CASE)
436
      {
437
        throw TypeCheckingExceptionPrivate(
438
            n, "expected a match case in match expression");
439
      }
440
      // get the pattern type
441
41
      unsigned pindex = nck == kind::MATCH_CASE ? 0 : 1;
442
82
      TypeNode patType = nc[pindex].getType();
443
      // should be caught in the above call
444
41
      if (!patType.isDatatype())
445
      {
446
        throw TypeCheckingExceptionPrivate(
447
            n, "expecting datatype pattern in match");
448
      }
449
41
      Kind ncpk = nc[pindex].getKind();
450
41
      if (ncpk == kind::APPLY_CONSTRUCTOR)
451
      {
452
60
        for (const Node& arg : nc[pindex])
453
        {
454
22
          if (bvs.find(arg) == bvs.end())
455
          {
456
            throw TypeCheckingExceptionPrivate(
457
                n,
458
                "expecting distinct bound variable as argument to "
459
                "constructor in pattern of match");
460
          }
461
22
          bvs.erase(arg);
462
        }
463
38
        unsigned ci = utils::indexOf(nc[pindex].getOperator());
464
38
        patIndices.insert(ci);
465
      }
466
3
      else if (ncpk == kind::BOUND_VARIABLE)
467
      {
468
3
        patHasVariable = true;
469
      }
470
      else
471
      {
472
        throw TypeCheckingExceptionPrivate(
473
            n, "unexpected kind of term in pattern in match");
474
      }
475
41
      const DType& pdt = patType.getDType();
476
      // compare datatypes instead of the types to catch parametric case,
477
      // where the pattern has parametric type.
478
41
      if (hdt.getTypeNode() != pdt.getTypeNode())
479
      {
480
        std::stringstream ss;
481
        ss << "pattern of a match case does not match the head type in match";
482
        throw TypeCheckingExceptionPrivate(n, ss.str());
483
      }
484
    }
485
82
    TypeNode currType = nc.getType(check);
486
41
    if (i == 1)
487
    {
488
17
      retType = currType;
489
    }
490
    else
491
    {
492
24
      retType = TypeNode::leastCommonTypeNode(retType, currType);
493
24
      if (retType.isNull())
494
      {
495
        throw TypeCheckingExceptionPrivate(
496
            n, "incomparable types in match case list");
497
      }
498
    }
499
  }
500
17
  if (check)
501
  {
502
17
    if (!patHasVariable && patIndices.size() < hdt.getNumConstructors())
503
    {
504
      throw TypeCheckingExceptionPrivate(
505
          n, "cases for match term are not exhaustive");
506
    }
507
  }
508
34
  return retType;
509
}
510
511
27
TypeNode MatchCaseTypeRule::computeType(NodeManager* nodeManager,
512
                                        TNode n,
513
                                        bool check)
514
{
515
27
  Assert(n.getKind() == kind::MATCH_CASE);
516
27
  if (check)
517
  {
518
54
    TypeNode patType = n[0].getType(check);
519
27
    if (!patType.isDatatype())
520
    {
521
      throw TypeCheckingExceptionPrivate(
522
          n, "expecting datatype pattern in match case");
523
    }
524
  }
525
27
  return n[1].getType(check);
526
}
527
528
12
TypeNode MatchBindCaseTypeRule::computeType(NodeManager* nodeManager,
529
                                            TNode n,
530
                                            bool check)
531
{
532
12
  Assert(n.getKind() == kind::MATCH_BIND_CASE);
533
12
  if (check)
534
  {
535
12
    if (n[0].getKind() != kind::BOUND_VAR_LIST)
536
    {
537
      throw TypeCheckingExceptionPrivate(
538
          n, "expected a bound variable list in match bind case");
539
    }
540
24
    TypeNode patType = n[1].getType(check);
541
12
    if (!patType.isDatatype())
542
    {
543
      throw TypeCheckingExceptionPrivate(
544
          n, "expecting datatype pattern in match bind case");
545
    }
546
  }
547
12
  return n[2].getType(check);
548
}
549
550
20
TypeNode TupleProjectTypeRule::computeType(NodeManager* nm, TNode n, bool check)
551
{
552
20
  Assert(n.getKind() == kind::TUPLE_PROJECT && n.hasOperator()
553
         && n.getOperator().getKind() == kind::TUPLE_PROJECT_OP);
554
40
  TupleProjectOp op = n.getOperator().getConst<TupleProjectOp>();
555
20
  const std::vector<uint32_t>& indices = op.getIndices();
556
20
  if (check)
557
  {
558
20
    if (n.getNumChildren() != 1)
559
    {
560
      std::stringstream ss;
561
      ss << "operands in term " << n << " are " << n.getNumChildren()
562
         << ", but TUPLE_PROJECT expects 1 operand.";
563
      throw TypeCheckingExceptionPrivate(n, ss.str());
564
    }
565
40
    TypeNode tupleType = n[0].getType(check);
566
20
    if (!tupleType.isTuple())
567
    {
568
      std::stringstream ss;
569
      ss << "TUPLE_PROJECT expects a tuple for " << n[0] << ". Found"
570
         << tupleType;
571
      throw TypeCheckingExceptionPrivate(n, ss.str());
572
    }
573
574
    // make sure all indices are less than the length of the tuple type
575
40
    DType dType = tupleType.getDType();
576
40
    DTypeConstructor constructor = dType[0];
577
20
    size_t numArgs = constructor.getNumArgs();
578
60
    for (uint32_t index : indices)
579
    {
580
88
      std::stringstream ss;
581
44
      if (index >= numArgs)
582
      {
583
8
        ss << "Project index " << index << " in term " << n
584
8
           << " is >= " << numArgs << " which is the length of tuple " << n[0]
585
4
           << std::endl;
586
4
        throw TypeCheckingExceptionPrivate(n, ss.str());
587
      }
588
    }
589
  }
590
32
  TypeNode tupleType = n[0].getType(check);
591
32
  std::vector<TypeNode> types;
592
32
  DType dType = tupleType.getDType();
593
32
  DTypeConstructor constructor = dType[0];
594
54
  for (uint32_t index : indices)
595
  {
596
38
    types.push_back(constructor.getArgType(index));
597
  }
598
32
  return nm->mkTupleType(types);
599
}
600
601
}  // namespace datatypes
602
}  // namespace theory
603
29340
}  // namespace cvc5