@@ -1001,7 +1001,35 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode)
1001
1001
}
1002
1002
else if (expr.id () == ID_smv_setin)
1003
1003
{
1004
- expr.type ()=bool_typet ();
1004
+ auto &lhs = to_binary_expr (expr).lhs ();
1005
+ auto &rhs = to_binary_expr (expr).rhs ();
1006
+
1007
+ typecheck_expr_rec (lhs, mode);
1008
+ typecheck_expr_rec (rhs, mode);
1009
+
1010
+ // The RHS can be a set or a singleton
1011
+ if (rhs.type ().id () == ID_smv_set)
1012
+ {
1013
+ PRECONDITION (rhs.id () == ID_smv_set);
1014
+ // do type union
1015
+ typet op_type = lhs.type ();
1016
+ for (auto &op : rhs.operands ())
1017
+ op_type = type_union (op_type, op.type (), expr.source_location ());
1018
+ // now convert
1019
+ convert_expr_to (lhs, op_type);
1020
+ for (auto &op : rhs.operands ())
1021
+ convert_expr_to (op, op_type);
1022
+ }
1023
+ else
1024
+ {
1025
+ typet op_type =
1026
+ type_union (lhs.type (), rhs.type (), expr.source_location ());
1027
+
1028
+ convert_expr_to (lhs, op_type);
1029
+ convert_expr_to (rhs, op_type);
1030
+ }
1031
+
1032
+ expr.type () = bool_typet ();
1005
1033
}
1006
1034
else if (expr.id () == ID_smv_setnotin)
1007
1035
{
@@ -1232,6 +1260,11 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode)
1232
1260
<< " signed operand must have unsigned word type" ;
1233
1261
}
1234
1262
}
1263
+ else if (expr.id () == ID_smv_set)
1264
+ {
1265
+ // a set literal
1266
+ expr.type () = typet{ID_smv_set};
1267
+ }
1235
1268
else
1236
1269
{
1237
1270
throw errort ().with_location (expr.find_source_location ())
@@ -1271,6 +1304,33 @@ void smv_typecheckt::lower_node(exprt &expr) const
1271
1304
{
1272
1305
expr = typecast_exprt{to_smv_unsigned_cast_expr (expr).op (), expr.type ()};
1273
1306
}
1307
+ else if (expr.id () == ID_smv_setin)
1308
+ {
1309
+ auto &lhs = to_binary_expr (expr).lhs ();
1310
+ auto &rhs = to_binary_expr (expr).rhs ();
1311
+ if (rhs.type ().id () == ID_smv_set)
1312
+ {
1313
+ DATA_INVARIANT (
1314
+ rhs.id () == ID_smv_set, " rhs of in must be set expression" );
1315
+ // this is an 'or'
1316
+ exprt::operandst disjuncts;
1317
+ disjuncts.reserve (rhs.operands ().size ());
1318
+ for (auto &op : rhs.operands ())
1319
+ {
1320
+ DATA_INVARIANT (
1321
+ lhs.type () == op.type (), " lhs/rhs of in must have same type" );
1322
+ disjuncts.push_back (equal_exprt{lhs, op});
1323
+ }
1324
+ expr = disjunction (std::move (disjuncts));
1325
+ }
1326
+ else
1327
+ {
1328
+ // RHS is a singleton; this is equality
1329
+ expr.id (ID_equal);
1330
+ DATA_INVARIANT (
1331
+ lhs.type () == rhs.type (), " lhs/rhs of in must have same type" );
1332
+ }
1333
+ }
1274
1334
}
1275
1335
1276
1336
/* ******************************************************************\
@@ -1285,28 +1345,50 @@ Function: smv_typecheckt::convert_expr_to
1285
1345
1286
1346
\*******************************************************************/
1287
1347
1288
- void smv_typecheckt::convert_expr_to (exprt &expr, const typet &type )
1348
+ void smv_typecheckt::convert_expr_to (exprt &expr, const typet &dest_type )
1289
1349
{
1290
- PRECONDITION (type.is_not_nil ());
1350
+ const auto &src_type = expr.type ();
1351
+
1352
+ PRECONDITION (dest_type.is_not_nil ());
1291
1353
1292
- if (expr. type () != type )
1354
+ if (src_type != dest_type )
1293
1355
{
1294
- if (type.id () == ID_signedbv || type.id () == ID_unsignedbv)
1356
+ if (src_type.id () == ID_smv_set && expr.id () == ID_smv_set)
1357
+ {
1358
+ // sets can be assigned to scalars, which yields a nondeterministic
1359
+ // choice
1360
+ std::string identifier =
1361
+ module + " ::var::" + std::to_string (nondet_count++);
1362
+
1363
+ expr.set (ID_identifier, identifier);
1364
+ expr.set (" #smv_nondet_choice" , true );
1365
+
1366
+ expr.id (ID_constraint_select_one);
1367
+ expr.type () = dest_type;
1368
+
1369
+ // apply recursively
1370
+ for (auto &op : expr.operands ())
1371
+ convert_expr_to (op, dest_type);
1372
+
1373
+ return ;
1374
+ }
1375
+
1376
+ if (dest_type.id () == ID_signedbv || dest_type.id () == ID_unsignedbv)
1295
1377
{
1296
1378
// no implicit conversion
1297
1379
}
1298
- else if (type .id () == ID_range)
1380
+ else if (dest_type .id () == ID_range)
1299
1381
{
1300
- if (expr. type () .id () == ID_range)
1382
+ if (src_type .id () == ID_range)
1301
1383
{
1302
1384
// range to range
1303
1385
if (expr.id () == ID_constant)
1304
1386
{
1305
1387
// re-type the constant
1306
1388
auto value = numeric_cast_v<mp_integer>(to_constant_expr (expr));
1307
- if (to_range_type (type ).includes (value))
1389
+ if (to_range_type (dest_type ).includes (value))
1308
1390
{
1309
- expr = from_integer (value, type );
1391
+ expr = from_integer (value, dest_type );
1310
1392
return ;
1311
1393
}
1312
1394
}
@@ -1318,26 +1400,40 @@ void smv_typecheckt::convert_expr_to(exprt &expr, const typet &type)
1318
1400
for (auto &op : expr.operands ())
1319
1401
{
1320
1402
if (!condition)
1321
- convert_expr_to (op, type );
1403
+ convert_expr_to (op, dest_type );
1322
1404
1323
1405
condition = !condition;
1324
1406
}
1325
- expr.type () = type ;
1407
+ expr.type () = dest_type ;
1326
1408
return ;
1327
1409
}
1328
1410
else
1329
1411
{
1330
- expr = typecast_exprt{expr, type };
1412
+ expr = typecast_exprt{expr, dest_type };
1331
1413
return ;
1332
1414
}
1333
1415
}
1416
+ else if (src_type.id () == ID_integer)
1417
+ {
1418
+ // integer to range
1419
+ if (expr.id () == ID_constant)
1420
+ {
1421
+ // re-type the constant
1422
+ auto value = numeric_cast_v<mp_integer>(to_constant_expr (expr));
1423
+ if (to_range_type (dest_type).includes (value))
1424
+ {
1425
+ expr = from_integer (value, dest_type);
1426
+ return ;
1427
+ }
1428
+ }
1429
+ }
1334
1430
}
1335
- else if (type .id () == ID_bool)
1431
+ else if (dest_type .id () == ID_bool)
1336
1432
{
1337
1433
// legacy -- convert 0/1 to false/true
1338
- if (expr. type () .id () == ID_range)
1434
+ if (src_type .id () == ID_range)
1339
1435
{
1340
- auto &range_type = to_range_type (expr. type () );
1436
+ auto &range_type = to_range_type (src_type );
1341
1437
if (range_type.get_from () == 0 && range_type.get_to () == 0 )
1342
1438
{
1343
1439
expr = false_exprt{};
@@ -1350,43 +1446,41 @@ void smv_typecheckt::convert_expr_to(exprt &expr, const typet &type)
1350
1446
}
1351
1447
}
1352
1448
}
1353
- else if (type .id () == ID_enumeration)
1449
+ else if (dest_type .id () == ID_enumeration)
1354
1450
{
1355
- auto &e_type = to_enumeration_type (type );
1451
+ auto &e_type = to_enumeration_type (dest_type );
1356
1452
1357
- if (expr.id () == ID_constant && expr. type () .id () == ID_enumeration)
1453
+ if (expr.id () == ID_constant && src_type .id () == ID_enumeration)
1358
1454
{
1359
- if (is_contained_in (to_enumeration_type (expr. type () ), e_type))
1455
+ if (is_contained_in (to_enumeration_type (src_type ), e_type))
1360
1456
{
1361
1457
// re-type the constant
1362
- expr.type () = type ;
1458
+ expr.type () = dest_type ;
1363
1459
return ;
1364
1460
}
1365
1461
else
1366
1462
{
1367
1463
throw errort ().with_location (expr.find_source_location ())
1368
1464
<< " enum " << to_string (expr) << " not a member of "
1369
- << to_string (type );
1465
+ << to_string (dest_type );
1370
1466
}
1371
1467
}
1372
1468
else if (expr.id () == ID_typecast)
1373
1469
{
1374
1470
// created by type unions
1375
1471
auto &op = to_typecast_expr (expr).op ();
1376
- if (
1377
- expr.type ().id () == ID_enumeration &&
1378
- op.type ().id () == ID_enumeration)
1472
+ if (src_type.id () == ID_enumeration && op.type ().id () == ID_enumeration)
1379
1473
{
1380
- convert_expr_to (op, type );
1474
+ convert_expr_to (op, dest_type );
1381
1475
expr = std::move (op);
1382
1476
}
1383
1477
}
1384
1478
}
1385
1479
1386
1480
throw errort ().with_location (expr.find_source_location ())
1387
- << " Expected expression of type `" << to_string (type )
1481
+ << " Expected expression of type `" << to_string (dest_type )
1388
1482
<< " ', but got expression `" << to_string (expr) << " ', which is of type `"
1389
- << to_string (expr. type () ) << " '" ;
1483
+ << to_string (src_type ) << " '" ;
1390
1484
}
1391
1485
}
1392
1486
0 commit comments