in Sources/SolToBoogie/ProcedureTranslator.cs [3378:3471]
private void TranslateTypeCast(FunctionCall node, BoogieExpr lhs, out bool isElemenentaryTypeCast)
{
isElemenentaryTypeCast = false;
VeriSolAssert(node.Kind.Equals("typeConversion"));
VeriSolAssert(node.Arguments.Count == 1);
//VeriSolAssert(node.Arguments[0] is Identifier || node.Arguments[0] is MemberAccess || node.Arguments[0] is Literal || node.Arguments[0] is IndexAccess,
// "Argument to a typecast has to be an identifier, memberAccess, indexAccess or Literal");
// target: lhs := T(expr);
BoogieExpr exprToCast = TranslateExpr(node.Arguments[0]);
if (node.Expression is Identifier) // cast to user defined types
{
Identifier contractId = node.Expression as Identifier;
ContractDefinition contract = context.GetASTNodeById(contractId.ReferencedDeclaration) as ContractDefinition;
VeriSolAssert(contract != null);
// assume (DType[var] == T);
List<ContractDefinition> subtypes = new List<ContractDefinition>(context.GetSubTypesOfContract(contract));
Debug.Assert(subtypes.Count > 0);
BoogieExpr dtype = new BoogieMapSelect(new BoogieIdentifierExpr("DType"), exprToCast);
BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, dtype,
new BoogieIdentifierExpr(subtypes[0].Name));
for (int i = 1; i < subtypes.Count; ++i)
{
BoogieExpr subGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, dtype, new BoogieIdentifierExpr(subtypes[i].Name));
guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.OR, guard, subGuard);
}
currentStmtList.AddStatement(new BoogieAssumeCmd(guard));
// lhs := expr;
currentStmtList.AddStatement(new BoogieAssignCmd(lhs, exprToCast));
}
else if (node.Expression is ElementaryTypeNameExpression elemType) // cast to elementary types
{
isElemenentaryTypeCast = true;
BoogieExpr rhsExpr = exprToCast;
// most casts are skips, except address and int cast
if (elemType.TypeName.Equals("address") || elemType.TypeName.Equals("address payable"))
{
// skip by default, unless we have an integer/hex constant
if (exprToCast is BoogieLiteralExpr blit)
{
if (blit.ToString().Equals("0"))
{
rhsExpr = (BoogieExpr)new BoogieIdentifierExpr("null");
}
else
{
rhsExpr = new BoogieFuncCallExpr("ConstantToRef", new List<BoogieExpr>() { exprToCast });
}
} else if (node.Arguments[0].TypeDescriptions.IsInt() || node.Arguments[0].TypeDescriptions.IsUint())
{
rhsExpr = new BoogieFuncCallExpr("ConstantToRef", new List<BoogieExpr>() { exprToCast });
}
}
var castToInt = Regex.Match(elemType.TypeName, @"[int,uint]\d*").Success;
if (castToInt && node.Arguments[0].TypeDescriptions.IsAddress())
{
// uint addrInt = uint(addr);
// for any other type conversion, make it uninterpreted
rhsExpr = new BoogieFuncCallExpr("BoogieRefToInt", new List<BoogieExpr>() { exprToCast });
}
// We do not handle downcasts between unsigned integers, when /useModularArithmetic option is enabled:
if (context.TranslateFlags.UseModularArithmetic)
{
bool argTypeIsUint = node.Arguments[0].TypeDescriptions.IsUintWSize(node.Arguments[0], out uint argSz);
if (argTypeIsUint && elemType.ToString().StartsWith("uint"))
{
uint castSz = uint.Parse(Extensions.GetNumberFromEnd(elemType.ToString()));
if (argSz > castSz)
{
Console.WriteLine($"Warning: downcasts are not handled with /useModularArithmetic option");
}
}
}
// lets update currentExpr with rhsExpr. The caller may update it with the temporary
currentExpr = rhsExpr;
// lhs := expr;
currentStmtList.AddStatement(new BoogieAssignCmd(lhs, rhsExpr));
}
else
{
VeriSolAssert(false, $"Unknown type cast: {node.Expression}");
}
return;
}