--- a/cmajor++/Cm/Cm.Core/Function.cpp
+++ b/cmajor++/Cm/Cm.Core/Function.cpp
@@ -29,6 +29,7 @@
 #include <Cm.Core/Project.hpp>
 #include <Cm.Core/Enumeration.hpp>
 #include <Cm.Core/Flags.hpp>
+#include <Llvm.Ir/Global.hpp>
 #include <Llvm.Ir/Temporary.hpp>
 #include <Llvm.Ir/RegVar.hpp>
 #include <Llvm.Ir/Util.hpp>
@@ -44,7 +45,7 @@
 
 Function::Function(const std::string& name_, const Position& pos_, const ScopePtr& enclosingScope_, const ScopePtr& fileScope_, const std::string& functionSetName_, 
    Specifiers specifiers_): Object(name_, pos_, enclosingScope_, fileScope_), 
-   scope(new Scope("functionScope", pos_, enclosingScope_, fileScope_, enclosingScope_->Ns(), ScopeKind::function)), 
+   scope(new Scope("", pos_, enclosingScope_, fileScope_, enclosingScope_->Ns(), ScopeKind::function)), 
    functionSetName(functionSetName_), specifiers(specifiers_), conversion(ConversionOption::implicit), isConversion(false),
    addressTaken(false), constrainedTemplateTypeChecked(false), isProperArchetype(false), isWeakArchetype(false), conversionRank(ConversionRank::exactMatch), 
    conversionDistance(0), tempLabelCounter(0), tempVarNameCounter(0), instantiatedFromTemplate(false), stringValueCounter(0), checkedIfCanThrow(false)
@@ -167,6 +168,11 @@
     return clone;
 }
 
+TypePtr Function::GetType() const
+{
+    return functionType;
+}
+
 std::string Function::FullNameWithConstraint() const
 {
     std::string s = FullName();
@@ -258,42 +264,10 @@
 
 void Function::CreateIntermediateRepresentations()
 {
-    bool returnsClassObjectByValue = ReturnsClassObjectByValue();
-    TypePtr returnType = GetReturnType();
-    Llvm::Ir::TypePtr irReturnType = returnsClassObjectByValue ? Llvm::Ir::Void() : returnType ? returnType->IrType() : Llvm::Ir::Void();
-    std::vector<Llvm::Ir::ParameterPtr> irParameters;
-    std::vector<Llvm::Ir::TypePtr> irParameterTypes;
-    for (ParameterPtr parameter : parameters)
-    {
-        if (parameter->GetType()->IsClassType())
-        {
-            Llvm::Ir::ParameterPtr irParam(new Llvm::Ir::Parameter(parameter->Name() + "$p", Llvm::Ir::Pointer(parameter->GetType()->IrType())));
-            parameter->SetIrObject(irParam);
-            irParameters.push_back(irParam);
-            irParameterTypes.push_back(irParam->GetType());
-        }
-        else
-        {
-            irParameters.push_back(std::static_pointer_cast<Llvm::Ir::Parameter>(parameter->GetIrObject()));
-            Llvm::Ir::TypePtr irType = parameter->GetIrObject()->GetType();
-            irParameterTypes.push_back(irType);
-        }
-    }
-    if (returnsClassObjectByValue)
-    {
-        Llvm::Ir::TypePtr classObjectResultParamType = Llvm::Ir::Pointer(GetReturnType()->IrType());
-        irClassObjectPtrParam = Llvm::Ir::ParameterPtr(new Llvm::Ir::Parameter(Llvm::Ir::classObjectResultParamName, classObjectResultParamType));
-        irParameters.push_back(irClassObjectPtrParam);
-        irParameterTypes.push_back(classObjectResultParamType);
-    }
-    if (CanThrow())
-    {
-        Llvm::Ir::TypePtr i32ptr = Llvm::Ir::Pointer(Llvm::Ir::I32());
-        irParameters.push_back(Llvm::Ir::ParameterPtr(new Llvm::Ir::Parameter(Llvm::Ir::exceptionCodeParamName, i32ptr)));
-        irParameterTypes.push_back(i32ptr);
-    }
-    irFun = Llvm::Ir::FunctionPtr(new Llvm::Ir::Function(mangledName, irReturnType, irParameters));
-    irFunPtrType = Llvm::Ir::TypePtr(Llvm::Ir::Pointer(Llvm::Ir::TypePtr(new Llvm::Ir::FunctionType(irReturnType, irParameterTypes))));
+    Callable::CreateIntermediateRepresentations();
+    irFun = Llvm::Ir::FunctionPtr(new Llvm::Ir::Function(mangledName, GetIrReturnType(), GetIrParams()));
+    irFunPtrType = Llvm::Ir::TypePtr(Llvm::Ir::Pointer(Llvm::Ir::TypePtr(new Llvm::Ir::FunctionType(GetIrReturnType(), GetIrParamTypes()))));
+    SetIrObject(Llvm::Ir::ObjectPtr(new Llvm::Ir::Global(mangledName, irFunPtrType)));
 }
 
 void Function::TypeCheckSignature(TypeCheckContext& context)
@@ -351,6 +325,17 @@
         {
             typeCheckingForTemplateName = true;
         }
+    }
+    std::vector<TypePtr> parameterTypes;
+    for (ParameterPtr param : parameters)
+    {
+        TypePtr paramType = param->GetType();
+        parameterTypes.push_back(paramType);
+    }
+    if (!GeneratingLibraryDeclarations() && returnType)
+    {
+        functionType = FunctionTypePtr(new FunctionType(Pos(), returnType, parameterTypes));
+        functionType->TypeCheck(context);
     }
     if (IsConversionFunction())
     {
@@ -1119,6 +1104,13 @@
     irFun->WriteDefinition(formatter);
 }
 
+GenResult Function::Gen(Ir& ir, GenFlags flags)
+{
+    GenResult result(ir, flags);
+    result.AddObject(GetIrObject());
+    return result;
+}
+
 void Function::Generate(Ir& ir, GenResult& result)
 {
     ir.Emit(Llvm::Ir::Call(result.MainObject(), irFun, result.Args()));
@@ -1304,6 +1296,100 @@
     }
     s.append(FullName()).append(";");
     formatter.WriteLine(s);
+}
+
+class FunctionTypeDirectory;
+typedef std::shared_ptr<FunctionTypeDirectory> FunctionTypeDirectoryPtr;
+
+class FunctionTypeDirectory
+{
+public:
+    ~FunctionTypeDirectory();
+    static void Init();
+    static void Done();
+    static FunctionTypeDirectoryPtr Instance();
+    FunctionTypePtr GetFunctionType(const std::string& functionTypeName) const
+    {
+        FunctionTypeMapIt i = functionTypeMap.find(functionTypeName);
+        if (i != functionTypeMap.end())
+        {
+            return i->second;
+        }
+        return FunctionTypePtr();
+    }
+    void AddFunctionType(FunctionTypePtr functionType)
+    {
+        functionTypeMap[functionType->Name()] = functionType;
+    }
+private:
+    FunctionTypeDirectory() {}
+    static FunctionTypeDirectoryPtr instance;
+    static std::stack<FunctionTypeDirectoryPtr> instanceStack;
+    typedef std::map<std::string, FunctionTypePtr> FunctionTypeMap;
+    typedef FunctionTypeMap::const_iterator FunctionTypeMapIt;
+    FunctionTypeMap functionTypeMap;
+};
+
+FunctionTypeDirectoryPtr FunctionTypeDirectory::instance;
+
+std::stack<FunctionTypeDirectoryPtr> FunctionTypeDirectory::instanceStack;
+
+FunctionTypeDirectory::~FunctionTypeDirectory()
+{
+    FunctionTypeMapIt e = functionTypeMap.end();
+    for (FunctionTypeMapIt i = functionTypeMap.begin(); i != e; ++i)
+    {
+        i->second->Dispose();
+    }
+    functionTypeMap.clear();
+}
+
+void FunctionTypeDirectory::Init()
+{
+    instanceStack.push(instance);
+    instance = FunctionTypeDirectoryPtr(new FunctionTypeDirectory());
+}
+
+void FunctionTypeDirectory::Done()
+{
+    instance = instanceStack.top();
+    instanceStack.pop();
+}
+
+FunctionTypeDirectoryPtr FunctionTypeDirectory::Instance()
+{
+    CM_CORE_ASSERT(instance);
+    return instance;
+}
+
+FunctionType::FunctionType(const Position& pos_, TypePtr returnType_, const std::vector<TypePtr>& parameterTypes_):
+    Type(MakeFunctionTypeName(returnType_, parameterTypes_), pos_, GlobalScope(), ScopePtr(), GetNextTypeId(), USER_RANK),
+    returnType(returnType_), parameterTypes(parameterTypes_)
+{
+}
+
+void FunctionType::TypeCheckSignature(TypeCheckContext& context)
+{
+    Type::TypeCheckSignature(context);
+    FunctionTypePtr foundType = FunctionTypeDirectory::Instance()->GetFunctionType(Name());
+    if (foundType)
+    {
+        SetId(foundType->Id());
+        SetIrType(foundType->IrType());
+        SetDefaultIrValue(foundType->DefaultIrValue());
+    }
+    else
+    {
+        FunctionTypePtr thisType = std::static_pointer_cast<FunctionType>(shared_from_this());
+        FunctionTypeDirectory::Instance()->AddFunctionType(thisType);
+        std::vector<Llvm::Ir::TypePtr> irParameterTypes;
+        for (TypePtr paramType : parameterTypes)
+        {
+            irParameterTypes.push_back(paramType->IrType());
+        }
+        SetIrType(Llvm::Ir::TypePtr(new Llvm::Ir::PointerType(Llvm::Ir::TypePtr(new Llvm::Ir::FunctionType((returnType ? returnType->IrType() : Llvm::Ir::Void()), irParameterTypes)))));
+        SetDefaultIrValue(Llvm::Ir::Null(IrType()));
+    }
 }
 
 class DoNothingFunction;
@@ -1623,12 +1709,14 @@
 
 void FunctionInit()
 {
+    FunctionTypeDirectory::Init();
     DoNothingFunction::Init();
 }
 
 void FunctionDone()
 {
     DoNothingFunction::Done();
+    FunctionTypeDirectory::Done();
 }
 
 } } // namespace Cm::Core