diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 2f4f409f54f..dddc70a26ec 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -95,6 +95,7 @@ GRS_OBJS = \
     rust/rust-ast-lower-pattern.o \
     rust/rust-ast-lower-item.o \
     rust/rust-ast-lower-expr.o \
+    rust/rust-ast-lower-type.o \
     rust/rust-early-name-resolver.o \
     rust/rust-name-resolver.o \
     rust/rust-ast-resolve.o \
diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h
index 9683ad6ad68..b5c9c3aab3a 100644
--- a/gcc/rust/ast/rust-path.h
+++ b/gcc/rust/ast/rust-path.h
@@ -898,6 +898,8 @@ public:
     rust_assert (has_return_type ());
     return return_type;
   }
+
+  Location get_locus () const { return locus; }
 };
 
 // Segment used in type path with a function argument
diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc
index 098014ff92b..f5402efe066 100644
--- a/gcc/rust/hir/rust-ast-lower-base.cc
+++ b/gcc/rust/hir/rust-ast-lower-base.cc
@@ -658,119 +658,6 @@ ASTLoweringBase::lower_self (AST::SelfParam &self)
 			 self.get_locus ());
 }
 
-void
-ASTLowerTypePath::visit (AST::TypePathSegmentGeneric &segment)
-{
-  std::vector<HIR::GenericArgsBinding> binding_args; // TODO
-
-  std::string segment_name = segment.get_ident_segment ().as_string ();
-  bool has_separating_scope_resolution
-    = segment.get_separating_scope_resolution ();
-
-  auto generic_args = lower_generic_args (segment.get_generic_args ());
-
-  auto crate_num = mappings->get_current_crate ();
-  auto hirid = mappings->get_next_hir_id (crate_num);
-  Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid,
-				 UNKNOWN_LOCAL_DEFID);
-
-  translated_segment
-    = new HIR::TypePathSegmentGeneric (std::move (mapping), segment_name,
-				       has_separating_scope_resolution,
-				       generic_args, segment.get_locus ());
-}
-
-void
-ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path)
-{
-  auto crate_num = mappings->get_current_crate ();
-  auto hirid = mappings->get_next_hir_id (crate_num);
-  Analysis::NodeMapping qual_mappings (
-    crate_num, path.get_qualified_path_type ().get_node_id (), hirid,
-    UNKNOWN_LOCAL_DEFID);
-
-  HIR::Type *qual_type = ASTLoweringType::translate (
-    path.get_qualified_path_type ().get_type ().get ());
-  HIR::TypePath *qual_trait = ASTLowerTypePath::translate (
-    path.get_qualified_path_type ().get_as_type_path ());
-
-  HIR::QualifiedPathType qual_path_type (
-    qual_mappings, std::unique_ptr<HIR::Type> (qual_type),
-    std::unique_ptr<HIR::TypePath> (qual_trait),
-    path.get_qualified_path_type ().get_locus ());
-
-  translated_segment = nullptr;
-  path.get_associated_segment ()->accept_vis (*this);
-  if (translated_segment == nullptr)
-    {
-      rust_fatal_error (path.get_associated_segment ()->get_locus (),
-			"failed to translate AST TypePathSegment");
-      return;
-    }
-  std::unique_ptr<HIR::TypePathSegment> associated_segment (translated_segment);
-
-  std::vector<std::unique_ptr<HIR::TypePathSegment>> translated_segments;
-  for (auto &seg : path.get_segments ())
-    {
-      translated_segment = nullptr;
-      seg->accept_vis (*this);
-      if (translated_segment == nullptr)
-	{
-	  rust_fatal_error (seg->get_locus (),
-			    "failed to translte AST TypePathSegment");
-	}
-      translated_segments.push_back (
-	std::unique_ptr<HIR::TypePathSegment> (translated_segment));
-    }
-
-  Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid,
-				 mappings->get_next_localdef_id (crate_num));
-  translated = new HIR::QualifiedPathInType (std::move (mapping),
-					     std::move (qual_path_type),
-					     std::move (associated_segment),
-					     std::move (translated_segments),
-					     path.get_locus ());
-}
-
-void
-ASTLoweringType::visit (AST::TraitObjectTypeOneBound &type)
-{
-  std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds;
-  HIR::TypeParamBound *translated_bound
-    = ASTLoweringTypeBounds::translate (&type.get_trait_bound ());
-  bounds.push_back (std::unique_ptr<HIR::TypeParamBound> (translated_bound));
-
-  auto crate_num = mappings->get_current_crate ();
-  Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
-				 mappings->get_next_hir_id (crate_num),
-				 mappings->get_next_localdef_id (crate_num));
-
-  translated = new HIR::TraitObjectType (mapping, std::move (bounds),
-					 type.get_locus (), type.is_dyn ());
-}
-
-void
-ASTLoweringType::visit (AST::TraitObjectType &type)
-{
-  std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds;
-
-  for (auto &bound : type.get_type_param_bounds ())
-    {
-      HIR::TypeParamBound *translated_bound
-	= ASTLoweringTypeBounds::translate (bound.get ());
-      bounds.push_back (
-	std::unique_ptr<HIR::TypeParamBound> (translated_bound));
-    }
-
-  auto crate_num = mappings->get_current_crate ();
-  Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
-				 mappings->get_next_hir_id (crate_num),
-				 mappings->get_next_localdef_id (crate_num));
-
-  translated = new HIR::TraitObjectType (mapping, std::move (bounds),
-					 type.get_locus (), type.is_dyn ());
-}
-
 HIR::Type *
 ASTLoweringBase::lower_type_no_bounds (AST::TypeNoBounds *type)
 {
diff --git a/gcc/rust/hir/rust-ast-lower-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc
new file mode 100644
index 00000000000..92a14f4dacf
--- /dev/null
+++ b/gcc/rust/hir/rust-ast-lower-type.cc
@@ -0,0 +1,232 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-lower-type.h"
+
+namespace Rust {
+namespace HIR {
+
+HIR::TypePath *
+ASTLowerTypePath::translate (AST::TypePath &type)
+{
+  ASTLowerTypePath resolver;
+  type.accept_vis (resolver);
+  rust_assert (resolver.translated != nullptr);
+  return resolver.translated;
+}
+
+void
+ASTLowerTypePath::visit (AST::TypePathSegmentFunction &segment)
+{
+  auto crate_num = mappings->get_current_crate ();
+  auto hirid = mappings->get_next_hir_id (crate_num);
+  Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid,
+				 UNKNOWN_LOCAL_DEFID);
+
+  HIR::PathIdentSegment ident (segment.get_ident_segment ().as_string ());
+
+  AST::TypePathFunction &fn = segment.get_type_path_function ();
+  std::vector<std::unique_ptr<HIR::Type>> inputs;
+  for (auto &param : fn.get_params ())
+    {
+      HIR::Type *hir_type = ASTLoweringType::translate (param.get ());
+      inputs.push_back (std::unique_ptr<HIR::Type> (hir_type));
+    }
+
+  HIR::Type *result_type
+    = fn.has_return_type ()
+	? ASTLoweringType::translate (fn.get_return_type ().get ())
+	: nullptr;
+
+  HIR::TypePathFunction function_path (std::move (inputs),
+				       std::unique_ptr<HIR::Type> (
+					 result_type));
+
+  translated_segment = new HIR::TypePathSegmentFunction (
+    mapping, std::move (ident), segment.get_separating_scope_resolution (),
+    std::move (function_path), segment.get_locus ());
+}
+
+void
+ASTLowerTypePath::visit (AST::TypePathSegment &segment)
+{
+  auto crate_num = mappings->get_current_crate ();
+  auto hirid = mappings->get_next_hir_id (crate_num);
+  Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid,
+				 UNKNOWN_LOCAL_DEFID);
+
+  HIR::PathIdentSegment ident (segment.get_ident_segment ().as_string ());
+  translated_segment
+    = new HIR::TypePathSegment (std::move (mapping), ident,
+				segment.get_separating_scope_resolution (),
+				segment.get_locus ());
+}
+
+void
+ASTLowerTypePath::visit (AST::TypePathSegmentGeneric &segment)
+{
+  std::vector<HIR::GenericArgsBinding> binding_args; // TODO
+
+  std::string segment_name = segment.get_ident_segment ().as_string ();
+  bool has_separating_scope_resolution
+    = segment.get_separating_scope_resolution ();
+
+  auto generic_args = lower_generic_args (segment.get_generic_args ());
+
+  auto crate_num = mappings->get_current_crate ();
+  auto hirid = mappings->get_next_hir_id (crate_num);
+  Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid,
+				 UNKNOWN_LOCAL_DEFID);
+
+  translated_segment
+    = new HIR::TypePathSegmentGeneric (std::move (mapping), segment_name,
+				       has_separating_scope_resolution,
+				       generic_args, segment.get_locus ());
+}
+
+void
+ASTLowerTypePath::visit (AST::TypePath &path)
+{
+  std::vector<std::unique_ptr<HIR::TypePathSegment>> translated_segments;
+
+  for (auto &seg : path.get_segments ())
+    {
+      translated_segment = nullptr;
+      seg->accept_vis (*this);
+      if (translated_segment == nullptr)
+	{
+	  rust_fatal_error (seg->get_locus (),
+			    "failed to translate AST TypePathSegment");
+	}
+      translated_segments.push_back (
+	std::unique_ptr<HIR::TypePathSegment> (translated_segment));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  auto hirid = mappings->get_next_hir_id (crate_num);
+  Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid,
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated
+    = new HIR::TypePath (std::move (mapping), std::move (translated_segments),
+			 path.get_locus (),
+			 path.has_opening_scope_resolution_op ());
+}
+
+HIR::QualifiedPathInType *
+ASTLowerQualifiedPathInType::translate (AST::QualifiedPathInType &type)
+{
+  ASTLowerQualifiedPathInType resolver;
+  type.accept_vis (resolver);
+  rust_assert (resolver.translated != nullptr);
+  return resolver.translated;
+}
+
+void
+ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path)
+{
+  auto crate_num = mappings->get_current_crate ();
+  auto hirid = mappings->get_next_hir_id (crate_num);
+  Analysis::NodeMapping qual_mappings (
+    crate_num, path.get_qualified_path_type ().get_node_id (), hirid,
+    UNKNOWN_LOCAL_DEFID);
+
+  HIR::Type *qual_type = ASTLoweringType::translate (
+    path.get_qualified_path_type ().get_type ().get ());
+  HIR::TypePath *qual_trait = ASTLowerTypePath::translate (
+    path.get_qualified_path_type ().get_as_type_path ());
+
+  HIR::QualifiedPathType qual_path_type (
+    qual_mappings, std::unique_ptr<HIR::Type> (qual_type),
+    std::unique_ptr<HIR::TypePath> (qual_trait),
+    path.get_qualified_path_type ().get_locus ());
+
+  translated_segment = nullptr;
+  path.get_associated_segment ()->accept_vis (*this);
+  if (translated_segment == nullptr)
+    {
+      rust_fatal_error (path.get_associated_segment ()->get_locus (),
+			"failed to translate AST TypePathSegment");
+      return;
+    }
+  std::unique_ptr<HIR::TypePathSegment> associated_segment (translated_segment);
+
+  std::vector<std::unique_ptr<HIR::TypePathSegment>> translated_segments;
+  for (auto &seg : path.get_segments ())
+    {
+      translated_segment = nullptr;
+      seg->accept_vis (*this);
+      if (translated_segment == nullptr)
+	{
+	  rust_fatal_error (seg->get_locus (),
+			    "failed to translte AST TypePathSegment");
+	}
+      translated_segments.push_back (
+	std::unique_ptr<HIR::TypePathSegment> (translated_segment));
+    }
+
+  Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid,
+				 mappings->get_next_localdef_id (crate_num));
+  translated = new HIR::QualifiedPathInType (std::move (mapping),
+					     std::move (qual_path_type),
+					     std::move (associated_segment),
+					     std::move (translated_segments),
+					     path.get_locus ());
+}
+
+void
+ASTLoweringType::visit (AST::TraitObjectTypeOneBound &type)
+{
+  std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds;
+  HIR::TypeParamBound *translated_bound
+    = ASTLoweringTypeBounds::translate (&type.get_trait_bound ());
+  bounds.push_back (std::unique_ptr<HIR::TypeParamBound> (translated_bound));
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::TraitObjectType (mapping, std::move (bounds),
+					 type.get_locus (), type.is_dyn ());
+}
+
+void
+ASTLoweringType::visit (AST::TraitObjectType &type)
+{
+  std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds;
+
+  for (auto &bound : type.get_type_param_bounds ())
+    {
+      HIR::TypeParamBound *translated_bound
+	= ASTLoweringTypeBounds::translate (bound.get ());
+      bounds.push_back (
+	std::unique_ptr<HIR::TypeParamBound> (translated_bound));
+    }
+
+  auto crate_num = mappings->get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
+				 mappings->get_next_hir_id (crate_num),
+				 mappings->get_next_localdef_id (crate_num));
+
+  translated = new HIR::TraitObjectType (mapping, std::move (bounds),
+					 type.get_locus (), type.is_dyn ());
+}
+
+} // namespace HIR
+} // namespace Rust
diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h
index 56442110e07..a0761023ce8 100644
--- a/gcc/rust/hir/rust-ast-lower-type.h
+++ b/gcc/rust/hir/rust-ast-lower-type.h
@@ -32,59 +32,12 @@ protected:
   using Rust::HIR::ASTLoweringBase::visit;
 
 public:
-  static HIR::TypePath *translate (AST::TypePath &type)
-  {
-    ASTLowerTypePath resolver;
-    type.accept_vis (resolver);
-    rust_assert (resolver.translated != nullptr);
-    return resolver.translated;
-  }
-
-  void visit (AST::TypePathSegmentFunction &) override { gcc_unreachable (); }
-
-  void visit (AST::TypePathSegment &segment) override
-  {
-    auto crate_num = mappings->get_current_crate ();
-    auto hirid = mappings->get_next_hir_id (crate_num);
-    Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid,
-				   UNKNOWN_LOCAL_DEFID);
-
-    HIR::PathIdentSegment ident (segment.get_ident_segment ().as_string ());
-    translated_segment
-      = new HIR::TypePathSegment (std::move (mapping), ident,
-				  segment.get_separating_scope_resolution (),
-				  segment.get_locus ());
-  }
+  static HIR::TypePath *translate (AST::TypePath &type);
 
+  void visit (AST::TypePathSegmentFunction &segment) override;
+  void visit (AST::TypePathSegment &segment) override;
   void visit (AST::TypePathSegmentGeneric &segment) override;
-
-  void visit (AST::TypePath &path) override
-  {
-    std::vector<std::unique_ptr<HIR::TypePathSegment>> translated_segments;
-
-    for (auto &seg : path.get_segments ())
-      {
-	translated_segment = nullptr;
-	seg->accept_vis (*this);
-	if (translated_segment == nullptr)
-	  {
-	    rust_fatal_error (seg->get_locus (),
-			      "failed to translate AST TypePathSegment");
-	  }
-	translated_segments.push_back (
-	  std::unique_ptr<HIR::TypePathSegment> (translated_segment));
-      }
-
-    auto crate_num = mappings->get_current_crate ();
-    auto hirid = mappings->get_next_hir_id (crate_num);
-    Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid,
-				   mappings->get_next_localdef_id (crate_num));
-
-    translated
-      = new HIR::TypePath (std::move (mapping), std::move (translated_segments),
-			   path.get_locus (),
-			   path.has_opening_scope_resolution_op ());
-  }
+  void visit (AST::TypePath &path) override;
 
 protected:
   HIR::TypePathSegment *translated_segment;
@@ -98,13 +51,7 @@ class ASTLowerQualifiedPathInType : public ASTLowerTypePath
   using ASTLowerTypePath::visit;
 
 public:
-  static HIR::QualifiedPathInType *translate (AST::QualifiedPathInType &type)
-  {
-    ASTLowerQualifiedPathInType resolver;
-    type.accept_vis (resolver);
-    rust_assert (resolver.translated != nullptr);
-    return resolver.translated;
-  }
+  static HIR::QualifiedPathInType *translate (AST::QualifiedPathInType &type);
 
   void visit (AST::QualifiedPathInType &path) override;
 
diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h
index 64df6f7fd02..fa8347b2cf8 100644
--- a/gcc/rust/hir/tree/rust-hir-path.h
+++ b/gcc/rust/hir/tree/rust-hir-path.h
@@ -529,24 +529,9 @@ protected:
 struct TypePathFunction
 {
 private:
-  // TODO: remove
-  /*bool has_inputs;
-  TypePathFnInputs inputs;*/
-  // inlined from TypePathFnInputs
   std::vector<std::unique_ptr<Type> > inputs;
-
-  // bool has_type;
   std::unique_ptr<Type> return_type;
 
-  // FIXME: think of better way to mark as invalid than taking up storage
-  bool is_invalid;
-
-  // TODO: should this have location info?
-
-protected:
-  // Constructor only used to create invalid type path functions.
-  TypePathFunction (bool is_invalid) : is_invalid (is_invalid) {}
-
 public:
   // Returns whether the return type of the function has been specified.
   bool has_return_type () const { return return_type != nullptr; }
@@ -554,31 +539,19 @@ public:
   // Returns whether the function has inputs.
   bool has_inputs () const { return !inputs.empty (); }
 
-  // Returns whether function is in an error state.
-  bool is_error () const { return is_invalid; }
-
-  // Creates an error state function.
-  static TypePathFunction create_error () { return TypePathFunction (true); }
-
-  // Constructor
-  TypePathFunction (std::vector<std::unique_ptr<Type> > inputs,
-		    Type *type = nullptr)
-    : inputs (std::move (inputs)), return_type (type), is_invalid (false)
-  {}
-  // FIXME: deprecated
-
   // Constructor
   TypePathFunction (std::vector<std::unique_ptr<Type> > inputs,
-		    std::unique_ptr<Type> type = nullptr)
-    : inputs (std::move (inputs)), return_type (std::move (type)),
-      is_invalid (false)
+		    std::unique_ptr<Type> type)
+    : inputs (std::move (inputs)), return_type (std::move (type))
   {}
 
   // Copy constructor with clone
   TypePathFunction (TypePathFunction const &other)
-    : return_type (other.return_type->clone_type ()),
-      is_invalid (other.is_invalid)
   {
+    return_type = other.has_return_type ()
+		    ? other.get_return_type ()->clone_type ()
+		    : nullptr;
+
     inputs.reserve (other.inputs.size ());
     for (const auto &e : other.inputs)
       inputs.push_back (e->clone_type ());
@@ -589,8 +562,9 @@ public:
   // Overloaded assignment operator to clone type
   TypePathFunction &operator= (TypePathFunction const &other)
   {
-    return_type = other.return_type->clone_type ();
-    is_invalid = other.is_invalid;
+    return_type = other.has_return_type ()
+		    ? other.get_return_type ()->clone_type ()
+		    : nullptr;
 
     inputs.reserve (other.inputs.size ());
     for (const auto &e : other.inputs)
@@ -604,6 +578,23 @@ public:
   TypePathFunction &operator= (TypePathFunction &&other) = default;
 
   std::string as_string () const;
+
+  const std::vector<std::unique_ptr<Type> > &get_params () const
+  {
+    return inputs;
+  };
+  std::vector<std::unique_ptr<Type> > &get_params () { return inputs; };
+
+  const std::unique_ptr<Type> &get_return_type () const
+  {
+    rust_assert (has_return_type ());
+    return return_type;
+  };
+  std::unique_ptr<Type> &get_return_type ()
+  {
+    rust_assert (has_return_type ());
+    return return_type;
+  };
 };
 
 // Segment used in type path with a function argument
@@ -638,10 +629,9 @@ public:
 
   void accept_vis (HIRFullVisitor &vis) override;
 
-  virtual SegmentType get_type () const override final
-  {
-    return SegmentType::FUNCTION;
-  }
+  SegmentType get_type () const override final { return SegmentType::FUNCTION; }
+
+  TypePathFunction &get_function_path () { return function_path; }
 
 protected:
   // Use covariance to override base class method
