aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGav Wood <g@ethdev.com>2015-01-11 18:07:36 +0800
committerGav Wood <g@ethdev.com>2015-01-11 18:07:36 +0800
commit94cff9684f8b1d4a5e2eeba58444a99e32e8a7ae (patch)
treeb14986766ba825f33176c82c66be8f10887d6517
parent26f9cd7f682b9d26252ab13f2a12178dc238abee (diff)
parentc5c893319285993dd9a1c6a790537e7acc35e5d0 (diff)
downloaddexon-solidity-94cff9684f8b1d4a5e2eeba58444a99e32e8a7ae.tar
dexon-solidity-94cff9684f8b1d4a5e2eeba58444a99e32e8a7ae.tar.gz
dexon-solidity-94cff9684f8b1d4a5e2eeba58444a99e32e8a7ae.tar.bz2
dexon-solidity-94cff9684f8b1d4a5e2eeba58444a99e32e8a7ae.tar.lz
dexon-solidity-94cff9684f8b1d4a5e2eeba58444a99e32e8a7ae.tar.xz
dexon-solidity-94cff9684f8b1d4a5e2eeba58444a99e32e8a7ae.tar.zst
dexon-solidity-94cff9684f8b1d4a5e2eeba58444a99e32e8a7ae.zip
Merge pull request #768 from chriseth/sol_contractsAreAddresses
Contracts inherit all address members
-rw-r--r--ExpressionCompiler.cpp63
-rw-r--r--Types.cpp15
-rw-r--r--Types.h9
3 files changed, 62 insertions, 25 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 1ce5ca5b..4fdea332 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -194,13 +194,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
solAssert(_functionCall.getArguments().size() == 1, "");
Expression const& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this);
- if (firstArgument.getType()->getCategory() == Type::Category::CONTRACT &&
- _functionCall.getType()->getCategory() == Type::Category::INTEGER)
- {
- // explicit type conversion contract -> address, nothing to do.
- }
- else
- appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
+ appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
}
else
{
@@ -250,13 +244,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
FunctionCallOptions options;
options.bare = true;
options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); };
- options.obtainValue = [&]() { arguments.front()->accept(*this); };
+ options.obtainValue = [&]()
+ {
+ arguments.front()->accept(*this);
+ appendTypeConversion(*arguments.front()->getType(),
+ *function.getParameterTypes().front(), true);
+ };
appendExternalFunctionCall(FunctionType({}, {}, Location::EXTERNAL), {}, options);
break;
}
case Location::SUICIDE:
arguments.front()->accept(*this);
- //@todo might not be necessary
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true);
m_context << eth::Instruction::SUICIDE;
break;
@@ -347,6 +345,18 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
ASTString const& member = _memberAccess.getMemberName();
switch (_memberAccess.getExpression().getType()->getCategory())
{
+ case Type::Category::CONTRACT:
+ {
+ ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.getExpression().getType());
+ u256 identifier = type.getFunctionIdentifier(member);
+ if (identifier != Invalid256)
+ {
+ appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::ADDRESS), true);
+ m_context << identifier;
+ break;
+ }
+ // fall-through to "integer" otherwise (address)
+ }
case Type::Category::INTEGER:
if (member == "balance")
{
@@ -360,12 +370,6 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
break;
- case Type::Category::CONTRACT:
- {
- ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.getExpression().getType());
- m_context << type.getFunctionIdentifier(member);
- break;
- }
case Type::Category::MAGIC:
// we can ignore the kind of magic and only look at the name of the member
if (member == "coinbase")
@@ -592,15 +596,36 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
return;
Type::Category stackTypeCategory = _typeOnStack.getCategory();
Type::Category targetTypeCategory = _targetType.getCategory();
- if (stackTypeCategory == Type::Category::INTEGER)
+ if (stackTypeCategory == Type::Category::INTEGER || stackTypeCategory == Type::Category::CONTRACT ||
+ stackTypeCategory == Type::Category::INTEGER_CONSTANT)
{
solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, "");
- appendHighBitsCleanup(dynamic_cast<IntegerType const&>(_typeOnStack));
+ IntegerType addressType(0, IntegerType::Modifier::ADDRESS);
+ IntegerType const& targetType = targetTypeCategory == Type::Category::INTEGER
+ ? dynamic_cast<IntegerType const&>(_targetType) : addressType;
+ if (stackTypeCategory == Type::Category::INTEGER_CONSTANT)
+ {
+ IntegerConstantType const& constType = dynamic_cast<IntegerConstantType const&>(_typeOnStack);
+ // We know that the stack is clean, we only have to clean for a narrowing conversion
+ // where cleanup is forced.
+ if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded)
+ appendHighBitsCleanup(targetType);
+ }
+ else
+ {
+ IntegerType const& typeOnStack = stackTypeCategory == Type::Category::INTEGER
+ ? dynamic_cast<IntegerType const&>(_typeOnStack) : addressType;
+ // Widening: clean up according to source type width
+ // Non-widening and force: clean up according to target type bits
+ if (targetType.getNumBits() > typeOnStack.getNumBits())
+ appendHighBitsCleanup(typeOnStack);
+ else if (_cleanupNeeded)
+ appendHighBitsCleanup(targetType);
+ }
}
- else if (stackTypeCategory == Type::Category::INTEGER_CONSTANT)
- solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, "");
else if (stackTypeCategory == Type::Category::STRING)
{
+ solAssert(targetTypeCategory == Type::Category::STRING, "");
// nothing to do, strings are high-order-bit-aligned
//@todo clear lower-order bytes if we allow explicit conversion to shorter strings
}
diff --git a/Types.cpp b/Types.cpp
index da042edb..eda022cc 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -424,15 +424,20 @@ TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer c
return TypePointer();
}
-bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
- if (isImplicitlyConvertibleTo(_convertTo))
+ if (*this == _convertTo)
return true;
if (_convertTo.getCategory() == Category::INTEGER)
return dynamic_cast<IntegerType const&>(_convertTo).isAddress();
return false;
}
+bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ return isImplicitlyConvertibleTo(_convertTo) || _convertTo.getCategory() == Category::INTEGER;
+}
+
bool ContractType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
@@ -459,7 +464,9 @@ MemberList const& ContractType::getMembers() const
// We need to lazy-initialize it because of recursive references.
if (!m_members)
{
- map<string, shared_ptr<Type const>> members;
+ // All address members and all interface functions
+ map<string, shared_ptr<Type const>> members(IntegerType::AddressMemberList.begin(),
+ IntegerType::AddressMemberList.end());
for (auto const& it: m_contract.getInterfaceFunctions())
members[it.second->getName()] = make_shared<FunctionType>(*it.second, false);
m_members.reset(new MemberList(members));
@@ -487,7 +494,7 @@ u256 ContractType::getFunctionIdentifier(string const& _functionName) const
if (it->second->getName() == _functionName)
return FixedHash<4>::Arith(it->first);
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Index of non-existing contract function requested."));
+ return Invalid256;
}
bool StructType::operator==(Type const& _other) const
diff --git a/Types.h b/Types.h
index 69f69ef6..335c58a3 100644
--- a/Types.h
+++ b/Types.h
@@ -180,10 +180,11 @@ public:
bool isAddress() const { return m_modifier == Modifier::ADDRESS; }
int isSigned() const { return m_modifier == Modifier::SIGNED; }
+ static const MemberList AddressMemberList;
+
private:
int m_bits;
Modifier m_modifier;
- static const MemberList AddressMemberList;
};
/**
@@ -279,7 +280,9 @@ class ContractType: public Type
public:
virtual Category getCategory() const override { return Category::CONTRACT; }
ContractType(ContractDefinition const& _contract): m_contract(_contract) {}
- /// Contracts can be converted to themselves and to addresses.
+ /// Contracts can be implicitly converted to super classes and to addresses.
+ virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ /// Contracts can be converted to themselves and to integers.
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const override;
@@ -292,6 +295,8 @@ public:
/// is not used, as this type cannot be the type of a variable or expression.
std::shared_ptr<FunctionType const> const& getConstructorType() const;
+ /// @returns the identifier of the function with the given name or Invalid256 if such a name does
+ /// not exist.
u256 getFunctionIdentifier(std::string const& _functionName) const;
private: