mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Parsing of immutable state variable.
This commit is contained in:
parent
f8f18f2e55
commit
fa148f2483
@ -328,6 +328,8 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
|
||||
if (_variable.isConstant() && !_variable.isStateVariable())
|
||||
m_errorReporter.declarationError(_variable.location(), "The \"constant\" keyword can only be used for state variables.");
|
||||
if (_variable.immutable() && !_variable.isStateVariable())
|
||||
m_errorReporter.declarationError(_variable.location(), "The \"immutable\" keyword can only be used for state variables.");
|
||||
|
||||
if (!_variable.typeName())
|
||||
{
|
||||
@ -394,7 +396,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
else if (_variable.isStateVariable())
|
||||
{
|
||||
solAssert(varLoc == Location::Unspecified, "");
|
||||
typeLoc = _variable.isConstant() ? DataLocation::Memory : DataLocation::Storage;
|
||||
typeLoc = (_variable.isConstant() || _variable.immutable()) ? DataLocation::Memory : DataLocation::Storage;
|
||||
}
|
||||
else if (
|
||||
dynamic_cast<StructDefinition const*>(_variable.scope()) ||
|
||||
|
@ -480,6 +480,10 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
"Initial value for constant variable has to be compile-time constant."
|
||||
);
|
||||
}
|
||||
else if (_variable.immutable())
|
||||
if (!_variable.type()->isValueType())
|
||||
m_errorReporter.typeError(_variable.location(), "Immutable variables cannot have a non-value type.");
|
||||
|
||||
if (!_variable.isStateVariable())
|
||||
{
|
||||
if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData))
|
||||
@ -641,6 +645,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
{
|
||||
solAssert(var->type(), "Expected variable type!");
|
||||
if (var->immutable())
|
||||
{
|
||||
m_errorReporter.typeError(_identifier.location, "Assembly access to immutable variables is not supported.");
|
||||
return size_t(-1);
|
||||
}
|
||||
if (var->isConstant())
|
||||
{
|
||||
var = rootConstVariableDeclaration(*var);
|
||||
|
@ -508,8 +508,6 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
|
||||
|
||||
if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
|
||||
return set<Location>{ Location::Unspecified };
|
||||
else if (isStateVariable() && isConstant())
|
||||
return set<Location>{ Location::Memory };
|
||||
else if (isExternalCallableParameter())
|
||||
{
|
||||
set<Location> locations{ Location::CallData };
|
||||
|
@ -879,6 +879,7 @@ public:
|
||||
bool isStateVariable() const { return m_isStateVariable; }
|
||||
bool isIndexed() const { return m_isIndexed; }
|
||||
bool isConstant() const { return m_constantness == Constantness::Constant; }
|
||||
bool immutable() const { return m_constantness == Constantness::Immutable; }
|
||||
ASTPointer<OverrideSpecifier> const& overrides() const { return m_overrides; }
|
||||
Location referenceLocation() const { return m_location; }
|
||||
/// @returns a set of allowed storage locations for the variable.
|
||||
|
@ -1988,7 +1988,7 @@ vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVar
|
||||
vector<VariableDeclaration const*> variables;
|
||||
for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts))
|
||||
for (VariableDeclaration const* variable: contract->stateVariables())
|
||||
if (!variable->isConstant())
|
||||
if (!(variable->isConstant() || variable->immutable()))
|
||||
variables.push_back(variable);
|
||||
TypePointers types;
|
||||
for (auto variable: variables)
|
||||
|
@ -525,7 +525,7 @@ void ContractCompiler::initializeStateVariables(ContractDefinition const& _contr
|
||||
{
|
||||
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
|
||||
for (VariableDeclaration const* variable: _contract.stateVariables())
|
||||
if (variable->value() && !variable->isConstant())
|
||||
if (variable->value() && !variable->isConstant() && !variable->immutable())
|
||||
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableInitialization(*variable);
|
||||
}
|
||||
|
||||
@ -541,6 +541,8 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
|
||||
if (_variableDeclaration.isConstant())
|
||||
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals)
|
||||
.appendConstStateVariableAccessor(_variableDeclaration);
|
||||
else if (_variableDeclaration.immutable())
|
||||
solUnimplementedAssert(false, "");
|
||||
else
|
||||
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals)
|
||||
.appendStateVariableAccessor(_variableDeclaration);
|
||||
@ -680,6 +682,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else if (auto variable = dynamic_cast<VariableDeclaration const*>(decl))
|
||||
{
|
||||
solAssert(!variable->immutable(), "");
|
||||
if (variable->isConstant())
|
||||
{
|
||||
variable = rootConstVariableDeclaration(*variable);
|
||||
|
@ -88,7 +88,7 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co
|
||||
|
||||
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(!_varDecl.isConstant(), "");
|
||||
solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), "");
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
|
||||
FunctionType accessorType(_varDecl);
|
||||
|
||||
@ -2438,10 +2438,12 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
|
||||
|
||||
void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression)
|
||||
{
|
||||
if (!_variable.isConstant())
|
||||
setLValueFromDeclaration(_variable, _expression);
|
||||
else
|
||||
if (_variable.isConstant())
|
||||
acceptAndConvert(*_variable.value(), *_variable.annotation().type);
|
||||
else if (_variable.immutable())
|
||||
solUnimplemented("");
|
||||
else
|
||||
setLValueFromDeclaration(_variable, _expression);
|
||||
}
|
||||
|
||||
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)
|
||||
|
@ -157,6 +157,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
||||
Type const* type = _varDecl.annotation().type;
|
||||
|
||||
solAssert(!_varDecl.isConstant(), "");
|
||||
solAssert(!_varDecl.immutable(), "");
|
||||
solAssert(_varDecl.isStateVariable(), "");
|
||||
|
||||
if (auto const* mappingType = dynamic_cast<MappingType const*>(type))
|
||||
@ -249,7 +250,7 @@ string IRGenerator::constructorCode(ContractDefinition const& _contract)
|
||||
|
||||
IRGeneratorForStatements generator{m_context, m_utils};
|
||||
for (VariableDeclaration const* variable: contract->stateVariables())
|
||||
if (!variable->isConstant())
|
||||
if (!variable->isConstant() && !variable->immutable())
|
||||
generator.initializeStateVar(*variable);
|
||||
out << generator.code();
|
||||
|
||||
|
@ -140,6 +140,7 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va
|
||||
{
|
||||
solAssert(m_context.isStateVariable(_varDecl), "Must be a state variable.");
|
||||
solAssert(!_varDecl.isConstant(), "");
|
||||
solAssert(!_varDecl.immutable(), "");
|
||||
if (_varDecl.value())
|
||||
{
|
||||
_varDecl.value()->accept(*this);
|
||||
@ -1123,6 +1124,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
||||
// If the value is visited twice, `defineExpression` is called twice on
|
||||
// the same expression.
|
||||
solUnimplementedAssert(!varDecl->isConstant(), "");
|
||||
solUnimplementedAssert(!varDecl->immutable(), "");
|
||||
if (m_context.isLocalVariable(*varDecl))
|
||||
setLValue(_identifier, IRLValue{
|
||||
*varDecl->annotation().type,
|
||||
|
@ -730,8 +730,18 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
{
|
||||
if (_options.allowIndexed && token == Token::Indexed)
|
||||
isIndexed = true;
|
||||
else if (token == Token::Constant)
|
||||
constantness = VariableDeclaration::Constantness::Constant;
|
||||
else if (token == Token::Constant || token == Token::Immutable)
|
||||
{
|
||||
if (constantness != VariableDeclaration::Constantness::Mutable)
|
||||
parserError(
|
||||
string("Constantness already set to ") +
|
||||
(constantness == VariableDeclaration::Constantness::Constant ? "\"constant\"" : "\"immutable\"")
|
||||
);
|
||||
else if (token == Token::Constant)
|
||||
constantness = VariableDeclaration::Constantness::Constant;
|
||||
else if (token == Token::Immutable)
|
||||
constantness = VariableDeclaration::Constantness::Immutable;
|
||||
}
|
||||
else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token))
|
||||
{
|
||||
if (location != VariableDeclaration::Location::Unspecified)
|
||||
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function f(uint immutable) public pure {}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError: (28-42): The "immutable" keyword can only be used for state variables.
|
11
test/libsolidity/syntaxTests/immutable/assembly.sol
Normal file
11
test/libsolidity/syntaxTests/immutable/assembly.sol
Normal file
@ -0,0 +1,11 @@
|
||||
contract C {
|
||||
uint immutable x;
|
||||
function f() public view {
|
||||
uint t;
|
||||
assembly {
|
||||
t := x
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (118-119): Assembly access to immutable variables is not supported.
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
uint immutable immutable x;
|
||||
uint immutable constant x;
|
||||
}
|
||||
// ----
|
||||
// ParserError: (32-41): Constantness already set to "immutable"
|
||||
// ParserError: (64-72): Constantness already set to "immutable"
|
5
test/libsolidity/syntaxTests/immutable/getter.sol
Normal file
5
test/libsolidity/syntaxTests/immutable/getter.sol
Normal file
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
uint immutable public x;
|
||||
}
|
||||
// ----
|
||||
// UnimplementedFeatureError: NONE
|
@ -0,0 +1,3 @@
|
||||
contract C {
|
||||
uint immutable x;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
uint[] immutable x;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (17-35): Immutable variables cannot have a non-value type.
|
@ -0,0 +1,8 @@
|
||||
contract B {
|
||||
uint immutable x;
|
||||
function f() public pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (96-97): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
|
Loading…
Reference in New Issue
Block a user