aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2016-10-25 18:50:24 +0800
committerGitHub <noreply@github.com>2016-10-25 18:50:24 +0800
commite00a4b47c06d412cd9342b8be2163e861c591c28 (patch)
tree3c8584a2d12591f6dd5766f0c3f074bf0a6ffd97
parentd190f016ad70f78f3abb06a09472235844e7c04d (diff)
parent59f6c18c2be86152261bb20732161c60fd2a6485 (diff)
downloaddexon-solidity-e00a4b47c06d412cd9342b8be2163e861c591c28.tar
dexon-solidity-e00a4b47c06d412cd9342b8be2163e861c591c28.tar.gz
dexon-solidity-e00a4b47c06d412cd9342b8be2163e861c591c28.tar.bz2
dexon-solidity-e00a4b47c06d412cd9342b8be2163e861c591c28.tar.lz
dexon-solidity-e00a4b47c06d412cd9342b8be2163e861c591c28.tar.xz
dexon-solidity-e00a4b47c06d412cd9342b8be2163e861c591c28.tar.zst
dexon-solidity-e00a4b47c06d412cd9342b8be2163e861c591c28.zip
Merge pull request #1264 from ethereum/988
State variable under contract's name
-rw-r--r--Changelog.md3
-rw-r--r--libsolidity/analysis/TypeChecker.cpp5
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp23
-rw-r--r--libsolidity/codegen/ExpressionCompiler.h2
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp114
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp13
6 files changed, 150 insertions, 10 deletions
diff --git a/Changelog.md b/Changelog.md
index fdce077f..71c7a0fe 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -16,7 +16,8 @@ Bugfixes:
* Type checker: fixed crash related to invalid literal numbers.
* Type Checker: ``super.x`` does not look up ``x`` in the current contract.
* Code generator: expect zero stack increase after ``super`` as an expression.
- * Code Generator: fixed an internal compiler error for ``L.Foo`` for ``enum Foo`` defined in library ``L``.
+ * Code Generator: fix an internal compiler error for ``L.Foo`` for ``enum Foo`` defined in library ``L``.
+ * Code generator: allow inheritance of ``enum`` definitions.
* Inline assembly: support the ``address`` opcode.
* Inline assembly: fix parsing of assignment after a label.
* Inline assembly: external variables of unsupported type (such as ``this``, ``super``, etc.)
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 10d24e5a..46f4f7f6 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1386,6 +1386,11 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
}
else if (exprType->category() == Type::Category::FixedBytes)
annotation.isLValue = false;
+ else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType.get()))
+ {
+ if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType().get()))
+ annotation.isLValue = annotation.referencedDeclaration->isLValue();
+ }
return false;
}
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 6d54b48b..9a096e2d 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -890,6 +890,8 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
{
// no-op
}
+ else if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
+ appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
else
_memberAccess.expression().accept(*this);
}
@@ -1203,15 +1205,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
m_context << m_context.virtualFunctionEntryLabel(*functionDef).pushTag();
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
- {
- if (!variable->isConstant())
- setLValueFromDeclaration(*declaration, _identifier);
- else
- {
- variable->value()->accept(*this);
- utils().convertType(*variable->value()->annotation().type, *variable->annotation().type);
- }
- }
+ appendVariable(*variable, static_cast<Expression const&>(_identifier));
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
{
if (contract->isLibrary())
@@ -1646,6 +1640,17 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
utils().storeInMemoryDynamic(_expectedType);
}
+void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression)
+{
+ if (!_variable.isConstant())
+ setLValueFromDeclaration(_variable, _expression);
+ else
+ {
+ _variable.value()->accept(*this);
+ utils().convertType(*_variable.value()->annotation().type, *_variable.annotation().type);
+ }
+}
+
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)
{
if (m_context.isLocalVariable(&_declaration))
diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h
index 43a92a10..f4ce1fec 100644
--- a/libsolidity/codegen/ExpressionCompiler.h
+++ b/libsolidity/codegen/ExpressionCompiler.h
@@ -103,6 +103,8 @@ private:
/// expected to be on the stack and is updated by this call.
void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression);
+ /// Appends code for a variable that might be a constant or not
+ void appendVariable(VariableDeclaration const& _variable, Expression const& _expression);
/// Sets the current LValue to a new one (of the appropriate type) from the given declaration.
/// Also retrieves the value if it was not requested by @a _expression.
void setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression);
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index bb197cca..8ef9a45b 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -5666,6 +5666,120 @@ BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable)
BOOST_CHECK(callContractFunction("ticketPrice()") == encodeArgs(u256(555)));
}
+BOOST_AUTO_TEST_CASE(state_variable_under_contract_name)
+{
+ char const* text = R"(
+ contract Scope {
+ uint stateVar = 42;
+
+ function getStateVar() constant returns (uint stateVar) {
+ stateVar = Scope.stateVar;
+ }
+ }
+ )";
+ compileAndRun(text);
+ BOOST_CHECK(callContractFunction("getStateVar()") == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(state_variable_local_variable_mixture)
+{
+ char const* sourceCode = R"(
+ contract A {
+ uint x = 1;
+ uint y = 2;
+ function a() returns (uint x) {
+ x = A.y;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(inherited_function) {
+ char const* sourceCode = R"(
+ contract A { function f() internal returns (uint) { return 1; } }
+ contract B is A {
+ function f() internal returns (uint) { return 2; }
+ function g() returns (uint) {
+ return A.f();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "B");
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(inherited_function_from_a_library) {
+ char const* sourceCode = R"(
+ library A { function f() internal returns (uint) { return 1; } }
+ contract B {
+ function f() internal returns (uint) { return 2; }
+ function g() returns (uint) {
+ return A.f();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "B");
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(inherited_constant_state_var)
+{
+ char const* sourceCode = R"(
+ contract A {
+ uint constant x = 7;
+ }
+ contract B is A {
+ function f() returns (uint) {
+ return A.x;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "B");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(multiple_inherited_state_vars)
+{
+ char const* sourceCode = R"(
+ contract A {
+ uint x = 7;
+ }
+ contract B {
+ uint x = 9;
+ }
+ contract C is A, B {
+ function a() returns (uint) {
+ return A.x;
+ }
+ function b() returns (uint) {
+ return B.x;
+ }
+ function a_set(uint _x) returns (uint) {
+ A.x = _x;
+ return 1;
+ }
+ function b_set(uint _x) returns (uint) {
+ B.x = _x;
+ return 1;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("b()") == encodeArgs(u256(9)));
+ BOOST_CHECK(callContractFunction("a_set(uint256)", u256(1)) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("b_set(uint256)", u256(3)) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("b()") == encodeArgs(u256(3)));
+}
+
BOOST_AUTO_TEST_CASE(constant_string_literal)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index f7ac73ae..9fe91cca 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -1036,6 +1036,19 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist");
}
+BOOST_AUTO_TEST_CASE(missing_state_variable)
+{
+ char const* text = R"(
+ contract Scope {
+ function getStateVar() constant returns (uint stateVar) {
+ stateVar = Scope.stateVar; // should fail.
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+
BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
{
// test for issue #1126 https://github.com/ethereum/cpp-ethereum/issues/1126