diff --git a/Changelog.md b/Changelog.md index ba0b062cc..3b97bda71 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,7 @@ Language Features: Compiler Features: + * Immutable variables can be read at construction time once they are initialized. Bugfixes: diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index 01a4f164c..b67068d63 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -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. \ No newline at end of file diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index d6dcff351..e28236fb6 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -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 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." ); } diff --git a/libsolidity/analysis/ImmutableValidator.h b/libsolidity/analysis/ImmutableValidator.h index 1ff58f0eb..e6d837efe 100644 --- a/libsolidity/analysis/ImmutableValidator.h +++ b/libsolidity/analysis/ImmutableValidator.h @@ -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; }; } diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index e7e069352..2622f2967 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -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(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 diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 1790655a2..b8affcbd8 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -65,13 +65,17 @@ using InternalDispatchMap = std::map; class IRGenerationContext { public: + enum class ExecutionContext { Creation, Deployed }; + IRGenerationContext( langutil::EVMVersion _evmVersion, + ExecutionContext _executionContext, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings, std::map _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 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 m_sourceIndices; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index ddbe4054b..418d112e0 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -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); diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 528fc3c7b..85d611108 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -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; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 96b8c991d..bee0e1611 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -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."); diff --git a/test/libsolidity/semanticTests/immutable/assign_from_immutables.sol b/test/libsolidity/semanticTests/immutable/assign_from_immutables.sol new file mode 100644 index 000000000..4e8610bb6 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/assign_from_immutables.sol @@ -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 diff --git a/test/libsolidity/semanticTests/immutable/fun_read_in_ctor.sol b/test/libsolidity/semanticTests/immutable/fun_read_in_ctor.sol new file mode 100644 index 000000000..b402ea8f2 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/fun_read_in_ctor.sol @@ -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 diff --git a/test/libsolidity/semanticTests/immutable/read_in_ctor.sol b/test/libsolidity/semanticTests/immutable/read_in_ctor.sol new file mode 100644 index 000000000..4b1201306 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/read_in_ctor.sol @@ -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 diff --git a/test/libsolidity/syntaxTests/immutable/ctor_initialization_indirect_reading.sol b/test/libsolidity/syntaxTests/immutable/ctor_initialization_indirect_reading.sol index 509e0d311..0ee583b56 100644 --- a/test/libsolidity/syntaxTests/immutable/ctor_initialization_indirect_reading.sol +++ b/test/libsolidity/syntaxTests/immutable/ctor_initialization_indirect_reading.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/ctor_initialization_reading.sol b/test/libsolidity/syntaxTests/immutable/ctor_initialization_reading.sol index 9f944a890..38ff92945 100644 --- a/test/libsolidity/syntaxTests/immutable/ctor_initialization_reading.sol +++ b/test/libsolidity/syntaxTests/immutable/ctor_initialization_reading.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/ctor_modifier_reading.sol b/test/libsolidity/syntaxTests/immutable/ctor_modifier_reading.sol index 61c13828d..5e3442e55 100644 --- a/test/libsolidity/syntaxTests/immutable/ctor_modifier_reading.sol +++ b/test/libsolidity/syntaxTests/immutable/ctor_modifier_reading.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/decrement.sol b/test/libsolidity/syntaxTests/immutable/decrement.sol index 5717f05c8..dd081438a 100644 --- a/test/libsolidity/syntaxTests/immutable/decrement.sol +++ b/test/libsolidity/syntaxTests/immutable/decrement.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/delete.sol b/test/libsolidity/syntaxTests/immutable/delete.sol index 541fceb53..bbb418c17 100644 --- a/test/libsolidity/syntaxTests/immutable/delete.sol +++ b/test/libsolidity/syntaxTests/immutable/delete.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/delete_and_initialize.sol b/test/libsolidity/syntaxTests/immutable/delete_and_initialize.sol index 859a30a77..1e55d90ce 100644 --- a/test/libsolidity/syntaxTests/immutable/delete_and_initialize.sol +++ b/test/libsolidity/syntaxTests/immutable/delete_and_initialize.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/function_initialization_reading.sol b/test/libsolidity/syntaxTests/immutable/function_initialization_reading.sol index a50ca6dd3..7933f8e7f 100644 --- a/test/libsolidity/syntaxTests/immutable/function_initialization_reading.sol +++ b/test/libsolidity/syntaxTests/immutable/function_initialization_reading.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/function_pointer_initializing.sol b/test/libsolidity/syntaxTests/immutable/function_pointer_initializing.sol index cc175d083..0d9dabf90 100644 --- a/test/libsolidity/syntaxTests/immutable/function_pointer_initializing.sol +++ b/test/libsolidity/syntaxTests/immutable/function_pointer_initializing.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/function_pointer_reading.sol b/test/libsolidity/syntaxTests/immutable/function_pointer_reading.sol index 10726cc04..e94fd155c 100644 --- a/test/libsolidity/syntaxTests/immutable/function_pointer_reading.sol +++ b/test/libsolidity/syntaxTests/immutable/function_pointer_reading.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/increment.sol b/test/libsolidity/syntaxTests/immutable/increment.sol index 11959ebc7..020620159 100644 --- a/test/libsolidity/syntaxTests/immutable/increment.sol +++ b/test/libsolidity/syntaxTests/immutable/increment.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/increment_decrement.sol b/test/libsolidity/syntaxTests/immutable/increment_decrement.sol index ccfaf1920..7b8092e1e 100644 --- a/test/libsolidity/syntaxTests/immutable/increment_decrement.sol +++ b/test/libsolidity/syntaxTests/immutable/increment_decrement.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/indirect_reading_during_statevar_init.sol b/test/libsolidity/syntaxTests/immutable/indirect_reading_during_statevar_init.sol index 11e56b2a8..eaa2186f1 100644 --- a/test/libsolidity/syntaxTests/immutable/indirect_reading_during_statevar_init.sol +++ b/test/libsolidity/syntaxTests/immutable/indirect_reading_during_statevar_init.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_reading.sol b/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_reading.sol index 4b4780452..2c670df6c 100644 --- a/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_reading.sol +++ b/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_reading.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions.sol index a241ee84c..dc11b8a61 100644 --- a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions.sol +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol index 7dfd75d52..b8ca24a2f 100644 --- a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_super.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_super.sol index 4782e7702..ffb699262 100644 --- a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_super.sol +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_super.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_modifiers.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_modifiers.sol index 3f4eba73e..95ea3e686 100644 --- a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_modifiers.sol +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_modifiers.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/init_in_ctor_param.sol b/test/libsolidity/syntaxTests/immutable/init_in_ctor_param.sol new file mode 100644 index 000000000..b67d149b2 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/init_in_ctor_param.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/init_in_inheritance_specifier_param.sol b/test/libsolidity/syntaxTests/immutable/init_in_inheritance_specifier_param.sol new file mode 100644 index 000000000..63662e1b7 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/init_in_inheritance_specifier_param.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/init_in_modifier_param.sol b/test/libsolidity/syntaxTests/immutable/init_in_modifier_param.sol new file mode 100644 index 000000000..3e354b4e9 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/init_in_modifier_param.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions.sol b/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions.sol index 36363159c..33749c8cd 100644 --- a/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions.sol +++ b/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions_with_super.sol b/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions_with_super.sol index e97e72b44..11da864db 100644 --- a/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions_with_super.sol +++ b/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions_with_super.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/private_state_var.sol b/test/libsolidity/syntaxTests/immutable/private_state_var.sol index 6e9ae734a..50af6ace8 100644 --- a/test/libsolidity/syntaxTests/immutable/private_state_var.sol +++ b/test/libsolidity/syntaxTests/immutable/private_state_var.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/read_in_function_before_init.sol b/test/libsolidity/syntaxTests/immutable/read_in_function_before_init.sol new file mode 100644 index 000000000..3ca0df270 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/read_in_function_before_init.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/read_in_function_before_init2.sol b/test/libsolidity/syntaxTests/immutable/read_in_function_before_init2.sol new file mode 100644 index 000000000..6e939b0b2 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/read_in_function_before_init2.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/reading_after_initialization_function.sol b/test/libsolidity/syntaxTests/immutable/reading_after_initialization_function.sol new file mode 100644 index 000000000..70d4ac4c8 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/reading_after_initialization_function.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/reading_during_statevar_init.sol b/test/libsolidity/syntaxTests/immutable/reading_during_statevar_init.sol index 2f4b98c3f..ae73679ea 100644 --- a/test/libsolidity/syntaxTests/immutable/reading_during_statevar_init.sol +++ b/test/libsolidity/syntaxTests/immutable/reading_during_statevar_init.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/immutable/variable_declaration_already.sol b/test/libsolidity/syntaxTests/immutable/variable_declaration_already.sol index 73fe59801..06d2bfa79 100644 --- a/test/libsolidity/syntaxTests/immutable/variable_declaration_already.sol +++ b/test/libsolidity/syntaxTests/immutable/variable_declaration_already.sol @@ -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.