mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11750 from ethereum/immutables-10463
Allow reading of immutables during construction time
This commit is contained in:
commit
45a910c2ca
@ -4,6 +4,7 @@ Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Immutable variables can be read at construction time once they are initialized.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
@ -76,7 +76,8 @@ 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 cannot be read during construction time and can only be assigned once.
|
||||
They can be assigned only once and can, from that point on, be read even during
|
||||
construction time.
|
||||
|
||||
The contract creation code generated by the compiler will modify the
|
||||
contract's runtime code before it is returned by replacing all references
|
||||
@ -84,3 +85,14 @@ to immutables by the values assigned to the them. This is important if
|
||||
you are comparing the
|
||||
runtime code generated by the compiler with the one actually stored in the
|
||||
blockchain.
|
||||
|
||||
.. 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.
|
@ -27,30 +27,31 @@ using namespace solidity::langutil;
|
||||
|
||||
void ImmutableValidator::analyze()
|
||||
{
|
||||
m_inConstructionContext = true;
|
||||
m_inCreationContext = true;
|
||||
|
||||
auto linearizedContracts = m_currentContract.annotation().linearizedBaseContracts | ranges::views::reverse;
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
for (VariableDeclaration const* stateVar: contract->stateVariables())
|
||||
if (stateVar->value())
|
||||
m_initializedStateVariables.emplace(stateVar);
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
for (VariableDeclaration const* stateVar: contract->stateVariables())
|
||||
if (stateVar->value())
|
||||
stateVar->value()->accept(*this);
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
if (contract->constructor())
|
||||
visitCallableIfNew(*contract->constructor());
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
for (std::shared_ptr<InheritanceSpecifier> const& inheritSpec: contract->baseContracts())
|
||||
if (auto args = inheritSpec->arguments())
|
||||
ASTNode::listAccept(*args, *this);
|
||||
|
||||
m_inConstructionContext = false;
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
{
|
||||
for (VariableDeclaration const* stateVar: contract->stateVariables())
|
||||
if (stateVar->value())
|
||||
m_initializedStateVariables.emplace(stateVar);
|
||||
|
||||
if (contract->constructor())
|
||||
visitCallableIfNew(*contract->constructor());
|
||||
}
|
||||
|
||||
m_inCreationContext = false;
|
||||
|
||||
for (ContractDefinition const* contract: linearizedContracts)
|
||||
{
|
||||
@ -64,6 +65,15 @@ void ImmutableValidator::analyze()
|
||||
checkAllVariablesInitialized(m_currentContract.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);
|
||||
@ -207,19 +217,37 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va
|
||||
"Cannot write to immutable here: Immutable variables cannot be initialized inside an if 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(
|
||||
1574_error,
|
||||
3969_error,
|
||||
_expression.location(),
|
||||
"Immutable state variable already initialized."
|
||||
"Immutable variables must be initialized using an assignment."
|
||||
);
|
||||
m_initializedStateVariables.emplace(&_variableReference);
|
||||
}
|
||||
if (read && m_inConstructionContext)
|
||||
if (
|
||||
read &&
|
||||
m_inCreationContext &&
|
||||
!m_initializedStateVariables.count(&_variableReference)
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
7733_error,
|
||||
_expression.location(),
|
||||
"Immutable variables cannot be read during contract creation time, which means "
|
||||
"they cannot be read in the constructor or any function or modifier called from it."
|
||||
"Immutable variables cannot be read before they are initialized."
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,9 @@ namespace solidity::frontend
|
||||
|
||||
/**
|
||||
* Validates access and initialization of immutable variables:
|
||||
* must be directly initialized in their respective c'tor
|
||||
* can not be read by any function/modifier called by the c'tor (or the c'tor itself)
|
||||
* 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)
|
||||
@ -48,6 +49,7 @@ public:
|
||||
void analyze();
|
||||
|
||||
private:
|
||||
bool visit(Assignment const& _assignment);
|
||||
bool visit(FunctionDefinition const& _functionDefinition);
|
||||
bool visit(ModifierDefinition const& _modifierDefinition);
|
||||
bool visit(MemberAccess const& _memberAccess);
|
||||
@ -74,7 +76,7 @@ private:
|
||||
FunctionDefinition const* m_currentConstructor = nullptr;
|
||||
bool m_inLoop = false;
|
||||
bool m_inBranch = false;
|
||||
bool m_inConstructionContext = false;
|
||||
bool m_inCreationContext = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -155,9 +155,15 @@ ImmutableItem::ImmutableItem(CompilerContext& _compilerContext, VariableDeclarat
|
||||
void ImmutableItem::retrieveValue(SourceLocation const&, bool) const
|
||||
{
|
||||
solUnimplementedAssert(m_dataType->isValueType(), "");
|
||||
solAssert(!m_context.runtimeContext(), "Tried to read immutable at construction time.");
|
||||
for (auto&& slotName: m_context.immutableVariableSlotNames(m_variable))
|
||||
m_context.appendImmutable(slotName);
|
||||
|
||||
if (m_context.runtimeContext())
|
||||
CompilerUtils(m_context).loadFromMemory(
|
||||
static_cast<unsigned>(m_context.immutableMemoryOffset(m_variable)),
|
||||
*m_dataType
|
||||
);
|
||||
else
|
||||
for (auto&& slotName: m_context.immutableVariableSlotNames(m_variable))
|
||||
m_context.appendImmutable(slotName);
|
||||
}
|
||||
|
||||
void ImmutableItem::storeValue(Type const& _sourceType, SourceLocation const&, bool _move) const
|
||||
|
@ -65,13 +65,17 @@ using InternalDispatchMap = std::map<YulArity, DispatchSet>;
|
||||
class IRGenerationContext
|
||||
{
|
||||
public:
|
||||
enum class ExecutionContext { Creation, Deployed };
|
||||
|
||||
IRGenerationContext(
|
||||
langutil::EVMVersion _evmVersion,
|
||||
ExecutionContext _executionContext,
|
||||
RevertStrings _revertStrings,
|
||||
OptimiserSettings _optimiserSettings,
|
||||
std::map<std::string, unsigned> _sourceIndices
|
||||
):
|
||||
m_evmVersion(_evmVersion),
|
||||
m_executionContext(_executionContext),
|
||||
m_revertStrings(_revertStrings),
|
||||
m_optimiserSettings(std::move(_optimiserSettings)),
|
||||
m_sourceIndices(std::move(_sourceIndices))
|
||||
@ -139,6 +143,7 @@ public:
|
||||
YulUtilFunctions utils();
|
||||
|
||||
langutil::EVMVersion evmVersion() const { return m_evmVersion; }
|
||||
ExecutionContext executionContext() const { return m_executionContext; }
|
||||
|
||||
void setArithmetic(Arithmetic _value) { m_arithmetic = _value; }
|
||||
Arithmetic arithmetic() const { return m_arithmetic; }
|
||||
@ -162,8 +167,11 @@ public:
|
||||
|
||||
std::map<std::string, unsigned> const& sourceIndices() const { return m_sourceIndices; }
|
||||
|
||||
bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); }
|
||||
|
||||
private:
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
ExecutionContext m_executionContext;
|
||||
RevertStrings m_revertStrings;
|
||||
OptimiserSettings m_optimiserSettings;
|
||||
std::map<std::string, unsigned> m_sourceIndices;
|
||||
|
@ -164,7 +164,7 @@ string IRGenerator::generate(
|
||||
}
|
||||
)");
|
||||
|
||||
resetContext(_contract);
|
||||
resetContext(_contract, ExecutionContext::Creation);
|
||||
for (VariableDeclaration const* var: ContractType(_contract).immutableVariables())
|
||||
m_context.registerImmutableVariable(*var);
|
||||
|
||||
@ -211,7 +211,7 @@ string IRGenerator::generate(
|
||||
bool creationInvolvesAssembly = m_context.inlineAssemblySeen();
|
||||
t("memoryInitCreation", memoryInit(!creationInvolvesAssembly));
|
||||
|
||||
resetContext(_contract);
|
||||
resetContext(_contract, ExecutionContext::Deployed);
|
||||
|
||||
// NOTE: Function pointers can be passed from creation code via storage variables. We need to
|
||||
// get all the functions they could point to into the dispatch functions even if they're never
|
||||
@ -1049,7 +1049,7 @@ string IRGenerator::memoryInit(bool _useMemoryGuard)
|
||||
).render();
|
||||
}
|
||||
|
||||
void IRGenerator::resetContext(ContractDefinition const& _contract)
|
||||
void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionContext _context)
|
||||
{
|
||||
solAssert(
|
||||
m_context.functionGenerationQueueEmpty(),
|
||||
@ -1063,7 +1063,7 @@ void IRGenerator::resetContext(ContractDefinition const& _contract)
|
||||
m_context.internalDispatchClean(),
|
||||
"Reset internal dispatch map without consuming it."
|
||||
);
|
||||
IRGenerationContext newContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings, m_context.sourceIndices());
|
||||
IRGenerationContext newContext(m_evmVersion, _context, m_context.revertStrings(), m_optimiserSettings, m_context.sourceIndices());
|
||||
newContext.copyFunctionIDsFrom(m_context);
|
||||
m_context = move(newContext);
|
||||
|
||||
|
@ -39,6 +39,8 @@ class SourceUnit;
|
||||
class IRGenerator
|
||||
{
|
||||
public:
|
||||
using ExecutionContext = IRGenerationContext::ExecutionContext;
|
||||
|
||||
IRGenerator(
|
||||
langutil::EVMVersion _evmVersion,
|
||||
RevertStrings _revertStrings,
|
||||
@ -47,7 +49,7 @@ public:
|
||||
):
|
||||
m_evmVersion(_evmVersion),
|
||||
m_optimiserSettings(_optimiserSettings),
|
||||
m_context(_evmVersion, _revertStrings, std::move(_optimiserSettings), std::move(_sourceIndices)),
|
||||
m_context(_evmVersion, ExecutionContext::Creation, _revertStrings, std::move(_optimiserSettings), std::move(_sourceIndices)),
|
||||
m_utils(_evmVersion, m_context.revertStrings(), m_context.functionCollector())
|
||||
{}
|
||||
|
||||
@ -115,7 +117,7 @@ private:
|
||||
/// to perform memory optimizations.
|
||||
std::string memoryInit(bool _useMemoryGuard);
|
||||
|
||||
void resetContext(ContractDefinition const& _contract);
|
||||
void resetContext(ContractDefinition const& _contract, ExecutionContext _context);
|
||||
|
||||
langutil::EVMVersion const m_evmVersion;
|
||||
OptimiserSettings const m_optimiserSettings;
|
||||
|
@ -2934,7 +2934,14 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue)
|
||||
solUnimplementedAssert(_lvalue.type.isValueType(), "");
|
||||
solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1, "");
|
||||
solAssert(_lvalue.type == *_immutable.variable->type(), "");
|
||||
define(result) << "loadimmutable(\"" << to_string(_immutable.variable->id()) << "\")\n";
|
||||
if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation)
|
||||
define(result) <<
|
||||
m_utils.readFromMemory(*_immutable.variable->type()) <<
|
||||
"(" <<
|
||||
to_string(m_context.immutableMemoryOffset(*_immutable.variable)) <<
|
||||
")\n";
|
||||
else
|
||||
define(result) << "loadimmutable(\"" << to_string(_immutable.variable->id()) << "\")\n";
|
||||
},
|
||||
[&](IRLValue::Tuple const&) {
|
||||
solAssert(false, "Attempted to read from tuple lvalue.");
|
||||
|
@ -0,0 +1,20 @@
|
||||
contract C {
|
||||
uint immutable public a;
|
||||
uint immutable public b;
|
||||
uint immutable public c;
|
||||
uint immutable public d;
|
||||
|
||||
constructor() {
|
||||
a = 1;
|
||||
b = a;
|
||||
c = b;
|
||||
d = c;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// a() -> 1
|
||||
// b() -> 1
|
||||
// c() -> 1
|
||||
// d() -> 1
|
@ -0,0 +1,22 @@
|
||||
contract A {
|
||||
uint8 immutable a;
|
||||
uint8 x;
|
||||
|
||||
constructor() {
|
||||
a = 3;
|
||||
x = readA();
|
||||
}
|
||||
|
||||
function readX() public view returns (uint8) {
|
||||
return x;
|
||||
}
|
||||
|
||||
function readA() public view returns (uint8) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// readX() -> 3
|
||||
// readA() -> 3
|
17
test/libsolidity/semanticTests/immutable/read_in_ctor.sol
Normal file
17
test/libsolidity/semanticTests/immutable/read_in_ctor.sol
Normal file
@ -0,0 +1,17 @@
|
||||
contract A {
|
||||
uint8 immutable a;
|
||||
uint8 x;
|
||||
|
||||
constructor() {
|
||||
a = 3;
|
||||
x = a;
|
||||
}
|
||||
|
||||
function readX() public view returns (uint8) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// readX() -> 3
|
@ -7,4 +7,4 @@ contract C {
|
||||
function f() public pure returns (uint) { return 3 + x; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (136-137): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (136-137): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -5,4 +5,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (71-72): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (71-72): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -11,4 +11,4 @@ contract C {
|
||||
function f(uint a) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (119-120): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (119-120): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -5,4 +5,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (63-64): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 3969: (63-64): Immutable variables must be initialized using an assignment.
|
||||
|
@ -5,4 +5,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (70-71): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 3969: (70-71): Immutable variables must be initialized using an assignment.
|
||||
|
@ -5,5 +5,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 1574: (74-75): Immutable state variable already initialized.
|
||||
// TypeError 7733: (74-75): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 2718: (74-75): Immutable variables cannot be modified after initialization.
|
||||
|
@ -4,4 +4,4 @@ contract C {
|
||||
function f() public pure returns (uint) { return 3 + x; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (99-100): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (99-100): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -11,3 +11,4 @@ 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,4 @@ contract C is B(C.f) {
|
||||
function f() internal returns(uint) { return x + 2; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (200-201): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (200-201): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -5,4 +5,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (63-64): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 3969: (63-64): Immutable variables must be initialized using an assignment.
|
||||
|
@ -7,5 +7,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (77-78): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (86-87): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// 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,4 @@ contract C {
|
||||
function f() internal returns(uint) { return x; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (107-108): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (107-108): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -13,4 +13,4 @@ contract C is B(C.y) {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (104-107): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (104-107): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -16,4 +16,4 @@ contract C is B {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (253-254): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (253-254): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -11,9 +11,8 @@ contract C is B {
|
||||
B.readX;
|
||||
}
|
||||
|
||||
function readX() internal override returns(uint) {
|
||||
function readX() internal pure override returns(uint) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (109-110): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
|
@ -11,9 +11,8 @@ contract C is B {
|
||||
super.readX();
|
||||
}
|
||||
|
||||
function readX() internal view override returns(uint) {
|
||||
function readX() internal pure override returns(uint) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (114-115): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
|
@ -18,4 +18,4 @@ contract C is B {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (245-246): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (245-246): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -0,0 +1,7 @@
|
||||
contract C { constructor(uint) {} }
|
||||
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,6 @@
|
||||
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.
|
@ -0,0 +1,7 @@
|
||||
contract D {
|
||||
uint immutable t;
|
||||
modifier m(uint) { _; }
|
||||
constructor() m(t=2) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (77-78): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
@ -26,4 +26,4 @@ contract C is A, B {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (489-490): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (489-490): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -26,4 +26,4 @@ contract C is A, B {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (493-494): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (493-494): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -17,4 +17,4 @@ contract C is B {
|
||||
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (202-203): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (202-203): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -0,0 +1,12 @@
|
||||
abstract contract A {
|
||||
uint public t;
|
||||
constructor() { t = f(); }
|
||||
|
||||
function f() virtual view internal returns (uint);
|
||||
}
|
||||
contract B is A {
|
||||
uint immutable x = 2;
|
||||
function f() override view internal returns (uint) { return x; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (223-224): Immutable variables cannot be read before they are initialized.
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
uint immutable t = 2;
|
||||
uint x = f();
|
||||
function f() internal pure returns (uint) { return t; }
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (106-107): Immutable variables cannot be read before they are initialized.
|
@ -0,0 +1,16 @@
|
||||
contract C {
|
||||
uint immutable x ;
|
||||
|
||||
constructor()
|
||||
{
|
||||
readX();
|
||||
x = 3;
|
||||
readX();
|
||||
}
|
||||
|
||||
function readX() public view returns(uint) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (145-146): Immutable variables cannot be read before they are initialized.
|
@ -3,4 +3,4 @@ contract C {
|
||||
uint y = x;
|
||||
}
|
||||
// ----
|
||||
// TypeError 7733: (52-53): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||
// TypeError 7733: (52-53): Immutable variables cannot be read before they are initialized.
|
||||
|
@ -4,5 +4,5 @@ contract C {
|
||||
uint immutable y = 5;
|
||||
}
|
||||
// ----
|
||||
// TypeError 1581: (62-63): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||
// 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.
|
||||
|
Loading…
Reference in New Issue
Block a user