mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8444 from ethereum/immutable2
Parsing of immutable state variable.
This commit is contained in:
commit
a1cc2504ba
@ -328,6 +328,8 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
|||||||
|
|
||||||
if (_variable.isConstant() && !_variable.isStateVariable())
|
if (_variable.isConstant() && !_variable.isStateVariable())
|
||||||
m_errorReporter.declarationError(_variable.location(), "The \"constant\" keyword can only be used for state variables.");
|
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())
|
if (!_variable.typeName())
|
||||||
{
|
{
|
||||||
@ -394,7 +396,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
|||||||
else if (_variable.isStateVariable())
|
else if (_variable.isStateVariable())
|
||||||
{
|
{
|
||||||
solAssert(varLoc == Location::Unspecified, "");
|
solAssert(varLoc == Location::Unspecified, "");
|
||||||
typeLoc = _variable.isConstant() ? DataLocation::Memory : DataLocation::Storage;
|
typeLoc = (_variable.isConstant() || _variable.immutable()) ? DataLocation::Memory : DataLocation::Storage;
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
dynamic_cast<StructDefinition const*>(_variable.scope()) ||
|
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."
|
"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 (!_variable.isStateVariable())
|
||||||
{
|
{
|
||||||
if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData))
|
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))
|
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
{
|
{
|
||||||
solAssert(var->type(), "Expected variable type!");
|
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())
|
if (var->isConstant())
|
||||||
{
|
{
|
||||||
var = rootConstVariableDeclaration(*var);
|
var = rootConstVariableDeclaration(*var);
|
||||||
|
@ -508,8 +508,6 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
|
|||||||
|
|
||||||
if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
|
if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
|
||||||
return set<Location>{ Location::Unspecified };
|
return set<Location>{ Location::Unspecified };
|
||||||
else if (isStateVariable() && isConstant())
|
|
||||||
return set<Location>{ Location::Memory };
|
|
||||||
else if (isExternalCallableParameter())
|
else if (isExternalCallableParameter())
|
||||||
{
|
{
|
||||||
set<Location> locations{ Location::CallData };
|
set<Location> locations{ Location::CallData };
|
||||||
|
@ -879,6 +879,7 @@ public:
|
|||||||
bool isStateVariable() const { return m_isStateVariable; }
|
bool isStateVariable() const { return m_isStateVariable; }
|
||||||
bool isIndexed() const { return m_isIndexed; }
|
bool isIndexed() const { return m_isIndexed; }
|
||||||
bool isConstant() const { return m_constantness == Constantness::Constant; }
|
bool isConstant() const { return m_constantness == Constantness::Constant; }
|
||||||
|
bool immutable() const { return m_constantness == Constantness::Immutable; }
|
||||||
ASTPointer<OverrideSpecifier> const& overrides() const { return m_overrides; }
|
ASTPointer<OverrideSpecifier> const& overrides() const { return m_overrides; }
|
||||||
Location referenceLocation() const { return m_location; }
|
Location referenceLocation() const { return m_location; }
|
||||||
/// @returns a set of allowed storage locations for the variable.
|
/// @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;
|
vector<VariableDeclaration const*> variables;
|
||||||
for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts))
|
for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts))
|
||||||
for (VariableDeclaration const* variable: contract->stateVariables())
|
for (VariableDeclaration const* variable: contract->stateVariables())
|
||||||
if (!variable->isConstant())
|
if (!(variable->isConstant() || variable->immutable()))
|
||||||
variables.push_back(variable);
|
variables.push_back(variable);
|
||||||
TypePointers types;
|
TypePointers types;
|
||||||
for (auto variable: variables)
|
for (auto variable: variables)
|
||||||
|
@ -525,7 +525,7 @@ void ContractCompiler::initializeStateVariables(ContractDefinition const& _contr
|
|||||||
{
|
{
|
||||||
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
|
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
|
||||||
for (VariableDeclaration const* variable: _contract.stateVariables())
|
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);
|
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableInitialization(*variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,6 +541,8 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
|
|||||||
if (_variableDeclaration.isConstant())
|
if (_variableDeclaration.isConstant())
|
||||||
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals)
|
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals)
|
||||||
.appendConstStateVariableAccessor(_variableDeclaration);
|
.appendConstStateVariableAccessor(_variableDeclaration);
|
||||||
|
else if (_variableDeclaration.immutable())
|
||||||
|
solUnimplementedAssert(false, "");
|
||||||
else
|
else
|
||||||
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals)
|
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals)
|
||||||
.appendStateVariableAccessor(_variableDeclaration);
|
.appendStateVariableAccessor(_variableDeclaration);
|
||||||
@ -680,6 +682,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else if (auto variable = dynamic_cast<VariableDeclaration const*>(decl))
|
else if (auto variable = dynamic_cast<VariableDeclaration const*>(decl))
|
||||||
{
|
{
|
||||||
|
solAssert(!variable->immutable(), "");
|
||||||
if (variable->isConstant())
|
if (variable->isConstant())
|
||||||
{
|
{
|
||||||
variable = rootConstVariableDeclaration(*variable);
|
variable = rootConstVariableDeclaration(*variable);
|
||||||
|
@ -88,7 +88,7 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co
|
|||||||
|
|
||||||
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
|
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
solAssert(!_varDecl.isConstant(), "");
|
solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), "");
|
||||||
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
|
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
|
||||||
FunctionType accessorType(_varDecl);
|
FunctionType accessorType(_varDecl);
|
||||||
|
|
||||||
@ -2438,10 +2438,12 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
|
|||||||
|
|
||||||
void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression)
|
void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression)
|
||||||
{
|
{
|
||||||
if (!_variable.isConstant())
|
if (_variable.isConstant())
|
||||||
setLValueFromDeclaration(_variable, _expression);
|
|
||||||
else
|
|
||||||
acceptAndConvert(*_variable.value(), *_variable.annotation().type);
|
acceptAndConvert(*_variable.value(), *_variable.annotation().type);
|
||||||
|
else if (_variable.immutable())
|
||||||
|
solUnimplemented("");
|
||||||
|
else
|
||||||
|
setLValueFromDeclaration(_variable, _expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _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;
|
Type const* type = _varDecl.annotation().type;
|
||||||
|
|
||||||
solAssert(!_varDecl.isConstant(), "");
|
solAssert(!_varDecl.isConstant(), "");
|
||||||
|
solAssert(!_varDecl.immutable(), "");
|
||||||
solAssert(_varDecl.isStateVariable(), "");
|
solAssert(_varDecl.isStateVariable(), "");
|
||||||
|
|
||||||
if (auto const* mappingType = dynamic_cast<MappingType const*>(type))
|
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};
|
IRGeneratorForStatements generator{m_context, m_utils};
|
||||||
for (VariableDeclaration const* variable: contract->stateVariables())
|
for (VariableDeclaration const* variable: contract->stateVariables())
|
||||||
if (!variable->isConstant())
|
if (!variable->isConstant() && !variable->immutable())
|
||||||
generator.initializeStateVar(*variable);
|
generator.initializeStateVar(*variable);
|
||||||
out << generator.code();
|
out << generator.code();
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va
|
|||||||
{
|
{
|
||||||
solAssert(m_context.isStateVariable(_varDecl), "Must be a state variable.");
|
solAssert(m_context.isStateVariable(_varDecl), "Must be a state variable.");
|
||||||
solAssert(!_varDecl.isConstant(), "");
|
solAssert(!_varDecl.isConstant(), "");
|
||||||
|
solAssert(!_varDecl.immutable(), "");
|
||||||
if (_varDecl.value())
|
if (_varDecl.value())
|
||||||
{
|
{
|
||||||
_varDecl.value()->accept(*this);
|
_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
|
// If the value is visited twice, `defineExpression` is called twice on
|
||||||
// the same expression.
|
// the same expression.
|
||||||
solUnimplementedAssert(!varDecl->isConstant(), "");
|
solUnimplementedAssert(!varDecl->isConstant(), "");
|
||||||
|
solUnimplementedAssert(!varDecl->immutable(), "");
|
||||||
if (m_context.isLocalVariable(*varDecl))
|
if (m_context.isLocalVariable(*varDecl))
|
||||||
setLValue(_identifier, IRLValue{
|
setLValue(_identifier, IRLValue{
|
||||||
*varDecl->annotation().type,
|
*varDecl->annotation().type,
|
||||||
|
@ -730,8 +730,18 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
|||||||
{
|
{
|
||||||
if (_options.allowIndexed && token == Token::Indexed)
|
if (_options.allowIndexed && token == Token::Indexed)
|
||||||
isIndexed = true;
|
isIndexed = true;
|
||||||
else if (token == Token::Constant)
|
else if (token == Token::Constant || token == Token::Immutable)
|
||||||
constantness = VariableDeclaration::Constantness::Constant;
|
{
|
||||||
|
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))
|
else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token))
|
||||||
{
|
{
|
||||||
if (location != VariableDeclaration::Location::Unspecified)
|
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