public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: arthur.cohen@embecosm.com
To: gcc-patches@gcc.gnu.org
Cc: gcc-rust@gcc.gnu.org, Philip Herron <herron.philip@googlemail.com>
Subject: [committed 50/88] gccrs: Refactor the type unification code
Date: Wed,  5 Apr 2023 16:03:34 +0200	[thread overview]
Message-ID: <20230405140411.3016563-51-arthur.cohen@embecosm.com> (raw)
In-Reply-To: <20230405140411.3016563-1-arthur.cohen@embecosm.com>

From: Philip Herron <herron.philip@googlemail.com>

This refactors the unification systems to be a consistent interface using
switch statements and simple functions instead of the old clunky visitor
system. This is more maintainable as it is harder to miss cases when we
can take advantages of switch statements.

Signed-off-by: Philip Herron <herron.philip@googlemail.com>

gcc/rust/ChangeLog:

	* Make-lang.in: update names
	* backend/rust-compile-expr.cc (CompileExpr::resolve_method_address):
	update to use new interface
	* typecheck/rust-coercion.cc (TypeCoercionRules::coerce_borrowed_pointer): likewise
	* typecheck/rust-hir-type-check-base.cc (TypeCheckBase::unify_site): likewise
	* typecheck/rust-tyty.cc (BaseType::destructure): likewise
	(InferType::unify): removed old unify interface
	(ErrorType::unify): likewise
	(ADTType::unify): likewise
	(TupleType::unify): likewise
	(FnType::unify): likewise
	(FnPtr::unify): likewise
	(ClosureType::unify): likewise
	(ArrayType::unify): likewise
	(SliceType::unify): likewise
	(BoolType::unify): likewise
	(IntType::unify): likewise
	(UintType::unify): likewise
	(FloatType::unify): likewise
	(USizeType::unify): likewise
	(ISizeType::unify): likewise
	(CharType::unify): likewise
	(ReferenceType::unify): likewise
	(PointerType::unify): likewise
	(ParamType::unify): likewise
	(StrType::unify): likewise
	(NeverType::unify): likewise
	(PlaceholderType::unify): likewise
	(ProjectionType::unify): likewise
	(DynamicObjectType::unify): likewise
	* typecheck/rust-tyty.h: update destructure interface
	* typecheck/rust-tyty-rules.h: Removed.
	* typecheck/rust-unify.cc: New file.
	* typecheck/rust-unify.h: New file.

gcc/testsuite/ChangeLog:

	* rust/compile/never_type_err1.rs: Moved to...
	* rust/compile/never_type1.rs: ...here. It now works
---
 gcc/rust/Make-lang.in                         |    1 +
 gcc/rust/backend/rust-compile-expr.cc         |    6 +-
 gcc/rust/typecheck/rust-coercion.cc           |    6 +-
 .../typecheck/rust-hir-type-check-base.cc     |   15 +-
 gcc/rust/typecheck/rust-tyty-rules.h          | 1406 --------------
 gcc/rust/typecheck/rust-tyty.cc               |  229 +--
 gcc/rust/typecheck/rust-tyty.h                |   31 +-
 gcc/rust/typecheck/rust-unify.cc              | 1640 +++++++++++++++++
 gcc/rust/typecheck/rust-unify.h               |   91 +
 .../{never_type_err1.rs => never_type1.rs}    |    3 +-
 10 files changed, 1807 insertions(+), 1621 deletions(-)
 delete mode 100644 gcc/rust/typecheck/rust-tyty-rules.h
 create mode 100644 gcc/rust/typecheck/rust-unify.cc
 create mode 100644 gcc/rust/typecheck/rust-unify.h
 rename gcc/testsuite/rust/compile/{never_type_err1.rs => never_type1.rs} (52%)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 4752bb83562..1d2f34d7919 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -134,6 +134,7 @@ GRS_OBJS = \
     rust/rust-hir-path-probe.o \
     rust/rust-coercion.o \
     rust/rust-casts.o \
+    rust/rust-unify.o \
     rust/rust-hir-type-check-base.o \
     rust/rust-autoderef.o \
     rust/rust-substitution-mapper.o \
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index c26f6f440ec..d7945dbf26b 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -26,6 +26,7 @@
 #include "rust-compile-block.h"
 #include "rust-compile-implitem.h"
 #include "rust-constexpr.h"
+#include "rust-unify.h"
 #include "rust-gcc.h"
 
 #include "fold-const.h"
@@ -2006,7 +2007,10 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref,
 	{
 	  TyTy::BaseType *infer_impl_call
 	    = candidate_call->infer_substitions (expr_locus);
-	  monomorphized = infer_impl_call->unify (fntype);
+	  monomorphized = Resolver::UnifyRules::Resolve (
+	    TyTy::TyWithLocation (infer_impl_call),
+	    TyTy::TyWithLocation (fntype), expr_locus, true /* commit */,
+	    true /* emit_errors */);
 	}
 
       return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized);
diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc
index fdf8eb95a33..bea40840fbf 100644
--- a/gcc/rust/typecheck/rust-coercion.cc
+++ b/gcc/rust/typecheck/rust-coercion.cc
@@ -18,6 +18,7 @@
 
 #include "rust-hir-type-check-base.h"
 #include "rust-coercion.h"
+#include "rust-unify.h"
 
 namespace Rust {
 namespace Resolver {
@@ -218,7 +219,10 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver,
 	// we might be able to replace this with a can_eq because we default
 	// back to a final unity anyway
 	rust_debug ("coerce_borrowed_pointer -- unify");
-	TyTy::BaseType *result = receiver->unify (expected);
+	TyTy::BaseType *result
+	  = UnifyRules::Resolve (TyTy::TyWithLocation (receiver),
+				 TyTy::TyWithLocation (expected), locus,
+				 true /* commit */, true /* emit_errors */);
 	return CoercionResult{{}, result};
       }
     }
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index 85826aec8fe..6e42b7b7b23 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -22,6 +22,7 @@
 #include "rust-hir-type-check-expr.h"
 #include "rust-hir-type-check-implitem.h"
 #include "rust-coercion.h"
+#include "rust-unify.h"
 #include "rust-casts.h"
 
 namespace Rust {
@@ -359,18 +360,8 @@ TypeCheckBase::unify_site (HirId id, TyTy::TyWithLocation lhs,
   rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
 	      expected->debug_str ().c_str (), expr->debug_str ().c_str ());
 
-  TyTy::BaseType *unified = expected->unify (expr);
-  if (unified->get_kind () == TyTy::TypeKind::ERROR)
-    {
-      RichLocation r (unify_locus);
-      r.add_range (lhs.get_locus ());
-      r.add_range (rhs.get_locus ());
-      rust_error_at (r, "expected %<%s%> got %<%s%>",
-		     expected->get_name ().c_str (),
-		     expr->get_name ().c_str ());
-    }
-
-  return unified;
+  return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
+			      true /*emit_error*/);
 }
 
 TyTy::BaseType *
diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h
deleted file mode 100644
index cfe269221bd..00000000000
--- a/gcc/rust/typecheck/rust-tyty-rules.h
+++ /dev/null
@@ -1,1406 +0,0 @@
-// Copyright (C) 2020-2023 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/>.
-
-#ifndef RUST_TYTY_RULES
-#define RUST_TYTY_RULES
-
-#include "rust-diagnostics.h"
-#include "rust-tyty.h"
-#include "rust-tyty-visitor.h"
-#include "rust-hir-map.h"
-#include "rust-hir-type-check.h"
-
-namespace Rust {
-namespace TyTy {
-
-/* Rules specify how to unify two Ty. For example, the result of unifying the
-   two tuples (u64, A) and (B, i64) would be (u64, i64).
-
-   Performing a unification requires a double dispatch. To illustrate, suppose
-   we want to unify `ty1` and `ty2`. Here's what it looks like:
-     1. The caller calls `ty1.unify(ty2)`. This is the first dispatch.
-     2. `ty1` creates a rule specific to its type(e.g. TupleRules).
-     3. The rule calls `ty2.accept_vis(rule)`. This is the second dispatch.
-     4. `ty2` calls `rule.visit(*this)`, which will method-overload to the
-	      correct implementation at compile time.
-
-   The nice thing about Rules is that they seperate unification logic from the
-   representation of Ty. To support unifying a new Ty, implement its
-   `accept_vis` and `unify` method to pass the unification request to Rules.
-   Then, create a new `XXXRules` class and implement one `visit` method for
-   every Ty it can unify with. */
-class BaseRules : public TyVisitor
-{
-public:
-  virtual ~BaseRules () {}
-
-  /* Unify two ty. Returns a pointer to the newly-created unified ty, or nullptr
-     if the two types cannot be unified. The caller is responsible for releasing
-     the memory of the returned ty.
-
-     This method is meant to be used internally by Ty. If you're trying to unify
-     two ty, you can simply call `unify` on ty themselves. */
-  virtual BaseType *unify (BaseType *other)
-  {
-    if (other->get_kind () == TypeKind::PARAM)
-      {
-	ParamType *p = static_cast<ParamType *> (other);
-	other = p->resolve ();
-      }
-    else if (other->get_kind () == TypeKind::PLACEHOLDER)
-      {
-	PlaceholderType *p = static_cast<PlaceholderType *> (other);
-	if (p->can_resolve ())
-	  {
-	    other = p->resolve ();
-	    return get_base ()->unify (other);
-	  }
-      }
-    else if (other->get_kind () == TypeKind::PROJECTION)
-      {
-	ProjectionType *p = static_cast<ProjectionType *> (other);
-	other = p->get ();
-	return get_base ()->unify (other);
-      }
-
-    other->accept_vis (*this);
-    if (resolved->get_kind () == TyTy::TypeKind::ERROR)
-      return resolved;
-
-    resolved->append_reference (get_base ()->get_ref ());
-    resolved->append_reference (other->get_ref ());
-    for (auto ref : get_base ()->get_combined_refs ())
-      resolved->append_reference (ref);
-    for (auto ref : other->get_combined_refs ())
-      resolved->append_reference (ref);
-
-    other->append_reference (resolved->get_ref ());
-    other->append_reference (get_base ()->get_ref ());
-    get_base ()->append_reference (resolved->get_ref ());
-    get_base ()->append_reference (other->get_ref ());
-
-    bool result_resolved = resolved->get_kind () != TyTy::TypeKind::INFER;
-    bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER;
-    bool results_is_non_general_infer_var
-      = (result_is_infer_var
-	 && (static_cast<InferType *> (resolved))->get_infer_kind ()
-	      != TyTy::InferType::GENERAL);
-    if (result_resolved || results_is_non_general_infer_var)
-      {
-	for (auto &ref : resolved->get_combined_refs ())
-	  {
-	    TyTy::BaseType *ref_tyty = nullptr;
-	    bool ok = context->lookup_type (ref, &ref_tyty);
-	    if (!ok)
-	      continue;
-
-	    // if any of the types are inference variables lets fix them
-	    if (ref_tyty->get_kind () == TyTy::TypeKind::INFER)
-	      {
-		context->insert_type (
-		  Analysis::NodeMapping (mappings->get_current_crate (),
-					 UNKNOWN_NODEID, ref,
-					 UNKNOWN_LOCAL_DEFID),
-		  resolved->clone ());
-	      }
-	  }
-      }
-    return resolved;
-  }
-
-  virtual void visit (TupleType &) override {}
-
-  virtual void visit (ADTType &) override {}
-
-  virtual void visit (InferType &) override {}
-
-  virtual void visit (FnType &) override {}
-
-  virtual void visit (FnPtr &) override {}
-
-  virtual void visit (ArrayType &) override {}
-
-  virtual void visit (SliceType &) override {}
-
-  virtual void visit (BoolType &) override {}
-
-  virtual void visit (IntType &) override {}
-
-  virtual void visit (UintType &) override {}
-
-  virtual void visit (USizeType &) override {}
-
-  virtual void visit (ISizeType &) override {}
-
-  virtual void visit (FloatType &) override {}
-
-  virtual void visit (ErrorType &) override {}
-
-  virtual void visit (CharType &) override {}
-
-  virtual void visit (ReferenceType &) override {}
-
-  virtual void visit (PointerType &) override {}
-
-  virtual void visit (ParamType &) override {}
-
-  virtual void visit (StrType &) override {}
-
-  virtual void visit (NeverType &) override {}
-
-  virtual void visit (PlaceholderType &) override {}
-
-  virtual void visit (ProjectionType &) override {}
-
-  virtual void visit (DynamicObjectType &) override {}
-
-  virtual void visit (ClosureType &) override {}
-
-protected:
-  BaseRules (BaseType *base)
-    : mappings (Analysis::Mappings::get ()),
-      context (Resolver::TypeCheckContext::get ()),
-      resolved (new ErrorType (base->get_ref (), base->get_ref ()))
-  {}
-
-  Analysis::Mappings *mappings;
-  Resolver::TypeCheckContext *context;
-
-  /* Temporary storage for the result of a unification.
-     We could return the result directly instead of storing it in the rule
-     object, but that involves modifying the visitor pattern to accommodate
-     the return value, which is too complex. */
-  BaseType *resolved;
-
-private:
-  /* Returns a pointer to the ty that created this rule. */
-  virtual BaseType *get_base () = 0;
-};
-
-class InferRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  InferRules (InferType *base) : BaseRules (base), base (base) {}
-
-  void visit (BoolType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (IntType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL)
-	|| (base->get_infer_kind ()
-	    == TyTy::InferType::InferTypeKind::INTEGRAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (UintType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL)
-	|| (base->get_infer_kind ()
-	    == TyTy::InferType::InferTypeKind::INTEGRAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (USizeType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL)
-	|| (base->get_infer_kind ()
-	    == TyTy::InferType::InferTypeKind::INTEGRAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (ISizeType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL)
-	|| (base->get_infer_kind ()
-	    == TyTy::InferType::InferTypeKind::INTEGRAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (FloatType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL)
-	|| (base->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (ArrayType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (SliceType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (ADTType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (TupleType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (InferType &type) override
-  {
-    switch (base->get_infer_kind ())
-      {
-      case InferType::InferTypeKind::GENERAL:
-	resolved = type.clone ();
-	return;
-
-	case InferType::InferTypeKind::INTEGRAL: {
-	  if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL)
-	    {
-	      resolved = type.clone ();
-	      return;
-	    }
-	  else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL)
-	    {
-	      resolved = base->clone ();
-	      return;
-	    }
-	}
-	break;
-
-	case InferType::InferTypeKind::FLOAT: {
-	  if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-	    {
-	      resolved = type.clone ();
-	      return;
-	    }
-	  else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL)
-	    {
-	      resolved = base->clone ();
-	      return;
-	    }
-	}
-	break;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (CharType &type) override
-  {
-    {
-      bool is_valid
-	= (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-      if (is_valid)
-	{
-	  resolved = type.clone ();
-	  return;
-	}
-
-      BaseRules::visit (type);
-    }
-  }
-
-  void visit (ReferenceType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (PointerType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (ParamType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (DynamicObjectType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-  void visit (ClosureType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseRules::visit (type);
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  InferType *base;
-};
-
-class FnRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  FnRules (FnType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (FnType &type) override
-  {
-    if (base->num_params () != type.num_params ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    for (size_t i = 0; i < base->num_params (); i++)
-      {
-	auto a = base->param_at (i).second;
-	auto b = type.param_at (i).second;
-
-	auto unified_param = a->unify (b);
-	if (unified_param == nullptr)
-	  {
-	    BaseRules::visit (type);
-	    return;
-	  }
-      }
-
-    auto unified_return
-      = base->get_return_type ()->unify (type.get_return_type ());
-    if (unified_return == nullptr)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  FnType *base;
-};
-
-class FnptrRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  FnptrRules (FnPtr *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (FnPtr &type) override
-  {
-    auto this_ret_type = base->get_return_type ();
-    auto other_ret_type = type.get_return_type ();
-    auto unified_result = this_ret_type->unify (other_ret_type);
-    if (unified_result == nullptr
-	|| unified_result->get_kind () == TypeKind::ERROR)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    if (base->num_params () != type.num_params ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    for (size_t i = 0; i < base->num_params (); i++)
-      {
-	auto this_param = base->param_at (i);
-	auto other_param = type.param_at (i);
-	auto unified_param = this_param->unify (other_param);
-	if (unified_param == nullptr
-	    || unified_param->get_kind () == TypeKind::ERROR)
-	  {
-	    BaseRules::visit (type);
-	    return;
-	  }
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (FnType &type) override
-  {
-    auto this_ret_type = base->get_return_type ();
-    auto other_ret_type = type.get_return_type ();
-    auto unified_result = this_ret_type->unify (other_ret_type);
-    if (unified_result == nullptr
-	|| unified_result->get_kind () == TypeKind::ERROR)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    if (base->num_params () != type.num_params ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    for (size_t i = 0; i < base->num_params (); i++)
-      {
-	auto this_param = base->param_at (i);
-	auto other_param = type.param_at (i).second;
-	auto unified_param = this_param->unify (other_param);
-	if (unified_param == nullptr
-	    || unified_param->get_kind () == TypeKind::ERROR)
-	  {
-	    BaseRules::visit (type);
-	    return;
-	  }
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  FnPtr *base;
-};
-
-class ClosureRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  ClosureRules (ClosureType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (ClosureType &type) override
-  {
-    if (base->get_def_id () != type.get_def_id ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    TyTy::BaseType *args_res
-      = base->get_parameters ().unify (&type.get_parameters ());
-    if (args_res == nullptr || args_res->get_kind () == TypeKind::ERROR)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    TyTy::BaseType *res
-      = base->get_result_type ().unify (&type.get_result_type ());
-    if (res == nullptr || res->get_kind () == TypeKind::ERROR)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ClosureType *base;
-};
-
-class ArrayRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  ArrayRules (ArrayType *base) : BaseRules (base), base (base) {}
-
-  void visit (ArrayType &type) override
-  {
-    // check base type
-    auto base_resolved
-      = base->get_element_type ()->unify (type.get_element_type ());
-    if (base_resolved == nullptr)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved
-      = new ArrayType (type.get_ref (), type.get_ty_ref (),
-		       type.get_ident ().locus, type.get_capacity_expr (),
-		       TyVar (base_resolved->get_ref ()));
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ArrayType *base;
-};
-
-class SliceRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  SliceRules (SliceType *base) : BaseRules (base), base (base) {}
-
-  void visit (SliceType &type) override
-  {
-    // check base type
-    auto base_resolved
-      = base->get_element_type ()->unify (type.get_element_type ());
-    if (base_resolved == nullptr)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = new SliceType (type.get_ref (), type.get_ty_ref (),
-			      type.get_ident ().locus,
-			      TyVar (base_resolved->get_ref ()));
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  SliceType *base;
-};
-
-class BoolRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  BoolRules (BoolType *base) : BaseRules (base), base (base) {}
-
-  void visit (BoolType &type) override
-  {
-    resolved = new BoolType (type.get_ref (), type.get_ty_ref ());
-  }
-
-  void visit (InferType &type) override
-  {
-    switch (type.get_infer_kind ())
-      {
-      case InferType::InferTypeKind::GENERAL:
-	resolved = base->clone ();
-	break;
-
-      default:
-	BaseRules::visit (type);
-	break;
-      }
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  BoolType *base;
-};
-
-class IntRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  IntRules (IntType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    // cant assign a float inference variable
-    if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (IntType &type) override
-  {
-    if (type.get_int_kind () != base->get_int_kind ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved
-      = new IntType (type.get_ref (), type.get_ty_ref (), type.get_int_kind ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  IntType *base;
-};
-
-class UintRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  UintRules (UintType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    // cant assign a float inference variable
-    if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (UintType &type) override
-  {
-    if (type.get_uint_kind () != base->get_uint_kind ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = new UintType (type.get_ref (), type.get_ty_ref (),
-			     type.get_uint_kind ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  UintType *base;
-};
-
-class FloatRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  FloatRules (FloatType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (FloatType &type) override
-  {
-    if (type.get_float_kind () != base->get_float_kind ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = new FloatType (type.get_ref (), type.get_ty_ref (),
-			      type.get_float_kind ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  FloatType *base;
-};
-
-class ADTRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  ADTRules (ADTType *base) : BaseRules (base), base (base) {}
-
-  void visit (ADTType &type) override
-  {
-    if (base->get_adt_kind () != type.get_adt_kind ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    if (base->get_identifier ().compare (type.get_identifier ()) != 0)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    if (base->number_of_variants () != type.number_of_variants ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    for (size_t i = 0; i < type.number_of_variants (); ++i)
-      {
-	TyTy::VariantDef *a = base->get_variants ().at (i);
-	TyTy::VariantDef *b = type.get_variants ().at (i);
-
-	if (a->num_fields () != b->num_fields ())
-	  {
-	    BaseRules::visit (type);
-	    return;
-	  }
-
-	for (size_t j = 0; j < a->num_fields (); j++)
-	  {
-	    TyTy::StructFieldType *base_field = a->get_field_at_index (j);
-	    TyTy::StructFieldType *other_field = b->get_field_at_index (j);
-
-	    TyTy::BaseType *this_field_ty = base_field->get_field_type ();
-	    TyTy::BaseType *other_field_ty = other_field->get_field_type ();
-
-	    BaseType *unified_ty = this_field_ty->unify (other_field_ty);
-	    if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
-	      return;
-	  }
-      }
-
-    // generic args for the unit-struct case
-    if (type.is_unit () && base->is_unit ())
-      {
-	rust_assert (type.get_num_substitutions ()
-		     == base->get_num_substitutions ());
-
-	for (size_t i = 0; i < type.get_num_substitutions (); i++)
-	  {
-	    auto &a = base->get_substs ().at (i);
-	    auto &b = type.get_substs ().at (i);
-
-	    auto pa = a.get_param_ty ();
-	    auto pb = b.get_param_ty ();
-
-	    auto res = pa->unify (pb);
-	    if (res->get_kind () == TyTy::TypeKind::ERROR)
-	      {
-		return;
-	      }
-	  }
-      }
-
-    resolved = type.clone ();
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ADTType *base;
-};
-
-class TupleRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  TupleRules (TupleType *base) : BaseRules (base), base (base) {}
-
-  void visit (TupleType &type) override
-  {
-    if (base->num_fields () != type.num_fields ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    std::vector<TyVar> fields;
-    for (size_t i = 0; i < base->num_fields (); i++)
-      {
-	BaseType *bo = base->get_field (i);
-	BaseType *fo = type.get_field (i);
-
-	BaseType *unified_ty = bo->unify (fo);
-	if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
-	  return;
-
-	fields.push_back (TyVar (unified_ty->get_ref ()));
-      }
-
-    resolved = new TyTy::TupleType (type.get_ref (), type.get_ty_ref (),
-				    type.get_ident ().locus, fields);
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  TupleType *base;
-};
-
-class USizeRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  USizeRules (USizeType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    // cant assign a float inference variable
-    if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (USizeType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  USizeType *base;
-};
-
-class ISizeRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  ISizeRules (ISizeType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    // cant assign a float inference variable
-    if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (ISizeType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ISizeType *base;
-};
-
-class CharRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  CharRules (CharType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (CharType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  CharType *base;
-};
-
-class ReferenceRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  ReferenceRules (ReferenceType *base) : BaseRules (base), base (base) {}
-
-  void visit (ReferenceType &type) override
-  {
-    auto base_type = base->get_base ();
-    auto other_base_type = type.get_base ();
-
-    TyTy::BaseType *base_resolved = base_type->unify (other_base_type);
-    if (base_resolved == nullptr
-	|| base_resolved->get_kind () == TypeKind::ERROR)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    // rust is permissive about mutablity here you can always go from mutable to
-    // immutable but not the otherway round
-    bool mutability_ok = base->is_mutable () ? type.is_mutable () : true;
-    if (!mutability_ok)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = new ReferenceType (base->get_ref (), base->get_ty_ref (),
-				  TyVar (base_resolved->get_ref ()),
-				  base->mutability ());
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ReferenceType *base;
-};
-
-class PointerRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  PointerRules (PointerType *base) : BaseRules (base), base (base) {}
-
-  void visit (PointerType &type) override
-  {
-    auto base_type = base->get_base ();
-    auto other_base_type = type.get_base ();
-
-    TyTy::BaseType *base_resolved = base_type->unify (other_base_type);
-    if (base_resolved == nullptr
-	|| base_resolved->get_kind () == TypeKind::ERROR)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    // rust is permissive about mutablity here you can always go from mutable to
-    // immutable but not the otherway round
-    bool mutability_ok = base->is_mutable () ? type.is_mutable () : true;
-    if (!mutability_ok)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = new PointerType (base->get_ref (), base->get_ty_ref (),
-				TyVar (base_resolved->get_ref ()),
-				base->mutability ());
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  PointerType *base;
-};
-
-class ParamRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  ParamRules (ParamType *base) : BaseRules (base), base (base) {}
-
-  // param types are a placeholder we shouldn't have cases where we unify
-  // against it. eg: struct foo<T> { a: T }; When we invoke it we can do either:
-  //
-  // foo<i32>{ a: 123 }.
-  // Then this enforces the i32 type to be referenced on the
-  // field via an hirid.
-  //
-  // rust also allows for a = foo{a:123}; Where we can use an Inference Variable
-  // to handle the typing of the struct
-  BaseType *unify (BaseType *other) override final
-  {
-    if (!base->can_resolve ())
-      return BaseRules::unify (other);
-
-    auto lookup = base->resolve ();
-    return lookup->unify (other);
-  }
-
-  void visit (ParamType &type) override
-  {
-    if (base->get_symbol ().compare (type.get_symbol ()) != 0)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = type.clone ();
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ParamType *base;
-};
-
-class StrRules : public BaseRules
-{
-  // FIXME we will need a enum for the StrType like ByteBuf etc..
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  StrRules (StrType *base) : BaseRules (base), base (base) {}
-
-  void visit (StrType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  StrType *base;
-};
-
-class NeverRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  NeverRules (NeverType *base) : BaseRules (base), base (base) {}
-
-  void visit (NeverType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  NeverType *base;
-};
-
-class PlaceholderRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  PlaceholderRules (PlaceholderType *base) : BaseRules (base), base (base) {}
-
-  BaseType *unify (BaseType *other) override final
-  {
-    if (!base->can_resolve ())
-      return BaseRules::unify (other);
-
-    BaseType *lookup = base->resolve ();
-    return lookup->unify (other);
-  }
-
-  void visit (PlaceholderType &type) override
-  {
-    if (base->get_symbol ().compare (type.get_symbol ()) != 0)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = type.clone ();
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  PlaceholderType *base;
-};
-
-class DynamicRules : public BaseRules
-{
-  using Rust::TyTy::BaseRules::visit;
-
-public:
-  DynamicRules (DynamicObjectType *base) : BaseRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-  }
-
-  void visit (DynamicObjectType &type) override
-  {
-    if (base->num_specified_bounds () != type.num_specified_bounds ())
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    if (!base->bounds_compatible (type, ref_locus, true))
-      {
-	BaseRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  DynamicObjectType *base;
-};
-
-} // namespace TyTy
-} // namespace Rust
-
-#endif // RUST_TYTY_RULES
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index a3271eb0d1a..fe5aa2b059c 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -30,7 +30,6 @@
 #include "rust-hir-trait-reference.h"
 #include "rust-hir-type-bounds.h"
 #include "rust-hir-trait-resolve.h"
-#include "rust-tyty-rules.h"
 #include "rust-tyty-cmp.h"
 
 #include "options.h"
@@ -376,6 +375,58 @@ BaseType::get_root () const
   return root;
 }
 
+BaseType *
+BaseType::destructure ()
+{
+  int recurisve_ops = 0;
+  BaseType *x = this;
+  while (true)
+    {
+      if (recurisve_ops++ >= rust_max_recursion_depth)
+	{
+	  rust_error_at (
+	    Location (),
+	    "%<recursion depth%> count exceeds limit of %i (use "
+	    "%<frust-max-recursion-depth=%> to increase the limit)",
+	    rust_max_recursion_depth);
+	  return new ErrorType (get_ref ());
+	}
+
+      switch (x->get_kind ())
+	{
+	  case TyTy::TypeKind::PARAM: {
+	    TyTy::ParamType *p = static_cast<TyTy::ParamType *> (x);
+	    TyTy::BaseType *pr = p->resolve ();
+	    if (pr == x)
+	      return pr;
+
+	    x = pr;
+	  }
+	  break;
+
+	  case TyTy::TypeKind::PLACEHOLDER: {
+	    TyTy::PlaceholderType *p = static_cast<TyTy::PlaceholderType *> (x);
+	    if (!p->can_resolve ())
+	      return p;
+
+	    x = p->resolve ();
+	  }
+	  break;
+
+	  case TyTy::TypeKind::PROJECTION: {
+	    TyTy::ProjectionType *p = static_cast<TyTy::ProjectionType *> (x);
+	    x = p->get ();
+	  }
+	  break;
+
+	default:
+	  return x;
+	}
+    }
+
+  return x;
+}
+
 const BaseType *
 BaseType::destructure () const
 {
@@ -397,14 +448,20 @@ BaseType::destructure () const
 	{
 	  case TyTy::TypeKind::PARAM: {
 	    const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (x);
-	    x = p->resolve ();
+	    const TyTy::BaseType *pr = p->resolve ();
+	    if (pr == x)
+	      return pr;
+
+	    x = pr;
 	  }
 	  break;
 
 	  case TyTy::TypeKind::PLACEHOLDER: {
 	    const TyTy::PlaceholderType *p
 	      = static_cast<const TyTy::PlaceholderType *> (x);
-	    rust_assert (p->can_resolve ());
+	    if (!p->can_resolve ())
+	      return p;
+
 	    x = p->resolve ();
 	  }
 	  break;
@@ -512,13 +569,6 @@ InferType::as_string () const
   return "<infer::error>";
 }
 
-BaseType *
-InferType::unify (BaseType *other)
-{
-  InferRules r (this);
-  return r.unify (other);
-}
-
 bool
 InferType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -637,12 +687,6 @@ ErrorType::as_string () const
   return "<tyty::error>";
 }
 
-BaseType *
-ErrorType::unify (BaseType *other)
-{
-  return this;
-}
-
 bool
 ErrorType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1009,13 +1053,6 @@ ADTType::as_string () const
   return identifier + subst_as_string () + "{" + variants_buffer + "}";
 }
 
-BaseType *
-ADTType::unify (BaseType *other)
-{
-  ADTRules r (this);
-  return r.unify (other);
-}
-
 bool
 ADTType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1278,13 +1315,6 @@ TupleType::get_field (size_t index) const
   return fields.at (index).get_tyty ();
 }
 
-BaseType *
-TupleType::unify (BaseType *other)
-{
-  TupleRules r (this);
-  return r.unify (other);
-}
-
 bool
 TupleType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1385,13 +1415,6 @@ FnType::as_string () const
   return "fn" + subst_as_string () + " (" + params_str + ") -> " + ret_str;
 }
 
-BaseType *
-FnType::unify (BaseType *other)
-{
-  FnRules r (this);
-  return r.unify (other);
-}
-
 bool
 FnType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1616,13 +1639,6 @@ FnPtr::as_string () const
   return "fnptr (" + params_str + ") -> " + get_return_type ()->as_string ();
 }
 
-BaseType *
-FnPtr::unify (BaseType *other)
-{
-  FnptrRules r (this);
-  return r.unify (other);
-}
-
 bool
 FnPtr::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1696,13 +1712,6 @@ ClosureType::as_string () const
   return "|" + params_buf + "| {" + result_type.get_tyty ()->as_string () + "}";
 }
 
-BaseType *
-ClosureType::unify (BaseType *other)
-{
-  ClosureRules r (this);
-  return r.unify (other);
-}
-
 bool
 ClosureType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1812,13 +1821,6 @@ ArrayType::as_string () const
   return "[" + get_element_type ()->as_string () + ":" + "CAPACITY" + "]";
 }
 
-BaseType *
-ArrayType::unify (BaseType *other)
-{
-  ArrayRules r (this);
-  return r.unify (other);
-}
-
 bool
 ArrayType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1895,13 +1897,6 @@ SliceType::as_string () const
   return "[" + get_element_type ()->as_string () + "]";
 }
 
-BaseType *
-SliceType::unify (BaseType *other)
-{
-  SliceRules r (this);
-  return r.unify (other);
-}
-
 bool
 SliceType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2006,13 +2001,6 @@ BoolType::as_string () const
   return "bool";
 }
 
-BaseType *
-BoolType::unify (BaseType *other)
-{
-  BoolRules r (this);
-  return r.unify (other);
-}
-
 bool
 BoolType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2094,13 +2082,6 @@ IntType::as_string () const
   return "__unknown_int_type";
 }
 
-BaseType *
-IntType::unify (BaseType *other)
-{
-  IntRules r (this);
-  return r.unify (other);
-}
-
 bool
 IntType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2200,13 +2181,6 @@ UintType::as_string () const
   return "__unknown_uint_type";
 }
 
-BaseType *
-UintType::unify (BaseType *other)
-{
-  UintRules r (this);
-  return r.unify (other);
-}
-
 bool
 UintType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2306,13 +2280,6 @@ FloatType::as_string () const
   return "__unknown_float_type";
 }
 
-BaseType *
-FloatType::unify (BaseType *other)
-{
-  FloatRules r (this);
-  return r.unify (other);
-}
-
 bool
 FloatType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2389,13 +2356,6 @@ USizeType::as_string () const
   return "usize";
 }
 
-BaseType *
-USizeType::unify (BaseType *other)
-{
-  USizeRules r (this);
-  return r.unify (other);
-}
-
 bool
 USizeType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2461,13 +2421,6 @@ ISizeType::as_string () const
   return "isize";
 }
 
-BaseType *
-ISizeType::unify (BaseType *other)
-{
-  ISizeRules r (this);
-  return r.unify (other);
-}
-
 bool
 ISizeType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2533,13 +2486,6 @@ CharType::as_string () const
   return "char";
 }
 
-BaseType *
-CharType::unify (BaseType *other)
-{
-  CharRules r (this);
-  return r.unify (other);
-}
-
 bool
 CharType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2655,13 +2601,6 @@ ReferenceType::get_name () const
 	 + get_base ()->get_name ();
 }
 
-BaseType *
-ReferenceType::unify (BaseType *other)
-{
-  ReferenceRules r (this);
-  return r.unify (other);
-}
-
 bool
 ReferenceType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2821,13 +2760,6 @@ PointerType::get_name () const
 	 + get_base ()->get_name ();
 }
 
-BaseType *
-PointerType::unify (BaseType *other)
-{
-  PointerRules r (this);
-  return r.unify (other);
-}
-
 bool
 PointerType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2964,13 +2896,6 @@ ParamType::get_name () const
   return resolve ()->get_name ();
 }
 
-BaseType *
-ParamType::unify (BaseType *other)
-{
-  ParamRules r (this);
-  return r.unify (other);
-}
-
 bool
 ParamType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -3130,13 +3055,6 @@ StrType::as_string () const
   return "str";
 }
 
-BaseType *
-StrType::unify (BaseType *other)
-{
-  StrRules r (this);
-  return r.unify (other);
-}
-
 bool
 StrType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -3202,13 +3120,6 @@ NeverType::as_string () const
   return "!";
 }
 
-BaseType *
-NeverType::unify (BaseType *other)
-{
-  NeverRules r (this);
-  return r.unify (other);
-}
-
 bool
 NeverType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -3295,13 +3206,6 @@ PlaceholderType::as_string () const
 	 + ">";
 }
 
-BaseType *
-PlaceholderType::unify (BaseType *other)
-{
-  PlaceholderRules r (this);
-  return r.unify (other);
-}
-
 bool
 PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -3465,12 +3369,6 @@ ProjectionType::as_string () const
   return "<Projection=" + subst_as_string () + "::" + base->as_string () + ">";
 }
 
-BaseType *
-ProjectionType::unify (BaseType *other)
-{
-  return base->unify (other);
-}
-
 bool
 ProjectionType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -3602,13 +3500,6 @@ DynamicObjectType::as_string () const
   return "dyn [" + raw_bounds_as_string () + "]";
 }
 
-BaseType *
-DynamicObjectType::unify (BaseType *other)
-{
-  DynamicRules r (this);
-  return r.unify (other);
-}
-
 bool
 DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const
 {
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 1cf7131c1cb..d2cf5b07fc1 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -105,11 +105,6 @@ public:
 
   virtual std::string get_name () const = 0;
 
-  // Unify two types. Returns a pointer to the newly-created unified ty, or
-  // nullptr if the two ty cannot be unified. The caller is responsible for
-  // releasing the memory of the returned ty.
-  virtual BaseType *unify (BaseType *other) = 0;
-
   // similar to unify but does not actually perform type unification but
   // determines whether they are compatible. Consider the following
   //
@@ -177,6 +172,7 @@ public:
 
   // This will get the monomorphized type from Params, Placeholders or
   // Projections if available or error
+  BaseType *destructure ();
   const BaseType *destructure () const;
 
   const RustIdent &get_ident () const;
@@ -221,8 +217,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
-
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -255,7 +249,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -284,7 +277,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -361,7 +353,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -598,7 +589,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -738,7 +728,6 @@ public:
 
   std::string get_identifier () const { return identifier; }
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -858,7 +847,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -938,7 +926,6 @@ public:
   std::string as_string () const override;
   std::string get_name () const override final { return as_string (); }
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -1007,7 +994,6 @@ public:
 
   std::string get_name () const override final { return as_string (); }
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -1055,7 +1041,6 @@ public:
 
   std::string get_name () const override final { return as_string (); }
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -1089,7 +1074,6 @@ public:
 
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -1120,7 +1104,6 @@ public:
 
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   IntKind get_int_kind () const;
@@ -1159,7 +1142,6 @@ public:
 
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   UintKind get_uint_kind () const;
@@ -1194,7 +1176,6 @@ public:
   std::string as_string () const override;
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   FloatKind get_float_kind () const;
@@ -1222,7 +1203,6 @@ public:
   std::string as_string () const override;
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -1243,7 +1223,6 @@ public:
   std::string as_string () const override;
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -1263,7 +1242,6 @@ public:
   std::string as_string () const override;
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -1284,7 +1262,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -1311,7 +1288,6 @@ public:
 
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -1354,7 +1330,6 @@ public:
   std::string as_string () const override;
   std::string get_name () const override final;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
@@ -1401,7 +1376,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -1428,7 +1402,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -1478,7 +1451,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   BaseType *clone () const final override;
@@ -1524,7 +1496,6 @@ public:
 
   std::string as_string () const override;
 
-  BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
   bool is_equal (const BaseType &other) const override;
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc
new file mode 100644
index 00000000000..072f76133bc
--- /dev/null
+++ b/gcc/rust/typecheck/rust-unify.cc
@@ -0,0 +1,1640 @@
+// 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-unify.h"
+
+namespace Rust {
+namespace Resolver {
+
+UnifyRules::UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
+			Location locus, bool commit_flag, bool emit_error)
+  : lhs (lhs), rhs (rhs), locus (locus), commit_flag (commit_flag),
+    emit_error (emit_error), mappings (*Analysis::Mappings::get ()),
+    context (*TypeCheckContext::get ())
+{}
+
+TyTy::BaseType *
+UnifyRules::Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
+		     Location locus, bool commit_flag, bool emit_error)
+{
+  UnifyRules r (lhs, rhs, locus, commit_flag, emit_error);
+  TyTy::BaseType *result = r.go ();
+
+  if (r.commit_flag)
+    r.commit (result);
+
+  bool failed = result->get_kind () == TyTy::TypeKind::ERROR;
+  if (failed && r.emit_error)
+    r.emit_type_mismatch ();
+
+  return result;
+}
+
+TyTy::BaseType *
+UnifyRules::get_base ()
+{
+  return lhs.get_ty ()->destructure ();
+}
+
+TyTy::BaseType *
+UnifyRules::get_other ()
+{
+  return rhs.get_ty ()->destructure ();
+}
+
+void
+UnifyRules::commit (TyTy::BaseType *resolved)
+{
+  resolved->append_reference (get_base ()->get_ref ());
+  resolved->append_reference (get_other ()->get_ref ());
+  for (auto ref : get_base ()->get_combined_refs ())
+    resolved->append_reference (ref);
+  for (auto ref : get_other ()->get_combined_refs ())
+    resolved->append_reference (ref);
+
+  get_other ()->append_reference (resolved->get_ref ());
+  get_other ()->append_reference (get_base ()->get_ref ());
+  get_base ()->append_reference (resolved->get_ref ());
+  get_base ()->append_reference (get_other ()->get_ref ());
+
+  bool result_resolved = resolved->get_kind () != TyTy::TypeKind::INFER;
+  bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER;
+  bool results_is_non_general_infer_var
+    = (result_is_infer_var
+       && (static_cast<TyTy::InferType *> (resolved))->get_infer_kind ()
+	    != TyTy::InferType::GENERAL);
+  if (result_resolved || results_is_non_general_infer_var)
+    {
+      for (auto &ref : resolved->get_combined_refs ())
+	{
+	  TyTy::BaseType *ref_tyty = nullptr;
+	  bool ok = context.lookup_type (ref, &ref_tyty);
+	  if (!ok)
+	    continue;
+
+	  // if any of the types are inference variables lets fix them
+	  if (ref_tyty->get_kind () == TyTy::TypeKind::INFER)
+	    {
+	      auto node = Analysis::NodeMapping (mappings.get_current_crate (),
+						 UNKNOWN_NODEID, ref,
+						 UNKNOWN_LOCAL_DEFID);
+	      context.insert_type (node, resolved->clone ());
+	    }
+	}
+    }
+}
+
+void
+UnifyRules::emit_type_mismatch () const
+{
+  TyTy::BaseType *expected = lhs.get_ty ();
+  TyTy::BaseType *expr = rhs.get_ty ();
+
+  RichLocation r (locus);
+  r.add_range (lhs.get_locus ());
+  r.add_range (rhs.get_locus ());
+  rust_error_at (r, "expected %<%s%> got %<%s%>",
+		 expected->get_name ().c_str (), expr->get_name ().c_str ());
+}
+
+TyTy::BaseType *
+UnifyRules::go ()
+{
+  TyTy::BaseType *ltype = lhs.get_ty ();
+  TyTy::BaseType *rtype = rhs.get_ty ();
+
+  ltype = lhs.get_ty ()->destructure ();
+  rtype = rhs.get_ty ()->destructure ();
+
+  rust_debug ("unify::go ltype={%s} rtype={%s}", ltype->debug_str ().c_str (),
+	      rtype->debug_str ().c_str ());
+
+  switch (ltype->get_kind ())
+    {
+    case TyTy::INFER:
+      return expect_inference_variable (static_cast<TyTy::InferType *> (ltype),
+					rtype);
+
+    case TyTy::ADT:
+      return expect_adt (static_cast<TyTy::ADTType *> (ltype), rtype);
+
+    case TyTy::STR:
+      return expect_str (static_cast<TyTy::StrType *> (ltype), rtype);
+
+    case TyTy::REF:
+      return expect_reference (static_cast<TyTy::ReferenceType *> (ltype),
+			       rtype);
+
+    case TyTy::POINTER:
+      return expect_pointer (static_cast<TyTy::PointerType *> (ltype), rtype);
+
+    case TyTy::PARAM:
+      return expect_param (static_cast<TyTy::ParamType *> (ltype), rtype);
+
+    case TyTy::ARRAY:
+      return expect_array (static_cast<TyTy::ArrayType *> (ltype), rtype);
+
+    case TyTy::SLICE:
+      return expect_slice (static_cast<TyTy::SliceType *> (ltype), rtype);
+
+    case TyTy::FNDEF:
+      return expect_fndef (static_cast<TyTy::FnType *> (ltype), rtype);
+
+    case TyTy::FNPTR:
+      return expect_fnptr (static_cast<TyTy::FnPtr *> (ltype), rtype);
+
+    case TyTy::TUPLE:
+      return expect_tuple (static_cast<TyTy::TupleType *> (ltype), rtype);
+
+    case TyTy::BOOL:
+      return expect_bool (static_cast<TyTy::BoolType *> (ltype), rtype);
+
+    case TyTy::CHAR:
+      return expect_char (static_cast<TyTy::CharType *> (ltype), rtype);
+
+    case TyTy::INT:
+      return expect_int (static_cast<TyTy::IntType *> (ltype), rtype);
+
+    case TyTy::UINT:
+      return expect_uint (static_cast<TyTy::UintType *> (ltype), rtype);
+
+    case TyTy::FLOAT:
+      return expect_float (static_cast<TyTy::FloatType *> (ltype), rtype);
+
+    case TyTy::USIZE:
+      return expect_usize (static_cast<TyTy::USizeType *> (ltype), rtype);
+
+    case TyTy::ISIZE:
+      return expect_isize (static_cast<TyTy::ISizeType *> (ltype), rtype);
+
+    case TyTy::NEVER:
+      return expect_never (static_cast<TyTy::NeverType *> (ltype), rtype);
+
+    case TyTy::PLACEHOLDER:
+      return expect_placeholder (static_cast<TyTy::PlaceholderType *> (ltype),
+				 rtype);
+
+    case TyTy::PROJECTION:
+      return expect_projection (static_cast<TyTy::ProjectionType *> (ltype),
+				rtype);
+
+    case TyTy::DYNAMIC:
+      return expect_dyn (static_cast<TyTy::DynamicObjectType *> (ltype), rtype);
+
+    case TyTy::CLOSURE:
+      return expect_closure (static_cast<TyTy::ClosureType *> (ltype), rtype);
+
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_inference_variable (TyTy::InferType *ltype,
+				       TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	switch (ltype->get_infer_kind ())
+	  {
+	  case TyTy::InferType::InferTypeKind::GENERAL:
+	    return rtype->clone ();
+
+	    case TyTy::InferType::InferTypeKind::INTEGRAL: {
+	      bool is_valid = r->get_infer_kind ()
+				== TyTy::InferType::InferTypeKind::INTEGRAL
+			      || r->get_infer_kind ()
+				   == TyTy::InferType::InferTypeKind::GENERAL;
+	      if (is_valid)
+		return rtype->clone ();
+	    }
+	    break;
+
+	    case TyTy::InferType::InferTypeKind::FLOAT: {
+	      bool is_valid
+		= r->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT
+		  || r->get_infer_kind ()
+		       == TyTy::InferType::InferTypeKind::GENERAL;
+	      if (is_valid)
+		return rtype->clone ();
+	    }
+	    break;
+	  }
+      }
+      break;
+
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::USIZE:
+      case TyTy::ISIZE: {
+	bool is_valid = (ltype->get_infer_kind ()
+			 == TyTy::InferType::InferTypeKind::GENERAL)
+			|| (ltype->get_infer_kind ()
+			    == TyTy::InferType::InferTypeKind::INTEGRAL);
+	if (is_valid)
+	  return rtype->clone ();
+      }
+      break;
+
+      case TyTy::FLOAT: {
+	bool is_valid = (ltype->get_infer_kind ()
+			 == TyTy::InferType::InferTypeKind::GENERAL)
+			|| (ltype->get_infer_kind ()
+			    == TyTy::InferType::InferTypeKind::FLOAT);
+	if (is_valid)
+	  return rtype->clone ();
+      }
+      break;
+
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+      case TyTy::CLOSURE: {
+	bool is_valid = (ltype->get_infer_kind ()
+			 == TyTy::InferType::InferTypeKind::GENERAL);
+	if (is_valid)
+	  return rtype->clone ();
+      }
+      break;
+
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::ADT: {
+	TyTy::ADTType &type = *static_cast<TyTy::ADTType *> (rtype);
+	if (ltype->get_adt_kind () != type.get_adt_kind ())
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	if (ltype->get_identifier ().compare (type.get_identifier ()) != 0)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	if (ltype->number_of_variants () != type.number_of_variants ())
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	for (size_t i = 0; i < type.number_of_variants (); ++i)
+	  {
+	    TyTy::VariantDef *a = ltype->get_variants ().at (i);
+	    TyTy::VariantDef *b = type.get_variants ().at (i);
+
+	    if (a->num_fields () != b->num_fields ())
+	      {
+		return new TyTy::ErrorType (0);
+	      }
+
+	    for (size_t j = 0; j < a->num_fields (); j++)
+	      {
+		TyTy::StructFieldType *base_field = a->get_field_at_index (j);
+		TyTy::StructFieldType *other_field = b->get_field_at_index (j);
+
+		TyTy::BaseType *this_field_ty = base_field->get_field_type ();
+		TyTy::BaseType *other_field_ty = other_field->get_field_type ();
+
+		TyTy::BaseType *unified_ty
+		  = UnifyRules::Resolve (TyTy::TyWithLocation (this_field_ty),
+					 TyTy::TyWithLocation (other_field_ty),
+					 locus, commit_flag,
+					 false /* emit_error */);
+		if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
+		  {
+		    return new TyTy::ErrorType (0);
+		  }
+	      }
+	  }
+
+	// generic args for the unit-struct case
+	if (type.is_unit () && ltype->is_unit ())
+	  {
+	    rust_assert (type.get_num_substitutions ()
+			 == ltype->get_num_substitutions ());
+
+	    for (size_t i = 0; i < type.get_num_substitutions (); i++)
+	      {
+		auto &a = ltype->get_substs ().at (i);
+		auto &b = type.get_substs ().at (i);
+
+		auto pa = a.get_param_ty ();
+		auto pb = b.get_param_ty ();
+
+		auto res
+		  = UnifyRules::Resolve (TyTy::TyWithLocation (pa),
+					 TyTy::TyWithLocation (pb), locus,
+					 commit_flag, false /* emit_error */);
+		if (res->get_kind () == TyTy::TypeKind::ERROR)
+		  {
+		    return new TyTy::ErrorType (0);
+		  }
+	      }
+	  }
+
+	return type.clone ();
+      }
+      break;
+
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+    case TyTy::STR:
+      return rtype->clone ();
+
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::REF: {
+	TyTy::ReferenceType &type = *static_cast<TyTy::ReferenceType *> (rtype);
+	auto base_type = ltype->get_base ();
+	auto other_base_type = type.get_base ();
+
+	TyTy::BaseType *base_resolved
+	  = UnifyRules::Resolve (TyTy::TyWithLocation (base_type),
+				 TyTy::TyWithLocation (other_base_type), locus,
+				 commit_flag, false /* emit_error */);
+	if (base_resolved->get_kind () == TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	// rust is permissive about mutablity here you can always go from
+	// mutable to immutable but not the otherway round
+	bool mutability_ok = ltype->is_mutable () ? type.is_mutable () : true;
+	if (!mutability_ok)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	return new TyTy::ReferenceType (ltype->get_ref (), ltype->get_ty_ref (),
+					TyTy::TyVar (base_resolved->get_ref ()),
+					ltype->mutability ());
+      }
+      break;
+
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::POINTER: {
+	TyTy::PointerType &type = *static_cast<TyTy::PointerType *> (rtype);
+	auto base_type = ltype->get_base ();
+	auto other_base_type = type.get_base ();
+
+	TyTy::BaseType *base_resolved
+	  = UnifyRules::Resolve (TyTy::TyWithLocation (base_type),
+				 TyTy::TyWithLocation (other_base_type), locus,
+				 commit_flag, false /* emit_error */);
+	if (base_resolved->get_kind () == TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	// rust is permissive about mutablity here you can always go from
+	// mutable to immutable but not the otherway round
+	bool mutability_ok = ltype->is_mutable () ? type.is_mutable () : true;
+	if (!mutability_ok)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	return new TyTy::PointerType (ltype->get_ref (), ltype->get_ty_ref (),
+				      TyTy::TyVar (base_resolved->get_ref ()),
+				      ltype->mutability ());
+      }
+      break;
+
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::PARAM: {
+	TyTy::ParamType &type = *static_cast<TyTy::ParamType *> (rtype);
+	// bool symbol_matches
+	//   = ltype->get_symbol ().compare (type.get_symbol ()) == 0;
+	// // TODO
+	// // I think rustc checks a debruinj index
+	// if (symbol_matches)
+	//   {
+	//     return type.clone ();
+	//   }
+
+	// matching symbol is not going to work when we mix symbol's and have
+	// nested generics
+
+	// bounds match? FIXME
+
+	return type.clone ();
+      }
+      break;
+
+    case TyTy::POINTER:
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::ARRAY: {
+	TyTy::ArrayType &type = *static_cast<TyTy::ArrayType *> (rtype);
+	TyTy::BaseType *element_unify = UnifyRules::Resolve (
+	  TyTy::TyWithLocation (ltype->get_element_type ()),
+	  TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag,
+	  false /* emit_error*/);
+
+	if (element_unify->get_kind () != TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (),
+					type.get_ident ().locus,
+					type.get_capacity_expr (),
+					TyTy::TyVar (
+					  element_unify->get_ref ()));
+	  }
+      }
+      break;
+
+    case TyTy::PARAM:
+    case TyTy::POINTER:
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::SLICE: {
+	TyTy::SliceType &type = *static_cast<TyTy::SliceType *> (rtype);
+	TyTy::BaseType *element_unify = UnifyRules::Resolve (
+	  TyTy::TyWithLocation (ltype->get_element_type ()),
+	  TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag,
+	  false /* emit_error*/);
+
+	if (element_unify->get_kind () != TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::SliceType (type.get_ref (), type.get_ty_ref (),
+					type.get_ident ().locus,
+					TyTy::TyVar (
+					  element_unify->get_ref ()));
+	  }
+      }
+      break;
+
+    case TyTy::PARAM:
+    case TyTy::POINTER:
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::ARRAY:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::FNDEF: {
+	TyTy::FnType &type = *static_cast<TyTy::FnType *> (rtype);
+	if (ltype->num_params () != type.num_params ())
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	for (size_t i = 0; i < ltype->num_params (); i++)
+	  {
+	    auto a = ltype->param_at (i).second;
+	    auto b = type.param_at (i).second;
+
+	    auto unified_param
+	      = UnifyRules::Resolve (TyTy::TyWithLocation (a),
+				     TyTy::TyWithLocation (b), locus,
+				     commit_flag, false /* emit_errors */);
+	    if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
+	      {
+		return new TyTy::ErrorType (0);
+	      }
+	  }
+
+	auto unified_return
+	  = UnifyRules::Resolve (TyTy::TyWithLocation (
+				   ltype->get_return_type ()),
+				 TyTy::TyWithLocation (type.get_return_type ()),
+				 locus, commit_flag, false /* emit_errors */);
+	if (unified_return->get_kind () == TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	return ltype->clone ();
+      }
+      break;
+
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::FLOAT:
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNPTR:
+    case TyTy::UINT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::FNPTR: {
+	TyTy::FnPtr &type = *static_cast<TyTy::FnPtr *> (rtype);
+	if (ltype->num_params () != type.num_params ())
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	for (size_t i = 0; i < ltype->num_params (); i++)
+	  {
+	    auto a = ltype->param_at (i);
+	    auto b = type.param_at (i);
+
+	    auto unified_param
+	      = UnifyRules::Resolve (TyTy::TyWithLocation (a),
+				     TyTy::TyWithLocation (b), locus,
+				     commit_flag, false /* emit_errors */);
+	    if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
+	      {
+		return new TyTy::ErrorType (0);
+	      }
+	  }
+
+	auto unified_return
+	  = UnifyRules::Resolve (TyTy::TyWithLocation (
+				   ltype->get_return_type ()),
+				 TyTy::TyWithLocation (type.get_return_type ()),
+				 locus, commit_flag, false /* emit_errors */);
+	if (unified_return->get_kind () == TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	return ltype->clone ();
+      }
+      break;
+
+      case TyTy::FNDEF: {
+	TyTy::FnType &type = *static_cast<TyTy::FnType *> (rtype);
+	auto this_ret_type = ltype->get_return_type ();
+	auto other_ret_type = type.get_return_type ();
+
+	auto unified_result
+	  = UnifyRules::Resolve (TyTy::TyWithLocation (this_ret_type),
+				 TyTy::TyWithLocation (other_ret_type), locus,
+				 commit_flag, false /*emit_errors*/);
+	if (unified_result->get_kind () == TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	if (ltype->num_params () != type.num_params ())
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	for (size_t i = 0; i < ltype->num_params (); i++)
+	  {
+	    auto this_param = ltype->param_at (i);
+	    auto other_param = type.param_at (i).second;
+
+	    auto unified_param
+	      = UnifyRules::Resolve (TyTy::TyWithLocation (this_param),
+				     TyTy::TyWithLocation (other_param), locus,
+				     commit_flag, false /* emit_errors */);
+	    if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
+	      {
+		return new TyTy::ErrorType (0);
+	      }
+	  }
+
+	return ltype->clone ();
+      }
+      break;
+
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::FLOAT:
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::UINT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::TUPLE: {
+	TyTy::TupleType &type = *static_cast<TyTy::TupleType *> (rtype);
+	if (ltype->num_fields () != type.num_fields ())
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	std::vector<TyTy::TyVar> fields;
+	for (size_t i = 0; i < ltype->num_fields (); i++)
+	  {
+	    TyTy::BaseType *bo = ltype->get_field (i);
+	    TyTy::BaseType *fo = type.get_field (i);
+
+	    TyTy::BaseType *unified_ty
+	      = UnifyRules::Resolve (TyTy::TyWithLocation (bo),
+				     TyTy::TyWithLocation (fo), locus,
+				     commit_flag, false /* emit_errors */);
+	    if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
+	      return new TyTy::ErrorType (0);
+
+	    fields.push_back (TyTy::TyVar (unified_ty->get_ref ()));
+	  }
+
+	return new TyTy::TupleType (type.get_ref (), type.get_ty_ref (),
+				    type.get_ident ().locus, fields);
+      }
+      break;
+
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::FLOAT:
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::UINT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+    case TyTy::BOOL:
+      return rtype->clone ();
+
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::FLOAT:
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::UINT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+    case TyTy::CHAR:
+      return rtype->clone ();
+
+    case TyTy::INT:
+    case TyTy::FLOAT:
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::UINT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL
+	    || r->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::INT: {
+	TyTy::IntType &type = *static_cast<TyTy::IntType *> (rtype);
+	bool is_valid = ltype->get_int_kind () == type.get_int_kind ();
+	if (is_valid)
+	  return new TyTy::IntType (type.get_ref (), type.get_ty_ref (),
+				    type.get_int_kind ());
+      }
+      break;
+
+    case TyTy::FLOAT:
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::UINT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL
+	    || r->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::UINT: {
+	TyTy::UintType &type = *static_cast<TyTy::UintType *> (rtype);
+	bool is_valid = ltype->get_uint_kind () == type.get_uint_kind ();
+	if (is_valid)
+	  return new TyTy::UintType (type.get_ref (), type.get_ty_ref (),
+				     type.get_uint_kind ());
+      }
+      break;
+
+    case TyTy::FLOAT:
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL
+	    || r->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::FLOAT: {
+	TyTy::FloatType &type = *static_cast<TyTy::FloatType *> (rtype);
+	bool is_valid = ltype->get_float_kind () == type.get_float_kind ();
+	if (is_valid)
+	  return new TyTy::FloatType (type.get_ref (), type.get_ty_ref (),
+				      type.get_float_kind ());
+      }
+      break;
+
+    case TyTy::ISIZE:
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+    case TyTy::ISIZE:
+      return rtype->clone ();
+
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+    case TyTy::USIZE:
+      return rtype->clone ();
+
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+    case TyTy::NEVER:
+      return rtype->clone ();
+
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::SLICE:
+    case TyTy::PARAM:
+    case TyTy::POINTER:
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::ARRAY:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_placeholder (TyTy::PlaceholderType *ltype,
+				TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::PLACEHOLDER: {
+	TyTy::PlaceholderType &type
+	  = *static_cast<TyTy::PlaceholderType *> (rtype);
+	bool symbol_match
+	  = ltype->get_symbol ().compare (type.get_symbol ()) == 0;
+	if (symbol_match)
+	  {
+	    return type.clone ();
+	  }
+      }
+      break;
+
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::SLICE:
+    case TyTy::PARAM:
+    case TyTy::POINTER:
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::ARRAY:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_projection (TyTy::ProjectionType *ltype,
+			       TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      // FIXME
+    case TyTy::PROJECTION:
+      gcc_unreachable ();
+      break;
+
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::SLICE:
+    case TyTy::PARAM:
+    case TyTy::POINTER:
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::ARRAY:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::DYNAMIC: {
+	TyTy::DynamicObjectType &type
+	  = *static_cast<TyTy::DynamicObjectType *> (rtype);
+	if (ltype->num_specified_bounds () != type.num_specified_bounds ())
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	if (!ltype->bounds_compatible (type, locus, true))
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	return ltype->clone ();
+      }
+      break;
+
+    case TyTy::CLOSURE:
+    case TyTy::SLICE:
+    case TyTy::PARAM:
+    case TyTy::POINTER:
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::ARRAY:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+TyTy::BaseType *
+UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype)
+{
+  switch (rtype->get_kind ())
+    {
+      case TyTy::INFER: {
+	TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype);
+	bool is_valid
+	  = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
+	if (is_valid)
+	  return ltype->clone ();
+      }
+      break;
+
+      case TyTy::CLOSURE: {
+	TyTy::ClosureType &type = *static_cast<TyTy::ClosureType *> (rtype);
+	if (ltype->get_def_id () != type.get_def_id ())
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	TyTy::BaseType *args_res
+	  = UnifyRules::Resolve (TyTy::TyWithLocation (
+				   &ltype->get_parameters ()),
+				 TyTy::TyWithLocation (&type.get_parameters ()),
+				 locus, commit_flag, false /* emit_error */);
+	if (args_res->get_kind () == TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	TyTy::BaseType *res = UnifyRules::Resolve (
+	  TyTy::TyWithLocation (&ltype->get_result_type ()),
+	  TyTy::TyWithLocation (&type.get_result_type ()), locus, commit_flag,
+	  false /* emit_error */);
+	if (res == nullptr || res->get_kind () == TyTy::TypeKind::ERROR)
+	  {
+	    return new TyTy::ErrorType (0);
+	  }
+
+	return ltype->clone ();
+      }
+      break;
+
+    case TyTy::SLICE:
+    case TyTy::PARAM:
+    case TyTy::POINTER:
+    case TyTy::STR:
+    case TyTy::ADT:
+    case TyTy::REF:
+    case TyTy::ARRAY:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::ERROR:
+      return new TyTy::ErrorType (0);
+    }
+  return new TyTy::ErrorType (0);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h
new file mode 100644
index 00000000000..6e46b9642a6
--- /dev/null
+++ b/gcc/rust/typecheck/rust-unify.h
@@ -0,0 +1,91 @@
+// 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/>.
+
+#ifndef RUST_UNIFY
+#define RUST_UNIFY
+
+#include "rust-tyty-util.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace Resolver {
+
+class UnifyRules
+{
+public:
+  static TyTy::BaseType *Resolve (TyTy::TyWithLocation lhs,
+				  TyTy::TyWithLocation rhs, Location locus,
+				  bool commit_flag, bool emit_error);
+
+protected:
+  TyTy::BaseType *expect_inference_variable (TyTy::InferType *ltype,
+					     TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_reference (TyTy::ReferenceType *ltype,
+				    TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_pointer (TyTy::PointerType *ltype,
+				  TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_placeholder (TyTy::PlaceholderType *ltype,
+				      TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_projection (TyTy::ProjectionType *ltype,
+				     TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_dyn (TyTy::DynamicObjectType *ltype,
+			      TyTy::BaseType *rtype);
+  TyTy::BaseType *expect_closure (TyTy::ClosureType *ltype,
+				  TyTy::BaseType *rtype);
+
+private:
+  UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
+	      Location locus, bool commit_flag, bool emit_error);
+
+  void emit_type_mismatch () const;
+  void commit (TyTy::BaseType *resolved);
+  TyTy::BaseType *go ();
+
+  TyTy::BaseType *get_base ();
+  TyTy::BaseType *get_other ();
+
+  TyTy::TyWithLocation lhs;
+  TyTy::TyWithLocation rhs;
+  Location locus;
+  bool commit_flag;
+  bool emit_error;
+
+  Analysis::Mappings &mappings;
+  TypeCheckContext &context;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_UNIFY
diff --git a/gcc/testsuite/rust/compile/never_type_err1.rs b/gcc/testsuite/rust/compile/never_type1.rs
similarity index 52%
rename from gcc/testsuite/rust/compile/never_type_err1.rs
rename to gcc/testsuite/rust/compile/never_type1.rs
index 52b1283fadf..8d56176fee3 100644
--- a/gcc/testsuite/rust/compile/never_type_err1.rs
+++ b/gcc/testsuite/rust/compile/never_type1.rs
@@ -1,8 +1,7 @@
 fn test() {
     let a;
 
-    // FIXME: Unimplemented features
-    a = if true { // { dg-error "expected .T.. got .!." }
+    a = if true {
         return;
     } else {
         return;
-- 
2.40.0


  parent reply	other threads:[~2023-04-05 14:06 UTC|newest]

Thread overview: 92+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-05 14:02 Rust front-end update 2023-04-05 arthur.cohen
2023-04-05 14:02 ` [committed 01/88] gccrs: fatal_error_flag: Fix typo in error message arthur.cohen
2023-04-05 14:02 ` [committed 02/88] gccrs: unsafe: check use of `target_feature` attribute arthur.cohen
2023-04-05 14:02 ` [committed 03/88] gccrs: Check for mutable references in const functions arthur.cohen
2023-04-05 14:02 ` [committed 04/88] gccrs: rust: add bound parsing in parse_generic_arg arthur.cohen
2023-04-05 14:02 ` [committed 05/88] gccrs: Implement declarative macro 2.0 parser arthur.cohen
2023-04-05 14:02 ` [committed 06/88] gccrs: Add name resolution to generic argument associated item bindings arthur.cohen
2023-04-05 14:02 ` [committed 07/88] gccrs: Support associated type bound arguments arthur.cohen
2023-04-05 14:02 ` [committed 08/88] gccrs: Reuse TypeCheckPattern on LetStmt's arthur.cohen
2023-04-05 14:02 ` [committed 09/88] gccrs: Add get_locus function for abstract class MetaItemInner arthur.cohen
2023-04-05 14:02 ` [committed 10/88] gccrs: diagnostics: Add underline for tokens in diagnostics arthur.cohen
2023-04-05 14:02 ` [committed 11/88] gccrs: Change how CompileVarDecl outputs Bvariable's arthur.cohen
2023-04-05 14:02 ` [committed 12/88] gccrs: testsuite: Handle Windows carriage returns properly arthur.cohen
2023-04-05 14:02 ` [committed 13/88] gccrs: Support GroupedPattern during name resolution arthur.cohen
2023-04-05 14:02 ` [committed 14/88] gccrs: Do not crash on empty macros expand. Fixes #1712 arthur.cohen
2023-04-05 14:02 ` [committed 15/88] gccrs: Add HIR lowering for GroupedPattern arthur.cohen
2023-04-05 14:03 ` [committed 16/88] gccrs: Add get_item method for HIR::GroupedPattern arthur.cohen
2023-04-05 14:03 ` [committed 17/88] gccrs: Add type resolution for grouped patterns arthur.cohen
2023-04-05 14:03 ` [committed 18/88] gccrs: Added missing GroupedPattern visitors for code generation arthur.cohen
2023-04-05 14:03 ` [committed 19/88] gccrs: Rename file rust-ast-full-test.cc to rust-ast.cc arthur.cohen
2023-04-05 14:03 ` [committed 20/88] gccrs: moved operator.h to util/rust-operators.h arthur.cohen
2023-04-05 14:03 ` [committed 21/88] gccrs: fixed compiler error message on wildcard pattern within expression arthur.cohen
2023-04-05 14:03 ` [committed 22/88] gccrs: fixed indentations in AST pretty expanded dump of trait arthur.cohen
2023-04-05 14:03 ` [committed 23/88] gccrs: macro: Allow builtin `MacroInvocation`s within the AST arthur.cohen
2023-04-05 14:03 ` [committed 24/88] gccrs: Create and use CompilePatternLet visitor for compiling let statments arthur.cohen
2023-04-05 14:03 ` [committed 25/88] gccrs: parser: Allow parsing multiple reference types arthur.cohen
2023-04-05 14:03 ` [committed 26/88] gccrs: Move rust-buffered-queue.h to util folder #1766 arthur.cohen
2023-04-05 14:03 ` [committed 27/88] gccrs: Improve GroupedPattern lowering arthur.cohen
2023-04-05 14:03 ` [committed 28/88] gccrs: Remove HIR::GroupedPattern arthur.cohen
2023-04-05 14:03 ` [committed 29/88] gccrs: Optimize HIR::ReferencePattern arthur.cohen
2023-04-05 14:03 ` [committed 30/88] gccrs: Implement lowering ReferencePattern from AST to HIR arthur.cohen
2023-04-05 14:03 ` [committed 31/88] gccrs: parser: Improve parsing of complex generic arguments arthur.cohen
2023-04-05 14:03 ` [committed 32/88] gccrs: parser: Fix parsing of closure param list arthur.cohen
2023-04-05 14:03 ` [committed 33/88] gccrs: Add support for feature check arthur.cohen
2023-04-05 14:03 ` [committed 34/88] gccrs: Removed comment copy-pasted from gcc/tree.def arthur.cohen
2023-04-05 14:03 ` [committed 35/88] gccrs: Add another test case for passing associated type-bounds arthur.cohen
2023-04-05 14:03 ` [committed 36/88] gccrs: Move TypePredicateItem impl out of the header arthur.cohen
2023-04-05 14:03 ` [committed 37/88] gccrs: Refactor TyVar and TypeBoundPredicates arthur.cohen
2023-04-05 14:03 ` [committed 38/88] gccrs: Refactor SubstitutionRef base class into its own CC file arthur.cohen
2023-04-05 14:03 ` [committed 39/88] gccrs: Refactor all substitution mapper code implementation " arthur.cohen
2023-04-05 14:03 ` [committed 40/88] gccrs: Refactor BaseType, InferType and ErrorType impl into cc file arthur.cohen
2023-04-05 14:03 ` [committed 41/88] gccrs: Refactor PathProbe " arthur.cohen
2023-04-05 14:03 ` [committed 42/88] gccrs: Refactor PathProbeType code into CC file arthur.cohen
2023-04-05 14:03 ` [committed 43/88] gccrs: Refactor all code out of the rust-tyty.h header arthur.cohen
2023-04-05 14:03 ` [committed 44/88] gccrs: Rename rust-tyctx.cc to rust-typecheck-context.cc arthur.cohen
2023-04-05 14:03 ` [committed 45/88] gccrs: Rename header rust-hir-trait-ref.h to rust-hir-trait-reference.h arthur.cohen
2023-04-05 14:03 ` [committed 46/88] gccrs: Refactor handle_substitutions to take a reference arthur.cohen
2023-04-05 14:03 ` [committed 47/88] gccrs: Clear the substitution callbacks when copying ArgumentMappings arthur.cohen
2023-04-05 14:03 ` [committed 48/88] gccrs: Add missing param subst callback arthur.cohen
2023-04-05 14:03 ` [committed 49/88] gccrs: Remove monomorphization hack to setup possible associated types arthur.cohen
2023-04-05 14:03 ` arthur.cohen [this message]
2023-04-05 14:03 ` [committed 51/88] gccrs: Fix nullptr dereference arthur.cohen
2023-04-05 14:03 ` [committed 52/88] gccrs: Add missing Sized, Copy and Clone lang item mappings arthur.cohen
2023-04-05 14:03 ` [committed 53/88] gccrs: Fix higher ranked trait bounds computation of self arthur.cohen
2023-04-05 14:03 ` [committed 54/88] gccrs: Remove bad error message on checking function arguments arthur.cohen
2023-04-05 14:03 ` [committed 55/88] gccrs: Add general TypeBounds checks arthur.cohen
2023-04-05 14:03 ` [committed 56/88] gccrs: Add support for TuplePattern in let statements arthur.cohen
2023-04-05 14:03 ` [committed 57/88] gccrs: rust-item: include rust-expr.h arthur.cohen
2023-04-05 14:03 ` [committed 58/88] gccrs: parser: Expose parse_macro_invocation as public API arthur.cohen
2023-04-05 14:03 ` [committed 59/88] gccrs: expansion: Add `get_token_slice` to `MacroInvocLexer` class arthur.cohen
2023-04-05 14:03 ` [committed 60/88] gccrs: macros: Perform macro expansion in a fixed-point fashion arthur.cohen
2023-04-05 14:03 ` [committed 61/88] gccrs: expander: Add documentation for `expand_eager_invocations` arthur.cohen
2023-04-05 14:03 ` [committed 62/88] gccrs: typecheck: Refactor rust-hir-trait-reference.h arthur.cohen
2023-04-05 14:03 ` [committed 63/88] gccrs: cli: Update safety warning message arthur.cohen
2023-04-05 14:03 ` [committed 64/88] gccrs: Update copyright years arthur.cohen
2023-04-05 14:03 ` [committed 65/88] gccrs: Add feature gate for "rust-intrinsic" arthur.cohen
2023-04-05 14:03 ` [committed 66/88] gccrs: Add variadic argument type checking arthur.cohen
2023-04-05 14:03 ` [committed 67/88] gccrs: Add test arthur.cohen
2023-04-05 14:03 ` [committed 68/88] gccrs: Simplify WildcardPattern let statement handling arthur.cohen
2023-04-05 14:03 ` [committed 69/88] gccrs: lex: Prevent directories in RAIIFile arthur.cohen
2023-04-05 14:03 ` [committed 70/88] gccrs: testsuite: Add empty string macro test arthur.cohen
2023-04-05 14:03 ` [committed 71/88] gccrs: Add support for parsing empty tuple patterns arthur.cohen
2023-04-05 14:03 ` [committed 72/88] gccrs: Implemented UTF-8 checking for include_str!() arthur.cohen
2023-04-05 14:03 ` [committed 73/88] gccrs: Extract query_type from TypeCheckBase to be a simple extern arthur.cohen
2023-04-05 14:03 ` [committed 74/88] gccrs: Add new virtual function HIR::ImplItem::get_impl_item_name arthur.cohen
2023-04-05 14:03 ` [committed 75/88] gccrs: Support for Sized builtin marker trait arthur.cohen
2023-04-05 14:04 ` [committed 76/88] gccrs: Fix regression in testcase arthur.cohen
2023-04-05 14:04 ` [committed 77/88] gccrs: Add trailing newline arthur.cohen
2023-04-05 14:04 ` [committed 78/88] gccrs: builtins: Return empty list of tokens instead of nullptr arthur.cohen
2023-04-05 14:04 ` [committed 79/88] gccrs: Fix formatting arthur.cohen
2023-04-05 14:04 ` [committed 80/88] gccrs: Add AST::AltPattern class arthur.cohen
2023-04-05 14:04 ` [committed 81/88] gccrs: Fix up DejaGnu directives in 'rust/compile/issue-1830_{bytes,str}.rs' test cases [#1838] arthur.cohen
2023-04-05 14:04 ` [committed 82/88] gccrs: rename rust-hir-full-tests.cc arthur.cohen
2023-04-05 14:04 ` [committed 83/88] gccrs: add test case to show our query-type system is working arthur.cohen
2023-04-05 14:04 ` [committed 84/88] gccrs: ast: Refactor TraitItem to keep Location info arthur.cohen
2023-04-05 14:04 ` [committed 85/88] gccrs: diagnostic: Refactor Error class arthur.cohen
2023-04-05 14:04 ` [committed 86/88] gccrs: Added AST Node AST::InlineAsm arthur.cohen
2023-04-05 14:04 ` [committed 87/88] gccrs: Address unsafe with/without block handling ambiguity arthur.cohen
2023-04-05 14:04 ` [committed 88/88] gccrs: Fix issue with parsing unsafe block expression statements arthur.cohen
2023-04-06  7:59 ` Rust front-end update 2023-04-05 Thomas Schwinge
2023-04-06  9:05   ` Arthur Cohen
2023-04-11  9:09 ` Richard Biener

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230405140411.3016563-51-arthur.cohen@embecosm.com \
    --to=arthur.cohen@embecosm.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=gcc-rust@gcc.gnu.org \
    --cc=herron.philip@googlemail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).