mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow fallback function to return data.
This commit is contained in:
parent
b62de4f16d
commit
fda352094f
@ -1831,15 +1831,21 @@ void TypeChecker::typeCheckFallbackFunction(FunctionDefinition const& _function)
|
||||
);
|
||||
if (_function.visibility() != Visibility::External)
|
||||
m_errorReporter.typeError(1159_error, _function.location(), "Fallback function must be defined as \"external\".");
|
||||
if (!_function.returnParameters().empty())
|
||||
|
||||
if (!_function.returnParameters().empty() || !_function.parameters().empty())
|
||||
{
|
||||
if (_function.returnParameters().size() > 1 || *type(*_function.returnParameters().front()) != *TypeProvider::bytesMemory())
|
||||
m_errorReporter.typeError(5570_error, _function.returnParameterList()->location(), "Fallback function can only have a single \"bytes memory\" return value.");
|
||||
else
|
||||
m_errorReporter.typeError(6151_error, _function.returnParameterList()->location(), "Return values for fallback functions are not yet implemented.");
|
||||
if (
|
||||
_function.returnParameters().size() != 1 ||
|
||||
*type(*_function.returnParameters().front()) != *TypeProvider::bytesMemory() ||
|
||||
_function.parameters().size() != 1 ||
|
||||
*type(*_function.parameters().front()) != *TypeProvider::bytesCalldata()
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
5570_error,
|
||||
_function.returnParameterList()->location(),
|
||||
"Fallback function either has to have the signature \"fallback()\" or \"fallback(bytes calldata) returns (bytes memory)\"."
|
||||
);
|
||||
}
|
||||
if (!_function.parameters().empty())
|
||||
m_errorReporter.typeError(3978_error, _function.parameterList().location(), "Fallback function cannot take parameters.");
|
||||
}
|
||||
|
||||
void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function)
|
||||
|
@ -467,10 +467,21 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
appendCallValueCheck();
|
||||
|
||||
solAssert(fallback->isFallback(), "");
|
||||
solAssert(FunctionType(*fallback).parameterTypes().empty(), "");
|
||||
solAssert(FunctionType(*fallback).returnParameterTypes().empty(), "");
|
||||
m_context.setStackOffset(0);
|
||||
|
||||
if (!FunctionType(*fallback).parameterTypes().empty())
|
||||
m_context << u256(0) << Instruction::CALLDATASIZE;
|
||||
|
||||
fallback->accept(*this);
|
||||
m_context << Instruction::STOP;
|
||||
|
||||
if (FunctionType(*fallback).returnParameterTypes().empty())
|
||||
m_context << Instruction::STOP;
|
||||
else
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::MLOAD << Instruction::SWAP1;
|
||||
m_context << u256(0x20) << Instruction::ADD;
|
||||
m_context << Instruction::RETURN;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_context.appendRevert("Unknown signature and no fallback defined");
|
||||
@ -479,6 +490,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
|
||||
for (auto const& it: interfaceFunctions)
|
||||
{
|
||||
m_context.setStackOffset(1);
|
||||
FunctionTypePointer const& functionType = it.second;
|
||||
solAssert(functionType->hasDeclaration(), "");
|
||||
CompilerContext::LocationSetter locationSetter(m_context, functionType->declaration());
|
||||
@ -588,7 +600,9 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
// reserve additional slots: [retarg0] ... [retargm]
|
||||
|
||||
unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters());
|
||||
if (!_function.isConstructor())
|
||||
if (_function.isFallback())
|
||||
m_context.adjustStackOffset(static_cast<int>(parametersSize));
|
||||
else if (!_function.isConstructor())
|
||||
// adding 1 for return address.
|
||||
m_context.adjustStackOffset(static_cast<int>(parametersSize) + 1);
|
||||
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters())
|
||||
@ -628,7 +642,8 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters());
|
||||
|
||||
vector<int> stackLayout;
|
||||
stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address
|
||||
if (!_function.isConstructor() && !_function.isFallback())
|
||||
stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address
|
||||
stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments
|
||||
for (size_t i = 0; i < c_returnValuesSize; ++i)
|
||||
stackLayout.push_back(static_cast<int>(i));
|
||||
@ -639,7 +654,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
errinfo_sourceLocation(_function.location()) <<
|
||||
errinfo_comment("Stack too deep, try removing local variables.")
|
||||
);
|
||||
while (stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
|
||||
while (!stackLayout.empty() && stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
|
||||
if (stackLayout.back() < 0)
|
||||
{
|
||||
m_context << Instruction::POP;
|
||||
|
@ -652,8 +652,16 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
{
|
||||
string fallbackCode;
|
||||
if (!fallback->isPayable())
|
||||
fallbackCode += callValueCheck();
|
||||
fallbackCode += m_context.enqueueFunctionForCodeGeneration(*fallback) + "() stop()";
|
||||
fallbackCode += callValueCheck() + "\n";
|
||||
if (fallback->parameters().empty())
|
||||
fallbackCode += m_context.enqueueFunctionForCodeGeneration(*fallback) + "() stop()";
|
||||
else
|
||||
{
|
||||
solAssert(fallback->parameters().size() == 1 && fallback->returnParameters().size() == 1, "");
|
||||
fallbackCode += "let retval := " + m_context.enqueueFunctionForCodeGeneration(*fallback) + "(0, calldatasize())\n";
|
||||
fallbackCode += "return(add(retval, 0x20), mload(retval))\n";
|
||||
|
||||
}
|
||||
|
||||
t("fallback", fallbackCode);
|
||||
}
|
||||
|
18
test/libsolidity/semanticTests/fallback/falback_return.sol
Normal file
18
test/libsolidity/semanticTests/fallback/falback_return.sol
Normal file
@ -0,0 +1,18 @@
|
||||
contract A {
|
||||
uint public x;
|
||||
fallback () external {
|
||||
if (x == 2) return;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// ()
|
||||
// x() -> 1
|
||||
// ()
|
||||
// x() -> 2
|
||||
// ()
|
||||
// x() -> 2
|
||||
// ()
|
||||
// x() -> 2
|
@ -0,0 +1,17 @@
|
||||
contract A {
|
||||
uint public x;
|
||||
fallback (bytes calldata _input) external returns (bytes memory) {
|
||||
x = _input.length;
|
||||
return "";
|
||||
}
|
||||
function f() public returns (bool, bytes memory) {
|
||||
(bool success, bytes memory retval) = address(this).call("abc");
|
||||
return (success, retval);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// f() -> 0x01, 0x40, 0x00
|
||||
// x() -> 3
|
@ -0,0 +1,16 @@
|
||||
contract A {
|
||||
bytes public x;
|
||||
fallback (bytes calldata _input) external returns (bytes memory) {
|
||||
x = _input;
|
||||
return "";
|
||||
}
|
||||
function f() public returns (bool, bytes memory) {
|
||||
(bool success, bytes memory retval) = address(this).call("abc");
|
||||
return (success, retval);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// f() -> 0x01, 0x40, 0x00
|
||||
// x() -> 0x20, 3, "abc"
|
@ -0,0 +1,14 @@
|
||||
contract A {
|
||||
fallback (bytes calldata _input) external returns (bytes memory) {
|
||||
return _input;
|
||||
}
|
||||
function f() public returns (bool, bytes memory) {
|
||||
(bool success, bytes memory retval) = address(this).call("abc");
|
||||
return (success, retval);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// f() -> 0x01, 0x40, 0x03, 0x6162630000000000000000000000000000000000000000000000000000000000
|
@ -2,4 +2,4 @@ contract C {
|
||||
fallback(uint256) external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3978: (25-34): Fallback function cannot take parameters.
|
||||
// TypeError 5570: (44-44): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
|
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
fallback() external returns (bytes memory _output) {}
|
||||
}
|
||||
contract D {
|
||||
fallback(bytes calldata _input) external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 5570: (45-67): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
// TypeError 5570: (131-131): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
@ -2,4 +2,4 @@ contract C {
|
||||
fallback() external returns (bytes memory, bytes memory) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 5570: (45-73): Fallback function can only have a single "bytes memory" return value.
|
||||
// TypeError 5570: (45-73): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
fallback() external returns (uint256) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 5570: (45-54): Fallback function can only have a single "bytes memory" return value.
|
||||
// TypeError 5570: (45-54): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
fallback() external returns (bytes memory) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 6151: (45-59): Return values for fallback functions are not yet implemented.
|
||||
// TypeError 5570: (45-59): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
|
4
test/libsolidity/syntaxTests/fallback/returns.sol
Normal file
4
test/libsolidity/syntaxTests/fallback/returns.sol
Normal file
@ -0,0 +1,4 @@
|
||||
contract C {
|
||||
fallback(bytes calldata _input) external returns (bytes memory _output) {}
|
||||
}
|
||||
// ----
|
@ -3,4 +3,4 @@ contract C {
|
||||
fallback(uint a) external { x = 2; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 3978: (37-45): Fallback function cannot take parameters.
|
||||
// TypeError 5570: (55-55): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
fallback() external returns (uint) { }
|
||||
}
|
||||
// ----
|
||||
// TypeError 5570: (45-51): Fallback function can only have a single "bytes memory" return value.
|
||||
// TypeError 5570: (45-51): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
|
Loading…
Reference in New Issue
Block a user