Merge pull request #8580 from ethereum/publicImmutables

Accessors for immutable variables.
This commit is contained in:
chriseth 2020-04-02 19:50:56 +02:00 committed by GitHub
commit 4816484964
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 56 additions and 8 deletions

View File

@ -74,6 +74,11 @@ 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))
@ -187,7 +192,8 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va
else if (m_inConstructionContext)
m_errorReporter.typeError(
_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 during contract creation time, which means "
"they cannot be read in the constructor or any function or modifier called from it."
);
}

View File

@ -566,8 +566,6 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
if (_variableDeclaration.isConstant())
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals)
.appendConstStateVariableAccessor(_variableDeclaration);
else if (_variableDeclaration.immutable())
solUnimplementedAssert(false, "");
else
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals)
.appendStateVariableAccessor(_variableDeclaration);

View File

@ -91,16 +91,22 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
{
solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), "");
solAssert(!_varDecl.isConstant(), "");
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
FunctionType accessorType(_varDecl);
TypePointers paramTypes = accessorType.parameterTypes();
if (_varDecl.immutable())
solAssert(paramTypes.empty(), "");
m_context.adjustStackOffset(1 + CompilerUtils::sizeOnStack(paramTypes));
// retrieve the position of the variable
auto const& location = m_context.storageLocationOfVariable(_varDecl);
m_context << location.first << u256(location.second);
if (!_varDecl.immutable())
{
// retrieve the position of the variable
auto const& location = m_context.storageLocationOfVariable(_varDecl);
m_context << location.first << u256(location.second);
}
TypePointer returnType = _varDecl.annotation().type;
@ -182,6 +188,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
solAssert(returnTypes.size() >= 1, "");
if (StructType const* structType = dynamic_cast<StructType const*>(returnType))
{
solAssert(!_varDecl.immutable(), "");
// remove offset
m_context << Instruction::POP;
auto const& names = accessorType.returnParameterNames();
@ -208,7 +215,10 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{
// simple value or array
solAssert(returnTypes.size() == 1, "");
StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true);
if (_varDecl.immutable())
ImmutableItem(m_context, _varDecl).retrieveValue(SourceLocation());
else
StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true);
utils().convertType(*returnType, *returnTypes.front());
retSizeOnStack = returnTypes.front()->sizeOnStack();
}

View File

@ -0,0 +1,12 @@
contract C {
function() external returns (uint, uint) immutable public x = this.f;
function f() external pure returns (uint, uint) {
return (1, 2);
}
function test() external returns (uint, uint) {
return this.x()();
}
}
// ----
// test() -> 1, 2

View File

@ -0,0 +1,5 @@
contract C {
uint immutable public x = 1;
}
// ----
// x() -> 1

View File

@ -0,0 +1,17 @@
contract A {
uint immutable public x = 1;
uint public y;
constructor() public {
y = this.x();
}
}
contract C {
function f() public returns (bool) {
try new A() { return false; }
catch { return true; }
}
}
// ====
// EVMVersion: >=tangerineWhistle
// ----
// f() -> true