From a2715c5f34cfa4050ba64b4a1467b9ca5821472b Mon Sep 17 00:00:00 2001
From: Christian <c@ethdev.com>
Date: Tue, 25 Nov 2014 14:43:23 +0100
Subject: [PATCH] More general function types and references.

---
 AST.cpp                | 12 ++++++------
 ExpressionCompiler.cpp | 10 +++++-----
 Types.cpp              | 41 ++++++++++++++++++++++++++++++++++++++---
 Types.h                | 38 +++++++++++++++++++++++---------------
 4 files changed, 72 insertions(+), 29 deletions(-)

diff --git a/AST.cpp b/AST.cpp
index 168a095c8..5c07ec80e 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -467,19 +467,19 @@ void FunctionCall::checkTypeRequirements()
 		//@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
 		// function parameters
-		FunctionDefinition const& fun = dynamic_cast<FunctionType const&>(*expressionType).getFunction();
-		vector<ASTPointer<VariableDeclaration>> const& parameters = fun.getParameters();
-		if (parameters.size() != m_arguments.size())
+		FunctionType const& functionType = dynamic_cast<FunctionType const&>(*expressionType);
+		TypePointers const& parameterTypes = functionType.getParameterTypes();
+		if (parameterTypes.size() != m_arguments.size())
 			BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
 		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."));
 		// @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
-		if (fun.getReturnParameters().empty())
+		if (functionType.getReturnParameterTypes().empty())
 			m_type = make_shared<VoidType>();
 		else
-			m_type = fun.getReturnParameters().front()->getType();
+			m_type = functionType.getReturnParameterTypes().front();
 	}
 }
 
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index de8bc1d28..9e396874c 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -183,16 +183,16 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
 
 		// Calling convention: Caller pushes return address and arguments
 		// 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();
 		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());
 		for (unsigned i = 0; i < arguments.size(); ++i)
 		{
 			arguments[i]->accept(*this);
-			appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType());
+			appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]);
 		}
 		_functionCall.getExpression().accept(*this);
 
@@ -200,11 +200,11 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
 		m_context << returnLabel;
 
 		// 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
 		// 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;
 	}
 	return false;
diff --git a/Types.cpp b/Types.cpp
index 616c91831..a6b18b10e 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -189,7 +189,10 @@ u256 IntegerType::literalValue(Literal const& _literal) const
 	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
 {
@@ -299,17 +302,49 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const
 	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
 {
 	if (_other.getCategory() != getCategory())
 		return false;
 	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
 {
-	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
diff --git a/Types.h b/Types.h
index 2dd4af64f..17d9053b4 100644
--- a/Types.h
+++ b/Types.h
@@ -39,6 +39,8 @@ namespace solidity
 // @todo realMxN, string<N>
 
 class Type; // forward
+using TypePointer = std::shared_ptr<Type const>;
+using TypePointers = std::vector<TypePointer>;
 
 /**
  * List of members of a type.
@@ -46,7 +48,6 @@ class Type; // forward
 class MemberList
 {
 public:
-	using TypePointer = std::shared_ptr<Type const>;
 	using MemberMap = std::map<std::string, TypePointer>;
 
 	MemberList() {}
@@ -54,7 +55,7 @@ public:
 	TypePointer getMemberType(std::string const& _name) const
 	{
 		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(); }
@@ -82,6 +83,7 @@ public:
 	static std::shared_ptr<Type> fromElementaryTypeName(Token::Value _typeToken);
 	static std::shared_ptr<Type> fromUserDefinedTypeName(UserDefinedTypeName 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
@@ -117,7 +119,7 @@ public:
 	/// Returns the list of all members of this type. Default implementation: no members.
 	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.
-	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 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
 {
 public:
 	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 std::string toString() const override;
@@ -263,7 +270,8 @@ public:
 	virtual bool canLiveOutsideStorage() const override { return false; }
 
 private:
-	FunctionDefinition const& m_function;
+	TypePointers m_parameterTypes;
+	TypePointers m_returnParameterTypes;
 };
 
 /**
@@ -273,19 +281,19 @@ class MappingType: public Type
 {
 public:
 	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) {}
 
 	virtual bool operator==(Type const& _other) const override;
 	virtual std::string toString() const override;
 	virtual bool canLiveOutsideStorage() const override { return false; }
 
-	std::shared_ptr<Type const> getKeyType() const { return m_keyType; }
-	std::shared_ptr<Type const> getValueType() const { return m_valueType; }
+	TypePointer getKeyType() const { return m_keyType; }
+	TypePointer getValueType() const { return m_valueType; }
 
 private:
-	std::shared_ptr<Type const> m_keyType;
-	std::shared_ptr<Type const> m_valueType;
+	TypePointer m_keyType;
+	TypePointer m_valueType;
 };
 
 /**
@@ -312,9 +320,9 @@ class TypeType: public Type
 {
 public:
 	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 canBeStored() const override { return false; }
@@ -323,7 +331,7 @@ public:
 	virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
 
 private:
-	std::shared_ptr<Type const> m_actualType;
+	TypePointer m_actualType;
 };