mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Disallow assignments to structs and mappings.
This commit is contained in:
parent
9e91596c8d
commit
a2ad47441e
12
AST.cpp
12
AST.cpp
@ -378,6 +378,9 @@ void Assignment::checkTypeRequirements()
|
|||||||
{
|
{
|
||||||
m_leftHandSide->checkTypeRequirements();
|
m_leftHandSide->checkTypeRequirements();
|
||||||
m_leftHandSide->requireLValue();
|
m_leftHandSide->requireLValue();
|
||||||
|
//@todo later, assignments to structs might be possible, but not to mappings
|
||||||
|
if (!m_leftHandSide->getType()->isValueType() && !m_leftHandSide->isLocalLValue())
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Assignment to non-local non-value lvalue."));
|
||||||
m_rightHandSide->expectType(*m_leftHandSide->getType());
|
m_rightHandSide->expectType(*m_leftHandSide->getType());
|
||||||
m_type = m_leftHandSide->getType();
|
m_type = m_leftHandSide->getType();
|
||||||
if (m_assigmentOperator != Token::ASSIGN)
|
if (m_assigmentOperator != Token::ASSIGN)
|
||||||
@ -403,7 +406,7 @@ void Expression::expectType(Type const& _expectedType)
|
|||||||
|
|
||||||
void Expression::requireLValue()
|
void Expression::requireLValue()
|
||||||
{
|
{
|
||||||
if (!isLvalue())
|
if (!isLValue())
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
|
BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
|
||||||
m_lvalueRequested = true;
|
m_lvalueRequested = true;
|
||||||
}
|
}
|
||||||
@ -495,7 +498,8 @@ void MemberAccess::checkTypeRequirements()
|
|||||||
m_type = type.getMemberType(*m_memberName);
|
m_type = type.getMemberType(*m_memberName);
|
||||||
if (!m_type)
|
if (!m_type)
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString()));
|
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString()));
|
||||||
m_isLvalue = (type.getCategory() == Type::Category::STRUCT && m_type->getCategory() != Type::Category::MAPPING);
|
//@todo later, this will not always be STORAGE
|
||||||
|
m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexAccess::checkTypeRequirements()
|
void IndexAccess::checkTypeRequirements()
|
||||||
@ -507,7 +511,7 @@ void IndexAccess::checkTypeRequirements()
|
|||||||
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
|
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
|
||||||
m_index->expectType(*type.getKeyType());
|
m_index->expectType(*type.getKeyType());
|
||||||
m_type = type.getValueType();
|
m_type = type.getValueType();
|
||||||
m_isLvalue = m_type->getCategory() != Type::Category::MAPPING;
|
m_lvalue = LValueType::STORAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Identifier::checkTypeRequirements()
|
void Identifier::checkTypeRequirements()
|
||||||
@ -521,7 +525,7 @@ void Identifier::checkTypeRequirements()
|
|||||||
if (!variable->getType())
|
if (!variable->getType())
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
|
BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
|
||||||
m_type = variable->getType();
|
m_type = variable->getType();
|
||||||
m_isLvalue = true;
|
m_lvalue = variable->isLocalVariable() ? LValueType::LOCAL : LValueType::STORAGE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//@todo can we unify these with TypeName::toType()?
|
//@todo can we unify these with TypeName::toType()?
|
||||||
|
16
AST.h
16
AST.h
@ -242,6 +242,8 @@ public:
|
|||||||
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
||||||
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
|
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
|
||||||
|
|
||||||
|
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition*>(getScope()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
|
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
|
||||||
|
|
||||||
@ -526,12 +528,16 @@ private:
|
|||||||
*/
|
*/
|
||||||
class Expression: public ASTNode
|
class Expression: public ASTNode
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
enum class LValueType { NONE, LOCAL, STORAGE };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Expression(Location const& _location): ASTNode(_location), m_isLvalue(false), m_lvalueRequested(false) {}
|
Expression(Location const& _location): ASTNode(_location), m_lvalue(LValueType::NONE), m_lvalueRequested(false) {}
|
||||||
virtual void checkTypeRequirements() = 0;
|
virtual void checkTypeRequirements() = 0;
|
||||||
|
|
||||||
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
||||||
bool isLvalue() const { return m_isLvalue; }
|
bool isLValue() const { return m_lvalue != LValueType::NONE; }
|
||||||
|
bool isLocalLValue() const { return m_lvalue == LValueType::LOCAL; }
|
||||||
|
|
||||||
/// Helper function, infer the type via @ref checkTypeRequirements and then check that it
|
/// Helper function, infer the type via @ref checkTypeRequirements and then check that it
|
||||||
/// is implicitly convertible to @a _expectedType. If not, throw exception.
|
/// is implicitly convertible to @a _expectedType. If not, throw exception.
|
||||||
@ -546,9 +552,9 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
//! Inferred type of the expression, only filled after a call to checkTypeRequirements().
|
//! Inferred type of the expression, only filled after a call to checkTypeRequirements().
|
||||||
std::shared_ptr<Type const> m_type;
|
std::shared_ptr<Type const> m_type;
|
||||||
//! Whether or not this expression is an lvalue, i.e. something that can be assigned to.
|
//! If this expression is an lvalue (i.e. something that can be assigned to) and is stored
|
||||||
//! This is set during calls to @a checkTypeRequirements()
|
//! locally or in storage. This is set during calls to @a checkTypeRequirements()
|
||||||
bool m_isLvalue;
|
LValueType m_lvalue;
|
||||||
//! Whether the outer expression requested the address (true) or the value (false) of this expression.
|
//! Whether the outer expression requested the address (true) or the value (false) of this expression.
|
||||||
bool m_lvalueRequested;
|
bool m_lvalueRequested;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user