mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Relax restrictions on immutable initialization
This commit is contained in:
parent
490b90d0ab
commit
dad2bf6472
@ -2,6 +2,7 @@
|
||||
|
||||
Language Features:
|
||||
* Allow qualified access to events from other contracts.
|
||||
* Relax restrictions on initialization of immutable variables. Reads and writes may now happen at any point at construction time outside of functions and modifiers. Explicit initialization is no longer mandatory.
|
||||
|
||||
Compiler Features:
|
||||
* Commandline Interface: Add ``--ast-compact-json`` output in assembler mode.
|
||||
|
@ -150,7 +150,7 @@ Modifiers
|
||||
- ``view`` for functions: Disallows modification of state.
|
||||
- ``payable`` for functions: Allows them to receive Ether together with a call.
|
||||
- ``constant`` for state variables: Disallows assignment (except initialisation), does not occupy storage slot.
|
||||
- ``immutable`` for state variables: Allows exactly one assignment at construction time and is constant afterwards. Is stored in code.
|
||||
- ``immutable`` for state variables: Allows assignment at construction time and is constant when deployed. Is stored in code.
|
||||
- ``anonymous`` for events: Does not store event signature as topic.
|
||||
- ``indexed`` for event parameters: Stores the parameter as topic.
|
||||
- ``virtual`` for functions and modifiers: Allows the function's or modifier's
|
||||
|
@ -30,19 +30,23 @@ Not all types for constants and immutables are implemented at this time. The onl
|
||||
.. code-block:: solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.7.4;
|
||||
pragma solidity ^0.8.21;
|
||||
|
||||
uint constant X = 32**22 + 8;
|
||||
|
||||
contract C {
|
||||
string constant TEXT = "abc";
|
||||
bytes32 constant MY_HASH = keccak256("abc");
|
||||
uint immutable decimals;
|
||||
uint immutable decimals = 18;
|
||||
uint immutable maxBalance;
|
||||
address immutable owner = msg.sender;
|
||||
|
||||
constructor(uint decimals_, address ref) {
|
||||
decimals = decimals_;
|
||||
if (decimals_ != 0)
|
||||
// Immutables are only immutable when deployed.
|
||||
// At construction time they can be assigned to any number of times.
|
||||
decimals = decimals_;
|
||||
|
||||
// Assignments to immutables can even access the environment.
|
||||
maxBalance = ref.balance;
|
||||
}
|
||||
@ -74,10 +78,29 @@ Immutable
|
||||
=========
|
||||
|
||||
Variables declared as ``immutable`` are a bit less restricted than those
|
||||
declared as ``constant``: Immutable variables can be assigned an arbitrary
|
||||
value in the constructor of the contract or at the point of their declaration.
|
||||
They can be assigned only once and can, from that point on, be read even during
|
||||
construction time.
|
||||
declared as ``constant``: Immutable variables can be assigned a
|
||||
value at construction time.
|
||||
The value can be changed at any time before deployment and then it becomes permanent.
|
||||
|
||||
One additional restriction is that immutables can only be assigned to inside expressions for which
|
||||
there is no possibility of being executed after creation.
|
||||
This excludes all modifier definitions and functions other than constructors.
|
||||
|
||||
There are no restrictions on reading immutable variables.
|
||||
The read is even allowed to happen before the variable is written to for the first time because variables in
|
||||
Solidity always have a well-defined initial value.
|
||||
For this reason it is also allowed to never explicitly assign a value to an immutable.
|
||||
|
||||
.. warning::
|
||||
When accessing immutables at construction time, please keep the :ref:`initialization order
|
||||
<state-variable-initialization-order>` in mind.
|
||||
Even if you provide an explicit initializer, some expressions may end up being evaluated before
|
||||
that initializer, especially when they are at a different level in inheritance hierarchy.
|
||||
|
||||
.. note::
|
||||
Before Solidity 0.8.21 initialization of immutable variables was more restrictive.
|
||||
Such variables had to be initialized exactly once at construction time and could not be read
|
||||
before then.
|
||||
|
||||
The contract creation code generated by the compiler will modify the
|
||||
contract's runtime code before it is returned by replacing all references
|
||||
@ -86,14 +109,3 @@ you are comparing the
|
||||
runtime code generated by the compiler with the one actually stored in the
|
||||
blockchain. The compiler outputs where these immutables are located in the deployed bytecode
|
||||
in the ``immutableReferences`` field of the :ref:`compiler JSON standard output <compiler-api>`.
|
||||
|
||||
.. note::
|
||||
Immutables that are assigned at their declaration are only considered
|
||||
initialized once the constructor of the contract is executing.
|
||||
This means you cannot initialize immutables inline with a value
|
||||
that depends on another immutable. You can do this, however,
|
||||
inside the constructor of the contract.
|
||||
|
||||
This is a safeguard against different interpretations about the order
|
||||
of state variable initialization and constructor execution, especially
|
||||
with regards to inheritance.
|
||||
|
@ -30,6 +30,8 @@ Semantic Only Changes
|
||||
This section lists the changes that are semantic-only, thus potentially
|
||||
hiding new and different behavior in existing code.
|
||||
|
||||
.. _state-variable-initialization-order:
|
||||
|
||||
- The order of state variable initialization has changed in case of inheritance.
|
||||
|
||||
The order used to be:
|
||||
|
@ -18,8 +18,6 @@
|
||||
|
||||
#include <libsolidity/analysis/ImmutableValidator.h>
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
#include <range/v3/view/reverse.hpp>
|
||||
|
||||
using namespace solidity::frontend;
|
||||
@ -27,275 +25,44 @@ using namespace solidity::langutil;
|
||||
|
||||
void ImmutableValidator::analyze()
|
||||
{
|
||||
m_inCreationContext = true;
|
||||
|
||||
auto linearizedContracts = m_mostDerivedContract.annotation().linearizedBaseContracts | ranges::views::reverse;
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
for (VariableDeclaration const* stateVar: contract->stateVariables())
|
||||
if (stateVar->value())
|
||||
stateVar->value()->accept(*this);
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
for (std::shared_ptr<InheritanceSpecifier> const& inheritSpec: contract->baseContracts())
|
||||
if (auto args = inheritSpec->arguments())
|
||||
ASTNode::listAccept(*args, *this);
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
{
|
||||
for (VariableDeclaration const* stateVar: contract->stateVariables())
|
||||
if (stateVar->value())
|
||||
m_initializedStateVariables.emplace(stateVar);
|
||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||
function->accept(*this);
|
||||
|
||||
if (contract->constructor())
|
||||
visitCallableIfNew(*contract->constructor());
|
||||
for (ModifierDefinition const* modifier: contract->functionModifiers())
|
||||
modifier->accept(*this);
|
||||
}
|
||||
|
||||
m_inCreationContext = false;
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
{
|
||||
for (auto funcDef: contract->definedFunctions())
|
||||
visitCallableIfNew(*funcDef);
|
||||
|
||||
for (auto modDef: contract->functionModifiers())
|
||||
visitCallableIfNew(*modDef);
|
||||
}
|
||||
|
||||
checkAllVariablesInitialized(m_mostDerivedContract.location());
|
||||
}
|
||||
|
||||
bool ImmutableValidator::visit(Assignment const& _assignment)
|
||||
{
|
||||
// Need to visit values first (rhs) as they might access other immutables.
|
||||
_assignment.rightHandSide().accept(*this);
|
||||
_assignment.leftHandSide().accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ImmutableValidator::visit(FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
return analyseCallable(_functionDefinition);
|
||||
return !_functionDefinition.isConstructor();
|
||||
}
|
||||
|
||||
bool ImmutableValidator::visit(ModifierDefinition const& _modifierDefinition)
|
||||
void ImmutableValidator::endVisit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
return analyseCallable(_modifierDefinition);
|
||||
}
|
||||
|
||||
bool ImmutableValidator::visit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
_memberAccess.expression().accept(*this);
|
||||
|
||||
if (auto contractType = dynamic_cast<ContractType const*>(_memberAccess.expression().annotation().type))
|
||||
if (!contractType->isSuper())
|
||||
// external access, no analysis needed.
|
||||
return false;
|
||||
|
||||
if (auto varDecl = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
||||
analyseVariableReference(*varDecl, _memberAccess);
|
||||
else if (auto funcType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
||||
if (funcType->kind() == FunctionType::Kind::Internal && funcType->hasDeclaration())
|
||||
visitCallableIfNew(funcType->declaration());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImmutableValidator::visit(IfStatement const& _ifStatement)
|
||||
{
|
||||
bool prevInBranch = m_inBranch;
|
||||
|
||||
_ifStatement.condition().accept(*this);
|
||||
|
||||
m_inBranch = true;
|
||||
_ifStatement.trueStatement().accept(*this);
|
||||
|
||||
if (auto falseStatement = _ifStatement.falseStatement())
|
||||
falseStatement->accept(*this);
|
||||
|
||||
m_inBranch = prevInBranch;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImmutableValidator::visit(WhileStatement const& _whileStatement)
|
||||
{
|
||||
bool prevInLoop = m_inLoop;
|
||||
m_inLoop = true;
|
||||
|
||||
_whileStatement.condition().accept(*this);
|
||||
_whileStatement.body().accept(*this);
|
||||
|
||||
m_inLoop = prevInLoop;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImmutableValidator::visit(TryStatement const& _tryStatement)
|
||||
{
|
||||
ScopedSaveAndRestore constructorGuard{m_inTryStatement, true};
|
||||
|
||||
_tryStatement.externalCall().accept(*this);
|
||||
|
||||
for (auto&& clause: _tryStatement.clauses())
|
||||
if (clause)
|
||||
clause->accept(*this);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImmutableValidator::endVisit(IdentifierPath const& _identifierPath)
|
||||
{
|
||||
if (auto const callableDef = dynamic_cast<CallableDeclaration const*>(_identifierPath.annotation().referencedDeclaration))
|
||||
visitCallableIfNew(
|
||||
*_identifierPath.annotation().requiredLookup == VirtualLookup::Virtual ?
|
||||
callableDef->resolveVirtual(m_mostDerivedContract) :
|
||||
*callableDef
|
||||
);
|
||||
|
||||
solAssert(!dynamic_cast<VariableDeclaration const*>(_identifierPath.annotation().referencedDeclaration), "");
|
||||
analyseVariableReference(_memberAccess.annotation().referencedDeclaration, _memberAccess);
|
||||
}
|
||||
|
||||
void ImmutableValidator::endVisit(Identifier const& _identifier)
|
||||
{
|
||||
if (auto const callableDef = dynamic_cast<CallableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||
visitCallableIfNew(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual ? callableDef->resolveVirtual(m_mostDerivedContract) : *callableDef);
|
||||
if (auto const varDecl = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||
analyseVariableReference(*varDecl, _identifier);
|
||||
analyseVariableReference(_identifier.annotation().referencedDeclaration, _identifier);
|
||||
}
|
||||
|
||||
void ImmutableValidator::endVisit(Return const& _return)
|
||||
void ImmutableValidator::analyseVariableReference(Declaration const* _reference, Expression const& _expression)
|
||||
{
|
||||
if (m_currentConstructor != nullptr)
|
||||
checkAllVariablesInitialized(_return.location());
|
||||
}
|
||||
|
||||
bool ImmutableValidator::analyseCallable(CallableDeclaration const& _callableDeclaration)
|
||||
{
|
||||
ScopedSaveAndRestore constructorGuard{m_currentConstructor, {}};
|
||||
ScopedSaveAndRestore constructorContractGuard{m_currentConstructorContract, {}};
|
||||
|
||||
if (FunctionDefinition const* funcDef = dynamic_cast<decltype(funcDef)>(&_callableDeclaration))
|
||||
{
|
||||
ASTNode::listAccept(funcDef->modifiers(), *this);
|
||||
|
||||
if (funcDef->isConstructor())
|
||||
{
|
||||
m_currentConstructorContract = funcDef->annotation().contract;
|
||||
m_currentConstructor = funcDef;
|
||||
}
|
||||
|
||||
if (funcDef->isImplemented())
|
||||
funcDef->body().accept(*this);
|
||||
}
|
||||
else if (ModifierDefinition const* modDef = dynamic_cast<decltype(modDef)>(&_callableDeclaration))
|
||||
if (modDef->isImplemented())
|
||||
modDef->body().accept(*this);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _variableReference, Expression const& _expression)
|
||||
{
|
||||
if (!_variableReference.isStateVariable() || !_variableReference.immutable())
|
||||
auto const* variable = dynamic_cast<VariableDeclaration const*>(_reference);
|
||||
if (!variable || !variable->isStateVariable() || !variable->immutable())
|
||||
return;
|
||||
|
||||
// If this is not an ordinary assignment, we write and read at the same time.
|
||||
bool write = _expression.annotation().willBeWrittenTo;
|
||||
bool read = !_expression.annotation().willBeWrittenTo || !_expression.annotation().lValueOfOrdinaryAssignment;
|
||||
if (write)
|
||||
{
|
||||
if (!m_currentConstructor)
|
||||
m_errorReporter.typeError(
|
||||
1581_error,
|
||||
_expression.location(),
|
||||
"Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor."
|
||||
);
|
||||
else if (m_currentConstructor->annotation().contract->id() != _variableReference.annotation().contract->id())
|
||||
m_errorReporter.typeError(
|
||||
7484_error,
|
||||
_expression.location(),
|
||||
"Cannot write to immutable here: Immutable variables must be initialized in the constructor of the contract they are defined in."
|
||||
);
|
||||
else if (m_inLoop)
|
||||
m_errorReporter.typeError(
|
||||
6672_error,
|
||||
_expression.location(),
|
||||
"Cannot write to immutable here: Immutable variables cannot be initialized inside a loop."
|
||||
);
|
||||
else if (m_inBranch)
|
||||
m_errorReporter.typeError(
|
||||
4599_error,
|
||||
_expression.location(),
|
||||
"Cannot write to immutable here: Immutable variables cannot be initialized inside an if statement."
|
||||
);
|
||||
else if (m_inTryStatement)
|
||||
m_errorReporter.typeError(
|
||||
4130_error,
|
||||
_expression.location(),
|
||||
"Cannot write to immutable here: Immutable variables cannot be initialized inside a try/catch statement."
|
||||
);
|
||||
else if (m_initializedStateVariables.count(&_variableReference))
|
||||
{
|
||||
if (!read)
|
||||
m_errorReporter.typeError(
|
||||
1574_error,
|
||||
_expression.location(),
|
||||
"Immutable state variable already initialized."
|
||||
);
|
||||
else
|
||||
m_errorReporter.typeError(
|
||||
2718_error,
|
||||
_expression.location(),
|
||||
"Immutable variables cannot be modified after initialization."
|
||||
);
|
||||
}
|
||||
else if (read)
|
||||
m_errorReporter.typeError(
|
||||
3969_error,
|
||||
_expression.location(),
|
||||
"Immutable variables must be initialized using an assignment."
|
||||
);
|
||||
m_initializedStateVariables.emplace(&_variableReference);
|
||||
}
|
||||
if (
|
||||
read &&
|
||||
m_inCreationContext &&
|
||||
!m_initializedStateVariables.count(&_variableReference)
|
||||
)
|
||||
if (_expression.annotation().willBeWrittenTo)
|
||||
m_errorReporter.typeError(
|
||||
7733_error,
|
||||
1581_error,
|
||||
_expression.location(),
|
||||
"Immutable variables cannot be read before they are initialized."
|
||||
"Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor."
|
||||
);
|
||||
}
|
||||
|
||||
void ImmutableValidator::checkAllVariablesInitialized(solidity::langutil::SourceLocation const& _location)
|
||||
{
|
||||
for (ContractDefinition const* contract: m_mostDerivedContract.annotation().linearizedBaseContracts | ranges::views::reverse)
|
||||
{
|
||||
for (VariableDeclaration const* varDecl: contract->stateVariables())
|
||||
if (varDecl->immutable())
|
||||
if (!util::contains(m_initializedStateVariables, varDecl))
|
||||
m_errorReporter.typeError(
|
||||
2658_error,
|
||||
_location,
|
||||
solidity::langutil::SecondarySourceLocation().append("Not initialized: ", varDecl->location()),
|
||||
"Construction control flow ends without initializing all immutable state variables."
|
||||
);
|
||||
|
||||
// Don't check further than the current c'tors contract
|
||||
if (contract == m_currentConstructorContract)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableValidator::visitCallableIfNew(Declaration const& _declaration)
|
||||
{
|
||||
CallableDeclaration const* _callable = dynamic_cast<CallableDeclaration const*>(&_declaration);
|
||||
solAssert(_callable != nullptr, "");
|
||||
|
||||
if (m_visitedCallables.emplace(_callable).second)
|
||||
_declaration.accept(*this);
|
||||
}
|
||||
|
@ -21,25 +21,15 @@
|
||||
#include <libsolidity/ast/ASTVisitor.h>
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
/**
|
||||
* Validates access and initialization of immutable variables:
|
||||
* must be directly initialized in their respective c'tor or inline
|
||||
* cannot be read before being initialized
|
||||
* cannot be read when initializing state variables inline
|
||||
* must be initialized outside loops (only one initialization)
|
||||
* must be initialized outside ifs (must be initialized unconditionally)
|
||||
* must be initialized exactly once (no multiple statements)
|
||||
* must be initialized exactly once (no early return to skip initialization)
|
||||
* must be directly initialized in a c'tor or inline
|
||||
*/
|
||||
class ImmutableValidator: private ASTConstVisitor
|
||||
{
|
||||
using CallableDeclarationSet = std::set<CallableDeclaration const*, ASTNode::CompareByID>;
|
||||
|
||||
public:
|
||||
ImmutableValidator(langutil::ErrorReporter& _errorReporter, ContractDefinition const& _contractDefinition):
|
||||
m_mostDerivedContract(_contractDefinition),
|
||||
@ -49,37 +39,15 @@ public:
|
||||
void analyze();
|
||||
|
||||
private:
|
||||
bool visit(Assignment const& _assignment);
|
||||
bool visit(FunctionDefinition const& _functionDefinition);
|
||||
bool visit(ModifierDefinition const& _modifierDefinition);
|
||||
bool visit(MemberAccess const& _memberAccess);
|
||||
bool visit(IfStatement const& _ifStatement);
|
||||
bool visit(WhileStatement const& _whileStatement);
|
||||
bool visit(TryStatement const& _tryStatement);
|
||||
void endVisit(IdentifierPath const& _identifierPath);
|
||||
void endVisit(MemberAccess const& _memberAccess);
|
||||
void endVisit(Identifier const& _identifier);
|
||||
void endVisit(Return const& _return);
|
||||
|
||||
bool analyseCallable(CallableDeclaration const& _callableDeclaration);
|
||||
void analyseVariableReference(VariableDeclaration const& _variableReference, Expression const& _expression);
|
||||
|
||||
void checkAllVariablesInitialized(langutil::SourceLocation const& _location);
|
||||
|
||||
void visitCallableIfNew(Declaration const& _declaration);
|
||||
void analyseVariableReference(Declaration const* _variableReference, Expression const& _expression);
|
||||
|
||||
ContractDefinition const& m_mostDerivedContract;
|
||||
|
||||
CallableDeclarationSet m_visitedCallables;
|
||||
|
||||
std::set<VariableDeclaration const*, ASTNode::CompareByID> m_initializedStateVariables;
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
|
||||
FunctionDefinition const* m_currentConstructor = nullptr;
|
||||
ContractDefinition const* m_currentConstructorContract = nullptr;
|
||||
bool m_inLoop = false;
|
||||
bool m_inBranch = false;
|
||||
bool m_inCreationContext = true;
|
||||
bool m_inTryStatement = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
15
test/libsolidity/semanticTests/immutable/delete.sol
Normal file
15
test/libsolidity/semanticTests/immutable/delete.sol
Normal file
@ -0,0 +1,15 @@
|
||||
contract C {
|
||||
uint8 immutable public a;
|
||||
uint8 immutable public b = 0x42;
|
||||
uint public c;
|
||||
|
||||
constructor() {
|
||||
delete a;
|
||||
delete b;
|
||||
c = b * 2 + a;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// a() -> 0
|
||||
// b() -> 0
|
||||
// c() -> 0
|
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
int immutable x = 1;
|
||||
int immutable y = 3;
|
||||
|
||||
constructor() {
|
||||
x--;
|
||||
--x;
|
||||
y++;
|
||||
++y;
|
||||
--y;
|
||||
}
|
||||
|
||||
function f() public view returns (int, int) {
|
||||
return (x, y);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f() -> -1, 4
|
@ -0,0 +1,27 @@
|
||||
contract A {
|
||||
uint immutable x = x + 1;
|
||||
uint immutable y = x += 2;
|
||||
|
||||
constructor(uint) m(x += 16) m(x += 32) {
|
||||
x += 64;
|
||||
x += 128;
|
||||
}
|
||||
|
||||
modifier m(uint) {
|
||||
_;
|
||||
}
|
||||
|
||||
function get() public returns (uint) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
contract B is A(A.x += 8) {
|
||||
constructor(uint) {}
|
||||
}
|
||||
|
||||
contract C is B {
|
||||
constructor() B(x += 4) {}
|
||||
}
|
||||
// ----
|
||||
// get() -> 0xff
|
11
test/libsolidity/semanticTests/immutable/uninitialized.sol
Normal file
11
test/libsolidity/semanticTests/immutable/uninitialized.sol
Normal file
@ -0,0 +1,11 @@
|
||||
contract C {
|
||||
uint immutable u;
|
||||
bool immutable b;
|
||||
address immutable a;
|
||||
|
||||
function get() public returns (uint, bool, address) {
|
||||
return (u, b, a);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// get() -> 0, false, 0x0
|
@ -7,5 +7,3 @@ contract C {
|
||||
x = 1;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 2658: (86-93): Construction control flow ends without initializing all immutable state variables.
|
||||
|
@ -5,5 +5,3 @@ contract C {
|
||||
x = 1;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 4599: (86-87): Cannot write to immutable here: Immutable variables cannot be initialized inside an if statement.
|
||||
|
@ -6,5 +6,3 @@ contract C {
|
||||
|
||||
function f() public view returns (uint) { return 3 + x; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (136-137): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -4,5 +4,3 @@ contract C {
|
||||
x = 3 + x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (71-72): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -9,4 +9,3 @@ contract C {
|
||||
function f(uint a) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (59-60): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
|
@ -10,5 +10,3 @@ contract C {
|
||||
|
||||
function f(uint a) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (119-120): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -4,5 +4,3 @@ contract C {
|
||||
x--;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3969: (63-64): Immutable variables must be initialized using an assignment.
|
||||
|
@ -1,8 +0,0 @@
|
||||
contract C {
|
||||
uint immutable x;
|
||||
constructor() {
|
||||
delete x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3969: (70-71): Immutable variables must be initialized using an assignment.
|
@ -1,8 +0,0 @@
|
||||
contract C {
|
||||
uint immutable x = 3;
|
||||
constructor() {
|
||||
delete x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 2718: (74-75): Immutable variables cannot be modified after initialization.
|
@ -3,5 +3,3 @@ contract C {
|
||||
|
||||
function f() public view returns (uint) { return 3 + x; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (99-100): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -11,4 +11,3 @@ contract C is B(C.f) {
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (200-201): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
// TypeError 1574: (109-110): Immutable state variable already initialized.
|
||||
|
@ -10,4 +10,3 @@ contract C is B(C.f) {
|
||||
function f() internal view returns(uint) { return x + 2; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (205-206): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -4,5 +4,3 @@ contract C {
|
||||
x++;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3969: (63-64): Immutable variables must be initialized using an assignment.
|
||||
|
@ -1,11 +0,0 @@
|
||||
contract C {
|
||||
uint immutable x;
|
||||
uint immutable y;
|
||||
constructor() {
|
||||
++x;
|
||||
--y;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3969: (77-78): Immutable variables must be initialized using an assignment.
|
||||
// TypeError 3969: (86-87): Immutable variables must be initialized using an assignment.
|
@ -5,4 +5,3 @@ contract C {
|
||||
function f() internal pure returns(uint) { return x; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (112-113): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -10,5 +10,3 @@ contract C is B {
|
||||
uint immutable y;
|
||||
constructor() B(y = 3) { }
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (148-149): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
|
@ -9,5 +9,3 @@ contract B {
|
||||
contract C is B(C.y = 3) {
|
||||
uint immutable y;
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (104-107): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
|
@ -12,5 +12,3 @@ contract C is B(C.y) {
|
||||
y = 3;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (104-107): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -16,4 +16,3 @@ contract C is B {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (263-264): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -17,5 +17,3 @@ contract C is B {
|
||||
_; f(x);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (245-246): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -7,5 +7,3 @@ contract C is B {
|
||||
x = 3;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7484: (88-89): Cannot write to immutable here: Immutable variables must be initialized in the constructor of the contract they are defined in.
|
||||
|
@ -4,4 +4,3 @@ contract D {
|
||||
constructor() m(t = 2) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (83-84): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
|
@ -3,5 +3,3 @@ contract D is C {
|
||||
uint immutable t;
|
||||
constructor() C(t=2) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (92-93): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
|
@ -0,0 +1,7 @@
|
||||
contract D {
|
||||
uint immutable t;
|
||||
modifier m(uint) { _; }
|
||||
function f() public m(t = 2) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (89-90): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
@ -0,0 +1,11 @@
|
||||
contract B {
|
||||
uint immutable x;
|
||||
}
|
||||
|
||||
contract C is B {
|
||||
function f() public {
|
||||
B.x = 42;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (90-93): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
@ -0,0 +1,13 @@
|
||||
contract B {
|
||||
uint immutable x;
|
||||
|
||||
function g() public {}
|
||||
}
|
||||
|
||||
contract C is B {
|
||||
function f() public {
|
||||
super.x = 42;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9582: (118-125): Member "x" not found or not visible after argument-dependent lookup in type(contract super C).
|
@ -2,5 +2,3 @@ contract C { constructor(uint) {} }
|
||||
contract D is C(D.t = 2) {
|
||||
uint immutable t;
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (52-55): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
|
@ -5,5 +5,3 @@ contract C {
|
||||
x = 1;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 6672: (88-89): Cannot write to immutable here: Immutable variables cannot be initialized inside a loop.
|
||||
|
@ -26,4 +26,3 @@ contract C is A, B {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (499-500): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -26,4 +26,3 @@ contract C is A, B {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (503-504): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -5,5 +5,3 @@ contract C {
|
||||
x = 4;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 1574: (78-79): Immutable state variable already initialized.
|
||||
|
@ -16,5 +16,3 @@ contract C is B {
|
||||
function f() internal view override returns(uint) { return readX(); }
|
||||
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (202-203): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -8,5 +8,3 @@ contract B is A {
|
||||
uint immutable x = 2;
|
||||
function f() override pure internal returns (uint) { return x; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (223-224): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -3,5 +3,3 @@ contract C {
|
||||
uint x = f();
|
||||
function f() internal pure returns (uint) { return t; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (106-107): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -13,4 +13,3 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (141-142): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -2,5 +2,3 @@ contract C {
|
||||
uint immutable x = 0;
|
||||
uint y = x;
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (52-53): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -7,4 +7,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 2658: (63-70): Construction control flow ends without initializing all immutable state variables.
|
||||
// Warning 5740: (80-85): Unreachable code.
|
||||
|
@ -0,0 +1,13 @@
|
||||
contract C {
|
||||
uint immutable public x = 42;
|
||||
|
||||
function g() external view returns (uint) {}
|
||||
|
||||
function f() public view returns (uint) {
|
||||
return this.x();
|
||||
}
|
||||
|
||||
function h() public view returns (function () external view returns (uint)) {
|
||||
return this.x;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
contract C {
|
||||
uint immutable public x = 42;
|
||||
|
||||
function g() external view returns (uint) {}
|
||||
|
||||
function f() public view {
|
||||
this.x = this.g;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 4247: (137-143): Expression has to be an lvalue.
|
@ -33,9 +33,3 @@ contract B
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// TypeError 4130: (108-116): Cannot write to immutable here: Immutable variables cannot be initialized inside a try/catch statement.
|
||||
// TypeError 4130: (144-152): Cannot write to immutable here: Immutable variables cannot be initialized inside a try/catch statement.
|
||||
// TypeError 4130: (216-224): Cannot write to immutable here: Immutable variables cannot be initialized inside a try/catch statement.
|
||||
// TypeError 4130: (297-305): Cannot write to immutable here: Immutable variables cannot be initialized inside a try/catch statement.
|
||||
// TypeError 4130: (357-365): Cannot write to immutable here: Immutable variables cannot be initialized inside a try/catch statement.
|
||||
|
@ -1,5 +1,3 @@
|
||||
contract C {
|
||||
uint immutable x;
|
||||
}
|
||||
// ----
|
||||
// TypeError 2658: (0-36): Construction control flow ends without initializing all immutable state variables.
|
||||
|
@ -16,6 +16,3 @@ contract C is B {
|
||||
function f() internal view override returns(uint) { return readX(); }
|
||||
|
||||
}
|
||||
// ----
|
||||
// TypeError 2658: (0-202): Construction control flow ends without initializing all immutable state variables.
|
||||
// TypeError 2658: (204-361): Construction control flow ends without initializing all immutable state variables.
|
||||
|
@ -3,6 +3,3 @@ contract C {
|
||||
uint immutable x = z = y = 3;
|
||||
uint immutable y = 5;
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (66-67): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
// TypeError 1581: (62-63): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
|
@ -1,5 +1,3 @@
|
||||
contract C {
|
||||
int immutable x = x = 5;
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (35-36): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
|
Loading…
Reference in New Issue
Block a user