More general function types and references.

This commit is contained in:
Christian 2014-11-25 14:43:23 +01:00
parent 6e6b85b58a
commit a2715c5f34
4 changed files with 72 additions and 29 deletions

12
AST.cpp
View File

@ -467,19 +467,19 @@ void FunctionCall::checkTypeRequirements()
//@todo would be nice to create a struct type from the arguments //@todo would be nice to create a struct type from the arguments
// and then ask if that is implicitly convertible to the struct represented by the // and then ask if that is implicitly convertible to the struct represented by the
// function parameters // function parameters
FunctionDefinition const& fun = dynamic_cast<FunctionType const&>(*expressionType).getFunction(); FunctionType const& functionType = dynamic_cast<FunctionType const&>(*expressionType);
vector<ASTPointer<VariableDeclaration>> const& parameters = fun.getParameters(); TypePointers const& parameterTypes = functionType.getParameterTypes();
if (parameters.size() != m_arguments.size()) if (parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
for (size_t i = 0; i < m_arguments.size(); ++i) for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
// @todo actually the return type should be an anonymous struct, // @todo actually the return type should be an anonymous struct,
// but we change it to the type of the first return value until we have structs // but we change it to the type of the first return value until we have structs
if (fun.getReturnParameters().empty()) if (functionType.getReturnParameterTypes().empty())
m_type = make_shared<VoidType>(); m_type = make_shared<VoidType>();
else else
m_type = fun.getReturnParameters().front()->getType(); m_type = functionType.getReturnParameterTypes().front();
} }
} }

View File

@ -183,16 +183,16 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
// Calling convention: Caller pushes return address and arguments // Calling convention: Caller pushes return address and arguments
// Callee removes them and pushes return values // Callee removes them and pushes return values
FunctionDefinition const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()).getFunction(); FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
eth::AssemblyItem returnLabel = m_context.pushNewTag(); eth::AssemblyItem returnLabel = m_context.pushNewTag();
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments(); std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
if (asserts(arguments.size() == function.getParameters().size())) if (asserts(arguments.size() == function.getParameterTypes().size()))
BOOST_THROW_EXCEPTION(InternalCompilerError()); BOOST_THROW_EXCEPTION(InternalCompilerError());
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
{ {
arguments[i]->accept(*this); arguments[i]->accept(*this);
appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType()); appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]);
} }
_functionCall.getExpression().accept(*this); _functionCall.getExpression().accept(*this);
@ -200,11 +200,11 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
m_context << returnLabel; m_context << returnLabel;
// callee adds return parameters, but removes arguments and return label // callee adds return parameters, but removes arguments and return label
m_context.adjustStackOffset(function.getReturnParameters().size() - arguments.size() - 1); m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1);
// @todo for now, the return value of a function is its first return value, so remove // @todo for now, the return value of a function is its first return value, so remove
// all others // all others
for (unsigned i = 1; i < function.getReturnParameters().size(); ++i) for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }
return false; return false;

View File

@ -189,7 +189,10 @@ u256 IntegerType::literalValue(Literal const& _literal) const
return u256(value); return u256(value);
} }
const MemberList IntegerType::AddressMemberList = MemberList({{"balance", std::make_shared<IntegerType const>(256)}}); const MemberList IntegerType::AddressMemberList =
MemberList({{"balance", make_shared<IntegerType const>(256)},
{"send", make_shared<FunctionType const>(TypePointers({make_shared<IntegerType const>(256)}),
TypePointers())}});
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
@ -299,17 +302,49 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested."));
} }
FunctionType::FunctionType(FunctionDefinition const& _function)
{
TypePointers params;
TypePointers retParams;
params.reserve(_function.getParameters().size());
for (ASTPointer<VariableDeclaration> const& var: _function.getParameters())
params.push_back(var->getType());
retParams.reserve(_function.getReturnParameters().size());
for (ASTPointer<VariableDeclaration> const& var: _function.getReturnParameters())
retParams.push_back(var->getType());
swap(params, m_parameterTypes);
swap(retParams, m_returnParameterTypes);
}
bool FunctionType::operator==(Type const& _other) const bool FunctionType::operator==(Type const& _other) const
{ {
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())
return false; return false;
FunctionType const& other = dynamic_cast<FunctionType const&>(_other); FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
return other.m_function == m_function;
if (m_parameterTypes.size() != other.m_parameterTypes.size() ||
m_returnParameterTypes.size() != other.m_returnParameterTypes.size())
return false;
auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; };
if (!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(),
other.m_parameterTypes.cbegin(), typeCompare))
return false;
if (!equal(m_returnParameterTypes.cbegin(), m_returnParameterTypes.cend(),
other.m_returnParameterTypes.cbegin(), typeCompare))
return false;
return true;
} }
string FunctionType::toString() const string FunctionType::toString() const
{ {
return "function " + m_function.getName(); string name = "function (";
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
name += (*it)->toString() + (it + 1 == m_parameterTypes.end() ? "" : ",");
name += ") returns (";
for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it)
name += (*it)->toString() + (it + 1 == m_returnParameterTypes.end() ? "" : ",");
return name + ")";
} }
bool MappingType::operator==(Type const& _other) const bool MappingType::operator==(Type const& _other) const

38
Types.h
View File

@ -39,6 +39,8 @@ namespace solidity
// @todo realMxN, string<N> // @todo realMxN, string<N>
class Type; // forward class Type; // forward
using TypePointer = std::shared_ptr<Type const>;
using TypePointers = std::vector<TypePointer>;
/** /**
* List of members of a type. * List of members of a type.
@ -46,7 +48,6 @@ class Type; // forward
class MemberList class MemberList
{ {
public: public:
using TypePointer = std::shared_ptr<Type const>;
using MemberMap = std::map<std::string, TypePointer>; using MemberMap = std::map<std::string, TypePointer>;
MemberList() {} MemberList() {}
@ -54,7 +55,7 @@ public:
TypePointer getMemberType(std::string const& _name) const TypePointer getMemberType(std::string const& _name) const
{ {
auto it = m_memberTypes.find(_name); auto it = m_memberTypes.find(_name);
return it != m_memberTypes.end() ? it->second : std::shared_ptr<Type const>(); return it != m_memberTypes.end() ? it->second : TypePointer();
} }
MemberMap::const_iterator begin() const { return m_memberTypes.begin(); } MemberMap::const_iterator begin() const { return m_memberTypes.begin(); }
@ -82,6 +83,7 @@ public:
static std::shared_ptr<Type> fromElementaryTypeName(Token::Value _typeToken); static std::shared_ptr<Type> fromElementaryTypeName(Token::Value _typeToken);
static std::shared_ptr<Type> fromUserDefinedTypeName(UserDefinedTypeName const& _typeName); static std::shared_ptr<Type> fromUserDefinedTypeName(UserDefinedTypeName const& _typeName);
static std::shared_ptr<Type> fromMapping(Mapping const& _typeName); static std::shared_ptr<Type> fromMapping(Mapping const& _typeName);
static std::shared_ptr<Type> fromFunction(FunctionDefinition const& _function);
/// @} /// @}
/// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
@ -117,7 +119,7 @@ public:
/// Returns the list of all members of this type. Default implementation: no members. /// Returns the list of all members of this type. Default implementation: no members.
virtual MemberList const& getMembers() const { return EmptyMemberList; } virtual MemberList const& getMembers() const { return EmptyMemberList; }
/// Convenience method, returns the type of the given named member or an empty pointer if no such member exists. /// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
std::shared_ptr<Type const> getMemberType(std::string const& _name) const { return getMembers().getMemberType(_name); } TypePointer getMemberType(std::string const& _name) const { return getMembers().getMemberType(_name); }
virtual std::string toString() const = 0; virtual std::string toString() const = 0;
virtual u256 literalValue(Literal const&) const virtual u256 literalValue(Literal const&) const
@ -246,15 +248,20 @@ private:
}; };
/** /**
* The type of a function, there is one distinct type per function definition. * The type of a function, identified by its (return) parameter types.
* @todo the return parameters should also have names, i.e. return parameters should be a struct
* type.
*/ */
class FunctionType: public Type class FunctionType: public Type
{ {
public: public:
virtual Category getCategory() const override { return Category::FUNCTION; } virtual Category getCategory() const override { return Category::FUNCTION; }
FunctionType(FunctionDefinition const& _function): m_function(_function) {} explicit FunctionType(FunctionDefinition const& _function);
FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes):
m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes) {}
FunctionDefinition const& getFunction() const { return m_function; } TypePointers const& getParameterTypes() const { return m_parameterTypes; }
TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override; virtual std::string toString() const override;
@ -263,7 +270,8 @@ public:
virtual bool canLiveOutsideStorage() const override { return false; } virtual bool canLiveOutsideStorage() const override { return false; }
private: private:
FunctionDefinition const& m_function; TypePointers m_parameterTypes;
TypePointers m_returnParameterTypes;
}; };
/** /**
@ -273,19 +281,19 @@ class MappingType: public Type
{ {
public: public:
virtual Category getCategory() const override { return Category::MAPPING; } virtual Category getCategory() const override { return Category::MAPPING; }
MappingType(std::shared_ptr<Type const> _keyType, std::shared_ptr<Type const> _valueType): MappingType(TypePointer const& _keyType, TypePointer const& _valueType):
m_keyType(_keyType), m_valueType(_valueType) {} m_keyType(_keyType), m_valueType(_valueType) {}
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override; virtual std::string toString() const override;
virtual bool canLiveOutsideStorage() const override { return false; } virtual bool canLiveOutsideStorage() const override { return false; }
std::shared_ptr<Type const> getKeyType() const { return m_keyType; } TypePointer getKeyType() const { return m_keyType; }
std::shared_ptr<Type const> getValueType() const { return m_valueType; } TypePointer getValueType() const { return m_valueType; }
private: private:
std::shared_ptr<Type const> m_keyType; TypePointer m_keyType;
std::shared_ptr<Type const> m_valueType; TypePointer m_valueType;
}; };
/** /**
@ -312,9 +320,9 @@ class TypeType: public Type
{ {
public: public:
virtual Category getCategory() const override { return Category::TYPE; } virtual Category getCategory() const override { return Category::TYPE; }
TypeType(std::shared_ptr<Type const> const& _actualType): m_actualType(_actualType) {} TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
std::shared_ptr<Type const> const& getActualType() const { return m_actualType; } TypePointer const& getActualType() const { return m_actualType; }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; } virtual bool canBeStored() const override { return false; }
@ -323,7 +331,7 @@ public:
virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
private: private:
std::shared_ptr<Type const> m_actualType; TypePointer m_actualType;
}; };