mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2722 from ethereum/statemutability
Introduce state mutability (to replace const/payable)
This commit is contained in:
commit
0a04a35a2e
@ -500,8 +500,6 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
|||||||
m_errorReporter.typeError(_function.location(), "Library functions cannot be payable.");
|
m_errorReporter.typeError(_function.location(), "Library functions cannot be payable.");
|
||||||
if (!_function.isConstructor() && !_function.isFallback() && !_function.isPartOfExternalInterface())
|
if (!_function.isConstructor() && !_function.isFallback() && !_function.isPartOfExternalInterface())
|
||||||
m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable.");
|
m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable.");
|
||||||
if (_function.isDeclaredConst())
|
|
||||||
m_errorReporter.typeError(_function.location(), "Functions cannot be constant and payable at the same time.");
|
|
||||||
}
|
}
|
||||||
for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
|
for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <libsolidity/ast/Types.h>
|
#include <libsolidity/ast/Types.h>
|
||||||
#include <libsolidity/interface/Exceptions.h>
|
#include <libsolidity/interface/Exceptions.h>
|
||||||
#include <libsolidity/ast/ASTAnnotations.h>
|
#include <libsolidity/ast/ASTAnnotations.h>
|
||||||
|
#include <libsolidity/ast/ASTEnums.h>
|
||||||
|
|
||||||
#include <libevmasm/SourceLocation.h>
|
#include <libevmasm/SourceLocation.h>
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
@ -584,21 +585,19 @@ public:
|
|||||||
SourceLocation const& _location,
|
SourceLocation const& _location,
|
||||||
ASTPointer<ASTString> const& _name,
|
ASTPointer<ASTString> const& _name,
|
||||||
Declaration::Visibility _visibility,
|
Declaration::Visibility _visibility,
|
||||||
|
StateMutability _stateMutability,
|
||||||
bool _isConstructor,
|
bool _isConstructor,
|
||||||
ASTPointer<ASTString> const& _documentation,
|
ASTPointer<ASTString> const& _documentation,
|
||||||
ASTPointer<ParameterList> const& _parameters,
|
ASTPointer<ParameterList> const& _parameters,
|
||||||
bool _isDeclaredConst,
|
|
||||||
std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
|
std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
|
||||||
ASTPointer<ParameterList> const& _returnParameters,
|
ASTPointer<ParameterList> const& _returnParameters,
|
||||||
bool _isPayable,
|
|
||||||
ASTPointer<Block> const& _body
|
ASTPointer<Block> const& _body
|
||||||
):
|
):
|
||||||
CallableDeclaration(_location, _name, _visibility, _parameters, _returnParameters),
|
CallableDeclaration(_location, _name, _visibility, _parameters, _returnParameters),
|
||||||
Documented(_documentation),
|
Documented(_documentation),
|
||||||
ImplementationOptional(_body != nullptr),
|
ImplementationOptional(_body != nullptr),
|
||||||
|
m_stateMutability(_stateMutability),
|
||||||
m_isConstructor(_isConstructor),
|
m_isConstructor(_isConstructor),
|
||||||
m_isDeclaredConst(_isDeclaredConst),
|
|
||||||
m_isPayable(_isPayable),
|
|
||||||
m_functionModifiers(_modifiers),
|
m_functionModifiers(_modifiers),
|
||||||
m_body(_body)
|
m_body(_body)
|
||||||
{}
|
{}
|
||||||
@ -606,10 +605,11 @@ public:
|
|||||||
virtual void accept(ASTVisitor& _visitor) override;
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
virtual void accept(ASTConstVisitor& _visitor) const override;
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
|
StateMutability stateMutability() const { return m_stateMutability; }
|
||||||
bool isConstructor() const { return m_isConstructor; }
|
bool isConstructor() const { return m_isConstructor; }
|
||||||
bool isFallback() const { return name().empty(); }
|
bool isFallback() const { return name().empty(); }
|
||||||
bool isDeclaredConst() const { return m_isDeclaredConst; }
|
bool isDeclaredConst() const { return m_stateMutability == StateMutability::View; }
|
||||||
bool isPayable() const { return m_isPayable; }
|
bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
|
||||||
std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
|
std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
|
||||||
std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); }
|
std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); }
|
||||||
Block const& body() const { solAssert(m_body, ""); return *m_body; }
|
Block const& body() const { solAssert(m_body, ""); return *m_body; }
|
||||||
@ -634,9 +634,8 @@ public:
|
|||||||
virtual FunctionDefinitionAnnotation& annotation() const override;
|
virtual FunctionDefinitionAnnotation& annotation() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
StateMutability m_stateMutability;
|
||||||
bool m_isConstructor;
|
bool m_isConstructor;
|
||||||
bool m_isDeclaredConst;
|
|
||||||
bool m_isPayable;
|
|
||||||
std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
|
std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
|
||||||
ASTPointer<Block> m_body;
|
ASTPointer<Block> m_body;
|
||||||
};
|
};
|
||||||
@ -896,11 +895,10 @@ public:
|
|||||||
ASTPointer<ParameterList> const& _parameterTypes,
|
ASTPointer<ParameterList> const& _parameterTypes,
|
||||||
ASTPointer<ParameterList> const& _returnTypes,
|
ASTPointer<ParameterList> const& _returnTypes,
|
||||||
Declaration::Visibility _visibility,
|
Declaration::Visibility _visibility,
|
||||||
bool _isDeclaredConst,
|
StateMutability _stateMutability
|
||||||
bool _isPayable
|
|
||||||
):
|
):
|
||||||
TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
|
TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
|
||||||
m_visibility(_visibility), m_isDeclaredConst(_isDeclaredConst), m_isPayable(_isPayable)
|
m_visibility(_visibility), m_stateMutability(_stateMutability)
|
||||||
{}
|
{}
|
||||||
virtual void accept(ASTVisitor& _visitor) override;
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
virtual void accept(ASTConstVisitor& _visitor) const override;
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
@ -914,15 +912,15 @@ public:
|
|||||||
{
|
{
|
||||||
return m_visibility == Declaration::Visibility::Default ? Declaration::Visibility::Internal : m_visibility;
|
return m_visibility == Declaration::Visibility::Default ? Declaration::Visibility::Internal : m_visibility;
|
||||||
}
|
}
|
||||||
bool isDeclaredConst() const { return m_isDeclaredConst; }
|
StateMutability stateMutability() const { return m_stateMutability; }
|
||||||
bool isPayable() const { return m_isPayable; }
|
bool isDeclaredConst() const { return m_stateMutability == StateMutability::View; }
|
||||||
|
bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ASTPointer<ParameterList> m_parameterTypes;
|
ASTPointer<ParameterList> m_parameterTypes;
|
||||||
ASTPointer<ParameterList> m_returnTypes;
|
ASTPointer<ParameterList> m_returnTypes;
|
||||||
Declaration::Visibility m_visibility;
|
Declaration::Visibility m_visibility;
|
||||||
bool m_isDeclaredConst;
|
StateMutability m_stateMutability;
|
||||||
bool m_isPayable;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
52
libsolidity/ast/ASTEnums.h
Normal file
52
libsolidity/ast/ASTEnums.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @date 2017
|
||||||
|
* Enums for AST classes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/interface/Exceptions.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace solidity
|
||||||
|
{
|
||||||
|
|
||||||
|
// How a function can mutate the EVM state.
|
||||||
|
enum class StateMutability { View, NonPayable, Payable };
|
||||||
|
|
||||||
|
inline std::string stateMutabilityToString(StateMutability const& _stateMutability)
|
||||||
|
{
|
||||||
|
switch(_stateMutability)
|
||||||
|
{
|
||||||
|
case StateMutability::View:
|
||||||
|
return "view";
|
||||||
|
case StateMutability::NonPayable:
|
||||||
|
return "nonpayable";
|
||||||
|
case StateMutability::Payable:
|
||||||
|
return "payable";
|
||||||
|
default:
|
||||||
|
solAssert(false, "Unknown state mutability.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -95,6 +95,5 @@ using ASTPointer = std::shared_ptr<T>;
|
|||||||
|
|
||||||
using ASTString = std::string;
|
using ASTString = std::string;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -477,8 +477,8 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
|
|||||||
if (isAddress())
|
if (isAddress())
|
||||||
return {
|
return {
|
||||||
{"balance", make_shared<IntegerType >(256)},
|
{"balance", make_shared<IntegerType >(256)},
|
||||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, false, true)},
|
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, StateMutability::Payable)},
|
||||||
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, false, true)},
|
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, StateMutability::Payable)},
|
||||||
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)},
|
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)},
|
||||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
|
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
|
||||||
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
|
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
|
||||||
@ -2000,8 +2000,7 @@ TypePointer TupleType::closestTemporaryType(TypePointer const& _targetType) cons
|
|||||||
|
|
||||||
FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal):
|
FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal):
|
||||||
m_kind(_isInternal ? Kind::Internal : Kind::External),
|
m_kind(_isInternal ? Kind::Internal : Kind::External),
|
||||||
m_isConstant(_function.isDeclaredConst()),
|
m_stateMutability(_function.stateMutability()),
|
||||||
m_isPayable(_isInternal ? false : _function.isPayable()),
|
|
||||||
m_declaration(&_function)
|
m_declaration(&_function)
|
||||||
{
|
{
|
||||||
TypePointers params;
|
TypePointers params;
|
||||||
@ -2009,6 +2008,9 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
|
|||||||
TypePointers retParams;
|
TypePointers retParams;
|
||||||
vector<string> retParamNames;
|
vector<string> retParamNames;
|
||||||
|
|
||||||
|
if (_isInternal && m_stateMutability == StateMutability::Payable)
|
||||||
|
m_stateMutability = StateMutability::NonPayable;
|
||||||
|
|
||||||
params.reserve(_function.parameters().size());
|
params.reserve(_function.parameters().size());
|
||||||
paramNames.reserve(_function.parameters().size());
|
paramNames.reserve(_function.parameters().size());
|
||||||
for (ASTPointer<VariableDeclaration> const& var: _function.parameters())
|
for (ASTPointer<VariableDeclaration> const& var: _function.parameters())
|
||||||
@ -2030,7 +2032,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
|
|||||||
}
|
}
|
||||||
|
|
||||||
FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
||||||
m_kind(Kind::External), m_isConstant(true), m_declaration(&_varDecl)
|
m_kind(Kind::External), m_stateMutability(StateMutability::View), m_declaration(&_varDecl)
|
||||||
{
|
{
|
||||||
TypePointers paramTypes;
|
TypePointers paramTypes;
|
||||||
vector<string> paramNames;
|
vector<string> paramNames;
|
||||||
@ -2090,7 +2092,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
|||||||
}
|
}
|
||||||
|
|
||||||
FunctionType::FunctionType(EventDefinition const& _event):
|
FunctionType::FunctionType(EventDefinition const& _event):
|
||||||
m_kind(Kind::Event), m_isConstant(true), m_declaration(&_event)
|
m_kind(Kind::Event), m_stateMutability(StateMutability::View), m_declaration(&_event)
|
||||||
{
|
{
|
||||||
TypePointers params;
|
TypePointers params;
|
||||||
vector<string> paramNames;
|
vector<string> paramNames;
|
||||||
@ -2107,14 +2109,10 @@ FunctionType::FunctionType(EventDefinition const& _event):
|
|||||||
|
|
||||||
FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
||||||
m_kind(_typeName.visibility() == VariableDeclaration::Visibility::External ? Kind::External : Kind::Internal),
|
m_kind(_typeName.visibility() == VariableDeclaration::Visibility::External ? Kind::External : Kind::Internal),
|
||||||
m_isConstant(_typeName.isDeclaredConst()),
|
m_stateMutability(_typeName.stateMutability())
|
||||||
m_isPayable(_typeName.isPayable())
|
|
||||||
{
|
{
|
||||||
if (_typeName.isPayable())
|
if (_typeName.isPayable())
|
||||||
{
|
|
||||||
solAssert(m_kind == Kind::External, "Internal payable function type used.");
|
solAssert(m_kind == Kind::External, "Internal payable function type used.");
|
||||||
solAssert(!m_isConstant, "Payable constant function");
|
|
||||||
}
|
|
||||||
for (auto const& t: _typeName.parameterTypes())
|
for (auto const& t: _typeName.parameterTypes())
|
||||||
{
|
{
|
||||||
solAssert(t->annotation().type, "Type not set for parameter.");
|
solAssert(t->annotation().type, "Type not set for parameter.");
|
||||||
@ -2142,7 +2140,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
|
|||||||
FunctionDefinition const* constructor = _contract.constructor();
|
FunctionDefinition const* constructor = _contract.constructor();
|
||||||
TypePointers parameters;
|
TypePointers parameters;
|
||||||
strings parameterNames;
|
strings parameterNames;
|
||||||
bool payable = false;
|
StateMutability stateMutability = StateMutability::NonPayable;
|
||||||
|
|
||||||
if (constructor)
|
if (constructor)
|
||||||
{
|
{
|
||||||
@ -2151,7 +2149,8 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
|
|||||||
parameterNames.push_back(var->name());
|
parameterNames.push_back(var->name());
|
||||||
parameters.push_back(var->annotation().type);
|
parameters.push_back(var->annotation().type);
|
||||||
}
|
}
|
||||||
payable = constructor->isPayable();
|
if (constructor->isPayable())
|
||||||
|
stateMutability = StateMutability::Payable;
|
||||||
}
|
}
|
||||||
return make_shared<FunctionType>(
|
return make_shared<FunctionType>(
|
||||||
parameters,
|
parameters,
|
||||||
@ -2161,8 +2160,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
|
|||||||
Kind::Creation,
|
Kind::Creation,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
false,
|
stateMutability
|
||||||
payable
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2241,8 +2239,8 @@ bool FunctionType::operator==(Type const& _other) const
|
|||||||
FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
|
FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
|
||||||
if (
|
if (
|
||||||
m_kind != other.m_kind ||
|
m_kind != other.m_kind ||
|
||||||
m_isConstant != other.isConstant() ||
|
isConstant() != other.isConstant() ||
|
||||||
m_isPayable != other.isPayable() ||
|
isPayable() != other.isPayable() ||
|
||||||
m_parameterTypes.size() != other.m_parameterTypes.size() ||
|
m_parameterTypes.size() != other.m_parameterTypes.size() ||
|
||||||
m_returnParameterTypes.size() != other.m_returnParameterTypes.size()
|
m_returnParameterTypes.size() != other.m_returnParameterTypes.size()
|
||||||
)
|
)
|
||||||
@ -2304,9 +2302,9 @@ string FunctionType::toString(bool _short) const
|
|||||||
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
|
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
|
||||||
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
|
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
|
||||||
name += ")";
|
name += ")";
|
||||||
if (m_isConstant)
|
if (isConstant())
|
||||||
name += " constant";
|
name += " constant";
|
||||||
if (m_isPayable)
|
if (isPayable())
|
||||||
name += " payable";
|
name += " payable";
|
||||||
if (m_kind == Kind::External)
|
if (m_kind == Kind::External)
|
||||||
name += " external";
|
name += " external";
|
||||||
@ -2420,8 +2418,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
|
|||||||
m_kind,
|
m_kind,
|
||||||
m_arbitraryParameters,
|
m_arbitraryParameters,
|
||||||
m_declaration,
|
m_declaration,
|
||||||
m_isConstant,
|
m_stateMutability
|
||||||
m_isPayable
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2438,7 +2435,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
MemberList::MemberMap members;
|
MemberList::MemberMap members;
|
||||||
if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall)
|
if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall)
|
||||||
{
|
{
|
||||||
if (m_isPayable)
|
if (isPayable())
|
||||||
members.push_back(MemberList::Member(
|
members.push_back(MemberList::Member(
|
||||||
"value",
|
"value",
|
||||||
make_shared<FunctionType>(
|
make_shared<FunctionType>(
|
||||||
@ -2449,8 +2446,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
Kind::SetValue,
|
Kind::SetValue,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
false,
|
StateMutability::NonPayable,
|
||||||
false,
|
|
||||||
m_gasSet,
|
m_gasSet,
|
||||||
m_valueSet
|
m_valueSet
|
||||||
)
|
)
|
||||||
@ -2467,8 +2463,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
Kind::SetGas,
|
Kind::SetGas,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
false,
|
StateMutability::NonPayable,
|
||||||
false,
|
|
||||||
m_gasSet,
|
m_gasSet,
|
||||||
m_valueSet
|
m_valueSet
|
||||||
)
|
)
|
||||||
@ -2604,8 +2599,7 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con
|
|||||||
m_kind,
|
m_kind,
|
||||||
m_arbitraryParameters,
|
m_arbitraryParameters,
|
||||||
m_declaration,
|
m_declaration,
|
||||||
m_isConstant,
|
m_stateMutability,
|
||||||
m_isPayable,
|
|
||||||
m_gasSet || _setGas,
|
m_gasSet || _setGas,
|
||||||
m_valueSet || _setValue,
|
m_valueSet || _setValue,
|
||||||
m_bound
|
m_bound
|
||||||
@ -2654,8 +2648,7 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound)
|
|||||||
kind,
|
kind,
|
||||||
m_arbitraryParameters,
|
m_arbitraryParameters,
|
||||||
m_declaration,
|
m_declaration,
|
||||||
m_isConstant,
|
m_stateMutability,
|
||||||
m_isPayable,
|
|
||||||
m_gasSet,
|
m_gasSet,
|
||||||
m_valueSet,
|
m_valueSet,
|
||||||
_bound
|
_bound
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/interface/Exceptions.h>
|
#include <libsolidity/interface/Exceptions.h>
|
||||||
#include <libsolidity/ast/ASTForward.h>
|
#include <libsolidity/ast/ASTForward.h>
|
||||||
|
#include <libsolidity/ast/ASTEnums.h>
|
||||||
#include <libsolidity/parsing/Token.h>
|
#include <libsolidity/parsing/Token.h>
|
||||||
|
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
@ -889,8 +890,7 @@ public:
|
|||||||
strings const& _returnParameterTypes,
|
strings const& _returnParameterTypes,
|
||||||
Kind _kind = Kind::Internal,
|
Kind _kind = Kind::Internal,
|
||||||
bool _arbitraryParameters = false,
|
bool _arbitraryParameters = false,
|
||||||
bool _constant = false,
|
StateMutability _stateMutability = StateMutability::NonPayable
|
||||||
bool _payable = false
|
|
||||||
): FunctionType(
|
): FunctionType(
|
||||||
parseElementaryTypeVector(_parameterTypes),
|
parseElementaryTypeVector(_parameterTypes),
|
||||||
parseElementaryTypeVector(_returnParameterTypes),
|
parseElementaryTypeVector(_returnParameterTypes),
|
||||||
@ -899,8 +899,7 @@ public:
|
|||||||
_kind,
|
_kind,
|
||||||
_arbitraryParameters,
|
_arbitraryParameters,
|
||||||
nullptr,
|
nullptr,
|
||||||
_constant,
|
_stateMutability
|
||||||
_payable
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -917,8 +916,7 @@ public:
|
|||||||
Kind _kind = Kind::Internal,
|
Kind _kind = Kind::Internal,
|
||||||
bool _arbitraryParameters = false,
|
bool _arbitraryParameters = false,
|
||||||
Declaration const* _declaration = nullptr,
|
Declaration const* _declaration = nullptr,
|
||||||
bool _isConstant = false,
|
StateMutability _stateMutability = StateMutability::NonPayable,
|
||||||
bool _isPayable = false,
|
|
||||||
bool _gasSet = false,
|
bool _gasSet = false,
|
||||||
bool _valueSet = false,
|
bool _valueSet = false,
|
||||||
bool _bound = false
|
bool _bound = false
|
||||||
@ -928,12 +926,11 @@ public:
|
|||||||
m_parameterNames(_parameterNames),
|
m_parameterNames(_parameterNames),
|
||||||
m_returnParameterNames(_returnParameterNames),
|
m_returnParameterNames(_returnParameterNames),
|
||||||
m_kind(_kind),
|
m_kind(_kind),
|
||||||
|
m_stateMutability(_stateMutability),
|
||||||
m_arbitraryParameters(_arbitraryParameters),
|
m_arbitraryParameters(_arbitraryParameters),
|
||||||
m_gasSet(_gasSet),
|
m_gasSet(_gasSet),
|
||||||
m_valueSet(_valueSet),
|
m_valueSet(_valueSet),
|
||||||
m_bound(_bound),
|
m_bound(_bound),
|
||||||
m_isConstant(_isConstant),
|
|
||||||
m_isPayable(_isPayable),
|
|
||||||
m_declaration(_declaration)
|
m_declaration(_declaration)
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
@ -985,6 +982,7 @@ public:
|
|||||||
/// @returns true if the ABI is used for this call (only meaningful for external calls)
|
/// @returns true if the ABI is used for this call (only meaningful for external calls)
|
||||||
bool isBareCall() const;
|
bool isBareCall() const;
|
||||||
Kind const& kind() const { return m_kind; }
|
Kind const& kind() const { return m_kind; }
|
||||||
|
StateMutability stateMutability() const { return m_stateMutability; }
|
||||||
/// @returns the external signature of this function type given the function name
|
/// @returns the external signature of this function type given the function name
|
||||||
std::string externalSignature() const;
|
std::string externalSignature() const;
|
||||||
/// @returns the external identifier of this function (the hash of the signature).
|
/// @returns the external identifier of this function (the hash of the signature).
|
||||||
@ -995,12 +993,12 @@ public:
|
|||||||
return *m_declaration;
|
return *m_declaration;
|
||||||
}
|
}
|
||||||
bool hasDeclaration() const { return !!m_declaration; }
|
bool hasDeclaration() const { return !!m_declaration; }
|
||||||
bool isConstant() const { return m_isConstant; }
|
bool isConstant() const { return m_stateMutability == StateMutability::View; }
|
||||||
/// @returns true if the the result of this function only depends on its arguments
|
/// @returns true if the the result of this function only depends on its arguments
|
||||||
/// and it does not modify the state.
|
/// and it does not modify the state.
|
||||||
/// Currently, this will only return true for internal functions like keccak and ecrecover.
|
/// Currently, this will only return true for internal functions like keccak and ecrecover.
|
||||||
bool isPure() const;
|
bool isPure() const;
|
||||||
bool isPayable() const { return m_isPayable; }
|
bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
|
||||||
/// @return A shared pointer of an ASTString.
|
/// @return A shared pointer of an ASTString.
|
||||||
/// Can contain a nullptr in which case indicates absence of documentation
|
/// Can contain a nullptr in which case indicates absence of documentation
|
||||||
ASTPointer<ASTString> documentation() const;
|
ASTPointer<ASTString> documentation() const;
|
||||||
@ -1033,13 +1031,12 @@ private:
|
|||||||
std::vector<std::string> m_parameterNames;
|
std::vector<std::string> m_parameterNames;
|
||||||
std::vector<std::string> m_returnParameterNames;
|
std::vector<std::string> m_returnParameterNames;
|
||||||
Kind const m_kind;
|
Kind const m_kind;
|
||||||
|
StateMutability m_stateMutability = StateMutability::NonPayable;
|
||||||
/// true if the function takes an arbitrary number of arguments of arbitrary types
|
/// true if the function takes an arbitrary number of arguments of arbitrary types
|
||||||
bool const m_arbitraryParameters = false;
|
bool const m_arbitraryParameters = false;
|
||||||
bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
|
bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
|
||||||
bool const m_valueSet = false; ///< true iff the value to be sent is on the stack
|
bool const m_valueSet = false; ///< true iff the value to be sent is on the stack
|
||||||
bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn)
|
bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn)
|
||||||
bool m_isConstant = false;
|
|
||||||
bool m_isPayable = false;
|
|
||||||
Declaration const* m_declaration = nullptr;
|
Declaration const* m_declaration = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -645,8 +645,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
FunctionType::Kind::BareCall,
|
FunctionType::Kind::BareCall,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
false,
|
StateMutability::NonPayable,
|
||||||
false,
|
|
||||||
true,
|
true,
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
|
@ -307,6 +307,19 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
|
|||||||
return visibility;
|
return visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StateMutability Parser::parseStateMutability(Token::Value _token)
|
||||||
|
{
|
||||||
|
StateMutability stateMutability(StateMutability::NonPayable);
|
||||||
|
if (_token == Token::Payable)
|
||||||
|
stateMutability = StateMutability::Payable;
|
||||||
|
else if (_token == Token::Constant)
|
||||||
|
stateMutability = StateMutability::View;
|
||||||
|
else
|
||||||
|
solAssert(false, "Invalid state mutability specifier.");
|
||||||
|
m_scanner->next();
|
||||||
|
return stateMutability;
|
||||||
|
}
|
||||||
|
|
||||||
Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers)
|
Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers)
|
||||||
{
|
{
|
||||||
FunctionHeaderParserResult result;
|
FunctionHeaderParserResult result;
|
||||||
@ -321,23 +334,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Token::Value token = m_scanner->currentToken();
|
Token::Value token = m_scanner->currentToken();
|
||||||
if (token == Token::Constant)
|
if (_allowModifiers && token == Token::Identifier)
|
||||||
{
|
|
||||||
if (result.isDeclaredConst)
|
|
||||||
parserError(string("Multiple \"constant\" specifiers."));
|
|
||||||
|
|
||||||
result.isDeclaredConst = true;
|
|
||||||
m_scanner->next();
|
|
||||||
}
|
|
||||||
else if (m_scanner->currentToken() == Token::Payable)
|
|
||||||
{
|
|
||||||
if (result.isPayable)
|
|
||||||
parserError(string("Multiple \"payable\" specifiers."));
|
|
||||||
|
|
||||||
result.isPayable = true;
|
|
||||||
m_scanner->next();
|
|
||||||
}
|
|
||||||
else if (_allowModifiers && token == Token::Identifier)
|
|
||||||
{
|
{
|
||||||
// This can either be a modifier (function declaration) or the name of the
|
// This can either be a modifier (function declaration) or the name of the
|
||||||
// variable (function type name plus variable).
|
// variable (function type name plus variable).
|
||||||
@ -364,6 +361,20 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN
|
|||||||
else
|
else
|
||||||
result.visibility = parseVisibilitySpecifier(token);
|
result.visibility = parseVisibilitySpecifier(token);
|
||||||
}
|
}
|
||||||
|
else if (Token::isStateMutabilitySpecifier(token))
|
||||||
|
{
|
||||||
|
if (result.stateMutability != StateMutability::NonPayable)
|
||||||
|
{
|
||||||
|
parserError(string(
|
||||||
|
"State mutability already specified as \"" +
|
||||||
|
stateMutabilityToString(result.stateMutability) +
|
||||||
|
"\"."
|
||||||
|
));
|
||||||
|
m_scanner->next();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.stateMutability = parseStateMutability(token);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -408,13 +419,12 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(A
|
|||||||
return nodeFactory.createNode<FunctionDefinition>(
|
return nodeFactory.createNode<FunctionDefinition>(
|
||||||
header.name,
|
header.name,
|
||||||
header.visibility,
|
header.visibility,
|
||||||
|
header.stateMutability,
|
||||||
c_isConstructor,
|
c_isConstructor,
|
||||||
docstring,
|
docstring,
|
||||||
header.parameters,
|
header.parameters,
|
||||||
header.isDeclaredConst,
|
|
||||||
header.modifiers,
|
header.modifiers,
|
||||||
header.returnParameters,
|
header.returnParameters,
|
||||||
header.isPayable,
|
|
||||||
block
|
block
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -425,8 +435,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(A
|
|||||||
header.parameters,
|
header.parameters,
|
||||||
header.returnParameters,
|
header.returnParameters,
|
||||||
header.visibility,
|
header.visibility,
|
||||||
header.isDeclaredConst,
|
header.stateMutability
|
||||||
header.isPayable
|
|
||||||
);
|
);
|
||||||
type = parseTypeNameSuffix(type, nodeFactory);
|
type = parseTypeNameSuffix(type, nodeFactory);
|
||||||
VarDeclParserOptions options;
|
VarDeclParserOptions options;
|
||||||
@ -751,8 +760,7 @@ ASTPointer<FunctionTypeName> Parser::parseFunctionType()
|
|||||||
header.parameters,
|
header.parameters,
|
||||||
header.returnParameters,
|
header.returnParameters,
|
||||||
header.visibility,
|
header.visibility,
|
||||||
header.isDeclaredConst,
|
header.stateMutability
|
||||||
header.isPayable
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,8 +60,7 @@ private:
|
|||||||
ASTPointer<ParameterList> parameters;
|
ASTPointer<ParameterList> parameters;
|
||||||
ASTPointer<ParameterList> returnParameters;
|
ASTPointer<ParameterList> returnParameters;
|
||||||
Declaration::Visibility visibility = Declaration::Visibility::Default;
|
Declaration::Visibility visibility = Declaration::Visibility::Default;
|
||||||
bool isDeclaredConst = false;
|
StateMutability stateMutability = StateMutability::NonPayable;
|
||||||
bool isPayable = false;
|
|
||||||
std::vector<ASTPointer<ModifierInvocation>> modifiers;
|
std::vector<ASTPointer<ModifierInvocation>> modifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,7 +72,7 @@ private:
|
|||||||
ASTPointer<ContractDefinition> parseContractDefinition(Token::Value _expectedKind);
|
ASTPointer<ContractDefinition> parseContractDefinition(Token::Value _expectedKind);
|
||||||
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
||||||
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
||||||
std::string visibilitySpecifierName(Declaration::Visibility _visibility);
|
StateMutability parseStateMutability(Token::Value _token);
|
||||||
FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers);
|
FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers);
|
||||||
ASTPointer<ASTNode> parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName);
|
ASTPointer<ASTNode> parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName);
|
||||||
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
||||||
|
@ -290,6 +290,7 @@ public:
|
|||||||
static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
|
static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
|
||||||
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; }
|
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; }
|
||||||
static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage; }
|
static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage; }
|
||||||
|
static bool isStateMutabilitySpecifier(Value op) { return op == Constant || op == Payable; }
|
||||||
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; }
|
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; }
|
||||||
static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; }
|
static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; }
|
||||||
static bool isReservedKeyword(Value op) { return (Abstract <= op && op <= TypeOf); }
|
static bool isReservedKeyword(Value op) { return (Abstract <= op && op <= TypeOf); }
|
||||||
|
@ -4771,15 +4771,6 @@ BOOST_AUTO_TEST_CASE(function_variable_mixin)
|
|||||||
CHECK_ERROR(text, DeclarationError, "Identifier already declared.");
|
CHECK_ERROR(text, DeclarationError, "Identifier already declared.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(payable_constant_conflict)
|
|
||||||
{
|
|
||||||
char const* text = R"(
|
|
||||||
contract C { function f() payable constant {} }
|
|
||||||
)";
|
|
||||||
CHECK_ERROR(text, TypeError, "Functions cannot be constant and payable at the same time.");
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(calling_payable)
|
BOOST_AUTO_TEST_CASE(calling_payable)
|
||||||
{
|
{
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
|
@ -906,22 +906,23 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
|
|||||||
CHECK_PARSE_ERROR(text, "Visibility already specified as \"private\".");
|
CHECK_PARSE_ERROR(text, "Visibility already specified as \"private\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(multiple_payable_specifiers)
|
BOOST_AUTO_TEST_CASE(multiple_statemutability_specifiers)
|
||||||
{
|
{
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
contract c {
|
contract c {
|
||||||
function f() payable payable {}
|
function f() payable payable {}
|
||||||
})";
|
})";
|
||||||
CHECK_PARSE_ERROR(text, "Multiple \"payable\" specifiers.");
|
CHECK_PARSE_ERROR(text, "State mutability already specified as \"payable\".");
|
||||||
}
|
text = R"(
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(multiple_constant_specifiers)
|
|
||||||
{
|
|
||||||
char const* text = R"(
|
|
||||||
contract c {
|
contract c {
|
||||||
function f() constant constant {}
|
function f() constant constant {}
|
||||||
})";
|
})";
|
||||||
CHECK_PARSE_ERROR(text, "Multiple \"constant\" specifiers.");
|
CHECK_PARSE_ERROR(text, "State mutability already specified as \"view\".");
|
||||||
|
text = R"(
|
||||||
|
contract c {
|
||||||
|
function f() payable constant {}
|
||||||
|
})";
|
||||||
|
CHECK_PARSE_ERROR(text, "State mutability already specified as \"payable\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
|
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
|
||||||
|
Loading…
Reference in New Issue
Block a user