mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10214 from ethereum/fallbackReturn
Allow fallback function to return data.
This commit is contained in:
commit
ee657f5361
@ -1,5 +1,8 @@
|
||||
### 0.7.6 (unreleased)
|
||||
|
||||
Language Features:
|
||||
* The fallback function can now also have a single ``calldata`` argument (equaling ``msg.data``) and return ``bytes memory`` (which will not be ABI-encoded but returned as-is).
|
||||
|
||||
Compiler Features:
|
||||
* SMTChecker: Support named arguments in function calls.
|
||||
* SMTChecker: Support struct constructor.
|
||||
|
@ -275,7 +275,10 @@ A contract can have at most one ``receive`` function, declared using
|
||||
``receive() external payable { ... }``
|
||||
(without the ``function`` keyword).
|
||||
This function cannot have arguments, cannot return anything and must have
|
||||
``external`` visibility and ``payable`` state mutability. It is executed on a
|
||||
``external`` visibility and ``payable`` state mutability.
|
||||
It can be virtual, can override and can have modifiers.
|
||||
|
||||
The receive function is executed on a
|
||||
call to the contract with empty calldata. This is the function that is executed
|
||||
on plain Ether transfers (e.g. via ``.send()`` or ``.transfer()``). If no such
|
||||
function exists, but a payable :ref:`fallback function <fallback-function>`
|
||||
@ -339,15 +342,22 @@ Below you can see an example of a Sink contract that uses function ``receive``.
|
||||
Fallback Function
|
||||
=================
|
||||
|
||||
A contract can have at most one ``fallback`` function, declared using ``fallback () external [payable]``
|
||||
(without the ``function`` keyword).
|
||||
This function cannot have arguments, cannot return anything and must have ``external`` visibility.
|
||||
It is executed on a call to the contract if none of the other
|
||||
A contract can have at most one ``fallback`` function, declared using either ``fallback () external [payable]``
|
||||
or ``fallback (bytes calldata _input) external [payable] returns (bytes memory _output)``
|
||||
(both without the ``function`` keyword).
|
||||
This function must have ``external`` visibility. A fallback function can be virtual, can override
|
||||
and can have modifiers.
|
||||
|
||||
The fallback function is executed on a call to the contract if none of the other
|
||||
functions match the given function signature, or if no data was supplied at
|
||||
all and there is no :ref:`receive Ether function <receive-ether-function>`.
|
||||
The fallback function always receives data, but in order to also receive Ether
|
||||
it must be marked ``payable``.
|
||||
|
||||
If the version with parameters is used, ``_input`` will contain the full data sent to the contract
|
||||
(equal to ``msg.data``) and can return data in ``_output``. The returned data will not be
|
||||
ABI-encoded. Instead it will be returned without modifications (not even padding).
|
||||
|
||||
In the worst case, if a payable fallback function is also used in
|
||||
place of a receive function, it can only rely on 2300 gas being
|
||||
available (see :ref:`receive Ether function <receive-ether-function>`
|
||||
@ -364,12 +374,11 @@ operations as long as there is enough gas passed on to it.
|
||||
to distinguish Ether transfers from interface confusions.
|
||||
|
||||
.. note::
|
||||
Even though the fallback function cannot have arguments, one can still use ``msg.data`` to retrieve
|
||||
any payload supplied with the call.
|
||||
After having checked the first four bytes of ``msg.data``,
|
||||
If you want to decode the input data, you can check the first four bytes
|
||||
for the function selector and then
|
||||
you can use ``abi.decode`` together with the array slice syntax to
|
||||
decode ABI-encoded data:
|
||||
``(c, d) = abi.decode(msg.data[4:], (uint256, uint256));``
|
||||
``(c, d) = abi.decode(_input[4:], (uint256, uint256));``
|
||||
Note that this should only be used as a last resort and
|
||||
proper functions should be used instead.
|
||||
|
||||
|
@ -84,7 +84,8 @@ contractBodyElement:
|
||||
constructorDefinition
|
||||
| functionDefinition
|
||||
| modifierDefinition
|
||||
| fallbackReceiveFunctionDefinition
|
||||
| fallbackFunctionDefinition
|
||||
| receiveFunctionDefinition
|
||||
| structDefinition
|
||||
| enumDefinition
|
||||
| stateVariableDeclaration
|
||||
@ -189,9 +190,32 @@ locals[
|
||||
(Semicolon | body=block);
|
||||
|
||||
/**
|
||||
* Definitions of the special fallback and receive functions.
|
||||
* Definition of the special fallback function.
|
||||
*/
|
||||
fallbackReceiveFunctionDefinition
|
||||
fallbackFunctionDefinition
|
||||
locals[
|
||||
boolean visibilitySet = false,
|
||||
boolean mutabilitySet = false,
|
||||
boolean virtualSet = false,
|
||||
boolean overrideSpecifierSet = false,
|
||||
boolean hasParameters = false
|
||||
]
|
||||
:
|
||||
kind=Fallback LParen (parameterList { $hasParameters = true; } )? RParen
|
||||
(
|
||||
{!$visibilitySet}? External {$visibilitySet = true;}
|
||||
| {!$mutabilitySet}? stateMutability {$mutabilitySet = true;}
|
||||
| modifierInvocation
|
||||
| {!$virtualSet}? Virtual {$virtualSet = true;}
|
||||
| {!$overrideSpecifierSet}? overrideSpecifier {$overrideSpecifierSet = true;}
|
||||
)*
|
||||
( {$hasParameters}? Returns LParen returnParameters=parameterList RParen | {!$hasParameters}? )
|
||||
(Semicolon | body=block);
|
||||
|
||||
/**
|
||||
* Definition of the special receive function.
|
||||
*/
|
||||
receiveFunctionDefinition
|
||||
locals[
|
||||
boolean visibilitySet = false,
|
||||
boolean mutabilitySet = false,
|
||||
@ -199,10 +223,10 @@ locals[
|
||||
boolean overrideSpecifierSet = false
|
||||
]
|
||||
:
|
||||
kind=(Fallback | Receive) LParen RParen
|
||||
kind=Receive LParen RParen
|
||||
(
|
||||
{!$visibilitySet}? visibility {$visibilitySet = true;}
|
||||
| {!$mutabilitySet}? stateMutability {$mutabilitySet = true;}
|
||||
{!$visibilitySet}? External {$visibilitySet = true;}
|
||||
| {!$mutabilitySet}? Payable {$mutabilitySet = true;}
|
||||
| modifierInvocation
|
||||
| {!$virtualSet}? Virtual {$virtualSet = true;}
|
||||
| {!$overrideSpecifierSet}? overrideSpecifier {$overrideSpecifierSet = true;}
|
||||
|
@ -394,6 +394,10 @@ bool OverrideProxy::OverrideComparator::operator<(OverrideComparator const& _oth
|
||||
if (functionKind != _other.functionKind)
|
||||
return *functionKind < *_other.functionKind;
|
||||
|
||||
// Parameters do not matter for non-regular functions.
|
||||
if (functionKind != Token::Function)
|
||||
return false;
|
||||
|
||||
if (!parameterTypes || !_other.parameterTypes)
|
||||
return false;
|
||||
|
||||
@ -574,16 +578,19 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
|
||||
FunctionType const* functionType = _overriding.functionType();
|
||||
FunctionType const* superType = _super.functionType();
|
||||
|
||||
solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!");
|
||||
if (_overriding.functionKind() != Token::Fallback)
|
||||
{
|
||||
solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!");
|
||||
|
||||
if (!functionType->hasEqualReturnTypes(*superType))
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
4822_error,
|
||||
"Overriding " + _overriding.astNodeName() + " return types differ.",
|
||||
"Overridden " + _overriding.astNodeName() + " is here:"
|
||||
);
|
||||
if (!functionType->hasEqualReturnTypes(*superType))
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
4822_error,
|
||||
"Overriding " + _overriding.astNodeName() + " return types differ.",
|
||||
"Overridden " + _overriding.astNodeName() + " is here:"
|
||||
);
|
||||
}
|
||||
|
||||
// Stricter mutability is always okay except when super is Payable
|
||||
if (
|
||||
|
@ -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,19 @@
|
||||
contract A {
|
||||
fallback (bytes calldata _input) virtual external returns (bytes memory) {
|
||||
return _input;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
fallback (bytes calldata _input) override external returns (bytes memory) {
|
||||
return "xyz";
|
||||
}
|
||||
function f() public returns (bool, bytes memory) {
|
||||
(bool success, bytes memory retval) = address(this).call("abc");
|
||||
return (success, retval);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x01, 0x40, 0x03, 0x78797a0000000000000000000000000000000000000000000000000000000000
|
@ -0,0 +1,18 @@
|
||||
contract A {
|
||||
fallback (bytes calldata _input) virtual external returns (bytes memory) {
|
||||
return _input;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
fallback () override external {
|
||||
}
|
||||
function f() public returns (bool, bytes memory) {
|
||||
(bool success, bytes memory retval) = address(this).call("abc");
|
||||
return (success, retval);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 1, 0x40, 0x00
|
@ -0,0 +1,22 @@
|
||||
contract A {
|
||||
fallback (bytes calldata _input) virtual external returns (bytes memory) {
|
||||
return _input;
|
||||
}
|
||||
}
|
||||
contract B {
|
||||
fallback (bytes calldata _input) virtual external returns (bytes memory) {
|
||||
return "xyz";
|
||||
}
|
||||
}
|
||||
contract C is B, A {
|
||||
fallback () external override (B, A) {}
|
||||
function f() public returns (bool, bytes memory) {
|
||||
(bool success, bytes memory retval) = address(this).call("abc");
|
||||
return (success, retval);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x01, 0x40, 0x00
|
@ -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,6 @@
|
||||
contract C {
|
||||
fallback(bytes calldata _input) external returns (bytes memory _output) {}
|
||||
fallback() external {}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 7301: (96-118): Only one fallback function is allowed.
|
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
fallback(bytes calldata _input) external returns (bytes memory _output) {}
|
||||
}
|
||||
contract D is C {
|
||||
fallback() external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9456: (116-138): Overriding function is missing "override" specifier.
|
||||
// TypeError 4334: (17-91): Trying to override non-virtual function. Did you forget to add "virtual"?
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
fallback(bytes calldata _input) external virtual returns (bytes memory _output) {}
|
||||
}
|
||||
contract D is C {
|
||||
fallback() external override {}
|
||||
}
|
||||
// ----
|
@ -0,0 +1,13 @@
|
||||
contract D {
|
||||
fallback(bytes memory) external returns (bytes memory) {}
|
||||
}
|
||||
contract E {
|
||||
fallback(bytes memory) external returns (bytes calldata) {}
|
||||
}
|
||||
contract F {
|
||||
fallback(bytes calldata) external returns (bytes calldata) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 5570: (57-71): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
// TypeError 5570: (134-150): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
||||
// TypeError 5570: (215-231): Fallback function either has to have the signature "fallback()" or "fallback(bytes calldata) returns (bytes memory)".
|
@ -0,0 +1,20 @@
|
||||
contract A {
|
||||
fallback (bytes calldata _input) external returns (bytes memory) {
|
||||
return _input;
|
||||
}
|
||||
}
|
||||
contract B {
|
||||
fallback (bytes calldata _input) external returns (bytes memory) {
|
||||
return "xyz";
|
||||
}
|
||||
}
|
||||
contract C is B, A {
|
||||
function f() public returns (bool, bytes memory) {
|
||||
(bool success, bytes memory retval) = address(this).call("abc");
|
||||
return (success, retval);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// TypeError 6480: (229-420): Derived contract must override function "". Two or more base classes define function with same name and parameter types.
|
@ -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