GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/datatypes/theory_datatypes_type_rules.cpp Lines: 217 279 77.8 %
Date: 2021-09-29 Branches: 445 1360 32.7 %

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