public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] gccrs: Refactor the type unification code
@ 2023-02-07 17:56 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2023-02-07 17:56 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:95fa967f5c5ce9445fa3f08195c01138338fd0bd

commit 95fa967f5c5ce9445fa3f08195c01138338fd0bd
Author: Philip Herron <herron.philip@googlemail.com>
Date:   Mon Jan 30 18:19:07 2023 +0000

    gccrs: Refactor the type unification code
    
    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

Diff:
---
 gcc/rust/Make-lang.in                              |    1 +
 gcc/rust/backend/rust-compile-expr.cc              |    6 +-
 gcc/rust/typecheck/rust-coercion.cc                |    6 +-
 gcc/rust/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 ++
 .../compile/{never_type_err1.rs => never_type1.rs} |    3 +-
 10 files changed, 1807 insertions(+), 1621 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 5f5cee71c13..6038c84c993 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 8b56be79e33..97df10761f9 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"
@@ -2030,7 +2031,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 a361856ae6a..623607868f9 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 8107ef5a092..6a6313287fe 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 dbb808b644e..00000000000
--- a/gcc/rust/typecheck/rust-tyty-rules.h
+++ /dev/null
@@ -1,1406 +0,0 @@
-// 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_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 3a642b69b47..8c3bed456a4 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 900b64d1c4c..89c320960a2 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;

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-02-07 17:56 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-07 17:56 [gcc/devel/rust/master] gccrs: Refactor the type unification code Thomas Schwinge

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).