mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Index access for bytesXX.
This commit is contained in:
@@ -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(),
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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, "");
|
||||
|
||||
Reference in New Issue
Block a user