public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Refactor our casts to follow the Rustc implemention
@ 2022-08-29 15:31 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-08-29 15:31 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:36a9255b1b6683bb060021c637997de396445049

commit 36a9255b1b6683bb060021c637997de396445049
Author: Philip Herron <philip.herron@embecosm.com>
Date:   Mon Aug 22 15:54:14 2022 +0100

    Refactor our casts to follow the Rustc implemention
    
    This gets rid of our old visitor system for cast type checking. Casts
    depend on type coercions as they are meant to attempt a type coercion
    before trying a simple cast. This explicitly defines the rules which should
    be allowed for simple casts. In rustc they use match expressions to write
    a list of casts which should not be allowed. We have likely missed some
    rules of what should be allowed but this is at least the start of how
    to implement this.
    
    Fixes #1496

Diff:
---
 gcc/rust/Make-lang.in                            |    1 +
 gcc/rust/backend/rust-compile-expr.cc            |   24 +-
 gcc/rust/typecheck/rust-casts.cc                 |  292 +++++
 gcc/rust/typecheck/rust-casts.h                  |   53 +
 gcc/rust/typecheck/rust-coercion.cc              |   89 +-
 gcc/rust/typecheck/rust-coercion.h               |   16 +-
 gcc/rust/typecheck/rust-hir-type-check-base.cc   |   33 +-
 gcc/rust/typecheck/rust-hir-type-check-base.h    |    7 +-
 gcc/rust/typecheck/rust-hir-type-check-expr.cc   |   15 +-
 gcc/rust/typecheck/rust-hir-type-check.h         |   20 +
 gcc/rust/typecheck/rust-tyty-cast.h              | 1425 ----------------------
 gcc/rust/typecheck/rust-tyty.cc                  |  178 +--
 gcc/rust/typecheck/rust-tyty.h                   |   64 +-
 gcc/testsuite/rust/execute/torture/issue-1496.rs |   75 ++
 14 files changed, 600 insertions(+), 1692 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 49be3a1b473..f687cc2f667 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -122,6 +122,7 @@ GRS_OBJS = \
     rust/rust-hir-type-check-implitem.o \
     rust/rust-hir-dot-operator.o \
     rust/rust-coercion.o \
+    rust/rust-casts.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 412ca091a42..865ad250f2c 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -237,16 +237,34 @@ CompileExpr::visit (HIR::LazyBooleanExpr &expr)
 void
 CompileExpr::visit (HIR::TypeCastExpr &expr)
 {
-  TyTy::BaseType *tyty = nullptr;
+  TyTy::BaseType *type_to_cast_to_ty = nullptr;
   if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
-				       &tyty))
+				       &type_to_cast_to_ty))
     {
       translated = error_mark_node;
       return;
     }
 
-  auto type_to_cast_to = TyTyResolveCompile::compile (ctx, tyty);
+  TyTy::BaseType *casted_tyty = nullptr;
+  if (!ctx->get_tyctx ()->lookup_type (
+	expr.get_casted_expr ()->get_mappings ().get_hirid (), &casted_tyty))
+    {
+      translated = error_mark_node;
+      return;
+    }
+
+  auto type_to_cast_to = TyTyResolveCompile::compile (ctx, type_to_cast_to_ty);
   auto casted_expr = CompileExpr::Compile (expr.get_casted_expr ().get (), ctx);
+
+  std::vector<Resolver::Adjustment> *adjustments = nullptr;
+  bool ok = ctx->get_tyctx ()->lookup_cast_autoderef_mappings (
+    expr.get_mappings ().get_hirid (), &adjustments);
+  if (ok)
+    {
+      casted_expr
+	= resolve_adjustements (*adjustments, casted_expr, expr.get_locus ());
+    }
+
   translated
     = type_cast_expression (type_to_cast_to, casted_expr, expr.get_locus ());
 }
diff --git a/gcc/rust/typecheck/rust-casts.cc b/gcc/rust/typecheck/rust-casts.cc
new file mode 100644
index 00000000000..61004dfabc3
--- /dev/null
+++ b/gcc/rust/typecheck/rust-casts.cc
@@ -0,0 +1,292 @@
+// 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-casts.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCastRules::TypeCastRules (Location locus, TyTy::TyWithLocation from,
+			      TyTy::TyWithLocation to)
+  : locus (locus), from (from), to (to)
+{}
+
+TypeCoercionRules::CoercionResult
+TypeCastRules::resolve (Location locus, TyTy::TyWithLocation from,
+			TyTy::TyWithLocation to)
+{
+  TypeCastRules cast_rules (locus, from, to);
+  return cast_rules.check ();
+}
+
+TypeCoercionRules::CoercionResult
+TypeCastRules::check ()
+{
+  // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
+  auto possible_coercion
+    = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus);
+  if (!possible_coercion.is_error ())
+    return possible_coercion;
+
+  // try the simple cast rules
+  auto simple_cast = cast_rules ();
+  if (!simple_cast.is_error ())
+    return simple_cast;
+
+  // failed to cast
+  emit_cast_error ();
+  return TypeCoercionRules::CoercionResult::get_error ();
+}
+
+TypeCoercionRules::CoercionResult
+TypeCastRules::cast_rules ()
+{
+  // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L596
+  // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L654
+
+  rust_debug ("cast_rules from={%s} to={%s}",
+	      from.get_ty ()->debug_str ().c_str (),
+	      to.get_ty ()->debug_str ().c_str ());
+
+  switch (from.get_ty ()->get_kind ())
+    {
+      case TyTy::TypeKind::INFER: {
+	TyTy::InferType *from_infer
+	  = static_cast<TyTy::InferType *> (from.get_ty ());
+	switch (from_infer->get_infer_kind ())
+	  {
+	  case TyTy::InferType::InferTypeKind::GENERAL:
+	    return TypeCoercionRules::CoercionResult{{},
+						     to.get_ty ()->clone ()};
+
+	  case TyTy::InferType::InferTypeKind::INTEGRAL:
+	    switch (to.get_ty ()->get_kind ())
+	      {
+	      case TyTy::TypeKind::CHAR:
+	      case TyTy::TypeKind::BOOL:
+	      case TyTy::TypeKind::USIZE:
+	      case TyTy::TypeKind::ISIZE:
+	      case TyTy::TypeKind::UINT:
+	      case TyTy::TypeKind::INT:
+	      case TyTy::TypeKind::POINTER:
+		return TypeCoercionRules::CoercionResult{
+		  {}, to.get_ty ()->clone ()};
+
+		case TyTy::TypeKind::INFER: {
+		  TyTy::InferType *to_infer
+		    = static_cast<TyTy::InferType *> (to.get_ty ());
+
+		  switch (to_infer->get_infer_kind ())
+		    {
+		    case TyTy::InferType::InferTypeKind::GENERAL:
+		    case TyTy::InferType::InferTypeKind::INTEGRAL:
+		      return TypeCoercionRules::CoercionResult{
+			{}, to.get_ty ()->clone ()};
+
+		    default:
+		      return TypeCoercionRules::CoercionResult::get_error ();
+		    }
+		}
+		break;
+
+	      default:
+		return TypeCoercionRules::CoercionResult::get_error ();
+	      }
+	    break;
+
+	  case TyTy::InferType::InferTypeKind::FLOAT:
+	    switch (to.get_ty ()->get_kind ())
+	      {
+	      case TyTy::TypeKind::USIZE:
+	      case TyTy::TypeKind::ISIZE:
+	      case TyTy::TypeKind::UINT:
+	      case TyTy::TypeKind::INT:
+		return TypeCoercionRules::CoercionResult{
+		  {}, to.get_ty ()->clone ()};
+
+		case TyTy::TypeKind::INFER: {
+		  TyTy::InferType *to_infer
+		    = static_cast<TyTy::InferType *> (to.get_ty ());
+
+		  switch (to_infer->get_infer_kind ())
+		    {
+		    case TyTy::InferType::InferTypeKind::GENERAL:
+		    case TyTy::InferType::InferTypeKind::FLOAT:
+		      return TypeCoercionRules::CoercionResult{
+			{}, to.get_ty ()->clone ()};
+
+		    default:
+		      return TypeCoercionRules::CoercionResult::get_error ();
+		    }
+		}
+		break;
+
+	      default:
+		return TypeCoercionRules::CoercionResult::get_error ();
+	      }
+	    break;
+	  }
+      }
+      break;
+
+    case TyTy::TypeKind::BOOL:
+      switch (to.get_ty ()->get_kind ())
+	{
+	case TyTy::TypeKind::INFER:
+	case TyTy::TypeKind::USIZE:
+	case TyTy::TypeKind::ISIZE:
+	case TyTy::TypeKind::UINT:
+	case TyTy::TypeKind::INT:
+	  return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
+
+	default:
+	  return TypeCoercionRules::CoercionResult::get_error ();
+	}
+      break;
+
+    case TyTy::TypeKind::CHAR:
+    case TyTy::TypeKind::USIZE:
+    case TyTy::TypeKind::ISIZE:
+    case TyTy::TypeKind::UINT:
+    case TyTy::TypeKind::INT:
+      switch (to.get_ty ()->get_kind ())
+	{
+	  case TyTy::TypeKind::CHAR: {
+	    // only u8 and char
+	    bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
+	    bool was_u8 = was_uint
+			  && (static_cast<TyTy::UintType *> (from.get_ty ())
+				->get_uint_kind ()
+			      == TyTy::UintType::UintKind::U8);
+	    if (was_u8)
+	      return TypeCoercionRules::CoercionResult{{},
+						       to.get_ty ()->clone ()};
+	  }
+	  break;
+
+	case TyTy::TypeKind::INFER:
+	case TyTy::TypeKind::USIZE:
+	case TyTy::TypeKind::ISIZE:
+	case TyTy::TypeKind::UINT:
+	case TyTy::TypeKind::INT:
+	  return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
+
+	default:
+	  return TypeCoercionRules::CoercionResult::get_error ();
+	}
+      break;
+
+    case TyTy::TypeKind::FLOAT:
+      switch (to.get_ty ()->get_kind ())
+	{
+	case TyTy::TypeKind::FLOAT:
+	  return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
+
+	  case TyTy::TypeKind::INFER: {
+	    TyTy::InferType *to_infer
+	      = static_cast<TyTy::InferType *> (to.get_ty ());
+
+	    switch (to_infer->get_infer_kind ())
+	      {
+	      case TyTy::InferType::InferTypeKind::GENERAL:
+	      case TyTy::InferType::InferTypeKind::FLOAT:
+		return TypeCoercionRules::CoercionResult{
+		  {}, to.get_ty ()->clone ()};
+
+	      default:
+		return TypeCoercionRules::CoercionResult::get_error ();
+	      }
+	  }
+	  break;
+
+	default:
+	  return TypeCoercionRules::CoercionResult::get_error ();
+	}
+      break;
+
+    case TyTy::TypeKind::REF:
+    case TyTy::TypeKind::POINTER:
+      switch (to.get_ty ()->get_kind ())
+	{
+	case TyTy::TypeKind::REF:
+	case TyTy::TypeKind::POINTER:
+	  return check_ptr_ptr_cast ();
+
+	  // FIXME can you cast a pointer to a integral type?
+
+	default:
+	  return TypeCoercionRules::CoercionResult::get_error ();
+	}
+      break;
+
+    default:
+      return TypeCoercionRules::CoercionResult::get_error ();
+    }
+
+  return TypeCoercionRules::CoercionResult::get_error ();
+}
+
+TypeCoercionRules::CoercionResult
+TypeCastRules::check_ptr_ptr_cast ()
+{
+  rust_debug ("check_ptr_ptr_cast from={%s} to={%s}",
+	      from.get_ty ()->debug_str ().c_str (),
+	      to.get_ty ()->debug_str ().c_str ());
+
+  bool from_is_ref = from.get_ty ()->get_kind () == TyTy::TypeKind::REF;
+  bool to_is_ref = to.get_ty ()->get_kind () == TyTy::TypeKind::REF;
+  bool from_is_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
+  bool to_is_ptr = to.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
+
+  if (from_is_ptr && to_is_ptr)
+    {
+      // mutability is ignored here as all pointer usage requires unsafe
+      return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
+    }
+  else if (from_is_ref && to_is_ref)
+    {
+      // mutability must be coercedable
+      TyTy::ReferenceType &f
+	= static_cast<TyTy::ReferenceType &> (*from.get_ty ());
+      TyTy::ReferenceType &t
+	= static_cast<TyTy::ReferenceType &> (*to.get_ty ());
+
+      if (TypeCoercionRules::coerceable_mutability (f.mutability (),
+						    t.mutability ()))
+	{
+	  return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
+	}
+    }
+
+  return TypeCoercionRules::CoercionResult::get_error ();
+}
+
+void
+TypeCastRules::emit_cast_error () const
+{
+  // error[E0604]
+  RichLocation r (locus);
+  r.add_range (from.get_locus ());
+  r.add_range (to.get_locus ());
+  rust_error_at (r, "invalid cast %<%s%> to %<%s%>",
+		 from.get_ty ()->get_name ().c_str (),
+		 to.get_ty ()->get_name ().c_str ());
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-casts.h b/gcc/rust/typecheck/rust-casts.h
new file mode 100644
index 00000000000..e908f49b656
--- /dev/null
+++ b/gcc/rust/typecheck/rust-casts.h
@@ -0,0 +1,53 @@
+// 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_CASTS
+#define RUST_CASTS
+
+#include "rust-tyty.h"
+#include "rust-coercion.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCastRules
+{
+public:
+  static TypeCoercionRules::CoercionResult
+  resolve (Location locus, TyTy::TyWithLocation from, TyTy::TyWithLocation to);
+
+protected:
+  TypeCoercionRules::CoercionResult check ();
+  TypeCoercionRules::CoercionResult cast_rules ();
+  TypeCoercionRules::CoercionResult check_ptr_ptr_cast ();
+
+  void emit_cast_error () const;
+
+protected:
+  TypeCastRules (Location locus, TyTy::TyWithLocation from,
+		 TyTy::TyWithLocation to);
+
+  Location locus;
+  TyTy::TyWithLocation from;
+  TyTy::TyWithLocation to;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_CASTS
diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc
index b7ef6774afd..2ad2b8007ff 100644
--- a/gcc/rust/typecheck/rust-coercion.cc
+++ b/gcc/rust/typecheck/rust-coercion.cc
@@ -21,24 +21,33 @@
 namespace Rust {
 namespace Resolver {
 
-AutoderefTypeCoercion::CoercionResult
-AutoderefTypeCoercion::Coerce (TyTy::BaseType *receiver,
-			       TyTy::BaseType *expected, Location locus)
+TypeCoercionRules::CoercionResult
+TypeCoercionRules::Coerce (TyTy::BaseType *receiver, TyTy::BaseType *expected,
+			   Location locus)
 {
-  AutoderefTypeCoercion resolver (expected, locus);
+  TypeCoercionRules resolver (expected, locus, true);
   bool ok = resolver.do_coercion (receiver);
   return ok ? resolver.try_result : CoercionResult::get_error ();
 }
 
-AutoderefTypeCoercion::AutoderefTypeCoercion (TyTy::BaseType *expected,
-					      Location locus)
+TypeCoercionRules::CoercionResult
+TypeCoercionRules::TryCoerce (TyTy::BaseType *receiver,
+			      TyTy::BaseType *expected, Location locus)
+{
+  TypeCoercionRules resolver (expected, locus, false);
+  bool ok = resolver.do_coercion (receiver);
+  return ok ? resolver.try_result : CoercionResult::get_error ();
+}
+
+TypeCoercionRules::TypeCoercionRules (TyTy::BaseType *expected, Location locus,
+				      bool emit_errors)
   : AutoderefCycle (false), mappings (Analysis::Mappings::get ()),
     context (TypeCheckContext::get ()), expected (expected), locus (locus),
-    try_result (CoercionResult::get_error ())
+    try_result (CoercionResult::get_error ()), emit_errors (emit_errors)
 {}
 
 bool
-AutoderefTypeCoercion::do_coercion (TyTy::BaseType *receiver)
+TypeCoercionRules::do_coercion (TyTy::BaseType *receiver)
 {
   // FIXME this is not finished and might be super simplified
   // see:
@@ -87,10 +96,10 @@ AutoderefTypeCoercion::do_coercion (TyTy::BaseType *receiver)
   return !try_result.is_error ();
 }
 
-AutoderefTypeCoercion::CoercionResult
-AutoderefTypeCoercion::coerce_unsafe_ptr (TyTy::BaseType *receiver,
-					  TyTy::PointerType *expected,
-					  Mutability to_mutbl)
+TypeCoercionRules::CoercionResult
+TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver,
+				      TyTy::PointerType *expected,
+				      Mutability to_mutbl)
 {
   rust_debug ("coerce_unsafe_ptr(a={%s}, b={%s})",
 	      receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
@@ -115,8 +124,10 @@ AutoderefTypeCoercion::coerce_unsafe_ptr (TyTy::BaseType *receiver,
       break;
 
       default: {
-	TyTy::BaseType *result = receiver->unify (expected);
-	return CoercionResult{{}, result};
+	if (receiver->can_eq (expected, false))
+	  return CoercionResult{{}, expected->clone ()};
+
+	return CoercionResult::get_error ();
       }
     }
 
@@ -125,22 +136,25 @@ AutoderefTypeCoercion::coerce_unsafe_ptr (TyTy::BaseType *receiver,
       Location lhs = mappings->lookup_location (receiver->get_ref ());
       Location rhs = mappings->lookup_location (expected->get_ref ());
       mismatched_mutability_error (locus, lhs, rhs);
-      return AutoderefTypeCoercion::CoercionResult::get_error ();
+      return TypeCoercionRules::CoercionResult::get_error ();
     }
 
   TyTy::PointerType *result
     = new TyTy::PointerType (receiver->get_ref (),
 			     TyTy::TyVar (element->get_ref ()), to_mutbl);
+  if (!result->can_eq (expected, false))
+    return CoercionResult::get_error ();
+
   return CoercionResult{{}, result};
 }
 
 /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
 /// To match `A` with `B`, autoderef will be performed,
 /// calling `deref`/`deref_mut` where necessary.
-AutoderefTypeCoercion::CoercionResult
-AutoderefTypeCoercion::coerce_borrowed_pointer (TyTy::BaseType *receiver,
-						TyTy::ReferenceType *expected,
-						Mutability to_mutbl)
+TypeCoercionRules::CoercionResult
+TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver,
+					    TyTy::ReferenceType *expected,
+					    Mutability to_mutbl)
 {
   rust_debug ("coerce_borrowed_pointer(a={%s}, b={%s})",
 	      receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
@@ -166,7 +180,7 @@ AutoderefTypeCoercion::coerce_borrowed_pointer (TyTy::BaseType *receiver,
       Location lhs = mappings->lookup_location (receiver->get_ref ());
       Location rhs = mappings->lookup_location (expected->get_ref ());
       mismatched_mutability_error (locus, lhs, rhs);
-      return AutoderefTypeCoercion::CoercionResult::get_error ();
+      return TypeCoercionRules::CoercionResult::get_error ();
     }
 
   AutoderefCycle::cycle (receiver);
@@ -176,10 +190,9 @@ AutoderefTypeCoercion::coerce_borrowed_pointer (TyTy::BaseType *receiver,
 // &[T; n] or &mut [T; n] -> &[T]
 // or &mut [T; n] -> &mut [T]
 // or &Concrete -> &Trait, etc.
-AutoderefTypeCoercion::CoercionResult
-AutoderefTypeCoercion::coerce_unsized (TyTy::BaseType *source,
-				       TyTy::BaseType *target,
-				       bool &unsafe_error)
+TypeCoercionRules::CoercionResult
+TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
+				   TyTy::BaseType *target, bool &unsafe_error)
 {
   rust_debug ("coerce_unsized(source={%s}, target={%s})",
 	      source->debug_str ().c_str (), target->debug_str ().c_str ());
@@ -207,7 +220,7 @@ AutoderefTypeCoercion::coerce_unsized (TyTy::BaseType *source,
 	  Location lhs = mappings->lookup_location (source->get_ref ());
 	  Location rhs = mappings->lookup_location (target->get_ref ());
 	  mismatched_mutability_error (locus, lhs, rhs);
-	  return AutoderefTypeCoercion::CoercionResult::get_error ();
+	  return TypeCoercionRules::CoercionResult::get_error ();
 	}
 
       ty_a = source_ref->get_base ();
@@ -232,7 +245,7 @@ AutoderefTypeCoercion::coerce_unsized (TyTy::BaseType *source,
 	  Location lhs = mappings->lookup_location (source->get_ref ());
 	  Location rhs = mappings->lookup_location (target->get_ref ());
 	  mismatched_mutability_error (locus, lhs, rhs);
-	  return AutoderefTypeCoercion::CoercionResult::get_error ();
+	  return TypeCoercionRules::CoercionResult::get_error ();
 	}
 
       ty_a = source_ref->get_base ();
@@ -262,7 +275,7 @@ AutoderefTypeCoercion::coerce_unsized (TyTy::BaseType *source,
       if (!bounds_compatible)
 	{
 	  unsafe_error = true;
-	  return AutoderefTypeCoercion::CoercionResult::get_error ();
+	  return TypeCoercionRules::CoercionResult::get_error ();
 	}
 
       // return the unsize coercion
@@ -291,11 +304,11 @@ AutoderefTypeCoercion::coerce_unsized (TyTy::BaseType *source,
     }
 
   adjustments.clear ();
-  return AutoderefTypeCoercion::CoercionResult::get_error ();
+  return TypeCoercionRules::CoercionResult::get_error ();
 }
 
 bool
-AutoderefTypeCoercion::select (const TyTy::BaseType &autoderefed)
+TypeCoercionRules::select (const TyTy::BaseType &autoderefed)
 {
   if (autoderefed.can_eq (expected, false))
     {
@@ -308,16 +321,19 @@ AutoderefTypeCoercion::select (const TyTy::BaseType &autoderefed)
 /// Coercing a mutable reference to an immutable works, while
 /// coercing `&T` to `&mut T` should be forbidden.
 bool
-AutoderefTypeCoercion::coerceable_mutability (Mutability from_mutbl,
-					      Mutability to_mutbl)
+TypeCoercionRules::coerceable_mutability (Mutability from_mutbl,
+					  Mutability to_mutbl)
 {
   return to_mutbl == Mutability::Imm || (from_mutbl == to_mutbl);
 }
 
 void
-AutoderefTypeCoercion::mismatched_mutability_error (Location expr_locus,
-						    Location lhs, Location rhs)
+TypeCoercionRules::mismatched_mutability_error (Location expr_locus,
+						Location lhs, Location rhs)
 {
+  if (!emit_errors)
+    return;
+
   RichLocation r (expr_locus);
   r.add_range (lhs);
   r.add_range (rhs);
@@ -325,9 +341,12 @@ AutoderefTypeCoercion::mismatched_mutability_error (Location expr_locus,
 }
 
 void
-AutoderefTypeCoercion::object_unsafe_error (Location expr_locus, Location lhs,
-					    Location rhs)
+TypeCoercionRules::object_unsafe_error (Location expr_locus, Location lhs,
+					Location rhs)
 {
+  if (!emit_errors)
+    return;
+
   RichLocation r (expr_locus);
   r.add_range (lhs);
   r.add_range (rhs);
diff --git a/gcc/rust/typecheck/rust-coercion.h b/gcc/rust/typecheck/rust-coercion.h
index f2f440afd8b..da28c7c5e1b 100644
--- a/gcc/rust/typecheck/rust-coercion.h
+++ b/gcc/rust/typecheck/rust-coercion.h
@@ -25,7 +25,7 @@
 namespace Rust {
 namespace Resolver {
 
-class AutoderefTypeCoercion : protected AutoderefCycle
+class TypeCoercionRules : protected AutoderefCycle
 {
 public:
   struct CoercionResult
@@ -44,6 +44,9 @@ public:
   static CoercionResult Coerce (TyTy::BaseType *receiver,
 				TyTy::BaseType *expected, Location locus);
 
+  static CoercionResult TryCoerce (TyTy::BaseType *receiver,
+				   TyTy::BaseType *expected, Location locus);
+
   CoercionResult coerce_unsafe_ptr (TyTy::BaseType *receiver,
 				    TyTy::PointerType *expected,
 				    Mutability mutability);
@@ -58,13 +61,13 @@ public:
   static bool coerceable_mutability (Mutability from_mutbl,
 				     Mutability to_mutbl);
 
-  static void mismatched_mutability_error (Location expr_locus, Location lhs,
-					   Location rhs);
-  static void object_unsafe_error (Location expr_locus, Location lhs,
-				   Location rhs);
+  void mismatched_mutability_error (Location expr_locus, Location lhs,
+				    Location rhs);
+  void object_unsafe_error (Location expr_locus, Location lhs, Location rhs);
 
 protected:
-  AutoderefTypeCoercion (TyTy::BaseType *expected, Location locus);
+  TypeCoercionRules (TyTy::BaseType *expected, Location locus,
+		     bool emit_errors);
 
   bool select (const TyTy::BaseType &autoderefed) override;
 
@@ -81,6 +84,7 @@ private:
 
   // mutable fields
   CoercionResult try_result;
+  bool emit_errors;
 };
 
 } // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index f7b21ea60d9..ac5c3b97475 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -20,6 +20,7 @@
 #include "rust-hir-type-check-type.h"
 #include "rust-hir-type-check-expr.h"
 #include "rust-coercion.h"
+#include "rust-casts.h"
 
 namespace Rust {
 namespace Resolver {
@@ -343,7 +344,7 @@ TypeCheckBase::coercion_site (HirId id, TyTy::BaseType *expected,
     return expr;
 
   // can we autoderef it?
-  auto result = AutoderefTypeCoercion::Coerce (expr, expected, locus);
+  auto result = TypeCoercionRules::Coerce (expr, expected, locus);
 
   // the result needs to be unified
   TyTy::BaseType *receiver = expr;
@@ -359,6 +360,36 @@ TypeCheckBase::coercion_site (HirId id, TyTy::BaseType *expected,
   return coerced;
 }
 
+TyTy::BaseType *
+TypeCheckBase::cast_site (HirId id, TyTy::TyWithLocation from,
+			  TyTy::TyWithLocation to, Location cast_locus)
+{
+  rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
+	      from.get_ty ()->debug_str ().c_str (),
+	      to.get_ty ()->debug_str ().c_str ());
+
+  auto context = TypeCheckContext::get ();
+  if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
+      || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
+    return to.get_ty ();
+
+  // do the cast
+  auto result = TypeCastRules::resolve (cast_locus, from, to);
+
+  // we assume error has already been emitted
+  if (result.is_error ())
+    return to.get_ty ();
+
+  // the result needs to be unified
+  TyTy::BaseType *casted_result = result.tyty;
+  rust_debug ("cast_default_unify(a={%s}, b={%s})",
+	      casted_result->debug_str ().c_str (),
+	      to.get_ty ()->debug_str ().c_str ());
+  TyTy::BaseType *casted = to.get_ty ()->unify (casted_result);
+  context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
+  return casted;
+}
+
 void
 TypeCheckBase::resolve_generic_params (
   const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h
index 449ff6ab92a..aa42d9d6dfd 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.h
@@ -36,7 +36,12 @@ public:
   virtual ~TypeCheckBase () {}
 
   static TyTy::BaseType *coercion_site (HirId id, TyTy::BaseType *lhs,
-					TyTy::BaseType *rhs, Location locus);
+					TyTy::BaseType *rhs,
+					Location coercion_locus);
+
+  static TyTy::BaseType *cast_site (HirId id, TyTy::TyWithLocation from,
+				    TyTy::TyWithLocation to,
+				    Location cast_locus);
 
 protected:
   TypeCheckBase ()
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 6d8bbda428c..4371f5a59a5 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -296,8 +296,12 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
   switch (expr.get_expr_type ())
     {
     case ArithmeticOrLogicalOperator::LEFT_SHIFT:
-    case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
-      infered = rhs->cast (lhs);
+      case ArithmeticOrLogicalOperator::RIGHT_SHIFT: {
+	TyTy::TyWithLocation from (rhs, expr.get_rhs ()->get_locus ());
+	TyTy::TyWithLocation to (lhs, expr.get_lhs ()->get_locus ());
+	infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
+			     expr.get_locus ());
+      }
       break;
 
     default:
@@ -1264,7 +1268,12 @@ TypeCheckExpr::visit (HIR::TypeCastExpr &expr)
   TyTy::BaseType *tyty_to_convert_to
     = TypeCheckType::Resolve (expr.get_type_to_convert_to ().get ());
 
-  infered = expr_to_convert->cast (tyty_to_convert_to);
+  TyTy::TyWithLocation from (expr_to_convert,
+			     expr.get_casted_expr ()->get_locus ());
+  TyTy::TyWithLocation to (tyty_to_convert_to,
+			   expr.get_type_to_convert_to ()->get_locus ());
+  infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
+		       expr.get_locus ());
 }
 
 void
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index 07c7a5cf60b..21694dd302b 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -282,6 +282,25 @@ public:
     return true;
   }
 
+  void insert_cast_autoderef_mappings (HirId id,
+				       std::vector<Adjustment> &&adjustments)
+  {
+    rust_assert (cast_autoderef_mappings.find (id)
+		 == cast_autoderef_mappings.end ());
+    cast_autoderef_mappings.emplace (id, std::move (adjustments));
+  }
+
+  bool lookup_cast_autoderef_mappings (HirId id,
+				       std::vector<Adjustment> **adjustments)
+  {
+    auto it = cast_autoderef_mappings.find (id);
+    if (it == cast_autoderef_mappings.end ())
+      return false;
+
+    *adjustments = &it->second;
+    return true;
+  }
+
   void insert_variant_definition (HirId id, HirId variant)
   {
     auto it = variants.find (id);
@@ -339,6 +358,7 @@ private:
 
   // adjustment mappings
   std::map<HirId, std::vector<Adjustment>> autoderef_mappings;
+  std::map<HirId, std::vector<Adjustment>> cast_autoderef_mappings;
 
   // operator overloads
   std::map<HirId, TyTy::FnType *> operator_overloads;
diff --git a/gcc/rust/typecheck/rust-tyty-cast.h b/gcc/rust/typecheck/rust-tyty-cast.h
deleted file mode 100644
index 5ca68d07aa2..00000000000
--- a/gcc/rust/typecheck/rust-tyty-cast.h
+++ /dev/null
@@ -1,1425 +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_CAST_RULES
-#define RUST_TYTY_CAST_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"
-
-extern ::Backend *
-rust_get_backend ();
-
-namespace Rust {
-namespace TyTy {
-
-class BaseCastRules : public TyVisitor
-{
-public:
-  virtual ~BaseCastRules () {}
-
-  virtual BaseType *cast (BaseType *other)
-  {
-    if (other->get_kind () == TypeKind::PARAM)
-      {
-	ParamType *p = static_cast<ParamType *> (other);
-	if (p->can_resolve ())
-	  {
-	    other = p->resolve ();
-	  }
-      }
-
-    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);
-
-    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 &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (ADTType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (InferType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (FnType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (FnPtr &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (ArrayType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (SliceType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (BoolType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (IntType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (UintType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (USizeType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (ISizeType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (FloatType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (ErrorType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (CharType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (ReferenceType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (PointerType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (ParamType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (StrType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (NeverType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (PlaceholderType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (ProjectionType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (DynamicObjectType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-  virtual void visit (ClosureType &type) override
-  {
-    Location ref_locus = mappings->lookup_location (type.get_ref ());
-    Location base_locus = mappings->lookup_location (get_base ()->get_ref ());
-    RichLocation r (ref_locus);
-    r.add_range (base_locus);
-    rust_error_at (r, "invalid cast [%s] to [%s]",
-		   get_base ()->as_string ().c_str (),
-		   type.as_string ().c_str ());
-  }
-
-protected:
-  BaseCastRules (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 InferCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  InferCastRules (InferType *base) : BaseCastRules (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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::visit (type);
-  }
-
-  void visit (FloatType &type) override
-  {
-    bool is_valid
-      = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL)
-	|| (base->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT);
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-	}
-
-      BaseCastRules::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;
-      }
-
-    BaseCastRules::visit (type);
-  }
-
-  void visit (PointerType &type) override
-  {
-    bool is_general_infer_var
-      = base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL;
-    bool is_integral_infer_var
-      = base->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL;
-    bool is_valid = is_general_infer_var || is_integral_infer_var;
-    if (is_valid)
-      {
-	resolved = type.clone ();
-	return;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::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;
-      }
-
-    BaseCastRules::visit (type);
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  InferType *base;
-};
-
-class FnCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  FnCastRules (FnType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (FnType &type) override
-  {
-    if (base->num_params () != type.num_params ())
-      {
-	BaseCastRules::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)
-	  {
-	    BaseCastRules::visit (type);
-	    return;
-	  }
-      }
-
-    auto unified_return
-      = base->get_return_type ()->unify (type.get_return_type ());
-    if (unified_return == nullptr)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  FnType *base;
-};
-
-class FnptrCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  FnptrCastRules (FnPtr *base) : BaseCastRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseCastRules::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)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    if (base->num_params () != type.num_params ())
-      {
-	BaseCastRules::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)
-	  {
-	    BaseCastRules::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)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    if (base->num_params () != type.num_params ())
-      {
-	BaseCastRules::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)
-	  {
-	    BaseCastRules::visit (type);
-	    return;
-	  }
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  FnPtr *base;
-};
-
-class ClosureCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  ClosureCastRules (ClosureType *base) : BaseCastRules (base), base (base) {}
-
-  // TODO
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ClosureType *base;
-};
-
-class ArrayCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  ArrayCastRules (ArrayType *base) : BaseCastRules (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)
-      {
-	BaseCastRules::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 ()));
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ArrayType *base;
-};
-
-class SliceCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  SliceCastRules (SliceType *base) : BaseCastRules (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)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = new SliceType (type.get_ref (), type.get_ty_ref (),
-			      type.get_ident ().locus,
-			      TyVar (base_resolved->get_ref ()));
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  SliceType *base;
-};
-
-class BoolCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  BoolCastRules (BoolType *base) : BaseCastRules (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:
-	BaseCastRules::visit (type);
-	break;
-      }
-  }
-
-  /* bools can be cast to any integer type (but not floats or chars).  */
-  void visit (IntType &type) override { resolved = type.clone (); }
-  void visit (UintType &type) override { resolved = type.clone (); }
-  void visit (USizeType &type) override { resolved = type.clone (); }
-  void visit (ISizeType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  BoolType *base;
-};
-
-class IntCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  IntCastRules (IntType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    // cant assign a float inference variable
-    if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (IntType &type) override { resolved = type.clone (); }
-
-  void visit (UintType &type) override { resolved = type.clone (); }
-
-  void visit (FloatType &type) override { resolved = type.clone (); }
-
-  void visit (USizeType &type) override { resolved = type.clone (); }
-
-  void visit (ISizeType &type) override { resolved = type.clone (); }
-
-  void visit (PointerType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  IntType *base;
-};
-
-class UintCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  UintCastRules (UintType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    // cant assign a float inference variable
-    if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (IntType &type) override { resolved = type.clone (); }
-
-  void visit (UintType &type) override { resolved = type.clone (); }
-
-  void visit (FloatType &type) override { resolved = type.clone (); }
-
-  void visit (USizeType &type) override { resolved = type.clone (); }
-
-  void visit (ISizeType &type) override { resolved = type.clone (); }
-
-  void visit (PointerType &type) override { resolved = type.clone (); }
-
-  void visit (CharType &type) override
-  {
-    // error[E0604]: only `u8` can be cast as `char`, not `i32`
-    if (base->get_uint_kind () != UintType::UintKind::U8)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = type.clone ();
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  UintType *base;
-};
-
-class FloatCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  FloatCastRules (FloatType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (IntType &type) override { resolved = type.clone (); }
-
-  void visit (UintType &type) override { resolved = type.clone (); }
-
-  void visit (FloatType &type) override { resolved = type.clone (); }
-
-  void visit (USizeType &type) override { resolved = type.clone (); }
-
-  void visit (ISizeType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  FloatType *base;
-};
-
-class ADTCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  ADTCastRules (ADTType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (ADTType &type) override
-  {
-    if (base->get_adt_kind () != type.get_adt_kind ())
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    if (base->get_identifier ().compare (type.get_identifier ()) != 0)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    if (base->number_of_variants () != type.number_of_variants ())
-      {
-	BaseCastRules::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 ())
-	  {
-	    BaseCastRules::visit (type);
-	    return;
-	  }
-
-	for (size_t j = 0; j < a->num_fields (); j++)
-	  {
-	    TyTy::StructFieldType *base_field = a->get_field_at_index (i);
-	    TyTy::StructFieldType *other_field = b->get_field_at_index (i);
-
-	    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;
-	  }
-      }
-
-    resolved = type.clone ();
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ADTType *base;
-};
-
-class TupleCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  TupleCastRules (TupleType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (TupleType &type) override
-  {
-    if (base->num_fields () != type.num_fields ())
-      {
-	BaseCastRules::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);
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  TupleType *base;
-};
-
-class USizeCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  USizeCastRules (USizeType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    // cant assign a float inference variable
-    if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (IntType &type) override { resolved = type.clone (); }
-
-  void visit (UintType &type) override { resolved = type.clone (); }
-
-  void visit (FloatType &type) override { resolved = type.clone (); }
-
-  void visit (USizeType &type) override { resolved = type.clone (); }
-
-  void visit (ISizeType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  USizeType *base;
-};
-
-class ISizeCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  ISizeCastRules (ISizeType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    // cant assign a float inference variable
-    if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (IntType &type) override { resolved = type.clone (); }
-
-  void visit (UintType &type) override { resolved = type.clone (); }
-
-  void visit (FloatType &type) override { resolved = type.clone (); }
-
-  void visit (USizeType &type) override { resolved = type.clone (); }
-
-  void visit (ISizeType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ISizeType *base;
-};
-
-class CharCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  CharCastRules (CharType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-    resolved->set_ref (type.get_ref ());
-  }
-
-  void visit (CharType &type) override { resolved = type.clone (); }
-
-  /* chars can be cast to any integer type (but not floats or bools).  */
-  void visit (IntType &type) override { resolved = type.clone (); }
-  void visit (UintType &type) override { resolved = type.clone (); }
-  void visit (USizeType &type) override { resolved = type.clone (); }
-  void visit (ISizeType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  CharType *base;
-};
-
-class ReferenceCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  ReferenceCastRules (ReferenceType *base) : BaseCastRules (base), base (base)
-  {}
-
-  void visit (ReferenceType &type) override { resolved = type.clone (); }
-
-  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)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = type.clone ();
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ReferenceType *base;
-};
-
-class PointerCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  PointerCastRules (PointerType *base) : BaseCastRules (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)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = type.clone ();
-  }
-
-  void visit (PointerType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  PointerType *base;
-};
-
-class ParamCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  ParamCastRules (ParamType *base) : BaseCastRules (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 *cast (BaseType *other) override final
-  {
-    if (base->get_ref () == base->get_ty_ref ())
-      return BaseCastRules::cast (other);
-
-    auto context = Resolver::TypeCheckContext::get ();
-    BaseType *lookup = nullptr;
-    bool ok = context->lookup_type (base->get_ty_ref (), &lookup);
-    rust_assert (ok);
-
-    return lookup->unify (other);
-  }
-
-  void visit (ParamType &type) override
-  {
-    if (base->get_symbol ().compare (type.get_symbol ()) != 0)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = type.clone ();
-  }
-
-  void visit (InferType &type) override
-  {
-    if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
-      {
-	BaseCastRules::visit (type);
-	return;
-      }
-
-    resolved = base->clone ();
-  }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  ParamType *base;
-};
-
-class StrCastRules : public BaseCastRules
-{
-  // FIXME we will need a enum for the StrType like ByteBuf etc..
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  StrCastRules (StrType *base) : BaseCastRules (base), base (base) {}
-
-  void visit (StrType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  StrType *base;
-};
-
-class NeverCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  NeverCastRules (NeverType *base) : BaseCastRules (base), base (base) {}
-
-  virtual void visit (NeverType &type) override { resolved = type.clone (); }
-
-private:
-  BaseType *get_base () override { return base; }
-
-  NeverType *base;
-};
-
-class PlaceholderCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  PlaceholderCastRules (PlaceholderType *base)
-    : BaseCastRules (base), base (base)
-  {}
-
-private:
-  BaseType *get_base () override { return base; }
-
-  PlaceholderType *base;
-};
-
-class DynamicCastRules : public BaseCastRules
-{
-  using Rust::TyTy::BaseCastRules::visit;
-
-public:
-  DynamicCastRules (DynamicObjectType *base) : BaseCastRules (base), base (base)
-  {}
-
-private:
-  BaseType *get_base () override { return base; }
-
-  DynamicObjectType *base;
-};
-
-} // namespace TyTy
-} // namespace Rust
-
-#endif // RUST_TYTY_CAST_RULES
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 24969dbdac6..3c2c6786940 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -23,7 +23,6 @@
 #include "rust-hir-type-check-type.h"
 #include "rust-tyty-rules.h"
 #include "rust-tyty-cmp.h"
-#include "rust-tyty-cast.h"
 #include "rust-hir-map.h"
 #include "rust-substitution-mapper.h"
 #include "rust-hir-trait-ref.h"
@@ -376,6 +375,16 @@ TyVar::monomorphized_clone () const
   return TyVar (c->get_ref ());
 }
 
+TyWithLocation::TyWithLocation (BaseType *ty, Location locus)
+  : ty (ty), locus (locus)
+{}
+
+TyWithLocation::TyWithLocation (BaseType *ty) : ty (ty)
+{
+  auto mappings = Analysis::Mappings::get ();
+  locus = mappings->lookup_location (ty->get_ref ());
+}
+
 void
 InferType::accept_vis (TyVisitor &vis)
 {
@@ -417,13 +426,6 @@ InferType::can_eq (const BaseType *other, bool emit_errors) const
   return r.can_eq (other);
 }
 
-BaseType *
-InferType::cast (BaseType *other)
-{
-  InferCastRules r (this);
-  return r.cast (other);
-}
-
 BaseType *
 InferType::clone () const
 {
@@ -518,12 +520,6 @@ ErrorType::can_eq (const BaseType *other, bool emit_errors) const
   return get_kind () == other->get_kind ();
 }
 
-BaseType *
-ErrorType::cast (BaseType *other)
-{
-  return this;
-}
-
 BaseType *
 ErrorType::clone () const
 {
@@ -984,13 +980,6 @@ ADTType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-ADTType::cast (BaseType *other)
-{
-  ADTCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 ADTType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1191,13 +1180,6 @@ TupleType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-TupleType::cast (BaseType *other)
-{
-  TupleCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 TupleType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1305,13 +1287,6 @@ FnType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-FnType::cast (BaseType *other)
-{
-  FnCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 FnType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1543,13 +1518,6 @@ FnPtr::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-FnPtr::cast (BaseType *other)
-{
-  FnptrCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 FnPtr::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1636,14 +1604,6 @@ ClosureType::can_eq (const BaseType *other, bool emit_errors) const
   return r.can_eq (other);
 }
 
-BaseType *
-ClosureType::cast (BaseType *other)
-{
-  // FIXME
-  gcc_unreachable ();
-  return nullptr;
-}
-
 bool
 ClosureType::is_equal (const BaseType &other) const
 {
@@ -1696,13 +1656,6 @@ ArrayType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-ArrayType::cast (BaseType *other)
-{
-  ArrayCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 ArrayType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1786,13 +1739,6 @@ SliceType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-SliceType::cast (BaseType *other)
-{
-  SliceCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 SliceType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1876,13 +1822,6 @@ BoolType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-BoolType::cast (BaseType *other)
-{
-  BoolCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 BoolType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -1941,13 +1880,6 @@ IntType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-IntType::cast (BaseType *other)
-{
-  IntCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 IntType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2017,13 +1949,6 @@ UintType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-UintType::cast (BaseType *other)
-{
-  UintCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 UintType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2087,13 +2012,6 @@ FloatType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-FloatType::cast (BaseType *other)
-{
-  FloatCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 FloatType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2149,13 +2067,6 @@ USizeType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-USizeType::cast (BaseType *other)
-{
-  USizeCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 USizeType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2200,13 +2111,6 @@ ISizeType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-ISizeType::cast (BaseType *other)
-{
-  ISizeCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 ISizeType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2251,13 +2155,6 @@ CharType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-CharType::cast (BaseType *other)
-{
-  CharCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 CharType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2303,13 +2200,6 @@ ReferenceType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-ReferenceType::cast (BaseType *other)
-{
-  ReferenceCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 ReferenceType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2393,13 +2283,6 @@ PointerType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-PointerType::cast (BaseType *other)
-{
-  PointerCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 PointerType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2497,13 +2380,6 @@ ParamType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-ParamType::cast (BaseType *other)
-{
-  ParamCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 ParamType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2636,13 +2512,6 @@ StrType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-StrType::cast (BaseType *other)
-{
-  StrCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 StrType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2681,13 +2550,6 @@ NeverType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-NeverType::cast (BaseType *other)
-{
-  NeverCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 NeverType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2735,13 +2597,6 @@ PlaceholderType::unify (BaseType *other)
   return r.unify (other);
 }
 
-BaseType *
-PlaceholderType::cast (BaseType *other)
-{
-  PlaceholderCastRules r (this);
-  return r.cast (other);
-}
-
 bool
 PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2839,12 +2694,6 @@ ProjectionType::unify (BaseType *other)
   return base->unify (other);
 }
 
-BaseType *
-ProjectionType::cast (BaseType *other)
-{
-  return base->cast (other);
-}
-
 bool
 ProjectionType::can_eq (const BaseType *other, bool emit_errors) const
 {
@@ -2969,13 +2818,6 @@ DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const
   return r.can_eq (other);
 }
 
-BaseType *
-DynamicObjectType::cast (BaseType *other)
-{
-  DynamicCastRules r (this);
-  return r.cast (other);
-}
-
 BaseType *
 DynamicObjectType::clone () const
 {
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 56a0e05cd94..c47921d44d7 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -180,9 +180,6 @@ public:
   // checks
   virtual bool can_eq (const BaseType *other, bool emit_errors) const = 0;
 
-  // this is the cast interface for TypeCastExpr
-  virtual BaseType *cast (BaseType *other) = 0;
-
   // Check value equality between two ty. Type inference rules are ignored. Two
   //   ty are considered equal if they're of the same kind, and
   //     1. (For ADTs, arrays, tuples, refs) have the same underlying ty
@@ -314,6 +311,20 @@ private:
   HirId ref;
 };
 
+class TyWithLocation
+{
+public:
+  TyWithLocation (BaseType *ty, Location locus);
+  TyWithLocation (BaseType *ty);
+
+  BaseType *get_ty () const { return ty; }
+  Location get_locus () const { return locus; }
+
+private:
+  BaseType *ty;
+  Location locus;
+};
+
 class InferType : public BaseType
 {
 public:
@@ -347,8 +358,6 @@ public:
 
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
 
@@ -387,8 +396,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
 
@@ -431,8 +438,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
 
@@ -531,8 +536,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   size_t num_fields () const { return fields.size (); }
@@ -1360,8 +1363,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   std::string get_identifier () const { return identifier; }
@@ -1497,8 +1498,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   size_t num_params () const { return params.size (); }
@@ -1619,8 +1618,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   BaseType *clone () const final override;
@@ -1693,8 +1690,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   BaseType *clone () const final override;
@@ -1759,8 +1754,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   BaseType *get_element_type () const;
@@ -1809,8 +1802,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   BaseType *get_element_type () const;
@@ -1856,8 +1847,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
   bool is_concrete () const override final { return true; }
@@ -1902,8 +1891,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   IntKind get_int_kind () const { return int_kind; }
 
   BaseType *clone () const final override;
@@ -1955,8 +1942,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   UintKind get_uint_kind () const { return uint_kind; }
 
   BaseType *clone () const final override;
@@ -2006,8 +1991,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   FloatKind get_float_kind () const { return float_kind; }
 
   BaseType *clone () const final override;
@@ -2047,8 +2030,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
   bool is_concrete () const override final { return true; }
@@ -2081,8 +2062,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
   bool is_concrete () const override final { return true; }
@@ -2115,8 +2094,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
   bool is_concrete () const override final { return true; }
@@ -2149,8 +2126,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   BaseType *clone () const final override;
@@ -2194,8 +2169,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   BaseType *clone () const final override;
@@ -2282,8 +2255,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   bool is_equal (const BaseType &other) const override;
 
   BaseType *clone () const final override;
@@ -2371,8 +2342,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
 
@@ -2413,8 +2382,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
 
@@ -2489,8 +2456,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
-
   BaseType *clone () const final override;
   BaseType *monomorphized_clone () const final override;
 
@@ -2547,7 +2512,6 @@ public:
   BaseType *unify (BaseType *other) override;
   bool can_eq (const BaseType *other, bool emit_errors) const override final;
 
-  BaseType *cast (BaseType *other) override;
   bool is_equal (const BaseType &other) const override;
 
   BaseType *clone () const final override;
diff --git a/gcc/testsuite/rust/execute/torture/issue-1496.rs b/gcc/testsuite/rust/execute/torture/issue-1496.rs
new file mode 100644
index 00000000000..9f08b2ae98a
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/issue-1496.rs
@@ -0,0 +1,75 @@
+/* { dg-output "foo_deref\nimm_deref\n123\n" } */
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+#[lang = "deref"]
+pub trait Deref {
+    type Target;
+
+    fn deref(&self) -> &Self::Target;
+}
+
+impl<T> Deref for &T {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe {
+            let a = "imm_deref\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        }
+
+        *self
+    }
+}
+
+impl<T> Deref for &mut T {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe {
+            let a = "mut_deref\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        }
+
+        *self
+    }
+}
+
+struct Foo<T>(T);
+impl<T> Deref for Foo<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        unsafe {
+            let a = "foo_deref\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        }
+
+        &self.0
+    }
+}
+
+fn main() -> i32 {
+    let foo = Foo(123);
+    let bar = &foo as &i32;
+
+    unsafe {
+        let a = "%i\n\0";
+        let b = a as *const str;
+        let c = b as *const i8;
+
+        printf(c, *bar);
+    }
+
+    0
+}

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

only message in thread, other threads:[~2022-08-29 15:31 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-29 15:31 [gcc/devel/rust/master] Refactor our casts to follow the Rustc implemention 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).