aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-02-11 21:09:53 +0800
committerchriseth <c@ethdev.com>2016-02-11 21:09:53 +0800
commitc6c3c78327751db3e27458596394ce3533a7fcbc (patch)
treee0c59eb242bccfb3f2e6a3cf4066f406e923ca11
parent7b5d96c43bc4019d8f64951be64a1d702ee63e5d (diff)
parent13732aed12008e0c389b55a8ef435173a7448809 (diff)
downloaddexon-solidity-c6c3c78327751db3e27458596394ce3533a7fcbc.tar.gz
dexon-solidity-c6c3c78327751db3e27458596394ce3533a7fcbc.tar.zst
dexon-solidity-c6c3c78327751db3e27458596394ce3533a7fcbc.zip
Merge pull request #382 from chriseth/bytesIndex
Index access for bytesXX.
-rw-r--r--docs/types.rst5
-rw-r--r--libsolidity/analysis/TypeChecker.cpp18
-rw-r--r--libsolidity/ast/Types.cpp5
-rw-r--r--libsolidity/ast/Types.h1
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp26
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp36
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp13
7 files changed, 104 insertions, 0 deletions
diff --git a/docs/types.rst b/docs/types.rst
index 9811df69..27ab82ff 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -110,6 +110,11 @@ Operators:
* Comparisons: `<=`, `<`, `==`, `!=`, `>=`, `>` (evaluate to `bool`)
* Bit operators: `&`, `|`, `^` (bitwise exclusive or), `~` (bitwise negation)
+* Index access: If `x` is of type `bytesI`, then `x[k]` for `0 <= k < I` returns the `k` th byte (read-only).
+
+Members:
+
+* `.length` yields the fixed length of the byte array (read-only).
Dynamically-sized byte array
----------------------------
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 0d74ddba..756f0e4f 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1253,6 +1253,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
arrayType.isDynamicallySized()
);
}
+ else if (exprType->category() == Type::Category::FixedBytes)
+ annotation.isLValue = false;
return false;
}
@@ -1317,6 +1319,22 @@ bool TypeChecker::visit(IndexAccess const& _access)
}
break;
}
+ case Type::Category::FixedBytes:
+ {
+ FixedBytesType const& bytesType = dynamic_cast<FixedBytesType const&>(*baseType);
+ if (!index)
+ typeError(_access.location(), "Index expression cannot be omitted.");
+ else
+ {
+ expectType(*index, IntegerType(256));
+ if (auto integerType = dynamic_cast<IntegerConstantType const*>(type(*index).get()))
+ if (bytesType.numBytes() <= integerType->literalValue(nullptr))
+ typeError(_access.location(), "Out of bounds array access.");
+ }
+ resultType = make_shared<FixedBytesType>(1);
+ isLValue = false; // @todo this heavily depends on how it is embedded
+ break;
+ }
default:
fatalTypeError(
_access.baseExpression().location(),
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 79e5bb02..01d1cb37 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -638,6 +638,11 @@ TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePoi
return TypePointer();
}
+MemberList::MemberMap FixedBytesType::nativeMembers(const ContractDefinition*) const
+{
+ return MemberList::MemberMap{MemberList::Member{"length", make_shared<IntegerType>(8)}};
+}
+
bool FixedBytesType::operator==(Type const& _other) const
{
if (_other.category() != category())
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 723d633b..90a0509b 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -399,6 +399,7 @@ public:
virtual bool isValueType() const override { return true; }
virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
+ virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
virtual TypePointer encodingType() const override { return shared_from_this(); }
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 9536c727..58db07b1 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1004,6 +1004,16 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
solAssert(false, "Illegal array member.");
break;
}
+ case Type::Category::FixedBytes:
+ {
+ auto const& type = dynamic_cast<FixedBytesType const&>(*_memberAccess.expression().annotation().type);
+ utils().popStackElement(type);
+ if (member == "length")
+ m_context << u256(type.numBytes());
+ else
+ solAssert(false, "Illegal fixed bytes member.");
+ break;
+ }
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type."));
}
@@ -1085,6 +1095,22 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
break;
}
}
+ else if (baseType.category() == Type::Category::FixedBytes)
+ {
+ FixedBytesType const& fixedBytesType = dynamic_cast<FixedBytesType const&>(baseType);
+ solAssert(_indexAccess.indexExpression(), "Index expression expected.");
+
+ _indexAccess.indexExpression()->accept(*this);
+ // stack layout: <value> <index>
+ // check out-of-bounds access
+ m_context << u256(fixedBytesType.numBytes());
+ m_context << eth::Instruction::DUP2 << eth::Instruction::LT << eth::Instruction::ISZERO;
+ // out-of-bounds access throws exception
+ m_context.appendConditionalJumpTo(m_context.errorTag());
+
+ m_context << eth::Instruction::BYTE;
+ m_context << (u256(1) << (256 - 8)) << eth::Instruction::MUL;
+ }
else if (baseType.category() == Type::Category::TypeType)
{
solAssert(baseType.sizeOnStack() == 0, "");
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 73e2d662..c6e1b10d 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -6394,6 +6394,42 @@ BOOST_AUTO_TEST_CASE(inline_long_string_return)
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f()") == encodeDyn(strLong));
}
+
+BOOST_AUTO_TEST_CASE(fixed_bytes_index_access)
+{
+ char const* sourceCode = R"(
+ contract C {
+ bytes16[] public data;
+ function f(bytes32 x) returns (byte) {
+ return x[2];
+ }
+ function g(bytes32 x) returns (uint) {
+ data = [x[0], x[1], x[2]];
+ data[0] = "12345";
+ return uint(data[0][4]);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(bytes32)", "789") == encodeArgs("9"));
+ BOOST_CHECK(callContractFunction("g(bytes32)", "789") == encodeArgs(u256(int('5'))));
+ BOOST_CHECK(callContractFunction("data(uint256)", u256(1)) == encodeArgs("8"));
+}
+
+BOOST_AUTO_TEST_CASE(fixed_bytes_length_access)
+{
+ char const* sourceCode = R"(
+ contract C {
+ byte a;
+ function f(bytes32 x) returns (uint, uint, uint) {
+ return (x.length, bytes16(2).length, a.length + 7);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(bytes32)", "789") == encodeArgs(u256(32), u256(16), u256(8)));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 820fd7d0..d202942c 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -3136,6 +3136,19 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
BOOST_CHECK(success(text));
}
+BOOST_AUTO_TEST_CASE(index_access_for_bytes)
+{
+ char const* text = R"(
+ contract C {
+ bytes20 x;
+ function f(bytes16 b) {
+ b[uint(x[2])];
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}