mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SMTChecker] Support named arguments in function calls
This commit is contained in:
parent
8d315ee130
commit
e4339b0526
@ -1,5 +1,8 @@
|
||||
### 0.7.6 (unreleased)
|
||||
|
||||
Compiler Features:
|
||||
* SMTChecker: Support named arguments in function calls.
|
||||
|
||||
|
||||
### 0.7.5 (2020-11-18)
|
||||
|
||||
|
@ -757,6 +757,44 @@ FunctionCallAnnotation& FunctionCall::annotation() const
|
||||
return initAnnotation<FunctionCallAnnotation>();
|
||||
}
|
||||
|
||||
vector<ASTPointer<Expression const>> FunctionCall::sortedArguments() const
|
||||
{
|
||||
// normal arguments
|
||||
if (m_names.empty())
|
||||
return arguments();
|
||||
|
||||
// named arguments
|
||||
FunctionTypePointer functionType;
|
||||
if (*annotation().kind == FunctionCallKind::StructConstructorCall)
|
||||
{
|
||||
auto const& type = dynamic_cast<TypeType const&>(*m_expression->annotation().type);
|
||||
auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
|
||||
functionType = structType.constructorType();
|
||||
}
|
||||
else
|
||||
functionType = dynamic_cast<FunctionType const*>(m_expression->annotation().type);
|
||||
|
||||
vector<ASTPointer<Expression const>> sorted;
|
||||
for (auto const& parameterName: functionType->parameterNames())
|
||||
{
|
||||
bool found = false;
|
||||
for (size_t j = 0; j < m_names.size() && !found; j++)
|
||||
if ((found = (parameterName == *m_names.at(j))))
|
||||
// we found the actual parameter position
|
||||
sorted.push_back(m_arguments.at(j));
|
||||
solAssert(found, "");
|
||||
}
|
||||
|
||||
if (!functionType->takesArbitraryParameters())
|
||||
{
|
||||
solAssert(m_arguments.size() == functionType->parameterTypes().size(), "");
|
||||
solAssert(m_arguments.size() == m_names.size(), "");
|
||||
solAssert(m_arguments.size() == sorted.size(), "");
|
||||
}
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
IdentifierAnnotation& Identifier::annotation() const
|
||||
{
|
||||
return initAnnotation<IdentifierAnnotation>();
|
||||
|
@ -1908,7 +1908,13 @@ public:
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
Expression const& expression() const { return *m_expression; }
|
||||
/// @returns the given arguments in the order they were written.
|
||||
std::vector<ASTPointer<Expression const>> arguments() const { return {m_arguments.begin(), m_arguments.end()}; }
|
||||
/// @returns the given arguments sorted by how the called function takes them.
|
||||
std::vector<ASTPointer<Expression const>> sortedArguments() const;
|
||||
/// @returns the list of given argument names if this is a named call,
|
||||
/// in the order they were written.
|
||||
/// If this is not a named call, this is empty.
|
||||
std::vector<ASTPointer<ASTString>> const& names() const { return m_names; }
|
||||
|
||||
FunctionCallAnnotation& annotation() const override;
|
||||
|
@ -539,26 +539,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
|
||||
|
||||
TypePointers parameterTypes = functionType->parameterTypes();
|
||||
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
|
||||
vector<ASTPointer<ASTString>> const& callArgumentNames = _functionCall.names();
|
||||
if (!functionType->takesArbitraryParameters())
|
||||
solAssert(callArguments.size() == parameterTypes.size(), "");
|
||||
|
||||
vector<ASTPointer<Expression const>> arguments;
|
||||
if (callArgumentNames.empty())
|
||||
// normal arguments
|
||||
arguments = callArguments;
|
||||
else
|
||||
// named arguments
|
||||
for (auto const& parameterName: functionType->parameterNames())
|
||||
{
|
||||
bool found = false;
|
||||
for (size_t j = 0; j < callArgumentNames.size() && !found; j++)
|
||||
if ((found = (parameterName == *callArgumentNames[j])))
|
||||
// we found the actual parameter position
|
||||
arguments.push_back(callArguments[j]);
|
||||
solAssert(found, "");
|
||||
}
|
||||
vector<ASTPointer<Expression const>> const& arguments = _functionCall.sortedArguments();
|
||||
|
||||
if (functionCallKind == FunctionCallKind::StructConstructorCall)
|
||||
{
|
||||
|
@ -846,26 +846,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
|
||||
|
||||
TypePointers parameterTypes = functionType->parameterTypes();
|
||||
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
|
||||
vector<ASTPointer<ASTString>> const& callArgumentNames = _functionCall.names();
|
||||
if (!functionType->takesArbitraryParameters())
|
||||
solAssert(callArguments.size() == parameterTypes.size(), "");
|
||||
|
||||
vector<ASTPointer<Expression const>> arguments;
|
||||
if (callArgumentNames.empty())
|
||||
// normal arguments
|
||||
arguments = callArguments;
|
||||
else
|
||||
// named arguments
|
||||
for (auto const& parameterName: functionType->parameterNames())
|
||||
{
|
||||
auto const it = std::find_if(callArgumentNames.cbegin(), callArgumentNames.cend(), [&](ASTPointer<ASTString> const& _argName) {
|
||||
return *_argName == parameterName;
|
||||
});
|
||||
|
||||
solAssert(it != callArgumentNames.cend(), "");
|
||||
arguments.push_back(callArguments[static_cast<size_t>(std::distance(callArgumentNames.begin(), it))]);
|
||||
}
|
||||
vector<ASTPointer<Expression const>> const& arguments = _functionCall.sortedArguments();
|
||||
|
||||
if (functionCallKind == FunctionCallKind::StructConstructorCall)
|
||||
{
|
||||
|
@ -2530,8 +2530,8 @@ vector<smtutil::Expression> SMTEncoder::symbolicArguments(FunctionCall const& _f
|
||||
auto const& funType = dynamic_cast<FunctionType const*>(calledExpr->annotation().type);
|
||||
solAssert(funType, "");
|
||||
|
||||
vector<ASTPointer<Expression const>> arguments = _funCall.sortedArguments();
|
||||
auto const& functionParams = function->parameters();
|
||||
auto const& arguments = _funCall.arguments();
|
||||
unsigned firstParam = 0;
|
||||
if (funType->bound())
|
||||
{
|
||||
|
@ -1,8 +1,10 @@
|
||||
contract test {
|
||||
function a(uint a, uint b, uint c) public returns (uint r) { r = a * 100 + b * 10 + c * 1; }
|
||||
function b() public returns (uint r) { r = a({a: 1, b: 2, c: 3}); }
|
||||
function c() public returns (uint r) { r = a({b: 2, c: 3, a: 1}); }
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// b() -> 123
|
||||
// c() -> 123
|
||||
|
@ -20,6 +20,8 @@ contract C {
|
||||
return f({b: 1, a: 2});
|
||||
if (num == 3)
|
||||
return f({c: 1, a: 2, b: 3});
|
||||
if (num == 4)
|
||||
return f({b: 5, c: 1, a: 2});
|
||||
|
||||
return 500;
|
||||
}
|
||||
@ -31,4 +33,5 @@ contract C {
|
||||
// call(uint256): 1 -> 1
|
||||
// call(uint256): 2 -> 3
|
||||
// call(uint256): 3 -> 6
|
||||
// call(uint256): 4 -> 500
|
||||
// call(uint256): 4 -> 8
|
||||
// call(uint256): 5 -> 500
|
||||
|
@ -6,7 +6,7 @@ contract C {
|
||||
S public s;
|
||||
|
||||
constructor() {
|
||||
s = S({a: 1, x: true});
|
||||
s = S({x: true, a: 1});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
pragma experimental SMTChecker;
|
||||
library L {
|
||||
function l(uint x, uint y) internal pure returns (uint) {
|
||||
return x + y;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f(uint u, uint s, bool b) internal pure returns (uint z) {
|
||||
if (b)
|
||||
z = u;
|
||||
else
|
||||
z = s;
|
||||
}
|
||||
|
||||
using L for uint;
|
||||
|
||||
function call() public pure {
|
||||
uint a = 2;
|
||||
uint b = a.l({y: 3});
|
||||
assert(b == 5);
|
||||
b = L.l({x: 3, y: 3});
|
||||
assert(b == 6);
|
||||
b = f({b: true, u: 1, s: 2});
|
||||
assert(b == 1);
|
||||
b = f({b: false, u: 1, s: 2});
|
||||
// Fails, should be 2.
|
||||
assert(b == 6);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 8364: (360-361): Assertion checker does not yet implement type type(library L)
|
||||
// Warning 6328: (507-521): CHC: Assertion violation happens here.
|
||||
// Warning 8364: (360-361): Assertion checker does not yet implement type type(library L)
|
@ -0,0 +1,14 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract C {
|
||||
function f(uint u, string memory s, bool b) internal {}
|
||||
|
||||
function call() public {
|
||||
f({s: "abc", u: 1, b: true});
|
||||
f({s: "abc", b: true, u: 1});
|
||||
f({u: 1, s: "abc", b: true});
|
||||
f({b: true, s: "abc", u: 1});
|
||||
f({u: 1, b: true, s: "abc"});
|
||||
f({b: true, u: 1, s: "abc"});
|
||||
}
|
||||
}
|
||||
// ----
|
@ -0,0 +1,15 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract C {
|
||||
function f(uint u, string memory s, bool b) internal {}
|
||||
function f(uint u, uint s, uint b) internal {}
|
||||
|
||||
function call() public {
|
||||
f({s: "abc", u: 1, b: true});
|
||||
f({s: "abc", b: true, u: 1});
|
||||
f({u: 1, s: "abc", b: true});
|
||||
f({b: true, s: "abc", u: 1});
|
||||
f({u: 1, b: true, s: "abc"});
|
||||
f({b: true, u: 1, s: "abc"});
|
||||
}
|
||||
}
|
||||
// ----
|
Loading…
Reference in New Issue
Block a user