From: herron.philip@googlemail.com
To: gcc-patches@gcc.gnu.org
Cc: gcc-rust@gcc.gnu.org, Philip Herron <philip.herron@embecosm.com>
Subject: [PATCH Rust front-end v2 22/37] gccrs: Add type resolution and trait solving pass
Date: Wed, 24 Aug 2022 12:59:41 +0100 [thread overview]
Message-ID: <20220824115956.737931-23-philip.herron@embecosm.com> (raw)
In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com>
From: Philip Herron <philip.herron@embecosm.com>
TODO
---
gcc/rust/typecheck/rust-autoderef.cc | 398 +++
gcc/rust/typecheck/rust-autoderef.h | 178 +
gcc/rust/typecheck/rust-casts.cc | 292 ++
gcc/rust/typecheck/rust-casts.h | 53 +
gcc/rust/typecheck/rust-coercion.cc | 357 ++
gcc/rust/typecheck/rust-coercion.h | 93 +
gcc/rust/typecheck/rust-hir-dot-operator.cc | 263 ++
gcc/rust/typecheck/rust-hir-dot-operator.h | 81 +
.../rust-hir-inherent-impl-overlap.h | 186 ++
gcc/rust/typecheck/rust-hir-path-probe.h | 540 +++
gcc/rust/typecheck/rust-hir-trait-ref.h | 472 +++
gcc/rust/typecheck/rust-hir-trait-resolve.cc | 599 ++++
gcc/rust/typecheck/rust-hir-trait-resolve.h | 87 +
gcc/rust/typecheck/rust-hir-type-bounds.h | 77 +
.../typecheck/rust-hir-type-check-base.cc | 439 +++
gcc/rust/typecheck/rust-hir-type-check-base.h | 80 +
.../typecheck/rust-hir-type-check-enumitem.cc | 213 ++
.../typecheck/rust-hir-type-check-enumitem.h | 50 +
.../typecheck/rust-hir-type-check-expr.cc | 1567 +++++++++
gcc/rust/typecheck/rust-hir-type-check-expr.h | 131 +
.../typecheck/rust-hir-type-check-implitem.cc | 583 ++++
.../typecheck/rust-hir-type-check-implitem.h | 114 +
.../typecheck/rust-hir-type-check-item.cc | 237 ++
gcc/rust/typecheck/rust-hir-type-check-item.h | 58 +
.../typecheck/rust-hir-type-check-path.cc | 467 +++
.../typecheck/rust-hir-type-check-pattern.cc | 416 +++
.../typecheck/rust-hir-type-check-pattern.h | 62 +
.../typecheck/rust-hir-type-check-stmt.cc | 498 +++
gcc/rust/typecheck/rust-hir-type-check-stmt.h | 96 +
.../rust-hir-type-check-struct-field.h | 59 +
.../typecheck/rust-hir-type-check-struct.cc | 340 ++
.../typecheck/rust-hir-type-check-toplevel.cc | 364 +++
.../typecheck/rust-hir-type-check-toplevel.h | 56 +
.../typecheck/rust-hir-type-check-type.cc | 838 +++++
gcc/rust/typecheck/rust-hir-type-check-type.h | 130 +
.../typecheck/rust-hir-type-check-util.cc | 41 +
gcc/rust/typecheck/rust-hir-type-check-util.h | 50 +
gcc/rust/typecheck/rust-hir-type-check.cc | 295 ++
gcc/rust/typecheck/rust-hir-type-check.h | 379 +++
.../typecheck/rust-substitution-mapper.cc | 77 +
gcc/rust/typecheck/rust-substitution-mapper.h | 394 +++
gcc/rust/typecheck/rust-tycheck-dump.h | 239 ++
gcc/rust/typecheck/rust-tyctx.cc | 155 +
gcc/rust/typecheck/rust-tyty-bounds.cc | 462 +++
gcc/rust/typecheck/rust-tyty-call.cc | 263 ++
gcc/rust/typecheck/rust-tyty-call.h | 147 +
gcc/rust/typecheck/rust-tyty-cmp.h | 1554 +++++++++
gcc/rust/typecheck/rust-tyty-rules.h | 1584 +++++++++
gcc/rust/typecheck/rust-tyty-visitor.h | 88 +
gcc/rust/typecheck/rust-tyty.cc | 2885 +++++++++++++++++
gcc/rust/typecheck/rust-tyty.h | 2533 +++++++++++++++
51 files changed, 21620 insertions(+)
create mode 100644 gcc/rust/typecheck/rust-autoderef.cc
create mode 100644 gcc/rust/typecheck/rust-autoderef.h
create mode 100644 gcc/rust/typecheck/rust-casts.cc
create mode 100644 gcc/rust/typecheck/rust-casts.h
create mode 100644 gcc/rust/typecheck/rust-coercion.cc
create mode 100644 gcc/rust/typecheck/rust-coercion.h
create mode 100644 gcc/rust/typecheck/rust-hir-dot-operator.cc
create mode 100644 gcc/rust/typecheck/rust-hir-dot-operator.h
create mode 100644 gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
create mode 100644 gcc/rust/typecheck/rust-hir-path-probe.h
create mode 100644 gcc/rust/typecheck/rust-hir-trait-ref.h
create mode 100644 gcc/rust/typecheck/rust-hir-trait-resolve.cc
create mode 100644 gcc/rust/typecheck/rust-hir-trait-resolve.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-bounds.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-base.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-base.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-enumitem.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-expr.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-expr.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-implitem.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-implitem.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-item.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-item.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-path.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-pattern.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-pattern.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-stmt.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-stmt.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-struct-field.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-struct.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-toplevel.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-toplevel.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-type.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-type.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-util.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check-util.h
create mode 100644 gcc/rust/typecheck/rust-hir-type-check.cc
create mode 100644 gcc/rust/typecheck/rust-hir-type-check.h
create mode 100644 gcc/rust/typecheck/rust-substitution-mapper.cc
create mode 100644 gcc/rust/typecheck/rust-substitution-mapper.h
create mode 100644 gcc/rust/typecheck/rust-tycheck-dump.h
create mode 100644 gcc/rust/typecheck/rust-tyctx.cc
create mode 100644 gcc/rust/typecheck/rust-tyty-bounds.cc
create mode 100644 gcc/rust/typecheck/rust-tyty-call.cc
create mode 100644 gcc/rust/typecheck/rust-tyty-call.h
create mode 100644 gcc/rust/typecheck/rust-tyty-cmp.h
create mode 100644 gcc/rust/typecheck/rust-tyty-rules.h
create mode 100644 gcc/rust/typecheck/rust-tyty-visitor.h
create mode 100644 gcc/rust/typecheck/rust-tyty.cc
create mode 100644 gcc/rust/typecheck/rust-tyty.h
diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc
new file mode 100644
index 00000000000..423f8e4709b
--- /dev/null
+++ b/gcc/rust/typecheck/rust-autoderef.cc
@@ -0,0 +1,398 @@
+// 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-autoderef.h"
+#include "rust-hir-path-probe.h"
+#include "rust-hir-dot-operator.h"
+#include "rust-hir-trait-resolve.h"
+
+namespace Rust {
+namespace Resolver {
+
+static bool
+resolve_operator_overload_fn (
+ Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty,
+ TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
+ Adjustment::AdjustmentType *requires_ref_adjustment);
+
+TyTy::BaseType *
+Adjuster::adjust_type (const std::vector<Adjustment> &adjustments)
+{
+ if (adjustments.size () == 0)
+ return base->clone ();
+
+ return adjustments.back ().get_expected ()->clone ();
+}
+
+Adjustment
+Adjuster::try_deref_type (const TyTy::BaseType *ty,
+ Analysis::RustLangItem::ItemType deref_lang_item)
+{
+ HIR::ImplItem *impl_item = nullptr;
+ TyTy::FnType *fn = nullptr;
+ Adjustment::AdjustmentType requires_ref_adjustment
+ = Adjustment::AdjustmentType::ERROR;
+ bool operator_overloaded
+ = resolve_operator_overload_fn (deref_lang_item, ty, &fn, &impl_item,
+ &requires_ref_adjustment);
+ if (!operator_overloaded)
+ {
+ return Adjustment::get_error ();
+ }
+
+ auto resolved_base = fn->get_return_type ()->clone ();
+ bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF;
+ if (!is_valid_type)
+ return Adjustment::get_error ();
+
+ TyTy::ReferenceType *ref_base
+ = static_cast<TyTy::ReferenceType *> (resolved_base);
+
+ Adjustment::AdjustmentType adjustment_type
+ = Adjustment::AdjustmentType::ERROR;
+ switch (deref_lang_item)
+ {
+ case Analysis::RustLangItem::ItemType::DEREF:
+ adjustment_type = Adjustment::AdjustmentType::DEREF;
+ break;
+
+ case Analysis::RustLangItem::ItemType::DEREF_MUT:
+ adjustment_type = Adjustment::AdjustmentType::DEREF_MUT;
+ break;
+
+ default:
+ break;
+ }
+
+ return Adjustment::get_op_overload_deref_adjustment (adjustment_type, ty,
+ ref_base, fn, impl_item,
+ requires_ref_adjustment);
+}
+
+Adjustment
+Adjuster::try_raw_deref_type (const TyTy::BaseType *ty)
+{
+ bool is_valid_type = ty->get_kind () == TyTy::TypeKind::REF;
+ if (!is_valid_type)
+ return Adjustment::get_error ();
+
+ const TyTy::ReferenceType *ref_base
+ = static_cast<const TyTy::ReferenceType *> (ty);
+ auto infered = ref_base->get_base ()->clone ();
+
+ return Adjustment (Adjustment::AdjustmentType::INDIRECTION, ty, infered);
+}
+
+Adjustment
+Adjuster::try_unsize_type (const TyTy::BaseType *ty)
+{
+ bool is_valid_type = ty->get_kind () == TyTy::TypeKind::ARRAY;
+ if (!is_valid_type)
+ return Adjustment::get_error ();
+
+ auto mappings = Analysis::Mappings::get ();
+ auto context = TypeCheckContext::get ();
+
+ const auto ref_base = static_cast<const TyTy::ArrayType *> (ty);
+ auto slice_elem = ref_base->get_element_type ();
+
+ auto slice
+ = new TyTy::SliceType (mappings->get_next_hir_id (), ty->get_ident ().locus,
+ TyTy::TyVar (slice_elem->get_ref ()));
+ context->insert_implicit_type (slice);
+
+ return Adjustment (Adjustment::AdjustmentType::UNSIZE, ty, slice);
+}
+
+static bool
+resolve_operator_overload_fn (
+ Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty,
+ TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
+ Adjustment::AdjustmentType *requires_ref_adjustment)
+{
+ auto context = TypeCheckContext::get ();
+ auto mappings = Analysis::Mappings::get ();
+
+ // look up lang item for arithmetic type
+ std::string associated_item_name
+ = Analysis::RustLangItem::ToString (lang_item_type);
+ DefId respective_lang_item_id = UNKNOWN_DEFID;
+ bool lang_item_defined
+ = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
+
+ if (!lang_item_defined)
+ return false;
+
+ auto segment = HIR::PathIdentSegment (associated_item_name);
+ auto candidate
+ = MethodResolver::Probe (ty, HIR::PathIdentSegment (associated_item_name),
+ true);
+
+ bool have_implementation_for_lang_item = !candidate.is_error ();
+ if (!have_implementation_for_lang_item)
+ return false;
+
+ // Get the adjusted self
+ Adjuster adj (ty);
+ TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
+
+ // is this the case we are recursive
+ // handle the case where we are within the impl block for this
+ // lang_item otherwise we end up with a recursive operator overload
+ // such as the i32 operator overload trait
+ TypeCheckContextItem &fn_context = context->peek_context ();
+ if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
+ {
+ auto &impl_item = fn_context.get_impl_item ();
+ HIR::ImplBlock *parent = impl_item.first;
+ HIR::Function *fn = impl_item.second;
+
+ if (parent->has_trait_ref ()
+ && fn->get_function_name ().compare (associated_item_name) == 0)
+ {
+ TraitReference *trait_reference
+ = TraitResolver::Lookup (*parent->get_trait_ref ().get ());
+ if (!trait_reference->is_error ())
+ {
+ TyTy::BaseType *lookup = nullptr;
+ bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
+ &lookup);
+ rust_assert (ok);
+ rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+
+ TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
+ rust_assert (fntype->is_method ());
+
+ bool is_lang_item_impl
+ = trait_reference->get_mappings ().get_defid ()
+ == respective_lang_item_id;
+ bool self_is_lang_item_self
+ = fntype->get_self_type ()->is_equal (*adjusted_self);
+ bool recursive_operator_overload
+ = is_lang_item_impl && self_is_lang_item_self;
+
+ if (recursive_operator_overload)
+ return false;
+ }
+ }
+ }
+
+ TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
+
+ // rust only support impl item deref operator overloading ie you must have an
+ // impl block for it
+ rust_assert (candidate.candidate.type
+ == PathProbeCandidate::CandidateType::IMPL_FUNC);
+ *impl_item = candidate.candidate.item.impl.impl_item;
+
+ rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::BaseType *lookup = lookup_tyty;
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
+ rust_assert (fn->is_method ());
+
+ if (fn->needs_substitution ())
+ {
+ if (ty->get_kind () == TyTy::TypeKind::ADT)
+ {
+ const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (ty);
+
+ auto s = fn->get_self_type ()->get_root ();
+ rust_assert (s->can_eq (adt, false));
+ rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
+ const TyTy::ADTType *self_adt
+ = static_cast<const TyTy::ADTType *> (s);
+
+ // we need to grab the Self substitutions as the inherit type
+ // parameters for this
+ if (self_adt->needs_substitution ())
+ {
+ rust_assert (adt->was_substituted ());
+
+ TyTy::SubstitutionArgumentMappings used_args_in_prev_segment
+ = GetUsedSubstArgs::From (adt);
+
+ TyTy::SubstitutionArgumentMappings inherit_type_args
+ = self_adt->solve_mappings_from_receiver_for_self (
+ used_args_in_prev_segment);
+
+ // there may or may not be inherited type arguments
+ if (!inherit_type_args.is_error ())
+ {
+ // need to apply the inherited type arguments to the
+ // function
+ lookup = fn->handle_substitions (inherit_type_args);
+ }
+ }
+ }
+ else
+ {
+ rust_assert (candidate.adjustments.size () < 2);
+
+ // lets infer the params for this we could probably fix this up by
+ // actually just performing a substitution of a single param but this
+ // seems more generic i think.
+ //
+ // this is the case where we had say Foo<&Bar>> and we have derefed to
+ // the &Bar and we are trying to match a method self of Bar which
+ // requires another deref which is matched to the deref trait impl of
+ // &&T so this requires another reference and deref call
+
+ lookup = fn->infer_substitions (Location ());
+ rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+ fn = static_cast<TyTy::FnType *> (lookup);
+ fn->get_self_type ()->unify (adjusted_self);
+ lookup = fn;
+ }
+ }
+
+ if (candidate.adjustments.size () > 0)
+ *requires_ref_adjustment = candidate.adjustments.at (0).get_type ();
+
+ *resolved_fn = static_cast<TyTy::FnType *> (lookup);
+
+ return true;
+}
+
+AutoderefCycle::AutoderefCycle (bool autoderef_flag)
+ : autoderef_flag (autoderef_flag)
+{}
+
+AutoderefCycle::~AutoderefCycle () {}
+
+void
+AutoderefCycle::try_hook (const TyTy::BaseType &)
+{}
+
+bool
+AutoderefCycle::cycle (const TyTy::BaseType *receiver)
+{
+ const TyTy::BaseType *r = receiver;
+ while (true)
+ {
+ if (try_autoderefed (r))
+ return true;
+
+ // 4. deref to to 1, if cannot deref then quit
+ if (autoderef_flag)
+ return false;
+
+ // try unsize
+ Adjustment unsize = Adjuster::try_unsize_type (r);
+ if (!unsize.is_error ())
+ {
+ adjustments.push_back (unsize);
+ auto unsize_r = unsize.get_expected ();
+
+ if (try_autoderefed (unsize_r))
+ return true;
+
+ adjustments.pop_back ();
+ }
+
+ Adjustment deref
+ = Adjuster::try_deref_type (r, Analysis::RustLangItem::ItemType::DEREF);
+ if (!deref.is_error ())
+ {
+ auto deref_r = deref.get_expected ();
+ adjustments.push_back (deref);
+
+ if (try_autoderefed (deref_r))
+ return true;
+
+ adjustments.pop_back ();
+ }
+
+ Adjustment deref_mut = Adjuster::try_deref_type (
+ r, Analysis::RustLangItem::ItemType::DEREF_MUT);
+ if (!deref_mut.is_error ())
+ {
+ auto deref_r = deref_mut.get_expected ();
+ adjustments.push_back (deref_mut);
+
+ if (try_autoderefed (deref_r))
+ return true;
+
+ adjustments.pop_back ();
+ }
+
+ if (!deref_mut.is_error ())
+ {
+ auto deref_r = deref_mut.get_expected ();
+ adjustments.push_back (deref_mut);
+ Adjustment raw_deref = Adjuster::try_raw_deref_type (deref_r);
+ adjustments.push_back (raw_deref);
+ deref_r = raw_deref.get_expected ();
+
+ if (try_autoderefed (deref_r))
+ return true;
+
+ adjustments.pop_back ();
+ adjustments.pop_back ();
+ }
+
+ if (!deref.is_error ())
+ {
+ r = deref.get_expected ();
+ adjustments.push_back (deref);
+ }
+ Adjustment raw_deref = Adjuster::try_raw_deref_type (r);
+ if (raw_deref.is_error ())
+ return false;
+
+ r = raw_deref.get_expected ();
+ adjustments.push_back (raw_deref);
+ }
+ return false;
+}
+
+bool
+AutoderefCycle::try_autoderefed (const TyTy::BaseType *r)
+{
+ try_hook (*r);
+
+ // 1. try raw
+ if (select (*r))
+ return true;
+
+ // 2. try ref
+ TyTy::ReferenceType *r1
+ = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
+ Mutability::Imm);
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::IMM_REF, r, r1));
+ if (select (*r1))
+ return true;
+
+ adjustments.pop_back ();
+
+ // 3. try mut ref
+ TyTy::ReferenceType *r2
+ = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
+ Mutability::Mut);
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::MUT_REF, r, r2));
+ if (select (*r2))
+ return true;
+
+ adjustments.pop_back ();
+
+ return false;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h
new file mode 100644
index 00000000000..2f8d64b97e6
--- /dev/null
+++ b/gcc/rust/typecheck/rust-autoderef.h
@@ -0,0 +1,178 @@
+// 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_AUTODEREF
+#define RUST_AUTODEREF
+
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+class Adjustment
+{
+public:
+ enum AdjustmentType
+ {
+ ERROR,
+
+ IMM_REF,
+ MUT_REF,
+ DEREF,
+ DEREF_MUT,
+ INDIRECTION,
+ UNSIZE,
+ };
+
+ // ctor for all adjustments except derefs
+ Adjustment (AdjustmentType type, const TyTy::BaseType *actual,
+ const TyTy::BaseType *expected)
+ : Adjustment (type, actual, expected, nullptr, nullptr,
+ AdjustmentType::ERROR)
+ {}
+
+ static Adjustment get_op_overload_deref_adjustment (
+ AdjustmentType type, const TyTy::BaseType *actual,
+ const TyTy::BaseType *expected, TyTy::FnType *fn, HIR::ImplItem *deref_item,
+ Adjustment::AdjustmentType requires_ref_adjustment)
+ {
+ rust_assert (type == DEREF || type == DEREF_MUT);
+ return Adjustment (type, actual, expected, fn, deref_item,
+ requires_ref_adjustment);
+ }
+
+ AdjustmentType get_type () const { return type; }
+
+ const TyTy::BaseType *get_actual () const { return actual; }
+ const TyTy::BaseType *get_expected () const { return expected; }
+
+ std::string as_string () const
+ {
+ return Adjustment::type_string (get_type ()) + "->"
+ + get_expected ()->debug_str ();
+ }
+
+ static std::string type_string (AdjustmentType type)
+ {
+ switch (type)
+ {
+ case AdjustmentType::ERROR:
+ return "ERROR";
+ case AdjustmentType::IMM_REF:
+ return "IMM_REF";
+ case AdjustmentType::MUT_REF:
+ return "MUT_REF";
+ case AdjustmentType::DEREF:
+ return "DEREF";
+ case AdjustmentType::DEREF_MUT:
+ return "DEREF_MUT";
+ case AdjustmentType::INDIRECTION:
+ return "INDIRECTION";
+ case AdjustmentType::UNSIZE:
+ return "UNSIZE";
+ }
+ gcc_unreachable ();
+ return "";
+ }
+
+ static Adjustment get_error () { return Adjustment{ERROR, nullptr, nullptr}; }
+
+ bool is_error () const { return type == ERROR; }
+
+ bool is_deref_adjustment () const { return type == DEREF; }
+
+ bool is_deref_mut_adjustment () const { return type == DEREF_MUT; }
+
+ bool has_operator_overload () const { return deref_operator_fn != nullptr; }
+
+ TyTy::FnType *get_deref_operator_fn () const { return deref_operator_fn; }
+
+ AdjustmentType get_deref_adjustment_type () const
+ {
+ return requires_ref_adjustment;
+ }
+
+ HIR::ImplItem *get_deref_hir_item () const { return deref_item; }
+
+private:
+ Adjustment (AdjustmentType type, const TyTy::BaseType *actual,
+ const TyTy::BaseType *expected, TyTy::FnType *deref_operator_fn,
+ HIR::ImplItem *deref_item,
+ Adjustment::AdjustmentType requires_ref_adjustment)
+ : type (type), actual (actual), expected (expected),
+ deref_operator_fn (deref_operator_fn), deref_item (deref_item),
+ requires_ref_adjustment (requires_ref_adjustment)
+ {}
+
+ AdjustmentType type;
+ const TyTy::BaseType *actual;
+ const TyTy::BaseType *expected;
+
+ // - only used for deref operator_overloads
+ //
+ // the fn that we are calling
+ TyTy::FnType *deref_operator_fn;
+ HIR::ImplItem *deref_item;
+ // operator overloads can requre a reference
+ Adjustment::AdjustmentType requires_ref_adjustment;
+};
+
+class Adjuster
+{
+public:
+ Adjuster (const TyTy::BaseType *ty) : base (ty) {}
+
+ TyTy::BaseType *adjust_type (const std::vector<Adjustment> &adjustments);
+
+ static Adjustment
+ try_deref_type (const TyTy::BaseType *ty,
+ Analysis::RustLangItem::ItemType deref_lang_item);
+
+ static Adjustment try_raw_deref_type (const TyTy::BaseType *ty);
+
+ static Adjustment try_unsize_type (const TyTy::BaseType *ty);
+
+private:
+ const TyTy::BaseType *base;
+};
+
+class AutoderefCycle
+{
+protected:
+ AutoderefCycle (bool autoderef_flag);
+
+ virtual ~AutoderefCycle ();
+
+ virtual bool select (const TyTy::BaseType &autoderefed) = 0;
+
+ // optional: this is a chance to hook in to grab predicate items on the raw
+ // type
+ virtual void try_hook (const TyTy::BaseType &);
+
+ virtual bool cycle (const TyTy::BaseType *receiver);
+
+ bool try_autoderefed (const TyTy::BaseType *r);
+
+ bool autoderef_flag;
+ std::vector<Adjustment> adjustments;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AUTODEREF
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
new file mode 100644
index 00000000000..2ad2b8007ff
--- /dev/null
+++ b/gcc/rust/typecheck/rust-coercion.cc
@@ -0,0 +1,357 @@
+// 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-coercion.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCoercionRules::CoercionResult
+TypeCoercionRules::Coerce (TyTy::BaseType *receiver, TyTy::BaseType *expected,
+ Location locus)
+{
+ TypeCoercionRules resolver (expected, locus, true);
+ bool ok = resolver.do_coercion (receiver);
+ return ok ? resolver.try_result : CoercionResult::get_error ();
+}
+
+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 ()), emit_errors (emit_errors)
+{}
+
+bool
+TypeCoercionRules::do_coercion (TyTy::BaseType *receiver)
+{
+ // FIXME this is not finished and might be super simplified
+ // see:
+ // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs
+
+ // unsize
+ bool unsafe_error = false;
+ CoercionResult unsize_coercion
+ = coerce_unsized (receiver, expected, unsafe_error);
+ bool valid_unsize_coercion = !unsize_coercion.is_error ();
+ if (valid_unsize_coercion)
+ {
+ try_result = unsize_coercion;
+ return true;
+ }
+ else if (unsafe_error)
+ {
+ // Location lhs = mappings->lookup_location (receiver->get_ref ());
+ // Location rhs = mappings->lookup_location (expected->get_ref ());
+ // object_unsafe_error (locus, lhs, rhs);
+ return false;
+ }
+
+ // pointers
+ switch (expected->get_kind ())
+ {
+ case TyTy::TypeKind::POINTER: {
+ TyTy::PointerType *ptr = static_cast<TyTy::PointerType *> (expected);
+ try_result = coerce_unsafe_ptr (receiver, ptr, ptr->mutability ());
+ return !try_result.is_error ();
+ }
+
+ case TyTy::TypeKind::REF: {
+ TyTy::ReferenceType *ptr
+ = static_cast<TyTy::ReferenceType *> (expected);
+ try_result
+ = coerce_borrowed_pointer (receiver, ptr, ptr->mutability ());
+ return !try_result.is_error ();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return !try_result.is_error ();
+}
+
+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 ());
+
+ Mutability from_mutbl = Mutability::Imm;
+ TyTy::BaseType *element = nullptr;
+ switch (receiver->get_kind ())
+ {
+ case TyTy::TypeKind::REF: {
+ TyTy::ReferenceType *ref
+ = static_cast<TyTy::ReferenceType *> (receiver);
+ from_mutbl = ref->mutability ();
+ element = ref->get_base ();
+ }
+ break;
+
+ case TyTy::TypeKind::POINTER: {
+ TyTy::PointerType *ref = static_cast<TyTy::PointerType *> (receiver);
+ from_mutbl = ref->mutability ();
+ element = ref->get_base ();
+ }
+ break;
+
+ default: {
+ if (receiver->can_eq (expected, false))
+ return CoercionResult{{}, expected->clone ()};
+
+ return CoercionResult::get_error ();
+ }
+ }
+
+ if (!coerceable_mutability (from_mutbl, to_mutbl))
+ {
+ Location lhs = mappings->lookup_location (receiver->get_ref ());
+ Location rhs = mappings->lookup_location (expected->get_ref ());
+ mismatched_mutability_error (locus, lhs, rhs);
+ 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.
+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 ());
+
+ Mutability from_mutbl = Mutability::Imm;
+ switch (receiver->get_kind ())
+ {
+ case TyTy::TypeKind::REF: {
+ TyTy::ReferenceType *ref
+ = static_cast<TyTy::ReferenceType *> (receiver);
+ from_mutbl = ref->mutability ();
+ }
+ break;
+
+ default: {
+ TyTy::BaseType *result = receiver->unify (expected);
+ return CoercionResult{{}, result};
+ }
+ }
+
+ if (!coerceable_mutability (from_mutbl, to_mutbl))
+ {
+ Location lhs = mappings->lookup_location (receiver->get_ref ());
+ Location rhs = mappings->lookup_location (expected->get_ref ());
+ mismatched_mutability_error (locus, lhs, rhs);
+ return TypeCoercionRules::CoercionResult::get_error ();
+ }
+
+ AutoderefCycle::cycle (receiver);
+ return try_result;
+}
+
+// &[T; n] or &mut [T; n] -> &[T]
+// or &mut [T; n] -> &mut [T]
+// or &Concrete -> &Trait, etc.
+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 ());
+
+ bool source_is_ref = source->get_kind () == TyTy::TypeKind::REF;
+ bool target_is_ref = target->get_kind () == TyTy::TypeKind::REF;
+ bool target_is_ptr = target->get_kind () == TyTy::TypeKind::POINTER;
+
+ bool needs_reborrow = false;
+ TyTy::BaseType *ty_a = source;
+ TyTy::BaseType *ty_b = target;
+ Mutability expected_mutability = Mutability::Imm;
+ if (source_is_ref && target_is_ref)
+ {
+ TyTy::ReferenceType *source_ref
+ = static_cast<TyTy::ReferenceType *> (source);
+ TyTy::ReferenceType *target_ref
+ = static_cast<TyTy::ReferenceType *> (target);
+
+ Mutability from_mutbl = source_ref->mutability ();
+ Mutability to_mutbl = target_ref->mutability ();
+ if (!coerceable_mutability (from_mutbl, to_mutbl))
+ {
+ unsafe_error = true;
+ Location lhs = mappings->lookup_location (source->get_ref ());
+ Location rhs = mappings->lookup_location (target->get_ref ());
+ mismatched_mutability_error (locus, lhs, rhs);
+ return TypeCoercionRules::CoercionResult::get_error ();
+ }
+
+ ty_a = source_ref->get_base ();
+ ty_b = target_ref->get_base ();
+ needs_reborrow = true;
+ expected_mutability = to_mutbl;
+
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::INDIRECTION, source_ref, ty_a));
+ }
+ else if (source_is_ref && target_is_ptr)
+ {
+ TyTy::ReferenceType *source_ref
+ = static_cast<TyTy::ReferenceType *> (source);
+ TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> (target);
+
+ Mutability from_mutbl = source_ref->mutability ();
+ Mutability to_mutbl = target_ref->mutability ();
+ if (!coerceable_mutability (from_mutbl, to_mutbl))
+ {
+ unsafe_error = true;
+ Location lhs = mappings->lookup_location (source->get_ref ());
+ Location rhs = mappings->lookup_location (target->get_ref ());
+ mismatched_mutability_error (locus, lhs, rhs);
+ return TypeCoercionRules::CoercionResult::get_error ();
+ }
+
+ ty_a = source_ref->get_base ();
+ ty_b = target_ref->get_base ();
+ needs_reborrow = true;
+ expected_mutability = to_mutbl;
+
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::INDIRECTION, source_ref, ty_a));
+ }
+
+ // FIXME
+ // there is a bunch of code to ensure something is coerce able to a dyn trait
+ // we need to support but we need to support a few more lang items for that
+ // see:
+ // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L582
+
+ const auto a = ty_a;
+ const auto b = ty_b;
+
+ bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC;
+ bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC;
+
+ if (expect_dyn && need_unsize)
+ {
+ bool bounds_compatible = b->bounds_compatible (*a, locus, true);
+ if (!bounds_compatible)
+ {
+ unsafe_error = true;
+ return TypeCoercionRules::CoercionResult::get_error ();
+ }
+
+ // return the unsize coercion
+ TyTy::BaseType *result = b->clone ();
+ // result->set_ref (a->get_ref ());
+
+ // append a dyn coercion adjustment
+ adjustments.push_back (Adjustment (Adjustment::UNSIZE, a, result));
+
+ // reborrow if needed
+ if (needs_reborrow)
+ {
+ TyTy::ReferenceType *reborrow
+ = new TyTy::ReferenceType (source->get_ref (),
+ TyTy::TyVar (result->get_ref ()),
+ expected_mutability);
+
+ Adjustment::AdjustmentType borrow_type
+ = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF
+ : Adjustment::MUT_REF;
+ adjustments.push_back (Adjustment (borrow_type, result, reborrow));
+ result = reborrow;
+ }
+
+ return CoercionResult{adjustments, result};
+ }
+
+ adjustments.clear ();
+ return TypeCoercionRules::CoercionResult::get_error ();
+}
+
+bool
+TypeCoercionRules::select (const TyTy::BaseType &autoderefed)
+{
+ if (autoderefed.can_eq (expected, false))
+ {
+ try_result = CoercionResult{adjustments, autoderefed.clone ()};
+ return true;
+ }
+ return false;
+}
+
+/// Coercing a mutable reference to an immutable works, while
+/// coercing `&T` to `&mut T` should be forbidden.
+bool
+TypeCoercionRules::coerceable_mutability (Mutability from_mutbl,
+ Mutability to_mutbl)
+{
+ return to_mutbl == Mutability::Imm || (from_mutbl == to_mutbl);
+}
+
+void
+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);
+ rust_error_at (r, "mismatched mutability");
+}
+
+void
+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);
+ rust_error_at (r, "unsafe unsize coercion");
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-coercion.h b/gcc/rust/typecheck/rust-coercion.h
new file mode 100644
index 00000000000..da28c7c5e1b
--- /dev/null
+++ b/gcc/rust/typecheck/rust-coercion.h
@@ -0,0 +1,93 @@
+// 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_COERCION
+#define RUST_COERCION
+
+#include "rust-autoderef.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCoercionRules : protected AutoderefCycle
+{
+public:
+ struct CoercionResult
+ {
+ std::vector<Adjustment> adjustments;
+ TyTy::BaseType *tyty;
+
+ bool is_error ()
+ {
+ return tyty == nullptr || tyty->get_kind () == TyTy::TypeKind::ERROR;
+ }
+
+ static CoercionResult get_error () { return CoercionResult{{}, nullptr}; }
+ };
+
+ 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);
+
+ CoercionResult coerce_borrowed_pointer (TyTy::BaseType *receiver,
+ TyTy::ReferenceType *expected,
+ Mutability mutability);
+
+ CoercionResult coerce_unsized (TyTy::BaseType *receiver,
+ TyTy::BaseType *expected, bool &unsafe_error);
+
+ static bool coerceable_mutability (Mutability from_mutbl,
+ Mutability to_mutbl);
+
+ void mismatched_mutability_error (Location expr_locus, Location lhs,
+ Location rhs);
+ void object_unsafe_error (Location expr_locus, Location lhs, Location rhs);
+
+protected:
+ TypeCoercionRules (TyTy::BaseType *expected, Location locus,
+ bool emit_errors);
+
+ bool select (const TyTy::BaseType &autoderefed) override;
+
+ bool do_coercion (TyTy::BaseType *receiver);
+
+private:
+ // context info
+ Analysis::Mappings *mappings;
+ TypeCheckContext *context;
+
+ // search
+ TyTy::BaseType *expected;
+ Location locus;
+
+ // mutable fields
+ CoercionResult try_result;
+ bool emit_errors;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_COERCION
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc
new file mode 100644
index 00000000000..d45f0903478
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -0,0 +1,263 @@
+// 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-hir-dot-operator.h"
+#include "rust-hir-path-probe.h"
+#include "rust-hir-trait-resolve.h"
+
+namespace Rust {
+namespace Resolver {
+
+MethodResolver::MethodResolver (bool autoderef_flag,
+ const HIR::PathIdentSegment &segment_name)
+ : AutoderefCycle (autoderef_flag), mappings (Analysis::Mappings::get ()),
+ context (TypeCheckContext::get ()), segment_name (segment_name),
+ try_result (MethodCandidate::get_error ())
+{}
+
+MethodCandidate
+MethodResolver::Probe (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &segment_name,
+ bool autoderef_flag)
+{
+ MethodResolver resolver (autoderef_flag, segment_name);
+ bool ok = resolver.cycle (receiver);
+ return ok ? resolver.try_result : MethodCandidate::get_error ();
+}
+
+void
+MethodResolver::try_hook (const TyTy::BaseType &r)
+{
+ const auto &specified_bounds = r.get_specified_bounds ();
+ predicate_items = get_predicate_items (segment_name, r, specified_bounds);
+}
+
+bool
+MethodResolver::select (const TyTy::BaseType &receiver)
+{
+ struct impl_item_candidate
+ {
+ HIR::Function *item;
+ HIR::ImplBlock *impl_block;
+ TyTy::FnType *ty;
+ };
+
+ // assemble inherent impl items
+ std::vector<impl_item_candidate> inherent_impl_fns;
+ mappings->iterate_impl_items (
+ [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
+ bool is_trait_impl = impl->has_trait_ref ();
+ if (is_trait_impl)
+ return true;
+
+ bool is_fn
+ = item->get_impl_item_type () == HIR::ImplItem::ImplItemType::FUNCTION;
+ if (!is_fn)
+ return true;
+
+ HIR::Function *func = static_cast<HIR::Function *> (item);
+ if (!func->is_method ())
+ return true;
+
+ bool name_matches
+ = func->get_function_name ().compare (segment_name.as_string ()) == 0;
+ if (!name_matches)
+ return true;
+
+ TyTy::BaseType *ty = nullptr;
+ if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
+ return true;
+ if (ty->get_kind () == TyTy::TypeKind::ERROR)
+ return true;
+
+ rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+ inherent_impl_fns.push_back ({func, impl, fnty});
+
+ return true;
+ });
+
+ struct trait_item_candidate
+ {
+ const HIR::TraitItemFunc *item;
+ const HIR::Trait *trait;
+ TyTy::FnType *ty;
+ const TraitReference *reference;
+ const TraitItemReference *item_ref;
+ };
+
+ std::vector<trait_item_candidate> trait_fns;
+ mappings->iterate_impl_blocks ([&] (HirId id,
+ HIR::ImplBlock *impl) mutable -> bool {
+ bool is_trait_impl = impl->has_trait_ref ();
+ if (!is_trait_impl)
+ return true;
+
+ // look for impl implementation else lookup the associated trait item
+ for (auto &impl_item : impl->get_impl_items ())
+ {
+ bool is_fn = impl_item->get_impl_item_type ()
+ == HIR::ImplItem::ImplItemType::FUNCTION;
+ if (!is_fn)
+ continue;
+
+ HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ());
+ if (!func->is_method ())
+ continue;
+
+ bool name_matches
+ = func->get_function_name ().compare (segment_name.as_string ()) == 0;
+ if (!name_matches)
+ continue;
+
+ TyTy::BaseType *ty = nullptr;
+ if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
+ continue;
+ if (ty->get_kind () == TyTy::TypeKind::ERROR)
+ continue;
+
+ rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+ inherent_impl_fns.push_back ({func, impl, fnty});
+ return true;
+ }
+
+ TraitReference *trait_ref
+ = TraitResolver::Resolve (*impl->get_trait_ref ().get ());
+ rust_assert (!trait_ref->is_error ());
+
+ auto item_ref
+ = trait_ref->lookup_trait_item (segment_name.as_string (),
+ TraitItemReference::TraitItemType::FN);
+ if (item_ref->is_error ())
+ return true;
+
+ const HIR::Trait *trait = trait_ref->get_hir_trait_ref ();
+ HIR::TraitItem *item = item_ref->get_hir_trait_item ();
+ rust_assert (item->get_item_kind () == HIR::TraitItem::TraitItemKind::FUNC);
+ HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item);
+
+ TyTy::BaseType *ty = item_ref->get_tyty ();
+ rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+ trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref};
+ trait_fns.push_back (candidate);
+
+ return true;
+ });
+
+ // lookup specified bounds for an associated item
+ struct precdicate_candidate
+ {
+ TyTy::TypeBoundPredicateItem lookup;
+ TyTy::FnType *fntype;
+ };
+
+ for (auto impl_item : inherent_impl_fns)
+ {
+ TyTy::FnType *fn = impl_item.ty;
+ rust_assert (fn->is_method ());
+
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (fn_self->can_eq (&receiver, false))
+ {
+ PathProbeCandidate::ImplItemCandidate c{impl_item.item,
+ impl_item.impl_block};
+ try_result = MethodCandidate{
+ PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC,
+ fn, impl_item.item->get_locus (), c),
+ adjustments};
+ return true;
+ }
+ }
+
+ for (auto trait_item : trait_fns)
+ {
+ TyTy::FnType *fn = trait_item.ty;
+ rust_assert (fn->is_method ());
+
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (fn_self->can_eq (&receiver, false))
+ {
+ PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
+ trait_item.item_ref,
+ nullptr};
+ try_result = MethodCandidate{
+ PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
+ fn, trait_item.item->get_locus (), c),
+ adjustments};
+ return true;
+ }
+ }
+
+ for (const auto &predicate : predicate_items)
+ {
+ const TyTy::FnType *fn = predicate.fntype;
+ rust_assert (fn->is_method ());
+
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (fn_self->can_eq (&receiver, false))
+ {
+ const TraitReference *trait_ref
+ = predicate.lookup.get_parent ()->get ();
+ const TraitItemReference *trait_item
+ = predicate.lookup.get_raw_item ();
+
+ PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
+ nullptr};
+ try_result = MethodCandidate{
+ PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
+ fn->clone (), trait_item->get_locus (), c),
+ adjustments};
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::vector<MethodResolver::predicate_candidate>
+MethodResolver::get_predicate_items (
+ const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
+ const std::vector<TyTy::TypeBoundPredicate> &specified_bounds)
+{
+ std::vector<predicate_candidate> predicate_items;
+ for (auto &bound : specified_bounds)
+ {
+ TyTy::TypeBoundPredicateItem lookup
+ = bound.lookup_associated_item (segment_name.as_string ());
+ if (lookup.is_error ())
+ continue;
+
+ TyTy::BaseType *ty = lookup.get_tyty_for_receiver (&receiver);
+ if (ty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+ predicate_candidate candidate{lookup, fnty};
+ predicate_items.push_back (candidate);
+ }
+ }
+
+ return predicate_items;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h
new file mode 100644
index 00000000000..750601a2d9e
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.h
@@ -0,0 +1,81 @@
+// 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_HIR_DOT_OPERATOR
+#define RUST_HIR_DOT_OPERATOR
+
+#include "rust-hir-path-probe.h"
+
+namespace Rust {
+namespace Resolver {
+
+struct MethodCandidate
+{
+ PathProbeCandidate candidate;
+ std::vector<Adjustment> adjustments;
+
+ static MethodCandidate get_error ()
+ {
+ return {PathProbeCandidate::get_error (), {}};
+ }
+
+ bool is_error () const { return candidate.is_error (); }
+};
+
+class MethodResolver : protected AutoderefCycle
+{
+public:
+ struct predicate_candidate
+ {
+ TyTy::TypeBoundPredicateItem lookup;
+ TyTy::FnType *fntype;
+ };
+
+ static MethodCandidate Probe (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &segment_name,
+ bool autoderef_flag = false);
+
+ static std::vector<predicate_candidate> get_predicate_items (
+ const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
+ const std::vector<TyTy::TypeBoundPredicate> &specified_bounds);
+
+protected:
+ MethodResolver (bool autoderef_flag,
+ const HIR::PathIdentSegment &segment_name);
+
+ void try_hook (const TyTy::BaseType &r) override;
+
+ bool select (const TyTy::BaseType &receiver) override;
+
+private:
+ // context info
+ Analysis::Mappings *mappings;
+ TypeCheckContext *context;
+
+ // search
+ const HIR::PathIdentSegment &segment_name;
+ std::vector<MethodResolver::predicate_candidate> predicate_items;
+
+ // mutable fields
+ MethodCandidate try_result;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_DOT_OPERATOR
diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
new file mode 100644
index 00000000000..2890b54a00d
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
@@ -0,0 +1,186 @@
+// 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_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
+#define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ImplItemToName : private TypeCheckBase, private HIR::HIRImplVisitor
+{
+public:
+ static bool resolve (HIR::ImplItem *item, std::string &name_result)
+ {
+ ImplItemToName resolver (name_result);
+ item->accept_vis (resolver);
+ return resolver.ok;
+ }
+
+ void visit (HIR::TypeAlias &alias) override
+ {
+ ok = true;
+ result.assign (alias.get_new_type_name ());
+ }
+
+ void visit (HIR::Function &function) override
+ {
+ ok = true;
+ result.assign (function.get_function_name ());
+ }
+
+ void visit (HIR::ConstantItem &constant) override
+ {
+ ok = true;
+ result.assign (constant.get_identifier ());
+ }
+
+private:
+ ImplItemToName (std::string &result)
+ : TypeCheckBase (), ok (false), result (result)
+ {}
+
+ bool ok;
+ std::string &result;
+};
+
+class OverlappingImplItemPass : public TypeCheckBase
+{
+public:
+ static void go ()
+ {
+ OverlappingImplItemPass pass;
+
+ // generate mappings
+ pass.mappings->iterate_impl_items (
+ [&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool {
+ // ignoring trait-impls might need thought later on
+ if (impl->has_trait_ref ())
+ return true;
+
+ pass.process_impl_item (id, impl_item, impl);
+ return true;
+ });
+
+ pass.scan ();
+ }
+
+ void process_impl_item (HirId id, HIR::ImplItem *impl_item,
+ HIR::ImplBlock *impl)
+ {
+ // lets make a mapping of impl-item Self type to (impl-item,name):
+ // {
+ // impl-type -> [ (item, name), ... ]
+ // }
+
+ HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid ();
+ TyTy::BaseType *impl_type = nullptr;
+ bool ok = context->lookup_type (impl_type_id, &impl_type);
+ rust_assert (ok);
+
+ std::string impl_item_name;
+ ok = ImplItemToName::resolve (impl_item, impl_item_name);
+ rust_assert (ok);
+
+ std::pair<HIR::ImplItem *, std::string> elem (impl_item, impl_item_name);
+ impl_mappings[impl_type].insert (std::move (elem));
+ }
+
+ void scan ()
+ {
+ // we can now brute force the map looking for can_eq on each of the
+ // impl_items_types to look for possible colliding impl blocks;
+ for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++)
+ {
+ TyTy::BaseType *query = it->first;
+
+ for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
+ {
+ TyTy::BaseType *candidate = iy->first;
+ if (query == candidate)
+ continue;
+
+ if (query->can_eq (candidate, false))
+ {
+ // we might be in the case that we have:
+ //
+ // *const T vs *const [T]
+ //
+ // so lets use an equality check when the
+ // candidates are both generic to be sure we dont emit a false
+ // positive
+
+ bool a = query->is_concrete ();
+ bool b = candidate->is_concrete ();
+ bool both_generic = !a && !b;
+ if (both_generic)
+ {
+ if (!query->is_equal (*candidate))
+ continue;
+ }
+
+ possible_collision (it->second, iy->second);
+ }
+ }
+ }
+ }
+
+ void possible_collision (
+ std::set<std::pair<HIR::ImplItem *, std::string> > query,
+ std::set<std::pair<HIR::ImplItem *, std::string> > candidate)
+ {
+ for (auto &q : query)
+ {
+ HIR::ImplItem *query_impl_item = q.first;
+ std::string query_impl_item_name = q.second;
+
+ for (auto &c : candidate)
+ {
+ HIR::ImplItem *candidate_impl_item = c.first;
+ std::string candidate_impl_item_name = c.second;
+
+ if (query_impl_item_name.compare (candidate_impl_item_name) == 0)
+ collision_detected (query_impl_item, candidate_impl_item,
+ candidate_impl_item_name);
+ }
+ }
+ }
+
+ void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
+ const std::string &name)
+ {
+ RichLocation r (dup->get_locus ());
+ r.add_range (query->get_locus ());
+ rust_error_at (r, "duplicate definitions with name %s", name.c_str ());
+ }
+
+private:
+ OverlappingImplItemPass () : TypeCheckBase () {}
+
+ std::map<TyTy::BaseType *,
+ std::set<std::pair<HIR::ImplItem *, std::string> > >
+ impl_mappings;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h
new file mode 100644
index 00000000000..bd4f91e49bf
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-path-probe.h
@@ -0,0 +1,540 @@
+// 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_HIR_PATH_PROBE_H
+#define RUST_HIR_PATH_PROBE_H
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+#include "rust-tyty.h"
+#include "rust-substitution-mapper.h"
+#include "rust-hir-type-bounds.h"
+
+namespace Rust {
+namespace Resolver {
+
+struct PathProbeCandidate
+{
+ enum CandidateType
+ {
+ ERROR,
+
+ ENUM_VARIANT,
+
+ IMPL_CONST,
+ IMPL_TYPE_ALIAS,
+ IMPL_FUNC,
+
+ TRAIT_ITEM_CONST,
+ TRAIT_TYPE_ALIAS,
+ TRAIT_FUNC,
+ };
+
+ struct EnumItemCandidate
+ {
+ const TyTy::ADTType *parent;
+ const TyTy::VariantDef *variant;
+ };
+
+ struct ImplItemCandidate
+ {
+ HIR::ImplItem *impl_item;
+ HIR::ImplBlock *parent;
+ };
+
+ struct TraitItemCandidate
+ {
+ const TraitReference *trait_ref;
+ const TraitItemReference *item_ref;
+ HIR::ImplBlock *impl;
+ };
+
+ CandidateType type;
+ TyTy::BaseType *ty;
+ Location locus;
+ union Candidate
+ {
+ EnumItemCandidate enum_field;
+ ImplItemCandidate impl;
+ TraitItemCandidate trait;
+
+ Candidate (EnumItemCandidate enum_field) : enum_field (enum_field) {}
+ Candidate (ImplItemCandidate impl) : impl (impl) {}
+ Candidate (TraitItemCandidate trait) : trait (trait) {}
+ } item;
+
+ PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus,
+ EnumItemCandidate enum_field)
+ : type (type), ty (ty), item (enum_field)
+ {}
+
+ PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus,
+ ImplItemCandidate impl)
+ : type (type), ty (ty), item (impl)
+ {}
+
+ PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus,
+ TraitItemCandidate trait)
+ : type (type), ty (ty), item (trait)
+ {}
+
+ std::string as_string () const
+ {
+ return "PathProbe candidate TODO - as_string";
+ }
+
+ bool is_enum_candidate () const { return type == ENUM_VARIANT; }
+
+ bool is_impl_candidate () const
+ {
+ return type == IMPL_CONST || type == IMPL_TYPE_ALIAS || type == IMPL_FUNC;
+ }
+
+ bool is_trait_candidate () const
+ {
+ return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS
+ || type == TRAIT_FUNC;
+ }
+
+ bool is_full_trait_item_candidate () const
+ {
+ return is_trait_candidate () && item.trait.impl == nullptr;
+ }
+
+ static PathProbeCandidate get_error ()
+ {
+ return PathProbeCandidate (ERROR, nullptr, Location (),
+ ImplItemCandidate{nullptr, nullptr});
+ }
+
+ bool is_error () const { return type == ERROR; }
+};
+
+class PathProbeType : public TypeCheckBase, public HIR::HIRImplVisitor
+{
+public:
+ static std::vector<PathProbeCandidate>
+ Probe (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &segment_name, bool probe_impls,
+ bool probe_bounds, bool ignore_mandatory_trait_items,
+ DefId specific_trait_id = UNKNOWN_DEFID)
+ {
+ PathProbeType probe (receiver, segment_name, specific_trait_id);
+ if (probe_impls)
+ {
+ if (receiver->get_kind () == TyTy::TypeKind::ADT)
+ {
+ const TyTy::ADTType *adt
+ = static_cast<const TyTy::ADTType *> (receiver);
+ if (adt->is_enum ())
+ probe.process_enum_item_for_candiates (adt);
+ }
+
+ probe.process_impl_items_for_candidates ();
+ }
+
+ if (!probe_bounds)
+ return probe.candidates;
+
+ if (!probe.is_reciever_generic ())
+ {
+ std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds
+ = TypeBoundsProbe::Probe (receiver);
+ for (auto &candidate : probed_bounds)
+ {
+ const TraitReference *trait_ref = candidate.first;
+ if (specific_trait_id != UNKNOWN_DEFID)
+ {
+ if (trait_ref->get_mappings ().get_defid ()
+ != specific_trait_id)
+ continue;
+ }
+
+ HIR::ImplBlock *impl = candidate.second;
+ probe.process_associated_trait_for_candidates (
+ trait_ref, impl, ignore_mandatory_trait_items);
+ }
+ }
+
+ for (const TyTy::TypeBoundPredicate &predicate :
+ receiver->get_specified_bounds ())
+ {
+ const TraitReference *trait_ref = predicate.get ();
+ if (specific_trait_id != UNKNOWN_DEFID)
+ {
+ if (trait_ref->get_mappings ().get_defid () != specific_trait_id)
+ continue;
+ }
+
+ probe.process_predicate_for_candidates (predicate,
+ ignore_mandatory_trait_items);
+ }
+
+ return probe.candidates;
+ }
+
+ void visit (HIR::TypeAlias &alias) override
+ {
+ Identifier name = alias.get_new_type_name ();
+ if (search.as_string ().compare (name) == 0)
+ {
+ HirId tyid = alias.get_mappings ().get_hirid ();
+ TyTy::BaseType *ty = nullptr;
+ bool ok = context->lookup_type (tyid, &ty);
+ rust_assert (ok);
+
+ PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias,
+ current_impl};
+ PathProbeCandidate candidate{
+ PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, ty,
+ alias.get_locus (), impl_item_candidate};
+ candidates.push_back (std::move (candidate));
+ }
+ }
+
+ void visit (HIR::ConstantItem &constant) override
+ {
+ Identifier name = constant.get_identifier ();
+ if (search.as_string ().compare (name) == 0)
+ {
+ HirId tyid = constant.get_mappings ().get_hirid ();
+ TyTy::BaseType *ty = nullptr;
+ bool ok = context->lookup_type (tyid, &ty);
+ rust_assert (ok);
+
+ PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant,
+ current_impl};
+ PathProbeCandidate candidate{
+ PathProbeCandidate::CandidateType::IMPL_CONST, ty,
+ constant.get_locus (), impl_item_candidate};
+ candidates.push_back (std::move (candidate));
+ }
+ }
+
+ void visit (HIR::Function &function) override
+ {
+ Identifier name = function.get_function_name ();
+ if (search.as_string ().compare (name) == 0)
+ {
+ HirId tyid = function.get_mappings ().get_hirid ();
+ TyTy::BaseType *ty = nullptr;
+ bool ok = context->lookup_type (tyid, &ty);
+ rust_assert (ok);
+
+ PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function,
+ current_impl};
+ PathProbeCandidate candidate{
+ PathProbeCandidate::CandidateType::IMPL_FUNC, ty,
+ function.get_locus (), impl_item_candidate};
+ candidates.push_back (std::move (candidate));
+ }
+ }
+
+protected:
+ void process_enum_item_for_candiates (const TyTy::ADTType *adt)
+ {
+ if (specific_trait_id != UNKNOWN_DEFID)
+ return;
+
+ TyTy::VariantDef *v;
+ if (!adt->lookup_variant (search.as_string (), &v))
+ return;
+
+ PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v};
+ PathProbeCandidate candidate{
+ PathProbeCandidate::CandidateType::ENUM_VARIANT, receiver->clone (),
+ mappings->lookup_location (adt->get_ty_ref ()), enum_item_candidate};
+ candidates.push_back (std::move (candidate));
+ }
+
+ void process_impl_items_for_candidates ()
+ {
+ mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item,
+ HIR::ImplBlock *impl) mutable -> bool {
+ process_impl_item_candidate (id, item, impl);
+ return true;
+ });
+ }
+
+ void process_impl_item_candidate (HirId id, HIR::ImplItem *item,
+ HIR::ImplBlock *impl)
+ {
+ current_impl = impl;
+ HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid ();
+ TyTy::BaseType *impl_block_ty = nullptr;
+ if (!context->lookup_type (impl_ty_id, &impl_block_ty))
+ return;
+
+ if (!receiver->can_eq (impl_block_ty, false))
+ {
+ if (!impl_block_ty->can_eq (receiver, false))
+ return;
+ }
+
+ // lets visit the impl_item
+ item->accept_vis (*this);
+ }
+
+ void
+ process_associated_trait_for_candidates (const TraitReference *trait_ref,
+ HIR::ImplBlock *impl,
+ bool ignore_mandatory_trait_items)
+ {
+ const TraitItemReference *trait_item_ref = nullptr;
+ if (!trait_ref->lookup_trait_item (search.as_string (), &trait_item_ref))
+ return;
+
+ bool trait_item_needs_implementation = !trait_item_ref->is_optional ();
+ if (ignore_mandatory_trait_items && trait_item_needs_implementation)
+ return;
+
+ PathProbeCandidate::CandidateType candidate_type;
+ switch (trait_item_ref->get_trait_item_type ())
+ {
+ case TraitItemReference::TraitItemType::FN:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
+ break;
+ case TraitItemReference::TraitItemType::CONST:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
+ break;
+ case TraitItemReference::TraitItemType::TYPE:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
+ break;
+
+ case TraitItemReference::TraitItemType::ERROR:
+ default:
+ gcc_unreachable ();
+ break;
+ }
+
+ TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty ();
+
+ // we can substitute the Self with the receiver here
+ if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty);
+ TyTy::SubstitutionParamMapping *param = nullptr;
+ for (auto ¶m_mapping : fn->get_substs ())
+ {
+ const HIR::TypeParam &type_param
+ = param_mapping.get_generic_param ();
+ if (type_param.get_type_representation ().compare ("Self") == 0)
+ {
+ param = ¶m_mapping;
+ break;
+ }
+ }
+ rust_assert (param != nullptr);
+
+ std::vector<TyTy::SubstitutionArg> mappings;
+ mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ()));
+
+ Location locus; // FIXME
+ TyTy::SubstitutionArgumentMappings args (std::move (mappings), locus);
+ trait_item_tyty = SubstMapperInternal::Resolve (trait_item_tyty, args);
+ }
+
+ PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
+ trait_item_ref,
+ impl};
+
+ PathProbeCandidate candidate{candidate_type, trait_item_tyty,
+ trait_ref->get_locus (), trait_item_candidate};
+ candidates.push_back (std::move (candidate));
+ }
+
+ void
+ process_predicate_for_candidates (const TyTy::TypeBoundPredicate &predicate,
+ bool ignore_mandatory_trait_items)
+ {
+ const TraitReference *trait_ref = predicate.get ();
+
+ TyTy::TypeBoundPredicateItem item
+ = predicate.lookup_associated_item (search.as_string ());
+ if (item.is_error ())
+ return;
+
+ if (ignore_mandatory_trait_items && item.needs_implementation ())
+ return;
+
+ const TraitItemReference *trait_item_ref = item.get_raw_item ();
+ PathProbeCandidate::CandidateType candidate_type;
+ switch (trait_item_ref->get_trait_item_type ())
+ {
+ case TraitItemReference::TraitItemType::FN:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
+ break;
+ case TraitItemReference::TraitItemType::CONST:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
+ break;
+ case TraitItemReference::TraitItemType::TYPE:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
+ break;
+
+ case TraitItemReference::TraitItemType::ERROR:
+ default:
+ gcc_unreachable ();
+ break;
+ }
+
+ TyTy::BaseType *trait_item_tyty = item.get_tyty_for_receiver (receiver);
+ PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
+ trait_item_ref,
+ nullptr};
+ PathProbeCandidate candidate{candidate_type, trait_item_tyty,
+ trait_item_ref->get_locus (),
+ trait_item_candidate};
+ candidates.push_back (std::move (candidate));
+ }
+
+protected:
+ PathProbeType (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &query, DefId specific_trait_id)
+ : TypeCheckBase (), receiver (receiver), search (query),
+ current_impl (nullptr), specific_trait_id (specific_trait_id)
+ {}
+
+ std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>>
+ union_bounds (
+ const std::vector<std::pair</*const*/ TraitReference *, HIR::ImplBlock *>>
+ a,
+ const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> b)
+ const
+ {
+ std::map<DefId, std::pair<const TraitReference *, HIR::ImplBlock *>> mapper;
+ for (auto &ref : a)
+ {
+ mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
+ }
+ for (auto &ref : b)
+ {
+ mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
+ }
+
+ std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_set;
+ for (auto it = mapper.begin (); it != mapper.end (); it++)
+ {
+ union_set.push_back ({it->second.first, it->second.second});
+ }
+ return union_set;
+ }
+
+ bool is_reciever_generic () const
+ {
+ const TyTy::BaseType *root = receiver->get_root ();
+ bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
+ bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
+ return receiver_is_type_param || receiver_is_dyn;
+ }
+
+ const TyTy::BaseType *receiver;
+ const HIR::PathIdentSegment &search;
+ std::vector<PathProbeCandidate> candidates;
+ HIR::ImplBlock *current_impl;
+ DefId specific_trait_id;
+};
+
+class ReportMultipleCandidateError : private TypeCheckBase,
+ private HIR::HIRImplVisitor
+{
+public:
+ static void Report (std::vector<PathProbeCandidate> &candidates,
+ const HIR::PathIdentSegment &query, Location query_locus)
+ {
+ RichLocation r (query_locus);
+ ReportMultipleCandidateError visitor (r);
+ for (auto &c : candidates)
+ {
+ switch (c.type)
+ {
+ case PathProbeCandidate::CandidateType::ERROR:
+ case PathProbeCandidate::CandidateType::ENUM_VARIANT:
+ gcc_unreachable ();
+ break;
+
+ case PathProbeCandidate::CandidateType::IMPL_CONST:
+ case PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS:
+ case PathProbeCandidate::CandidateType::IMPL_FUNC:
+ c.item.impl.impl_item->accept_vis (visitor);
+ break;
+
+ case PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST:
+ case PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS:
+ case PathProbeCandidate::CandidateType::TRAIT_FUNC:
+ r.add_range (c.item.trait.item_ref->get_locus ());
+ break;
+ }
+ }
+
+ rust_error_at (r, "multiple applicable items in scope for: %s",
+ query.as_string ().c_str ());
+ }
+
+ void visit (HIR::TypeAlias &alias) override
+ {
+ r.add_range (alias.get_locus ());
+ }
+
+ void visit (HIR::ConstantItem &constant) override
+ {
+ r.add_range (constant.get_locus ());
+ }
+
+ void visit (HIR::Function &function) override
+ {
+ r.add_range (function.get_locus ());
+ }
+
+private:
+ ReportMultipleCandidateError (RichLocation &r) : TypeCheckBase (), r (r) {}
+
+ RichLocation &r;
+};
+
+class PathProbeImplTrait : public PathProbeType
+{
+public:
+ static std::vector<PathProbeCandidate>
+ Probe (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &segment_name,
+ const TraitReference *trait_reference)
+ {
+ PathProbeImplTrait probe (receiver, segment_name, trait_reference);
+ // iterate all impls for this trait and receiver
+ // then search for possible candidates using base class behaviours
+ probe.process_trait_impl_items_for_candidates ();
+ return probe.candidates;
+ }
+
+private:
+ void process_trait_impl_items_for_candidates ();
+
+ PathProbeImplTrait (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &query,
+ const TraitReference *trait_reference)
+ : PathProbeType (receiver, query, UNKNOWN_DEFID),
+ trait_reference (trait_reference)
+ {}
+
+ const TraitReference *trait_reference;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_PATH_PROBE_H
diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h
new file mode 100644
index 00000000000..6eec461e8a5
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-trait-ref.h
@@ -0,0 +1,472 @@
+// Copyright (C) 2021-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_HIR_TRAIT_REF_H
+#define RUST_HIR_TRAIT_REF_H
+
+#include "rust-hir-full.h"
+#include "rust-tyty-visitor.h"
+#include "rust-hir-type-check-util.h"
+
+namespace Rust {
+namespace Resolver {
+
+// Data Objects for the associated trait items in a structure we can work with
+// https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/associated-constants.html
+class TypeCheckContext;
+class TraitItemReference
+{
+public:
+ enum TraitItemType
+ {
+ FN,
+ CONST,
+ TYPE,
+ ERROR
+ };
+
+ TraitItemReference (std::string identifier, bool optional, TraitItemType type,
+ HIR::TraitItem *hir_trait_item, TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions,
+ Location locus);
+
+ TraitItemReference (TraitItemReference const &other);
+
+ TraitItemReference &operator= (TraitItemReference const &other);
+
+ static TraitItemReference error ()
+ {
+ return TraitItemReference ("", false, ERROR, nullptr, nullptr, {},
+ Location ());
+ }
+
+ static TraitItemReference &error_node ()
+ {
+ static TraitItemReference error = TraitItemReference::error ();
+ return error;
+ }
+
+ bool is_error () const { return type == ERROR; }
+
+ std::string as_string () const
+ {
+ return "(" + trait_item_type_as_string (type) + " " + identifier + " "
+ + ")";
+ }
+
+ static std::string trait_item_type_as_string (TraitItemType ty)
+ {
+ switch (ty)
+ {
+ case FN:
+ return "FN";
+ case CONST:
+ return "CONST";
+ case TYPE:
+ return "TYPE";
+ case ERROR:
+ return "ERROR";
+ }
+ return "ERROR";
+ }
+
+ bool is_optional () const { return optional_flag; }
+
+ std::string get_identifier () const { return identifier; }
+
+ TraitItemType get_trait_item_type () const { return type; }
+
+ HIR::TraitItem *get_hir_trait_item () const { return hir_trait_item; }
+
+ Location get_locus () const { return locus; }
+
+ const Analysis::NodeMapping get_mappings () const
+ {
+ return hir_trait_item->get_mappings ();
+ }
+
+ TyTy::BaseType *get_tyty () const
+ {
+ rust_assert (hir_trait_item != nullptr);
+
+ switch (type)
+ {
+ case CONST:
+ return get_type_from_constant (
+ static_cast</*const*/ HIR::TraitItemConst &> (*hir_trait_item));
+ break;
+
+ case TYPE:
+ return get_type_from_typealias (
+ static_cast</*const*/ HIR::TraitItemType &> (*hir_trait_item));
+
+ case FN:
+ return get_type_from_fn (
+ static_cast</*const*/ HIR::TraitItemFunc &> (*hir_trait_item));
+ break;
+
+ default:
+ return get_error ();
+ }
+
+ gcc_unreachable ();
+ return get_error ();
+ }
+
+ Analysis::NodeMapping get_parent_trait_mappings () const;
+
+ // this is called when the trait is completed resolution and gives the items a
+ // chance to run their specific type resolution passes. If we call their
+ // resolution on construction it can lead to a case where the trait being
+ // resolved recursively trying to resolve the trait itself infinitely since
+ // the trait will not be stored in its own map yet
+ void on_resolved ();
+
+ void associated_type_set (TyTy::BaseType *ty) const;
+
+ void associated_type_reset () const;
+
+ bool is_object_safe () const;
+
+private:
+ TyTy::ErrorType *get_error () const
+ {
+ return new TyTy::ErrorType (get_mappings ().get_hirid ());
+ }
+
+ TyTy::BaseType *get_type_from_typealias (/*const*/
+ HIR::TraitItemType &type) const;
+
+ TyTy::BaseType *
+ get_type_from_constant (/*const*/ HIR::TraitItemConst &constant) const;
+
+ TyTy::BaseType *get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const;
+
+ bool is_item_resolved () const;
+ void resolve_item (HIR::TraitItemType &type);
+ void resolve_item (HIR::TraitItemConst &constant);
+ void resolve_item (HIR::TraitItemFunc &func);
+
+ std::string identifier;
+ bool optional_flag;
+ TraitItemType type;
+ HIR::TraitItem *hir_trait_item;
+ std::vector<TyTy::SubstitutionParamMapping> inherited_substitutions;
+ Location locus;
+
+ TyTy::BaseType
+ *self; // this is the implict Self TypeParam required for methods
+ Resolver::TypeCheckContext *context;
+};
+
+// this wraps up the HIR::Trait so we can do analysis on it
+
+class TraitReference
+{
+public:
+ TraitReference (const HIR::Trait *hir_trait_ref,
+ std::vector<TraitItemReference> item_refs,
+ std::vector<const TraitReference *> super_traits,
+ std::vector<TyTy::SubstitutionParamMapping> substs)
+ : hir_trait_ref (hir_trait_ref), item_refs (item_refs),
+ super_traits (super_traits)
+ {
+ trait_substs.clear ();
+ trait_substs.reserve (substs.size ());
+ for (const auto &p : substs)
+ trait_substs.push_back (p.clone ());
+ }
+
+ TraitReference (TraitReference const &other)
+ : hir_trait_ref (other.hir_trait_ref), item_refs (other.item_refs),
+ super_traits (other.super_traits)
+ {
+ trait_substs.clear ();
+ trait_substs.reserve (other.trait_substs.size ());
+ for (const auto &p : other.trait_substs)
+ trait_substs.push_back (p.clone ());
+ }
+
+ TraitReference &operator= (TraitReference const &other)
+ {
+ hir_trait_ref = other.hir_trait_ref;
+ item_refs = other.item_refs;
+ super_traits = other.super_traits;
+
+ trait_substs.clear ();
+ trait_substs.reserve (other.trait_substs.size ());
+ for (const auto &p : other.trait_substs)
+ trait_substs.push_back (p.clone ());
+
+ return *this;
+ }
+
+ TraitReference (TraitReference &&other) = default;
+ TraitReference &operator= (TraitReference &&other) = default;
+
+ static TraitReference error ()
+ {
+ return TraitReference (nullptr, {}, {}, {});
+ }
+
+ bool is_error () const { return hir_trait_ref == nullptr; }
+
+ static TraitReference &error_node ()
+ {
+ static TraitReference trait_error_node = TraitReference::error ();
+ return trait_error_node;
+ }
+
+ Location get_locus () const { return hir_trait_ref->get_locus (); }
+
+ std::string get_name () const
+ {
+ rust_assert (!is_error ());
+ return hir_trait_ref->get_name ();
+ }
+
+ std::string as_string () const
+ {
+ if (is_error ())
+ return "<trait-ref-error-node>";
+
+ std::string item_buf;
+ for (auto &item : item_refs)
+ {
+ item_buf += item.as_string () + ", ";
+ }
+ return "HIR Trait: " + get_name () + "->"
+ + hir_trait_ref->get_mappings ().as_string () + " [" + item_buf
+ + "]";
+ }
+
+ const HIR::Trait *get_hir_trait_ref () const { return hir_trait_ref; }
+
+ const Analysis::NodeMapping &get_mappings () const
+ {
+ return hir_trait_ref->get_mappings ();
+ }
+
+ DefId get_defid () const { return get_mappings ().get_defid (); }
+
+ bool lookup_hir_trait_item (const HIR::TraitItem &item,
+ TraitItemReference **ref)
+ {
+ return lookup_trait_item (item.trait_identifier (), ref);
+ }
+
+ bool lookup_trait_item (const std::string &ident, TraitItemReference **ref)
+ {
+ for (auto &item : item_refs)
+ {
+ if (ident.compare (item.get_identifier ()) == 0)
+ {
+ *ref = &item;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool lookup_trait_item_by_type (const std::string &ident,
+ TraitItemReference::TraitItemType type,
+ TraitItemReference **ref)
+ {
+ for (auto &item : item_refs)
+ {
+ if (item.get_trait_item_type () != type)
+ continue;
+
+ if (ident.compare (item.get_identifier ()) == 0)
+ {
+ *ref = &item;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool lookup_trait_item_by_type (const std::string &ident,
+ TraitItemReference::TraitItemType type,
+ const TraitItemReference **ref) const
+ {
+ for (auto &item : item_refs)
+ {
+ if (item.get_trait_item_type () != type)
+ continue;
+
+ if (ident.compare (item.get_identifier ()) == 0)
+ {
+ *ref = &item;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool lookup_hir_trait_item (const HIR::TraitItem &item,
+ const TraitItemReference **ref) const
+ {
+ return lookup_trait_item (item.trait_identifier (), ref);
+ }
+
+ bool lookup_trait_item (const std::string &ident,
+ const TraitItemReference **ref) const
+ {
+ for (auto &item : item_refs)
+ {
+ if (ident.compare (item.get_identifier ()) == 0)
+ {
+ *ref = &item;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ const TraitItemReference *
+ lookup_trait_item (const std::string &ident,
+ TraitItemReference::TraitItemType type) const
+ {
+ for (auto &item : item_refs)
+ {
+ if (item.get_trait_item_type () != type)
+ continue;
+
+ if (ident.compare (item.get_identifier ()) == 0)
+ return &item;
+ }
+ return &TraitItemReference::error_node ();
+ }
+
+ size_t size () const { return item_refs.size (); }
+
+ const std::vector<TraitItemReference> &get_trait_items () const
+ {
+ return item_refs;
+ }
+
+ void on_resolved ()
+ {
+ for (auto &item : item_refs)
+ {
+ item.on_resolved ();
+ }
+ }
+
+ void clear_associated_types ()
+ {
+ for (auto &item : item_refs)
+ {
+ bool is_assoc_type = item.get_trait_item_type ()
+ == TraitItemReference::TraitItemType::TYPE;
+ if (is_assoc_type)
+ item.associated_type_reset ();
+ }
+ }
+
+ bool is_equal (const TraitReference &other) const
+ {
+ DefId this_id = get_mappings ().get_defid ();
+ DefId other_id = other.get_mappings ().get_defid ();
+ return this_id == other_id;
+ }
+
+ const std::vector<const TraitReference *> get_super_traits () const
+ {
+ return super_traits;
+ }
+
+ bool is_object_safe (bool emit_error, Location locus) const
+ {
+ // https: // doc.rust-lang.org/reference/items/traits.html#object-safety
+ std::vector<const TraitReference *> non_object_super_traits;
+ for (auto &item : super_traits)
+ {
+ if (!item->is_object_safe (false, Location ()))
+ non_object_super_traits.push_back (item);
+ }
+
+ std::vector<const Resolver::TraitItemReference *> non_object_safe_items;
+ for (auto &item : get_trait_items ())
+ {
+ if (!item.is_object_safe ())
+ non_object_safe_items.push_back (&item);
+ }
+
+ bool is_safe
+ = non_object_super_traits.empty () && non_object_safe_items.empty ();
+ if (emit_error && !is_safe)
+ {
+ RichLocation r (locus);
+ for (auto &item : non_object_super_traits)
+ r.add_range (item->get_locus ());
+ for (auto &item : non_object_safe_items)
+ r.add_range (item->get_locus ());
+
+ rust_error_at (r, "trait bound is not object safe");
+ }
+
+ return is_safe;
+ }
+
+ bool trait_has_generics () const { return !trait_substs.empty (); }
+
+ std::vector<TyTy::SubstitutionParamMapping> get_trait_substs () const
+ {
+ return trait_substs;
+ }
+
+private:
+ const HIR::Trait *hir_trait_ref;
+ std::vector<TraitItemReference> item_refs;
+ std::vector<const TraitReference *> super_traits;
+ std::vector<TyTy::SubstitutionParamMapping> trait_substs;
+};
+
+class AssociatedImplTrait
+{
+public:
+ AssociatedImplTrait (TraitReference *trait, HIR::ImplBlock *impl,
+ TyTy::BaseType *self,
+ Resolver::TypeCheckContext *context)
+ : trait (trait), impl (impl), self (self), context (context)
+ {}
+
+ TraitReference *get_trait () { return trait; }
+
+ HIR::ImplBlock *get_impl_block () { return impl; }
+
+ TyTy::BaseType *get_self () { return self; }
+
+ void setup_associated_types (const TyTy::BaseType *self,
+ const TyTy::TypeBoundPredicate &bound);
+
+ void reset_associated_types ();
+
+private:
+ TraitReference *trait;
+ HIR::ImplBlock *impl;
+ TyTy::BaseType *self;
+ Resolver::TypeCheckContext *context;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TRAIT_REF_H
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
new file mode 100644
index 00000000000..5ad9540868c
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -0,0 +1,599 @@
+// Copyright (C) 2021-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-hir-trait-resolve.h"
+#include "rust-hir-type-check-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+ResolveTraitItemToRef::visit (HIR::TraitItemType &type)
+{
+ // create trait-item-ref
+ Location locus = type.get_locus ();
+ bool is_optional = false;
+ std::string identifier = type.get_name ();
+
+ resolved = TraitItemReference (identifier, is_optional,
+ TraitItemReference::TraitItemType::TYPE, &type,
+ self, substitutions, locus);
+}
+
+void
+ResolveTraitItemToRef::visit (HIR::TraitItemConst &cst)
+{
+ // create trait-item-ref
+ Location locus = cst.get_locus ();
+ bool is_optional = cst.has_expr ();
+ std::string identifier = cst.get_name ();
+
+ resolved = TraitItemReference (identifier, is_optional,
+ TraitItemReference::TraitItemType::CONST, &cst,
+ self, substitutions, locus);
+}
+
+void
+ResolveTraitItemToRef::visit (HIR::TraitItemFunc &fn)
+{
+ // create trait-item-ref
+ Location locus = fn.get_locus ();
+ bool is_optional = fn.has_block_defined ();
+ std::string identifier = fn.get_decl ().get_function_name ();
+
+ resolved = TraitItemReference (identifier, is_optional,
+ TraitItemReference::TraitItemType::FN, &fn,
+ self, std::move (substitutions), locus);
+}
+
+ResolveTraitItemToRef::ResolveTraitItemToRef (
+ TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> &&substitutions)
+ : TypeCheckBase (), resolved (TraitItemReference::error ()), self (self),
+ substitutions (std::move (substitutions))
+{}
+
+// TraitItemReference items
+
+TraitReference *
+TraitResolver::Resolve (HIR::TypePath &path)
+{
+ TraitResolver resolver;
+ return resolver.resolve_path (path);
+}
+
+TraitReference *
+TraitResolver::Resolve (HIR::Trait &trait)
+{
+ TraitResolver resolver;
+ return resolver.resolve_trait (&trait);
+}
+
+TraitReference *
+TraitResolver::Lookup (HIR::TypePath &path)
+{
+ TraitResolver resolver;
+ return resolver.lookup_path (path);
+}
+
+TraitResolver::TraitResolver ()
+ : TypeCheckBase (), resolved_trait_reference (nullptr)
+{}
+
+TraitReference *
+TraitResolver::resolve_path (HIR::TypePath &path)
+{
+ NodeId ref;
+ if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (),
+ &ref))
+ {
+ rust_error_at (path.get_locus (), "Failed to resolve path to node-id");
+ return &TraitReference::error_node ();
+ }
+
+ HirId hir_node = UNKNOWN_HIRID;
+ if (!mappings->lookup_node_to_hir (ref, &hir_node))
+ {
+ rust_error_at (path.get_locus (), "Failed to resolve path to hir-id");
+ return &TraitReference::error_node ();
+ }
+
+ HIR::Item *resolved_item = mappings->lookup_hir_item (hir_node);
+
+ rust_assert (resolved_item != nullptr);
+ resolved_item->accept_vis (*this);
+ rust_assert (resolved_trait_reference != nullptr);
+
+ return resolve_trait (resolved_trait_reference);
+}
+
+TraitReference *
+TraitResolver::resolve_trait (HIR::Trait *trait_reference)
+{
+ TraitReference *tref = &TraitReference::error_node ();
+ if (context->lookup_trait_reference (
+ trait_reference->get_mappings ().get_defid (), &tref))
+ {
+ return tref;
+ }
+
+ TyTy::BaseType *self = nullptr;
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ for (auto &generic_param : trait_reference->get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (), param_type);
+
+ auto &typaram = static_cast<HIR::TypeParam &> (*generic_param);
+ substitutions.push_back (
+ TyTy::SubstitutionParamMapping (typaram, param_type));
+
+ if (typaram.get_type_representation ().compare ("Self") == 0)
+ {
+ self = param_type;
+ }
+ }
+ break;
+ }
+ }
+ rust_assert (self != nullptr);
+
+ // Check if there is a super-trait, and apply this bound to the Self
+ // TypeParam
+ std::vector<TyTy::TypeBoundPredicate> specified_bounds;
+
+ // copy the substitition mappings
+ std::vector<TyTy::SubstitutionParamMapping> self_subst_copy;
+ for (auto &sub : substitutions)
+ self_subst_copy.push_back (sub.clone ());
+
+ // They also inherit themselves as a bound this enables a trait item to
+ // reference other Self::trait_items
+ auto self_hrtb
+ = TyTy::TypeBoundPredicate (trait_reference->get_mappings ().get_defid (),
+ std::move (self_subst_copy),
+ trait_reference->get_locus ());
+ specified_bounds.push_back (self_hrtb);
+
+ // look for any
+ std::vector<const TraitReference *> super_traits;
+ if (trait_reference->has_type_param_bounds ())
+ {
+ for (auto &bound : trait_reference->get_type_param_bounds ())
+ {
+ if (bound->get_bound_type ()
+ == HIR::TypeParamBound::BoundType::TRAITBOUND)
+ {
+ HIR::TraitBound *b
+ = static_cast<HIR::TraitBound *> (bound.get ());
+
+ // FIXME this might be recursive we need a check for that
+ auto predicate = get_predicate_from_bound (b->get_path ());
+ specified_bounds.push_back (predicate);
+ super_traits.push_back (predicate.get ());
+ }
+ }
+ }
+ self->inherit_bounds (specified_bounds);
+
+ std::vector<TraitItemReference> item_refs;
+ for (auto &item : trait_reference->get_trait_items ())
+ {
+ // make a copy of the substs
+ std::vector<TyTy::SubstitutionParamMapping> item_subst;
+ for (auto &sub : substitutions)
+ item_subst.push_back (sub.clone ());
+
+ TraitItemReference trait_item_ref
+ = ResolveTraitItemToRef::Resolve (*item.get (), self,
+ std::move (item_subst));
+ item_refs.push_back (std::move (trait_item_ref));
+ }
+
+ TraitReference trait_object (trait_reference, item_refs,
+ std::move (super_traits),
+ std::move (substitutions));
+ context->insert_trait_reference (
+ trait_reference->get_mappings ().get_defid (), std::move (trait_object));
+
+ tref = &TraitReference::error_node ();
+ bool ok = context->lookup_trait_reference (
+ trait_reference->get_mappings ().get_defid (), &tref);
+ rust_assert (ok);
+
+ // hook to allow the trait to resolve its optional item blocks, we cant
+ // resolve the blocks of functions etc because it can end up in a recursive
+ // loop of trying to resolve traits as required by the types
+ tref->on_resolved ();
+
+ return tref;
+}
+
+TraitReference *
+TraitResolver::lookup_path (HIR::TypePath &path)
+{
+ NodeId ref;
+ if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (),
+ &ref))
+ {
+ rust_error_at (path.get_locus (), "Failed to resolve path to node-id");
+ return &TraitReference::error_node ();
+ }
+
+ HirId hir_node = UNKNOWN_HIRID;
+ if (!mappings->lookup_node_to_hir (ref, &hir_node))
+ {
+ rust_error_at (path.get_locus (), "Failed to resolve path to hir-id");
+ return &TraitReference::error_node ();
+ }
+
+ HIR::Item *resolved_item = mappings->lookup_hir_item (hir_node);
+
+ rust_assert (resolved_item != nullptr);
+ resolved_item->accept_vis (*this);
+ rust_assert (resolved_trait_reference != nullptr);
+
+ TraitReference *tref = &TraitReference::error_node ();
+ if (context->lookup_trait_reference (
+ resolved_trait_reference->get_mappings ().get_defid (), &tref))
+ {
+ return tref;
+ }
+ return &TraitReference::error_node ();
+}
+
+void
+TraitItemReference::on_resolved ()
+{
+ switch (type)
+ {
+ case CONST:
+ resolve_item (static_cast<HIR::TraitItemConst &> (*hir_trait_item));
+ break;
+
+ case TYPE:
+ resolve_item (static_cast<HIR::TraitItemType &> (*hir_trait_item));
+ break;
+
+ case FN:
+ resolve_item (static_cast<HIR::TraitItemFunc &> (*hir_trait_item));
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+TraitItemReference::resolve_item (HIR::TraitItemType &type)
+{
+ TyTy::BaseType *ty
+ = new TyTy::PlaceholderType (type.get_name (),
+ type.get_mappings ().get_hirid ());
+ context->insert_type (type.get_mappings (), ty);
+}
+
+void
+TraitItemReference::resolve_item (HIR::TraitItemConst &constant)
+{
+ // TODO
+}
+
+void
+TraitItemReference::resolve_item (HIR::TraitItemFunc &func)
+{
+ if (!is_optional ())
+ return;
+
+ TyTy::BaseType *item_tyty = get_tyty ();
+ if (item_tyty->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ // check the block and return types
+ rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF);
+
+ // need to get the return type from this
+ TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (item_tyty);
+ auto expected_ret_tyty = resolved_fn_type->get_return_type ();
+ context->push_return_type (TypeCheckContextItem (&func), expected_ret_tyty);
+
+ auto block_expr_ty = TypeCheckExpr::Resolve (func.get_block_expr ().get ());
+
+ context->pop_return_type ();
+
+ if (block_expr_ty->get_kind () != TyTy::NEVER)
+ expected_ret_tyty->unify (block_expr_ty);
+}
+
+void
+TraitItemReference::associated_type_set (TyTy::BaseType *ty) const
+{
+ rust_assert (get_trait_item_type () == TraitItemType::TYPE);
+
+ TyTy::BaseType *item_ty = get_tyty ();
+ rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER);
+ TyTy::PlaceholderType *placeholder
+ = static_cast<TyTy::PlaceholderType *> (item_ty);
+
+ placeholder->set_associated_type (ty->get_ty_ref ());
+}
+
+void
+TraitItemReference::associated_type_reset () const
+{
+ rust_assert (get_trait_item_type () == TraitItemType::TYPE);
+
+ TyTy::BaseType *item_ty = get_tyty ();
+ rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER);
+ TyTy::PlaceholderType *placeholder
+ = static_cast<TyTy::PlaceholderType *> (item_ty);
+
+ placeholder->clear_associated_type ();
+}
+
+void
+AssociatedImplTrait::setup_associated_types (
+ const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound)
+{
+ // compute the constrained impl block generic arguments based on self and the
+ // higher ranked trait bound
+ TyTy::BaseType *receiver = self->clone ();
+
+ // impl<Y> SliceIndex<[Y]> for Range<usize>
+ // vs
+ // I: SliceIndex<[<integer>]> and Range<<integer>>
+ //
+ // we need to figure out what Y is
+
+ TyTy::BaseType *associated_self = get_self ();
+ rust_assert (associated_self->can_eq (self, false));
+
+ // grab the parameters
+ HIR::ImplBlock &impl_block = *get_impl_block ();
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ for (auto &generic_param : impl_block.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ TyTy::BaseType *l = nullptr;
+ bool ok = context->lookup_type (
+ generic_param->get_mappings ().get_hirid (), &l);
+ if (ok && l->get_kind () == TyTy::TypeKind::PARAM)
+ {
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param),
+ static_cast<TyTy::ParamType *> (l)));
+ }
+ }
+ break;
+ }
+ }
+
+ // generate inference variables for these bound arguments so we can compute
+ // their values
+ Location locus;
+ std::vector<TyTy::SubstitutionArg> args;
+ for (auto &p : substitutions)
+ {
+ if (p.needs_substitution ())
+ {
+ TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus);
+ args.push_back (TyTy::SubstitutionArg (&p, infer_var.get_tyty ()));
+ }
+ else
+ {
+ args.push_back (
+ TyTy::SubstitutionArg (&p, p.get_param_ty ()->resolve ()));
+ }
+ }
+
+ // this callback gives us the parameters that get substituted so we can
+ // compute the constrained type parameters for this impl block
+ std::map<std::string, HirId> param_mappings;
+ TyTy::ParamSubstCb param_subst_cb
+ = [&] (const TyTy::ParamType &p, const TyTy::SubstitutionArg &a) {
+ param_mappings[p.get_symbol ()] = a.get_tyty ()->get_ref ();
+ };
+
+ TyTy::SubstitutionArgumentMappings infer_arguments (std::move (args), locus,
+ param_subst_cb);
+ TyTy::BaseType *impl_self_infer
+ = (associated_self->needs_generic_substitutions ())
+ ? SubstMapperInternal::Resolve (associated_self, infer_arguments)
+ : associated_self;
+
+ // FIXME this needs to do a lookup for the trait-reference DefId instead of
+ // assuming its the first one in the list
+ rust_assert (associated_self->num_specified_bounds () > 0);
+ TyTy::TypeBoundPredicate &impl_predicate
+ = associated_self->get_specified_bounds ().at (0);
+
+ // infer the arguments on the predicate
+ std::vector<TyTy::BaseType *> impl_trait_predicate_args;
+ for (const auto &arg : impl_predicate.get_substs ())
+ {
+ const TyTy::ParamType *p = arg.get_param_ty ();
+ if (p->get_symbol ().compare ("Self") == 0)
+ continue;
+
+ TyTy::BaseType *r = p->resolve ();
+ r = SubstMapperInternal::Resolve (r, infer_arguments);
+ impl_trait_predicate_args.push_back (r);
+ }
+
+ // we need to unify the receiver with the impl-block Self so that we compute
+ // the type correctly as our receiver may be generic and we are inferring its
+ // generic arguments and this Self might be the concrete version or vice
+ // versa.
+ auto result = receiver->unify (impl_self_infer);
+ rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
+
+ // unify the bounds arguments
+ std::vector<TyTy::BaseType *> hrtb_bound_arguments;
+ for (const auto &arg : bound.get_substs ())
+ {
+ const TyTy::ParamType *p = arg.get_param_ty ();
+ if (p->get_symbol ().compare ("Self") == 0)
+ continue;
+
+ TyTy::BaseType *r = p->resolve ();
+ hrtb_bound_arguments.push_back (r);
+ }
+
+ rust_assert (impl_trait_predicate_args.size ()
+ == hrtb_bound_arguments.size ());
+ for (size_t i = 0; i < impl_trait_predicate_args.size (); i++)
+ {
+ TyTy::BaseType *a = impl_trait_predicate_args.at (i);
+ TyTy::BaseType *b = hrtb_bound_arguments.at (i);
+
+ result = a->unify (b);
+ rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
+ }
+
+ // create the argument list
+ std::vector<TyTy::SubstitutionArg> associated_arguments;
+ for (auto &p : substitutions)
+ {
+ std::string symbol = p.get_param_ty ()->get_symbol ();
+ auto it = param_mappings.find (symbol);
+ rust_assert (it != param_mappings.end ());
+
+ HirId id = it->second;
+ TyTy::BaseType *argument = nullptr;
+ bool ok = context->lookup_type (id, &argument);
+ rust_assert (ok);
+
+ TyTy::SubstitutionArg arg (&p, argument);
+ associated_arguments.push_back (arg);
+ }
+
+ TyTy::SubstitutionArgumentMappings associated_type_args (
+ std::move (associated_arguments), locus);
+
+ ImplTypeIterator iter (*impl, [&] (HIR::TypeAlias &type) {
+ TraitItemReference *resolved_trait_item = nullptr;
+ bool ok = trait->lookup_trait_item (type.get_new_type_name (),
+ &resolved_trait_item);
+ if (!ok)
+ return;
+ if (resolved_trait_item->get_trait_item_type ()
+ != TraitItemReference::TraitItemType::TYPE)
+ return;
+
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
+ return;
+
+ // this might be generic
+ TyTy::BaseType *substituted
+ = SubstMapperInternal::Resolve (lookup, associated_type_args);
+ resolved_trait_item->associated_type_set (substituted);
+ });
+ iter.go ();
+}
+
+void
+AssociatedImplTrait::reset_associated_types ()
+{
+ trait->clear_associated_types ();
+}
+
+Analysis::NodeMapping
+TraitItemReference::get_parent_trait_mappings () const
+{
+ auto mappings = Analysis::Mappings::get ();
+
+ HIR::Trait *trait
+ = mappings->lookup_trait_item_mapping (get_mappings ().get_hirid ());
+ rust_assert (trait != nullptr);
+
+ return trait->get_mappings ();
+}
+
+bool
+TraitItemReference::is_object_safe () const
+{
+ // https://doc.rust-lang.org/reference/items/traits.html#object-safety
+ switch (get_trait_item_type ())
+ {
+ case TraitItemReference::TraitItemType::FN: {
+ // lets be boring and just check that this is indeed a method will do
+ // for now
+ const HIR::TraitItem *item = get_hir_trait_item ();
+ const HIR::TraitItemFunc *fn
+ = static_cast<const HIR::TraitItemFunc *> (item);
+ return fn->get_decl ().is_method ();
+ }
+
+ // constants are not available via dyn dispatch and so is not object safe
+ case TraitItemReference::TraitItemType::CONST:
+ return false;
+
+ // types are object safe since they are not available via dyn dispatch
+ case TraitItemReference::TraitItemType::TYPE:
+ return true;
+
+ // this is just an error so lets just fail it
+ case TraitItemReference::TraitItemType::ERROR:
+ return false;
+ }
+ return false;
+}
+
+// rust-hir-path-probe.h
+
+void
+PathProbeImplTrait::process_trait_impl_items_for_candidates ()
+{
+ mappings->iterate_impl_items (
+ [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
+ // just need to check if this is an impl block for this trait the next
+ // function checks the receiver
+ if (!impl->has_trait_ref ())
+ return true;
+
+ TraitReference *resolved
+ = TraitResolver::Lookup (*(impl->get_trait_ref ().get ()));
+ if (!trait_reference->is_equal (*resolved))
+ return true;
+
+ process_impl_item_candidate (id, item, impl);
+ return true;
+ });
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h
new file mode 100644
index 00000000000..c4aaf42b141
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2021-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_HIR_TRAIT_RESOLVE_H
+#define RUST_HIR_TRAIT_RESOLVE_H
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-hir-trait-ref.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveTraitItemToRef : public TypeCheckBase,
+ private HIR::HIRTraitItemVisitor
+{
+public:
+ static TraitItemReference
+ Resolve (HIR::TraitItem &item, TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions)
+ {
+ ResolveTraitItemToRef resolver (self, std::move (substitutions));
+ item.accept_vis (resolver);
+ return std::move (resolver.resolved);
+ }
+
+ void visit (HIR::TraitItemType &type) override;
+
+ void visit (HIR::TraitItemConst &cst) override;
+
+ void visit (HIR::TraitItemFunc &fn) override;
+
+private:
+ ResolveTraitItemToRef (
+ TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> &&substitutions);
+
+ TraitItemReference resolved;
+ TyTy::BaseType *self;
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+};
+
+class TraitResolver : public TypeCheckBase, private HIR::HIRFullVisitorBase
+{
+ using HIR::HIRFullVisitorBase::visit;
+
+public:
+ static TraitReference *Resolve (HIR::TypePath &path);
+
+ static TraitReference *Resolve (HIR::Trait &trait);
+
+ static TraitReference *Lookup (HIR::TypePath &path);
+
+private:
+ TraitResolver ();
+
+ TraitReference *resolve_path (HIR::TypePath &path);
+
+ TraitReference *resolve_trait (HIR::Trait *trait_reference);
+
+ TraitReference *lookup_path (HIR::TypePath &path);
+
+ HIR::Trait *resolved_trait_reference;
+
+public:
+ void visit (HIR::Trait &trait) override { resolved_trait_reference = &trait; }
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TRAIT_RESOLVE_H
diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h
new file mode 100644
index 00000000000..44400efbbf7
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-bounds.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2021-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_HIR_TYPE_BOUNDS_H
+#define RUST_HIR_TYPE_BOUNDS_H
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeBoundsProbe : public TypeCheckBase
+{
+public:
+ static std::vector<std::pair<TraitReference *, HIR::ImplBlock *>>
+ Probe (const TyTy::BaseType *receiver)
+ {
+ TypeBoundsProbe probe (receiver);
+ probe.scan ();
+ return probe.trait_references;
+ }
+
+ static bool is_bound_satisfied_for_type (TyTy::BaseType *receiver,
+ TraitReference *ref)
+ {
+ for (auto &bound : receiver->get_specified_bounds ())
+ {
+ const TraitReference *b = bound.get ();
+ if (b->is_equal (*ref))
+ return true;
+ }
+
+ std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
+ = Probe (receiver);
+ for (auto &bound : bounds)
+ {
+ const TraitReference *b = bound.first;
+ if (b->is_equal (*ref))
+ return true;
+ }
+
+ return false;
+ }
+
+private:
+ void scan ();
+
+private:
+ TypeBoundsProbe (const TyTy::BaseType *receiver)
+ : TypeCheckBase (), receiver (receiver)
+ {}
+
+ const TyTy::BaseType *receiver;
+ std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> trait_references;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_BOUNDS_H
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc
new file mode 100644
index 00000000000..ac5c3b97475
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -0,0 +1,439 @@
+// 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-hir-type-check-base.h"
+#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 {
+
+bool
+TypeCheckBase::check_for_unconstrained (
+ const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain,
+ const TyTy::SubstitutionArgumentMappings &constraint_a,
+ const TyTy::SubstitutionArgumentMappings &constraint_b,
+ const TyTy::BaseType *reference)
+{
+ std::set<HirId> symbols_to_constrain;
+ std::map<HirId, Location> symbol_to_location;
+ for (const auto &p : params_to_constrain)
+ {
+ HirId ref = p.get_param_ty ()->get_ref ();
+ symbols_to_constrain.insert (ref);
+ symbol_to_location.insert ({ref, p.get_param_locus ()});
+ }
+
+ // set up the set of constrained symbols
+ std::set<HirId> constrained_symbols;
+ for (const auto &c : constraint_a.get_mappings ())
+ {
+ const TyTy::BaseType *arg = c.get_tyty ();
+ if (arg != nullptr)
+ {
+ const TyTy::BaseType *p = arg->get_root ();
+ constrained_symbols.insert (p->get_ty_ref ());
+ }
+ }
+ for (const auto &c : constraint_b.get_mappings ())
+ {
+ const TyTy::BaseType *arg = c.get_tyty ();
+ if (arg != nullptr)
+ {
+ const TyTy::BaseType *p = arg->get_root ();
+ constrained_symbols.insert (p->get_ty_ref ());
+ }
+ }
+
+ const auto root = reference->get_root ();
+ if (root->get_kind () == TyTy::TypeKind::PARAM)
+ {
+ const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (root);
+ constrained_symbols.insert (p->get_ty_ref ());
+ }
+
+ // check for unconstrained
+ bool unconstrained = false;
+ for (auto &sym : symbols_to_constrain)
+ {
+ bool used = constrained_symbols.find (sym) != constrained_symbols.end ();
+ if (!used)
+ {
+ Location locus = symbol_to_location.at (sym);
+ rust_error_at (locus, "unconstrained type parameter");
+ unconstrained = true;
+ }
+ }
+ return unconstrained;
+}
+
+TyTy::BaseType *
+TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings,
+ HIR::Literal &literal, Location locus)
+{
+ TyTy::BaseType *infered = nullptr;
+ switch (literal.get_lit_type ())
+ {
+ case HIR::Literal::LitType::INT: {
+ bool ok = false;
+
+ switch (literal.get_type_hint ())
+ {
+ case CORETYPE_I8:
+ ok = context->lookup_builtin ("i8", &infered);
+ break;
+ case CORETYPE_I16:
+ ok = context->lookup_builtin ("i16", &infered);
+ break;
+ case CORETYPE_I32:
+ ok = context->lookup_builtin ("i32", &infered);
+ break;
+ case CORETYPE_I64:
+ ok = context->lookup_builtin ("i64", &infered);
+ break;
+ case CORETYPE_I128:
+ ok = context->lookup_builtin ("i128", &infered);
+ break;
+
+ case CORETYPE_U8:
+ ok = context->lookup_builtin ("u8", &infered);
+ break;
+ case CORETYPE_U16:
+ ok = context->lookup_builtin ("u16", &infered);
+ break;
+ case CORETYPE_U32:
+ ok = context->lookup_builtin ("u32", &infered);
+ break;
+ case CORETYPE_U64:
+ ok = context->lookup_builtin ("u64", &infered);
+ break;
+ case CORETYPE_U128:
+ ok = context->lookup_builtin ("u128", &infered);
+ break;
+
+ case CORETYPE_F32:
+ literal.set_lit_type (HIR::Literal::LitType::FLOAT);
+ ok = context->lookup_builtin ("f32", &infered);
+ break;
+ case CORETYPE_F64:
+ literal.set_lit_type (HIR::Literal::LitType::FLOAT);
+ ok = context->lookup_builtin ("f64", &infered);
+ break;
+
+ case CORETYPE_ISIZE:
+ ok = context->lookup_builtin ("isize", &infered);
+ break;
+
+ case CORETYPE_USIZE:
+ ok = context->lookup_builtin ("usize", &infered);
+ break;
+
+ default:
+ ok = true;
+ infered
+ = new TyTy::InferType (expr_mappings.get_hirid (),
+ TyTy::InferType::InferTypeKind::INTEGRAL,
+ locus);
+ break;
+ }
+ rust_assert (ok);
+ }
+ break;
+
+ case HIR::Literal::LitType::FLOAT: {
+ bool ok = false;
+
+ switch (literal.get_type_hint ())
+ {
+ case CORETYPE_F32:
+ ok = context->lookup_builtin ("f32", &infered);
+ break;
+ case CORETYPE_F64:
+ ok = context->lookup_builtin ("f64", &infered);
+ break;
+
+ default:
+ ok = true;
+ infered
+ = new TyTy::InferType (expr_mappings.get_hirid (),
+ TyTy::InferType::InferTypeKind::FLOAT,
+ locus);
+ break;
+ }
+ rust_assert (ok);
+ }
+ break;
+
+ case HIR::Literal::LitType::BOOL: {
+ auto ok = context->lookup_builtin ("bool", &infered);
+ rust_assert (ok);
+ }
+ break;
+
+ case HIR::Literal::LitType::CHAR: {
+ auto ok = context->lookup_builtin ("char", &infered);
+ rust_assert (ok);
+ }
+ break;
+
+ case HIR::Literal::LitType::BYTE: {
+ auto ok = context->lookup_builtin ("u8", &infered);
+ rust_assert (ok);
+ }
+ break;
+
+ case HIR::Literal::LitType::STRING: {
+ TyTy::BaseType *base = nullptr;
+ auto ok = context->lookup_builtin ("str", &base);
+ rust_assert (ok);
+
+ infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
+ TyTy::TyVar (base->get_ref ()),
+ Mutability::Imm);
+ }
+ break;
+
+ case HIR::Literal::LitType::BYTE_STRING: {
+ /* This is an arraytype of u8 reference (&[u8;size]). It isn't in
+ UTF-8, but really just a byte array. Code to construct the array
+ reference copied from ArrayElemsValues and ArrayType. */
+ TyTy::BaseType *u8;
+ auto ok = context->lookup_builtin ("u8", &u8);
+ rust_assert (ok);
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping capacity_mapping (crate_num, UNKNOWN_NODEID,
+ mappings->get_next_hir_id (
+ crate_num),
+ UNKNOWN_LOCAL_DEFID);
+
+ /* Capacity is the size of the string (number of chars).
+ It is a constant, but for fold it to get a tree. */
+ std::string capacity_str
+ = std::to_string (literal.as_string ().size ());
+ HIR::LiteralExpr *literal_capacity
+ = new HIR::LiteralExpr (capacity_mapping, capacity_str,
+ HIR::Literal::LitType::INT,
+ PrimitiveCoreType::CORETYPE_USIZE, locus, {});
+
+ // mark the type for this implicit node
+ TyTy::BaseType *expected_ty = nullptr;
+ ok = context->lookup_builtin ("usize", &expected_ty);
+ rust_assert (ok);
+ context->insert_type (capacity_mapping, expected_ty);
+
+ Analysis::NodeMapping array_mapping (crate_num, UNKNOWN_NODEID,
+ mappings->get_next_hir_id (
+ crate_num),
+ UNKNOWN_LOCAL_DEFID);
+
+ TyTy::ArrayType *array
+ = new TyTy::ArrayType (array_mapping.get_hirid (), locus,
+ *literal_capacity,
+ TyTy::TyVar (u8->get_ref ()));
+ context->insert_type (array_mapping, array);
+
+ infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
+ TyTy::TyVar (array->get_ref ()),
+ Mutability::Imm);
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+
+ return infered;
+}
+
+TyTy::ADTType::ReprOptions
+TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, Location locus)
+{
+ TyTy::ADTType::ReprOptions repr;
+ repr.pack = 0;
+ repr.align = 0;
+
+ for (const auto &attr : attrs)
+ {
+ bool is_repr = attr.get_path ().as_string ().compare ("repr") == 0;
+ if (is_repr)
+ {
+ const AST::AttrInput &input = attr.get_attr_input ();
+ bool is_token_tree = input.get_attr_input_type ()
+ == AST::AttrInput::AttrInputType::TOKEN_TREE;
+ rust_assert (is_token_tree);
+ const auto &option = static_cast<const AST::DelimTokenTree &> (input);
+ AST::AttrInputMetaItemContainer *meta_items
+ = option.parse_to_meta_item ();
+
+ const std::string inline_option
+ = meta_items->get_items ().at (0)->as_string ();
+
+ // TODO: it would probably be better to make the MetaItems more aware
+ // of constructs with nesting like #[repr(packed(2))] rather than
+ // manually parsing the string "packed(2)" here.
+
+ size_t oparen = inline_option.find ('(', 0);
+ bool is_pack = false, is_align = false;
+ unsigned char value = 1;
+
+ if (oparen == std::string::npos)
+ {
+ is_pack = inline_option.compare ("packed") == 0;
+ is_align = inline_option.compare ("align") == 0;
+ }
+
+ else
+ {
+ std::string rep = inline_option.substr (0, oparen);
+ is_pack = rep.compare ("packed") == 0;
+ is_align = rep.compare ("align") == 0;
+
+ size_t cparen = inline_option.find (')', oparen);
+ if (cparen == std::string::npos)
+ {
+ rust_error_at (locus, "malformed attribute");
+ }
+
+ std::string value_str = inline_option.substr (oparen, cparen);
+ value = strtoul (value_str.c_str () + 1, NULL, 10);
+ }
+
+ if (is_pack)
+ repr.pack = value;
+ else if (is_align)
+ repr.align = value;
+
+ // Multiple repr options must be specified with e.g. #[repr(C,
+ // packed(2))].
+ break;
+ }
+ }
+
+ return repr;
+}
+
+TyTy::BaseType *
+TypeCheckBase::coercion_site (HirId id, TyTy::BaseType *expected,
+ TyTy::BaseType *expr, Location locus)
+{
+ rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
+ expected->debug_str ().c_str (), expr->debug_str ().c_str ());
+
+ auto context = TypeCheckContext::get ();
+ if (expected->get_kind () == TyTy::TypeKind::ERROR
+ || expr->get_kind () == TyTy::TypeKind::ERROR)
+ return expr;
+
+ // can we autoderef it?
+ auto result = TypeCoercionRules::Coerce (expr, expected, locus);
+
+ // the result needs to be unified
+ TyTy::BaseType *receiver = expr;
+ if (!result.is_error ())
+ {
+ receiver = result.tyty;
+ }
+
+ rust_debug ("coerce_default_unify(a={%s}, b={%s})",
+ receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
+ TyTy::BaseType *coerced = expected->unify (receiver);
+ context->insert_autoderef_mappings (id, std::move (result.adjustments));
+ 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,
+ std::vector<TyTy::SubstitutionParamMapping> &substitutions)
+{
+ for (auto &generic_param : generic_params)
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ // FIXME: Skipping Lifetime completely until better
+ // handling.
+ break;
+ case HIR::GenericParam::GenericKind::CONST: {
+ auto param
+ = static_cast<HIR::ConstGenericParam *> (generic_param.get ());
+ auto specified_type
+ = TypeCheckType::Resolve (param->get_type ().get ());
+
+ if (param->has_default_expression ())
+ {
+ auto expr_type = TypeCheckExpr::Resolve (
+ param->get_default_expression ().get ());
+
+ specified_type->unify (expr_type);
+ }
+
+ context->insert_type (generic_param->get_mappings (),
+ specified_type);
+ }
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (), param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h
new file mode 100644
index 00000000000..aa42d9d6dfd
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.h
@@ -0,0 +1,80 @@
+// 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_HIR_TYPE_CHECK_BASE
+#define RUST_HIR_TYPE_CHECK_BASE
+
+#include "rust-diagnostics.h"
+#include "rust-hir-type-check.h"
+#include "rust-name-resolver.h"
+#include "rust-hir-visitor.h"
+#include "rust-hir-map.h"
+#include "rust-backend.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TraitReference;
+class TypeCheckBase
+{
+public:
+ virtual ~TypeCheckBase () {}
+
+ static TyTy::BaseType *coercion_site (HirId id, TyTy::BaseType *lhs,
+ TyTy::BaseType *rhs,
+ Location coercion_locus);
+
+ static TyTy::BaseType *cast_site (HirId id, TyTy::TyWithLocation from,
+ TyTy::TyWithLocation to,
+ Location cast_locus);
+
+protected:
+ TypeCheckBase ()
+ : mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()),
+ context (TypeCheckContext::get ())
+ {}
+
+ TraitReference *resolve_trait_path (HIR::TypePath &);
+
+ TyTy::TypeBoundPredicate get_predicate_from_bound (HIR::TypePath &path);
+
+ bool check_for_unconstrained (
+ const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain,
+ const TyTy::SubstitutionArgumentMappings &constraint_a,
+ const TyTy::SubstitutionArgumentMappings &constraint_b,
+ const TyTy::BaseType *reference);
+
+ TyTy::BaseType *resolve_literal (const Analysis::NodeMapping &mappings,
+ HIR::Literal &literal, Location locus);
+
+ TyTy::ADTType::ReprOptions parse_repr_options (const AST::AttrVec &attrs,
+ Location locus);
+
+ void resolve_generic_params (
+ const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
+ std::vector<TyTy::SubstitutionParamMapping> &substitutions);
+
+ Analysis::Mappings *mappings;
+ Resolver *resolver;
+ TypeCheckContext *context;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_BASE
diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
new file mode 100644
index 00000000000..e65b2011d36
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
@@ -0,0 +1,213 @@
+// 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-hir-full.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-enumitem.h"
+
+namespace Rust {
+namespace Resolver {
+
+TyTy::VariantDef *
+TypeCheckEnumItem::Resolve (HIR::EnumItem *item, int64_t last_discriminant)
+{
+ TypeCheckEnumItem resolver (last_discriminant);
+ switch (item->get_enum_item_kind ())
+ {
+ case HIR::EnumItem::EnumItemKind::Named:
+ resolver.visit (static_cast<HIR::EnumItem &> (*item));
+ break;
+
+ case HIR::EnumItem::EnumItemKind::Tuple:
+ resolver.visit (static_cast<HIR::EnumItemTuple &> (*item));
+ break;
+
+ case HIR::EnumItem::EnumItemKind::Struct:
+ resolver.visit (static_cast<HIR::EnumItemStruct &> (*item));
+ break;
+
+ case HIR::EnumItem::EnumItemKind::Discriminant:
+ resolver.visit (static_cast<HIR::EnumItemDiscriminant &> (*item));
+ break;
+ }
+ return resolver.variant;
+}
+
+TypeCheckEnumItem::TypeCheckEnumItem (int64_t last_discriminant)
+ : TypeCheckBase (), variant (nullptr), last_discriminant (last_discriminant)
+{}
+
+void
+TypeCheckEnumItem::visit (HIR::EnumItem &item)
+{
+ if (last_discriminant == INT64_MAX)
+ rust_error_at (item.get_locus (), "discriminant too big");
+
+ Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (),
+ item.get_mappings ().get_nodeid (),
+ mappings->get_next_hir_id (
+ item.get_mappings ().get_crate_num ()),
+ item.get_mappings ().get_local_defid ());
+ HIR::LiteralExpr *discim_expr
+ = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant),
+ HIR::Literal::LitType::INT,
+ PrimitiveCoreType::CORETYPE_I64, item.get_locus (),
+ {});
+
+ TyTy::BaseType *isize = nullptr;
+ bool ok = context->lookup_builtin ("isize", &isize);
+ rust_assert (ok);
+ context->insert_type (mapping, isize);
+
+ const CanonicalPath *canonical_path = nullptr;
+ ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+
+ RustIdent ident{*canonical_path, item.get_locus ()};
+ variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
+ item.get_identifier (), ident, discim_expr);
+}
+
+void
+TypeCheckEnumItem::visit (HIR::EnumItemDiscriminant &item)
+{
+ if (last_discriminant == INT64_MAX)
+ rust_error_at (item.get_locus (), "discriminant too big");
+
+ auto &discriminant = item.get_discriminant_expression ();
+ auto capacity_type = TypeCheckExpr::Resolve (discriminant.get ());
+ if (capacity_type->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ TyTy::ISizeType *expected_ty
+ = new TyTy::ISizeType (discriminant->get_mappings ().get_hirid ());
+ context->insert_type (discriminant->get_mappings (), expected_ty);
+
+ auto unified = expected_ty->unify (capacity_type);
+ if (unified->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+
+ RustIdent ident{*canonical_path, item.get_locus ()};
+ variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
+ item.get_identifier (), ident,
+ item.get_discriminant_expression ().get ());
+}
+
+void
+TypeCheckEnumItem::visit (HIR::EnumItemTuple &item)
+{
+ if (last_discriminant == INT64_MAX)
+ rust_error_at (item.get_locus (), "discriminant too big");
+
+ std::vector<TyTy::StructFieldType *> fields;
+ size_t idx = 0;
+ for (auto &field : item.get_tuple_fields ())
+ {
+ TyTy::BaseType *field_type
+ = TypeCheckType::Resolve (field.get_field_type ().get ());
+ TyTy::StructFieldType *ty_field
+ = new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+ std::to_string (idx), field_type);
+ fields.push_back (ty_field);
+ context->insert_type (field.get_mappings (), ty_field->get_field_type ());
+ idx++;
+ }
+
+ Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (),
+ item.get_mappings ().get_nodeid (),
+ mappings->get_next_hir_id (
+ item.get_mappings ().get_crate_num ()),
+ item.get_mappings ().get_local_defid ());
+ HIR::LiteralExpr *discim_expr
+ = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant),
+ HIR::Literal::LitType::INT,
+ PrimitiveCoreType::CORETYPE_I64, item.get_locus (),
+ {});
+
+ TyTy::BaseType *isize = nullptr;
+ bool ok = context->lookup_builtin ("isize", &isize);
+ rust_assert (ok);
+ context->insert_type (mapping, isize);
+
+ const CanonicalPath *canonical_path = nullptr;
+ ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+
+ RustIdent ident{*canonical_path, item.get_locus ()};
+ variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
+ item.get_identifier (), ident,
+ TyTy::VariantDef::VariantType::TUPLE,
+ discim_expr, fields);
+}
+
+void
+TypeCheckEnumItem::visit (HIR::EnumItemStruct &item)
+{
+ if (last_discriminant == INT64_MAX)
+ rust_error_at (item.get_locus (), "discriminant too big");
+
+ std::vector<TyTy::StructFieldType *> fields;
+ for (auto &field : item.get_struct_fields ())
+ {
+ TyTy::BaseType *field_type
+ = TypeCheckType::Resolve (field.get_field_type ().get ());
+ TyTy::StructFieldType *ty_field
+ = new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+ field.get_field_name (), field_type);
+ fields.push_back (ty_field);
+ context->insert_type (field.get_mappings (), ty_field->get_field_type ());
+ }
+
+ Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (),
+ item.get_mappings ().get_nodeid (),
+ mappings->get_next_hir_id (
+ item.get_mappings ().get_crate_num ()),
+ item.get_mappings ().get_local_defid ());
+ HIR::LiteralExpr *discrim_expr
+ = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant),
+ HIR::Literal::LitType::INT,
+ PrimitiveCoreType::CORETYPE_I64, item.get_locus (),
+ {});
+
+ TyTy::BaseType *isize = nullptr;
+ bool ok = context->lookup_builtin ("isize", &isize);
+ rust_assert (ok);
+ context->insert_type (mapping, isize);
+
+ const CanonicalPath *canonical_path = nullptr;
+ ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+
+ RustIdent ident{*canonical_path, item.get_locus ()};
+ variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
+ item.get_identifier (), ident,
+ TyTy::VariantDef::VariantType::STRUCT,
+ discrim_expr, fields);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.h b/gcc/rust/typecheck/rust-hir-type-check-enumitem.h
new file mode 100644
index 00000000000..c771ea3782d
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.h
@@ -0,0 +1,50 @@
+// 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_HIR_TYPE_CHECK_ENUMITEM
+#define RUST_HIR_TYPE_CHECK_ENUMITEM
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckEnumItem : public TypeCheckBase
+{
+public:
+ static TyTy::VariantDef *Resolve (HIR::EnumItem *item,
+ int64_t last_discriminant);
+
+protected:
+ void visit (HIR::EnumItem &item);
+ void visit (HIR::EnumItemDiscriminant &item);
+ void visit (HIR::EnumItemTuple &item);
+ void visit (HIR::EnumItemStruct &item);
+
+private:
+ TypeCheckEnumItem (int64_t last_discriminant);
+
+ TyTy::VariantDef *variant;
+ int64_t last_discriminant;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_ENUMITEM
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
new file mode 100644
index 00000000000..4371f5a59a5
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -0,0 +1,1567 @@
+// 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-hir-full.h"
+#include "rust-tyty-call.h"
+#include "rust-hir-type-check-struct-field.h"
+#include "rust-hir-path-probe.h"
+#include "rust-substitution-mapper.h"
+#include "rust-hir-trait-resolve.h"
+#include "rust-hir-type-bounds.h"
+#include "rust-hir-dot-operator.h"
+#include "rust-hir-type-check-pattern.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-stmt.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCheckExpr::TypeCheckExpr () : TypeCheckBase (), infered (nullptr) {}
+
+// Perform type checking on expr. Also runs type unification algorithm.
+// Returns the unified type of expr
+TyTy::BaseType *
+TypeCheckExpr::Resolve (HIR::Expr *expr)
+{
+ TypeCheckExpr resolver;
+ expr->accept_vis (resolver);
+
+ if (resolver.infered == nullptr)
+ {
+ // FIXME
+ // this is an internal error message for debugging and should be removed
+ // at some point
+ rust_error_at (expr->get_locus (), "failed to type resolve expression");
+ return new TyTy::ErrorType (expr->get_mappings ().get_hirid ());
+ }
+
+ auto ref = expr->get_mappings ().get_hirid ();
+ resolver.infered->set_ref (ref);
+ resolver.context->insert_type (expr->get_mappings (), resolver.infered);
+
+ return resolver.infered;
+}
+
+void
+TypeCheckExpr::visit (HIR::TupleIndexExpr &expr)
+{
+ auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ().get ());
+ if (resolved->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (expr.get_tuple_expr ()->get_locus (),
+ "failed to resolve TupleIndexExpr receiver");
+ return;
+ }
+
+ // FIXME does this require autoderef here?
+ if (resolved->get_kind () == TyTy::TypeKind::REF)
+ {
+ TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (resolved);
+ resolved = r->get_base ();
+ }
+
+ bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT
+ || resolved->get_kind () == TyTy::TypeKind::TUPLE;
+ if (!is_valid_type)
+ {
+ rust_error_at (expr.get_tuple_expr ()->get_locus (),
+ "Expected Tuple or ADT got: %s",
+ resolved->as_string ().c_str ());
+ return;
+ }
+
+ if (resolved->get_kind () == TyTy::TypeKind::TUPLE)
+ {
+ TyTy::TupleType *tuple = static_cast<TyTy::TupleType *> (resolved);
+ TupleIndex index = expr.get_tuple_index ();
+ if ((size_t) index >= tuple->num_fields ())
+ {
+ rust_error_at (expr.get_locus (), "unknown field at index %i", index);
+ return;
+ }
+
+ auto field_tyty = tuple->get_field ((size_t) index);
+ if (field_tyty == nullptr)
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to lookup field type at index %i", index);
+ return;
+ }
+
+ infered = field_tyty;
+ return;
+ }
+
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (resolved);
+ rust_assert (!adt->is_enum ());
+ rust_assert (adt->number_of_variants () == 1);
+
+ TyTy::VariantDef *variant = adt->get_variants ().at (0);
+ TupleIndex index = expr.get_tuple_index ();
+ if ((size_t) index >= variant->num_fields ())
+ {
+ rust_error_at (expr.get_locus (), "unknown field at index %i", index);
+ return;
+ }
+
+ auto field_tyty = variant->get_field_at_index ((size_t) index);
+ if (field_tyty == nullptr)
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to lookup field type at index %i", index);
+ return;
+ }
+
+ infered = field_tyty->get_field_type ();
+}
+
+void
+TypeCheckExpr::visit (HIR::TupleExpr &expr)
+{
+ if (expr.is_unit ())
+ {
+ auto unit_node_id = resolver->get_unit_type_node_id ();
+ if (!context->lookup_builtin (unit_node_id, &infered))
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to lookup builtin unit type");
+ }
+ return;
+ }
+
+ std::vector<TyTy::TyVar> fields;
+ for (auto &elem : expr.get_tuple_elems ())
+ {
+ auto field_ty = TypeCheckExpr::Resolve (elem.get ());
+ fields.push_back (TyTy::TyVar (field_ty->get_ref ()));
+ }
+ infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (),
+ expr.get_locus (), fields);
+}
+
+void
+TypeCheckExpr::visit (HIR::ReturnExpr &expr)
+{
+ auto fn_return_tyty = context->peek_return_type ();
+ rust_assert (fn_return_tyty != nullptr);
+
+ TyTy::BaseType *expr_ty
+ = expr.has_return_expr ()
+ ? TypeCheckExpr::Resolve (expr.get_expr ())
+ : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+
+ infered = fn_return_tyty->unify (expr_ty);
+ fn_return_tyty->append_reference (expr_ty->get_ref ());
+ for (auto &ref : infered->get_combined_refs ())
+ fn_return_tyty->append_reference (ref);
+
+ infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckExpr::visit (HIR::CallExpr &expr)
+{
+ TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ());
+
+ bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::ADT
+ || function_tyty->get_kind () == TyTy::TypeKind::FNDEF
+ || function_tyty->get_kind () == TyTy::TypeKind::FNPTR;
+ if (!valid_tyty)
+ {
+ rust_error_at (expr.get_locus (),
+ "Failed to resolve expression of function call");
+ return;
+ }
+
+ TyTy::VariantDef &variant = TyTy::VariantDef::get_error_node ();
+ if (function_tyty->get_kind () == TyTy::TypeKind::ADT)
+ {
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (function_tyty);
+ if (adt->is_enum ())
+ {
+ // lookup variant id
+ HirId variant_id;
+ bool ok = context->lookup_variant_definition (
+ expr.get_fnexpr ()->get_mappings ().get_hirid (), &variant_id);
+ rust_assert (ok);
+
+ TyTy::VariantDef *lookup_variant = nullptr;
+ ok = adt->lookup_variant_by_id (variant_id, &lookup_variant);
+ rust_assert (ok);
+
+ variant = *lookup_variant;
+ }
+ else
+ {
+ rust_assert (adt->number_of_variants () == 1);
+ variant = *adt->get_variants ().at (0);
+ }
+ }
+
+ infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
+}
+
+void
+TypeCheckExpr::visit (HIR::AssignmentExpr &expr)
+{
+ infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+
+ auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
+ auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+
+ coercion_site (expr.get_mappings ().get_hirid (), lhs, rhs,
+ expr.get_locus ());
+}
+
+void
+TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr)
+{
+ infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+
+ auto lhs = TypeCheckExpr::Resolve (expr.get_left_expr ().get ());
+ auto rhs = TypeCheckExpr::Resolve (expr.get_right_expr ().get ());
+
+ // we dont care about the result of the unify from a compound assignment
+ // since this is a unit-type expr
+ auto result = lhs->unify (rhs);
+ if (result->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ auto lang_item_type
+ = Analysis::RustLangItem::CompoundAssignmentOperatorToLangItem (
+ expr.get_expr_type ());
+ bool operator_overloaded
+ = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
+ if (operator_overloaded)
+ return;
+
+ bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
+ bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
+ bool valid = valid_lhs && valid_rhs;
+ if (!valid)
+ {
+ rust_error_at (expr.get_locus (),
+ "cannot apply this operator to types %s and %s",
+ lhs->as_string ().c_str (), rhs->as_string ().c_str ());
+ return;
+ }
+}
+
+void
+TypeCheckExpr::visit (HIR::LiteralExpr &expr)
+{
+ infered = resolve_literal (expr.get_mappings (), expr.get_literal (),
+ expr.get_locus ());
+}
+
+void
+TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
+{
+ auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
+ auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+
+ auto lang_item_type
+ = Analysis::RustLangItem::OperatorToLangItem (expr.get_expr_type ());
+ bool operator_overloaded
+ = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
+ if (operator_overloaded)
+ return;
+
+ bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
+ bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
+ bool valid = valid_lhs && valid_rhs;
+ if (!valid)
+ {
+ rust_error_at (expr.get_locus (),
+ "cannot apply this operator to types %s and %s",
+ lhs->as_string ().c_str (), rhs->as_string ().c_str ());
+ return;
+ }
+
+ switch (expr.get_expr_type ())
+ {
+ case ArithmeticOrLogicalOperator::LEFT_SHIFT:
+ 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:
+ infered = lhs->unify (rhs);
+ break;
+ }
+}
+
+void
+TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
+{
+ auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
+ auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+
+ auto result = lhs->unify (rhs);
+ if (result == nullptr || result->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ bool ok = context->lookup_builtin ("bool", &infered);
+ rust_assert (ok);
+}
+
+void
+TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr)
+{
+ auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
+ auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+
+ // we expect the lhs and rhs must be bools at this point
+ TyTy::BoolType elhs (expr.get_mappings ().get_hirid ());
+ lhs = elhs.unify (lhs);
+ if (lhs->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ TyTy::BoolType rlhs (expr.get_mappings ().get_hirid ());
+ rhs = elhs.unify (rhs);
+ if (lhs->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ infered = lhs->unify (rhs);
+}
+
+void
+TypeCheckExpr::visit (HIR::NegationExpr &expr)
+{
+ auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ().get ());
+
+ // check for operator overload
+ auto lang_item_type = Analysis::RustLangItem::NegationOperatorToLangItem (
+ expr.get_expr_type ());
+ bool operator_overloaded
+ = resolve_operator_overload (lang_item_type, expr, negated_expr_ty,
+ nullptr);
+ if (operator_overloaded)
+ return;
+
+ // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators
+ switch (expr.get_expr_type ())
+ {
+ case NegationOperator::NEGATE: {
+ bool valid
+ = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::FLOAT)
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::ISIZE)
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::USIZE)
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
+ && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
+ == TyTy::InferType::INTEGRAL))
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
+ && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
+ == TyTy::InferType::FLOAT));
+ if (!valid)
+ {
+ rust_error_at (expr.get_locus (), "cannot apply unary - to %s",
+ negated_expr_ty->as_string ().c_str ());
+ return;
+ }
+ }
+ break;
+
+ case NegationOperator::NOT: {
+ bool valid
+ = (negated_expr_ty->get_kind () == TyTy::TypeKind::BOOL)
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
+ || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
+ && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
+ == TyTy::InferType::INTEGRAL));
+ if (!valid)
+ {
+ rust_error_at (expr.get_locus (), "cannot apply unary %<!%> to %s",
+ negated_expr_ty->as_string ().c_str ());
+ return;
+ }
+ }
+ break;
+ }
+
+ infered = negated_expr_ty->clone ();
+ infered->append_reference (negated_expr_ty->get_ref ());
+}
+
+void
+TypeCheckExpr::visit (HIR::IfExpr &expr)
+{
+ TypeCheckExpr::Resolve (expr.get_if_condition ());
+ TypeCheckExpr::Resolve (expr.get_if_block ());
+
+ infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckExpr::visit (HIR::IfExprConseqElse &expr)
+{
+ TypeCheckExpr::Resolve (expr.get_if_condition ());
+ auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ());
+ auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block ());
+
+ if (if_blk_resolved->get_kind () == TyTy::NEVER)
+ infered = else_blk_resolved;
+ else if (else_blk_resolved->get_kind () == TyTy::NEVER)
+ infered = if_blk_resolved;
+ else
+ infered = if_blk_resolved->unify (else_blk_resolved);
+}
+
+void
+TypeCheckExpr::visit (HIR::IfExprConseqIf &expr)
+{
+ TypeCheckExpr::Resolve (expr.get_if_condition ());
+ auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ());
+ auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_conseq_if_expr ());
+
+ if (if_blk_resolved->get_kind () == TyTy::NEVER)
+ infered = else_blk_resolved;
+ else if (else_blk_resolved->get_kind () == TyTy::NEVER)
+ infered = if_blk_resolved;
+ else
+ infered = if_blk_resolved->unify (else_blk_resolved);
+}
+
+void
+TypeCheckExpr::visit (HIR::IfLetExpr &expr)
+{
+ // this needs to perform a least upper bound coercion on the blocks and then
+ // unify the scruintee and arms
+ TyTy::BaseType *scrutinee_tyty
+ = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ());
+
+ for (auto &pattern : expr.get_patterns ())
+ {
+ TyTy::BaseType *kase_arm_ty
+ = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty);
+
+ TyTy::BaseType *checked_kase = scrutinee_tyty->unify (kase_arm_ty);
+ if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+
+ TypeCheckExpr::Resolve (expr.get_if_block ());
+
+ infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr)
+{
+ infered = TypeCheckExpr::Resolve (expr.get_block_expr ().get ());
+}
+
+void
+TypeCheckExpr::visit (HIR::BlockExpr &expr)
+{
+ for (auto &s : expr.get_statements ())
+ {
+ if (!s->is_item ())
+ continue;
+
+ TypeCheckStmt::Resolve (s.get ());
+ }
+
+ for (auto &s : expr.get_statements ())
+ {
+ if (s->is_item ())
+ continue;
+
+ auto resolved = TypeCheckStmt::Resolve (s.get ());
+ if (resolved == nullptr)
+ {
+ rust_error_at (s->get_locus (), "failure to resolve type");
+ return;
+ }
+
+ if (s->is_unit_check_needed () && !resolved->is_unit ())
+ {
+ auto unit
+ = TyTy::TupleType::get_unit_type (s->get_mappings ().get_hirid ());
+ resolved = unit->unify (resolved);
+ }
+ }
+
+ if (expr.has_expr ())
+ infered = TypeCheckExpr::Resolve (expr.get_final_expr ().get ())->clone ();
+ else if (expr.is_tail_reachable ())
+ infered
+ = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+ else
+ infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckExpr::visit (HIR::RangeFromToExpr &expr)
+{
+ auto lang_item_type = Analysis::RustLangItem::ItemType::RANGE;
+
+ DefId respective_lang_item_id = UNKNOWN_DEFID;
+ bool lang_item_defined
+ = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
+
+ // we need to have it maybe
+ if (!lang_item_defined)
+ {
+ rust_internal_error_at (
+ expr.get_locus (), "unable to find relevant lang item: %s",
+ Analysis::RustLangItem::ToString (lang_item_type).c_str ());
+ return;
+ }
+
+ // look it up and it _must_ be a struct definition
+ HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
+ rust_assert (item != nullptr);
+
+ TyTy::BaseType *item_type = nullptr;
+ bool ok
+ = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
+ rust_assert (ok);
+ rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
+
+ // this is a single generic item lets assert that
+ rust_assert (adt->get_num_substitutions () == 1);
+
+ // resolve the range expressions and these types must unify then we use that
+ // type to substitute into the ADT
+ TyTy::BaseType *from_ty
+ = TypeCheckExpr::Resolve (expr.get_from_expr ().get ());
+ TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ());
+ TyTy::BaseType *unified = from_ty->unify (to_ty);
+
+ // substitute it in
+ std::vector<TyTy::SubstitutionArg> subst_mappings;
+ const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
+ subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, unified));
+
+ TyTy::SubstitutionArgumentMappings subst (subst_mappings, expr.get_locus ());
+ infered = SubstMapperInternal::Resolve (adt, subst);
+}
+
+void
+TypeCheckExpr::visit (HIR::RangeFromExpr &expr)
+{
+ auto lang_item_type = Analysis::RustLangItem::ItemType::RANGE_FROM;
+
+ DefId respective_lang_item_id = UNKNOWN_DEFID;
+ bool lang_item_defined
+ = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
+
+ // we need to have it maybe
+ if (!lang_item_defined)
+ {
+ rust_internal_error_at (
+ expr.get_locus (), "unable to find relevant lang item: %s",
+ Analysis::RustLangItem::ToString (lang_item_type).c_str ());
+ return;
+ }
+
+ // look it up and it _must_ be a struct definition
+ HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
+ rust_assert (item != nullptr);
+
+ TyTy::BaseType *item_type = nullptr;
+ bool ok
+ = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
+ rust_assert (ok);
+ rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
+
+ // this is a single generic item lets assert that
+ rust_assert (adt->get_num_substitutions () == 1);
+
+ // resolve the range expressions and these types must unify then we use that
+ // type to substitute into the ADT
+ TyTy::BaseType *from_ty
+ = TypeCheckExpr::Resolve (expr.get_from_expr ().get ());
+
+ // substitute it in
+ std::vector<TyTy::SubstitutionArg> subst_mappings;
+ const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
+ subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, from_ty));
+
+ TyTy::SubstitutionArgumentMappings subst (subst_mappings, expr.get_locus ());
+ infered = SubstMapperInternal::Resolve (adt, subst);
+}
+
+void
+TypeCheckExpr::visit (HIR::RangeToExpr &expr)
+{
+ auto lang_item_type = Analysis::RustLangItem::ItemType::RANGE_TO;
+
+ DefId respective_lang_item_id = UNKNOWN_DEFID;
+ bool lang_item_defined
+ = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
+
+ // we need to have it maybe
+ if (!lang_item_defined)
+ {
+ rust_internal_error_at (
+ expr.get_locus (), "unable to find relevant lang item: %s",
+ Analysis::RustLangItem::ToString (lang_item_type).c_str ());
+ return;
+ }
+
+ // look it up and it _must_ be a struct definition
+ HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
+ rust_assert (item != nullptr);
+
+ TyTy::BaseType *item_type = nullptr;
+ bool ok
+ = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
+ rust_assert (ok);
+ rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
+
+ // this is a single generic item lets assert that
+ rust_assert (adt->get_num_substitutions () == 1);
+
+ // resolve the range expressions and these types must unify then we use that
+ // type to substitute into the ADT
+ TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ());
+
+ // substitute it in
+ std::vector<TyTy::SubstitutionArg> subst_mappings;
+ const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
+ subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, from_ty));
+
+ TyTy::SubstitutionArgumentMappings subst (subst_mappings, expr.get_locus ());
+ infered = SubstMapperInternal::Resolve (adt, subst);
+}
+
+void
+TypeCheckExpr::visit (HIR::RangeFullExpr &expr)
+{
+ auto lang_item_type = Analysis::RustLangItem::ItemType::RANGE_FULL;
+
+ DefId respective_lang_item_id = UNKNOWN_DEFID;
+ bool lang_item_defined
+ = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
+
+ // we need to have it maybe
+ if (!lang_item_defined)
+ {
+ rust_internal_error_at (
+ expr.get_locus (), "unable to find relevant lang item: %s",
+ Analysis::RustLangItem::ToString (lang_item_type).c_str ());
+ return;
+ }
+
+ // look it up and it _must_ be a struct definition
+ HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
+ rust_assert (item != nullptr);
+
+ TyTy::BaseType *item_type = nullptr;
+ bool ok
+ = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
+ rust_assert (ok);
+ rust_assert (item_type->is_unit ());
+
+ infered = item_type;
+}
+
+void
+TypeCheckExpr::visit (HIR::RangeFromToInclExpr &expr)
+{
+ auto lang_item_type = Analysis::RustLangItem::ItemType::RANGE_INCLUSIVE;
+
+ DefId respective_lang_item_id = UNKNOWN_DEFID;
+ bool lang_item_defined
+ = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
+
+ // we need to have it maybe
+ if (!lang_item_defined)
+ {
+ rust_internal_error_at (
+ expr.get_locus (), "unable to find relevant lang item: %s",
+ Analysis::RustLangItem::ToString (lang_item_type).c_str ());
+ return;
+ }
+
+ // look it up and it _must_ be a struct definition
+ HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
+ rust_assert (item != nullptr);
+
+ TyTy::BaseType *item_type = nullptr;
+ bool ok
+ = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
+ rust_assert (ok);
+ rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
+
+ // this is a single generic item lets assert that
+ rust_assert (adt->get_num_substitutions () == 1);
+
+ // resolve the range expressions and these types must unify then we use that
+ // type to substitute into the ADT
+ TyTy::BaseType *from_ty
+ = TypeCheckExpr::Resolve (expr.get_from_expr ().get ());
+ TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ());
+ TyTy::BaseType *unified = from_ty->unify (to_ty);
+
+ // substitute it in
+ std::vector<TyTy::SubstitutionArg> subst_mappings;
+ const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
+ subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, unified));
+
+ TyTy::SubstitutionArgumentMappings subst (subst_mappings, expr.get_locus ());
+ infered = SubstMapperInternal::Resolve (adt, subst);
+}
+
+void
+TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr)
+{
+ auto array_expr_ty = TypeCheckExpr::Resolve (expr.get_array_expr ());
+ if (array_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ auto index_expr_ty = TypeCheckExpr::Resolve (expr.get_index_expr ());
+ if (index_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ // first attempt to use direct array index logic
+ auto direct_array_expr_ty = array_expr_ty;
+ if (direct_array_expr_ty->get_kind () == TyTy::TypeKind::REF)
+ {
+ // lets try and deref it since rust allows this
+ auto ref = static_cast<TyTy::ReferenceType *> (direct_array_expr_ty);
+ auto base = ref->get_base ();
+ if (base->get_kind () == TyTy::TypeKind::ARRAY)
+ direct_array_expr_ty = base;
+ }
+
+ TyTy::BaseType *size_ty;
+ bool ok = context->lookup_builtin ("usize", &size_ty);
+ rust_assert (ok);
+
+ bool maybe_simple_array_access = index_expr_ty->can_eq (size_ty, false);
+ if (maybe_simple_array_access
+ && direct_array_expr_ty->get_kind () == TyTy::TypeKind::ARRAY)
+ {
+ auto resolved_index_expr = size_ty->unify (index_expr_ty);
+ if (resolved_index_expr->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ TyTy::ArrayType *array_type
+ = static_cast<TyTy::ArrayType *> (direct_array_expr_ty);
+ infered = array_type->get_element_type ()->clone ();
+ return;
+ }
+
+ // is this a case of core::ops::index?
+ auto lang_item_type = Analysis::RustLangItem::ItemType::INDEX;
+ bool operator_overloaded
+ = resolve_operator_overload (lang_item_type, expr, array_expr_ty,
+ index_expr_ty);
+ if (operator_overloaded)
+ {
+ // index and index mut always return a reference to the element
+ TyTy::BaseType *resolved = infered;
+ rust_assert (resolved->get_kind () == TyTy::TypeKind::REF);
+ TyTy::ReferenceType *ref = static_cast<TyTy::ReferenceType *> (resolved);
+
+ infered = ref->get_base ()->clone ();
+ return;
+ }
+
+ // error[E0277]: the type `[{integer}]` cannot be indexed by `u32`
+ RichLocation r (expr.get_locus ());
+ r.add_range (expr.get_array_expr ()->get_locus ());
+ r.add_range (expr.get_index_expr ()->get_locus ());
+ rust_error_at (r, "the type %<%s%> cannot be indexed by %<%s%>",
+ array_expr_ty->get_name ().c_str (),
+ index_expr_ty->get_name ().c_str ());
+}
+
+void
+TypeCheckExpr::visit (HIR::ArrayExpr &expr)
+{
+ HIR::ArrayElems &elements = *expr.get_internal_elements ();
+
+ HIR::Expr *capacity_expr = nullptr;
+ TyTy::BaseType *element_type = nullptr;
+ switch (elements.get_array_expr_type ())
+ {
+ case HIR::ArrayElems::ArrayExprType::COPIED: {
+ HIR::ArrayElemsCopied &elems
+ = static_cast<HIR::ArrayElemsCopied &> (elements);
+ element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ());
+
+ auto capacity_type
+ = TypeCheckExpr::Resolve (elems.get_num_copies_expr ());
+
+ TyTy::BaseType *expected_ty = nullptr;
+ bool ok = context->lookup_builtin ("usize", &expected_ty);
+ rust_assert (ok);
+ context->insert_type (elems.get_num_copies_expr ()->get_mappings (),
+ expected_ty);
+
+ auto unified = expected_ty->unify (capacity_type);
+ if (unified->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ capacity_expr = elems.get_num_copies_expr ();
+ }
+ break;
+
+ case HIR::ArrayElems::ArrayExprType::VALUES: {
+ HIR::ArrayElemsValues &elems
+ = static_cast<HIR::ArrayElemsValues &> (elements);
+
+ std::vector<TyTy::BaseType *> types;
+ for (auto &elem : elems.get_values ())
+ {
+ types.push_back (TypeCheckExpr::Resolve (elem.get ()));
+ }
+
+ element_type
+ = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
+ for (auto &type : types)
+ {
+ element_type = element_type->unify (type);
+ }
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID,
+ mappings->get_next_hir_id (crate_num),
+ UNKNOWN_LOCAL_DEFID);
+ std::string capacity_str = std::to_string (elems.get_num_elements ());
+ capacity_expr = new HIR::LiteralExpr (mapping, capacity_str,
+ HIR::Literal::LitType::INT,
+ PrimitiveCoreType::CORETYPE_USIZE,
+ Location (), {});
+
+ // mark the type for this implicit node
+ TyTy::BaseType *expected_ty = nullptr;
+ bool ok = context->lookup_builtin ("usize", &expected_ty);
+ rust_assert (ok);
+ context->insert_type (mapping, expected_ty);
+ }
+ break;
+ }
+
+ infered = new TyTy::ArrayType (expr.get_mappings ().get_hirid (),
+ expr.get_locus (), *capacity_expr,
+ TyTy::TyVar (element_type->get_ref ()));
+}
+
+// empty struct
+void
+TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr)
+{
+ TyTy::BaseType *struct_path_ty
+ = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ());
+ if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
+ {
+ rust_error_at (struct_expr.get_struct_name ().get_locus (),
+ "expected an ADT type for constructor");
+ return;
+ }
+
+ infered = struct_path_ty;
+}
+
+void
+TypeCheckExpr::visit (HIR::StructExprStructFields &struct_expr)
+{
+ infered = TypeCheckStructExpr::Resolve (&struct_expr);
+}
+
+void
+TypeCheckExpr::visit (HIR::GroupedExpr &expr)
+{
+ infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ().get ());
+}
+
+void
+TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
+{
+ auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ().get ());
+
+ // FIXME does this require autoderef here?
+ if (struct_base->get_kind () == TyTy::TypeKind::REF)
+ {
+ TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (struct_base);
+ struct_base = r->get_base ();
+ }
+
+ bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT;
+ if (!is_valid_type)
+ {
+ rust_error_at (expr.get_locus (),
+ "expected algebraic data type got: [%s]",
+ struct_base->as_string ().c_str ());
+ return;
+ }
+
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base);
+ rust_assert (!adt->is_enum ());
+ rust_assert (adt->number_of_variants () == 1);
+
+ TyTy::VariantDef *vaiant = adt->get_variants ().at (0);
+
+ TyTy::StructFieldType *lookup = nullptr;
+ bool found = vaiant->lookup_field (expr.get_field_name (), &lookup, nullptr);
+ if (!found)
+ {
+ rust_error_at (expr.get_locus (), "unknown field [%s] for type [%s]",
+ expr.get_field_name ().c_str (),
+ adt->as_string ().c_str ());
+ return;
+ }
+
+ infered = lookup->get_field_type ();
+}
+
+void
+TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
+{
+ auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ().get ());
+ if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (expr.get_receiver ()->get_locus (),
+ "failed to resolve receiver in MethodCallExpr");
+ return;
+ }
+
+ context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
+
+ auto candidate
+ = MethodResolver::Probe (receiver_tyty,
+ expr.get_method_name ().get_segment ());
+ if (candidate.is_error ())
+ {
+ rust_error_at (
+ expr.get_method_name ().get_locus (),
+ "failed to resolve method for %<%s%>",
+ expr.get_method_name ().get_segment ().as_string ().c_str ());
+ return;
+ }
+
+ // Get the adjusted self
+ Adjuster adj (receiver_tyty);
+ TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
+
+ // store the adjustments for code-generation to know what to do which must be
+ // stored onto the receiver to so as we don't trigger duplicate deref mappings
+ // ICE when an argument is a method call
+ HirId autoderef_mappings_id
+ = expr.get_receiver ()->get_mappings ().get_hirid ();
+ context->insert_autoderef_mappings (autoderef_mappings_id,
+ std::move (candidate.adjustments));
+
+ PathProbeCandidate &resolved_candidate = candidate.candidate;
+ TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
+ NodeId resolved_node_id
+ = resolved_candidate.is_impl_candidate ()
+ ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
+ .get_nodeid ()
+ : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
+
+ if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
+ {
+ RichLocation r (expr.get_method_name ().get_locus ());
+ r.add_range (resolved_candidate.locus);
+ rust_error_at (r, "associated impl item is not a method");
+ return;
+ }
+
+ TyTy::BaseType *lookup = lookup_tyty;
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
+ if (!fn->is_method ())
+ {
+ RichLocation r (expr.get_method_name ().get_locus ());
+ r.add_range (resolved_candidate.locus);
+ rust_error_at (r, "associated function is not a method");
+ return;
+ }
+
+ auto root = receiver_tyty->get_root ();
+ if (root->get_kind () == TyTy::TypeKind::ADT)
+ {
+ const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root);
+ if (adt->has_substitutions () && fn->needs_substitution ())
+ {
+ // consider the case where we have:
+ //
+ // struct Foo<X,Y>(X,Y);
+ //
+ // impl<T> Foo<T, i32> {
+ // fn test<X>(self, a:X) -> (T,X) { (self.0, a) }
+ // }
+ //
+ // In this case we end up with an fn type of:
+ //
+ // fn <T,X> test(self:Foo<T,i32>, a:X) -> (T,X)
+ //
+ // This means the instance or self we are calling this method for
+ // will be substituted such that we can get the inherited type
+ // arguments but then need to use the turbo fish if available or
+ // infer the remaining arguments. Luckily rust does not allow for
+ // default types GenericParams on impl blocks since these must
+ // always be at the end of the list
+
+ auto s = fn->get_self_type ()->get_root ();
+ rust_assert (s->can_eq (adt, false));
+ rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
+ const TyTy::ADTType *self_adt
+ = static_cast<const TyTy::ADTType *> (s);
+
+ // we need to grab the Self substitutions as the inherit type
+ // parameters for this
+ if (self_adt->needs_substitution ())
+ {
+ rust_assert (adt->was_substituted ());
+
+ TyTy::SubstitutionArgumentMappings used_args_in_prev_segment
+ = GetUsedSubstArgs::From (adt);
+
+ TyTy::SubstitutionArgumentMappings inherit_type_args
+ = self_adt->solve_mappings_from_receiver_for_self (
+ used_args_in_prev_segment);
+
+ // there may or may not be inherited type arguments
+ if (!inherit_type_args.is_error ())
+ {
+ // need to apply the inherited type arguments to the
+ // function
+ lookup = fn->handle_substitions (inherit_type_args);
+ }
+ }
+ }
+ }
+
+ // apply any remaining generic arguments
+ if (expr.get_method_name ().has_generic_args ())
+ {
+ HIR::GenericArgs &args = expr.get_method_name ().get_generic_args ();
+ lookup
+ = SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (),
+ &args);
+ if (lookup->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+ else if (lookup->needs_generic_substitutions ())
+ {
+ lookup = SubstMapper::InferSubst (lookup,
+ expr.get_method_name ().get_locus ());
+ }
+
+ TyTy::BaseType *function_ret_tyty
+ = TyTy::TypeCheckMethodCallExpr::go (lookup, expr, adjusted_self, context);
+ if (function_ret_tyty == nullptr
+ || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to lookup type to MethodCallExpr");
+ return;
+ }
+
+ // store the expected fntype
+ context->insert_type (expr.get_method_name ().get_mappings (), lookup);
+
+ // set up the resolved name on the path
+ resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
+ resolved_node_id);
+
+ // return the result of the function back
+ infered = function_ret_tyty;
+}
+
+void
+TypeCheckExpr::visit (HIR::LoopExpr &expr)
+{
+ context->push_new_loop_context (expr.get_mappings ().get_hirid (),
+ expr.get_locus ());
+ TyTy::BaseType *block_expr
+ = TypeCheckExpr::Resolve (expr.get_loop_block ().get ());
+ if (!block_expr->is_unit ())
+ {
+ rust_error_at (expr.get_loop_block ()->get_locus (),
+ "expected %<()%> got %s",
+ block_expr->as_string ().c_str ());
+ return;
+ }
+
+ TyTy::BaseType *loop_context_type = context->pop_loop_context ();
+
+ bool loop_context_type_infered
+ = (loop_context_type->get_kind () != TyTy::TypeKind::INFER)
+ || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER)
+ && (((TyTy::InferType *) loop_context_type)->get_infer_kind ()
+ != TyTy::InferType::GENERAL));
+
+ infered
+ = loop_context_type_infered
+ ? loop_context_type
+ : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckExpr::visit (HIR::WhileLoopExpr &expr)
+{
+ context->push_new_while_loop_context (expr.get_mappings ().get_hirid ());
+
+ TypeCheckExpr::Resolve (expr.get_predicate_expr ().get ());
+ TyTy::BaseType *block_expr
+ = TypeCheckExpr::Resolve (expr.get_loop_block ().get ());
+
+ if (!block_expr->is_unit ())
+ {
+ rust_error_at (expr.get_loop_block ()->get_locus (),
+ "expected %<()%> got %s",
+ block_expr->as_string ().c_str ());
+ return;
+ }
+
+ context->pop_loop_context ();
+ infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckExpr::visit (HIR::BreakExpr &expr)
+{
+ if (!context->have_loop_context ())
+ {
+ rust_error_at (expr.get_locus (), "cannot %<break%> outside of a loop");
+ return;
+ }
+
+ if (expr.has_break_expr ())
+ {
+ TyTy::BaseType *break_expr_tyty
+ = TypeCheckExpr::Resolve (expr.get_expr ().get ());
+
+ TyTy::BaseType *loop_context = context->peek_loop_context ();
+ if (loop_context->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (expr.get_locus (),
+ "can only break with a value inside %<loop%>");
+ return;
+ }
+
+ TyTy::BaseType *unified_ty = loop_context->unify (break_expr_tyty);
+ context->swap_head_loop_context (unified_ty);
+ }
+
+ infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckExpr::visit (HIR::ContinueExpr &expr)
+{
+ if (!context->have_loop_context ())
+ {
+ rust_error_at (expr.get_locus (),
+ "cannot %<continue%> outside of a loop");
+ return;
+ }
+
+ infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckExpr::visit (HIR::BorrowExpr &expr)
+{
+ TyTy::BaseType *resolved_base
+ = TypeCheckExpr::Resolve (expr.get_expr ().get ());
+
+ // In Rust this is valid because of DST's
+ //
+ // fn test() {
+ // let a:&str = "TEST 1";
+ // let b:&str = &"TEST 2";
+ // }
+ if (resolved_base->get_kind () == TyTy::TypeKind::REF)
+ {
+ const TyTy::ReferenceType *ref
+ = static_cast<const TyTy::ReferenceType *> (resolved_base);
+
+ // this might end up being a more generic is_dyn object check but lets
+ // double check dyn traits type-layout first
+ if (ref->is_dyn_str_type ())
+ {
+ infered = resolved_base;
+ return;
+ }
+ }
+
+ if (expr.get_is_double_borrow ())
+ {
+ // FIXME double_reference
+ gcc_unreachable ();
+ }
+
+ infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (),
+ TyTy::TyVar (resolved_base->get_ref ()),
+ expr.get_mut ());
+}
+
+void
+TypeCheckExpr::visit (HIR::DereferenceExpr &expr)
+{
+ TyTy::BaseType *resolved_base
+ = TypeCheckExpr::Resolve (expr.get_expr ().get ());
+
+ auto lang_item_type = Analysis::RustLangItem::ItemType::DEREF;
+ bool operator_overloaded
+ = resolve_operator_overload (lang_item_type, expr, resolved_base, nullptr);
+ if (operator_overloaded)
+ {
+ // operator overloaded deref always refurns a reference type lets assert
+ // this
+ rust_assert (infered->get_kind () == TyTy::TypeKind::REF);
+ resolved_base = infered;
+ }
+
+ bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF
+ || resolved_base->get_kind () == TyTy::TypeKind::POINTER;
+ if (!is_valid_type)
+ {
+ rust_error_at (expr.get_locus (), "expected reference type got %s",
+ resolved_base->as_string ().c_str ());
+ return;
+ }
+
+ if (resolved_base->get_kind () == TyTy::TypeKind::REF)
+ {
+ TyTy::ReferenceType *ref_base
+ = static_cast<TyTy::ReferenceType *> (resolved_base);
+ infered = ref_base->get_base ()->clone ();
+ }
+ else
+ {
+ TyTy::PointerType *ref_base
+ = static_cast<TyTy::PointerType *> (resolved_base);
+ infered = ref_base->get_base ()->clone ();
+ }
+}
+
+void
+TypeCheckExpr::visit (HIR::TypeCastExpr &expr)
+{
+ TyTy::BaseType *expr_to_convert
+ = TypeCheckExpr::Resolve (expr.get_casted_expr ().get ());
+ TyTy::BaseType *tyty_to_convert_to
+ = TypeCheckType::Resolve (expr.get_type_to_convert_to ().get ());
+
+ 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
+TypeCheckExpr::visit (HIR::MatchExpr &expr)
+{
+ // this needs to perform a least upper bound coercion on the blocks and then
+ // unify the scruintee and arms
+ TyTy::BaseType *scrutinee_tyty
+ = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ());
+
+ std::vector<TyTy::BaseType *> kase_block_tys;
+ for (auto &kase : expr.get_match_cases ())
+ {
+ // lets check the arms
+ HIR::MatchArm &kase_arm = kase.get_arm ();
+ for (auto &pattern : kase_arm.get_patterns ())
+ {
+ TyTy::BaseType *kase_arm_ty
+ = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty);
+
+ TyTy::BaseType *checked_kase = scrutinee_tyty->unify (kase_arm_ty);
+ if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+
+ // check the kase type
+ TyTy::BaseType *kase_block_ty
+ = TypeCheckExpr::Resolve (kase.get_expr ().get ());
+ kase_block_tys.push_back (kase_block_ty);
+ }
+
+ if (kase_block_tys.size () == 0)
+ {
+ infered
+ = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+ return;
+ }
+
+ infered = kase_block_tys.at (0);
+ for (size_t i = 1; i < kase_block_tys.size (); i++)
+ {
+ TyTy::BaseType *kase_ty = kase_block_tys.at (i);
+ infered = infered->unify (kase_ty);
+ if (infered->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+}
+
+bool
+TypeCheckExpr::resolve_operator_overload (
+ Analysis::RustLangItem::ItemType lang_item_type, HIR::OperatorExprMeta expr,
+ TyTy::BaseType *lhs, TyTy::BaseType *rhs)
+{
+ // look up lang item for arithmetic type
+ std::string associated_item_name
+ = Analysis::RustLangItem::ToString (lang_item_type);
+ DefId respective_lang_item_id = UNKNOWN_DEFID;
+ bool lang_item_defined
+ = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
+
+ // probe for the lang-item
+ if (!lang_item_defined)
+ return false;
+
+ auto segment = HIR::PathIdentSegment (associated_item_name);
+ auto candidate
+ = MethodResolver::Probe (lhs, HIR::PathIdentSegment (associated_item_name));
+
+ bool have_implementation_for_lang_item = !candidate.is_error ();
+ if (!have_implementation_for_lang_item)
+ return false;
+
+ // Get the adjusted self
+ Adjuster adj (lhs);
+ TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
+
+ // is this the case we are recursive
+ // handle the case where we are within the impl block for this lang_item
+ // otherwise we end up with a recursive operator overload such as the i32
+ // operator overload trait
+ TypeCheckContextItem &fn_context = context->peek_context ();
+ if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
+ {
+ auto &impl_item = fn_context.get_impl_item ();
+ HIR::ImplBlock *parent = impl_item.first;
+ HIR::Function *fn = impl_item.second;
+
+ if (parent->has_trait_ref ()
+ && fn->get_function_name ().compare (associated_item_name) == 0)
+ {
+ TraitReference *trait_reference
+ = TraitResolver::Lookup (*parent->get_trait_ref ().get ());
+ if (!trait_reference->is_error ())
+ {
+ TyTy::BaseType *lookup = nullptr;
+ bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
+ &lookup);
+ rust_assert (ok);
+ rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+
+ TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
+ rust_assert (fntype->is_method ());
+
+ bool is_lang_item_impl
+ = trait_reference->get_mappings ().get_defid ()
+ == respective_lang_item_id;
+ bool self_is_lang_item_self
+ = fntype->get_self_type ()->is_equal (*adjusted_self);
+ bool recursive_operator_overload
+ = is_lang_item_impl && self_is_lang_item_self;
+
+ if (recursive_operator_overload)
+ return false;
+ }
+ }
+ }
+
+ // store the adjustments for code-generation to know what to do
+ context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (),
+ std::move (candidate.adjustments));
+
+ // now its just like a method-call-expr
+ context->insert_receiver (expr.get_mappings ().get_hirid (), lhs);
+
+ PathProbeCandidate &resolved_candidate = candidate.candidate;
+ TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
+ NodeId resolved_node_id
+ = resolved_candidate.is_impl_candidate ()
+ ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
+ .get_nodeid ()
+ : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
+
+ rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::BaseType *lookup = lookup_tyty;
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
+ rust_assert (fn->is_method ());
+
+ auto root = lhs->get_root ();
+ if (root->get_kind () == TyTy::TypeKind::ADT)
+ {
+ const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root);
+ if (adt->has_substitutions () && fn->needs_substitution ())
+ {
+ // consider the case where we have:
+ //
+ // struct Foo<X,Y>(X,Y);
+ //
+ // impl<T> Foo<T, i32> {
+ // fn test<X>(self, a:X) -> (T,X) { (self.0, a) }
+ // }
+ //
+ // In this case we end up with an fn type of:
+ //
+ // fn <T,X> test(self:Foo<T,i32>, a:X) -> (T,X)
+ //
+ // This means the instance or self we are calling this method for
+ // will be substituted such that we can get the inherited type
+ // arguments but then need to use the turbo fish if available or
+ // infer the remaining arguments. Luckily rust does not allow for
+ // default types GenericParams on impl blocks since these must
+ // always be at the end of the list
+
+ auto s = fn->get_self_type ()->get_root ();
+ rust_assert (s->can_eq (adt, false));
+ rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
+ const TyTy::ADTType *self_adt
+ = static_cast<const TyTy::ADTType *> (s);
+
+ // we need to grab the Self substitutions as the inherit type
+ // parameters for this
+ if (self_adt->needs_substitution ())
+ {
+ rust_assert (adt->was_substituted ());
+
+ TyTy::SubstitutionArgumentMappings used_args_in_prev_segment
+ = GetUsedSubstArgs::From (adt);
+
+ TyTy::SubstitutionArgumentMappings inherit_type_args
+ = self_adt->solve_mappings_from_receiver_for_self (
+ used_args_in_prev_segment);
+
+ // there may or may not be inherited type arguments
+ if (!inherit_type_args.is_error ())
+ {
+ // need to apply the inherited type arguments to the
+ // function
+ lookup = fn->handle_substitions (inherit_type_args);
+ }
+ }
+ }
+ }
+
+ // handle generics
+ if (lookup->needs_generic_substitutions ())
+ lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
+
+ // type check the arguments if required
+ TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup);
+ rust_assert (type->num_params () > 0);
+ auto fnparam = type->param_at (0);
+ fnparam.second->unify (adjusted_self); // typecheck the self
+ if (rhs == nullptr)
+ {
+ rust_assert (type->num_params () == 1);
+ }
+ else
+ {
+ rust_assert (type->num_params () == 2);
+ auto fnparam = type->param_at (1);
+ fnparam.second->unify (rhs); // typecheck the rhs
+ }
+
+ rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+ fn = static_cast<TyTy::FnType *> (lookup);
+ fn->monomorphize ();
+
+ // get the return type
+ TyTy::BaseType *function_ret_tyty
+ = type->get_return_type ()->monomorphized_clone ();
+
+ // store the expected fntype
+ context->insert_operator_overload (expr.get_mappings ().get_hirid (), type);
+
+ // set up the resolved name on the path
+ resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
+ resolved_node_id);
+
+ // return the result of the function back
+ infered = function_ret_tyty;
+
+ return true;
+}
+
+bool
+TypeCheckExpr::validate_arithmetic_type (
+ const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type)
+{
+ const TyTy::BaseType *type = tyty->destructure ();
+
+ // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
+ // this will change later when traits are added
+ switch (expr_type)
+ {
+ case ArithmeticOrLogicalOperator::ADD:
+ case ArithmeticOrLogicalOperator::SUBTRACT:
+ case ArithmeticOrLogicalOperator::MULTIPLY:
+ case ArithmeticOrLogicalOperator::DIVIDE:
+ case ArithmeticOrLogicalOperator::MODULUS:
+ return (type->get_kind () == TyTy::TypeKind::INT)
+ || (type->get_kind () == TyTy::TypeKind::UINT)
+ || (type->get_kind () == TyTy::TypeKind::FLOAT)
+ || (type->get_kind () == TyTy::TypeKind::USIZE)
+ || (type->get_kind () == TyTy::TypeKind::ISIZE)
+ || (type->get_kind () == TyTy::TypeKind::INFER
+ && (((const TyTy::InferType *) type)->get_infer_kind ()
+ == TyTy::InferType::INTEGRAL))
+ || (type->get_kind () == TyTy::TypeKind::INFER
+ && (((const TyTy::InferType *) type)->get_infer_kind ()
+ == TyTy::InferType::FLOAT));
+
+ // integers or bools
+ case ArithmeticOrLogicalOperator::BITWISE_AND:
+ case ArithmeticOrLogicalOperator::BITWISE_OR:
+ case ArithmeticOrLogicalOperator::BITWISE_XOR:
+ return (type->get_kind () == TyTy::TypeKind::INT)
+ || (type->get_kind () == TyTy::TypeKind::UINT)
+ || (type->get_kind () == TyTy::TypeKind::USIZE)
+ || (type->get_kind () == TyTy::TypeKind::ISIZE)
+ || (type->get_kind () == TyTy::TypeKind::BOOL)
+ || (type->get_kind () == TyTy::TypeKind::INFER
+ && (((const TyTy::InferType *) type)->get_infer_kind ()
+ == TyTy::InferType::INTEGRAL));
+
+ // integers only
+ case ArithmeticOrLogicalOperator::LEFT_SHIFT:
+ case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
+ return (type->get_kind () == TyTy::TypeKind::INT)
+ || (type->get_kind () == TyTy::TypeKind::UINT)
+ || (type->get_kind () == TyTy::TypeKind::USIZE)
+ || (type->get_kind () == TyTy::TypeKind::ISIZE)
+ || (type->get_kind () == TyTy::TypeKind::INFER
+ && (((const TyTy::InferType *) type)->get_infer_kind ()
+ == TyTy::InferType::INTEGRAL));
+ }
+
+ gcc_unreachable ();
+ return false;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
new file mode 100644
index 00000000000..19a6c791a9d
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -0,0 +1,131 @@
+// 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_HIR_TYPE_CHECK_EXPR
+#define RUST_HIR_TYPE_CHECK_EXPR
+
+#include "rust-hir-type-check-base.h"
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckExpr : public TypeCheckBase, private HIR::HIRExpressionVisitor
+{
+public:
+ static TyTy::BaseType *Resolve (HIR::Expr *expr);
+
+ void visit (HIR::TupleIndexExpr &expr) override;
+ void visit (HIR::TupleExpr &expr) override;
+ void visit (HIR::ReturnExpr &expr) override;
+ void visit (HIR::CallExpr &expr) override;
+ void visit (HIR::MethodCallExpr &expr) override;
+ void visit (HIR::AssignmentExpr &expr) override;
+ void visit (HIR::CompoundAssignmentExpr &expr) override;
+ void visit (HIR::LiteralExpr &expr) override;
+ void visit (HIR::ArithmeticOrLogicalExpr &expr) override;
+ void visit (HIR::ComparisonExpr &expr) override;
+ void visit (HIR::LazyBooleanExpr &expr) override;
+ void visit (HIR::NegationExpr &expr) override;
+ void visit (HIR::IfExpr &expr) override;
+ void visit (HIR::IfExprConseqElse &expr) override;
+ void visit (HIR::IfExprConseqIf &expr) override;
+ void visit (HIR::IfLetExpr &expr) override;
+ void visit (HIR::BlockExpr &expr) override;
+ void visit (HIR::UnsafeBlockExpr &expr) override;
+ void visit (HIR::ArrayIndexExpr &expr) override;
+ void visit (HIR::ArrayExpr &expr) override;
+ void visit (HIR::StructExprStruct &struct_expr) override;
+ void visit (HIR::StructExprStructFields &struct_expr) override;
+ void visit (HIR::GroupedExpr &expr) override;
+ void visit (HIR::FieldAccessExpr &expr) override;
+ void visit (HIR::QualifiedPathInExpression &expr) override;
+ void visit (HIR::PathInExpression &expr) override;
+ void visit (HIR::LoopExpr &expr) override;
+ void visit (HIR::BreakExpr &expr) override;
+ void visit (HIR::ContinueExpr &expr) override;
+ void visit (HIR::BorrowExpr &expr) override;
+ void visit (HIR::DereferenceExpr &expr) override;
+ void visit (HIR::TypeCastExpr &expr) override;
+ void visit (HIR::MatchExpr &expr) override;
+ void visit (HIR::RangeFromToExpr &expr) override;
+ void visit (HIR::RangeFromExpr &expr) override;
+ void visit (HIR::RangeToExpr &expr) override;
+ void visit (HIR::RangeFullExpr &expr) override;
+ void visit (HIR::RangeFromToInclExpr &expr) override;
+ void visit (HIR::WhileLoopExpr &expr) override;
+
+ // TODO
+ void visit (HIR::ClosureExprInnerTyped &) override {}
+ void visit (HIR::ClosureExprInner &expr) override {}
+ void visit (HIR::ErrorPropagationExpr &expr) override {}
+ void visit (HIR::RangeToInclExpr &expr) override {}
+ void visit (HIR::WhileLetLoopExpr &expr) override {}
+ void visit (HIR::ForLoopExpr &expr) override {}
+ void visit (HIR::IfExprConseqIfLet &expr) override {}
+ void visit (HIR::IfLetExprConseqElse &expr) override {}
+ void visit (HIR::IfLetExprConseqIf &expr) override {}
+ void visit (HIR::IfLetExprConseqIfLet &expr) override {}
+ void visit (HIR::AwaitExpr &expr) override {}
+ void visit (HIR::AsyncBlockExpr &expr) override {}
+
+ // don't need to implement these see rust-hir-type-check-struct-field.h
+ void visit (HIR::StructExprFieldIdentifier &field) override
+ {
+ gcc_unreachable ();
+ }
+ void visit (HIR::StructExprFieldIdentifierValue &field) override
+ {
+ gcc_unreachable ();
+ }
+ void visit (HIR::StructExprFieldIndexValue &field) override
+ {
+ gcc_unreachable ();
+ }
+
+protected:
+ bool
+ resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_type,
+ HIR::OperatorExprMeta expr, TyTy::BaseType *lhs,
+ TyTy::BaseType *rhs);
+
+private:
+ TypeCheckExpr ();
+
+ TyTy::BaseType *resolve_root_path (HIR::PathInExpression &expr,
+ size_t *offset,
+ NodeId *root_resolved_node_id);
+
+ void resolve_segments (NodeId root_resolved_node_id,
+ std::vector<HIR::PathExprSegment> &segments,
+ size_t offset, TyTy::BaseType *tyseg,
+ const Analysis::NodeMapping &expr_mappings,
+ Location expr_locus);
+
+ bool
+ validate_arithmetic_type (const TyTy::BaseType *tyty,
+ HIR::ArithmeticOrLogicalExpr::ExprType expr_type);
+
+ /* The return value of TypeCheckExpr::Resolve */
+ TyTy::BaseType *infered;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_EXPR
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
new file mode 100644
index 00000000000..784e4990409
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -0,0 +1,583 @@
+// 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-hir-type-check-implitem.h"
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-pattern.h"
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCheckTopLevelExternItem::TypeCheckTopLevelExternItem (
+ const HIR::ExternBlock &parent)
+ : TypeCheckBase (), parent (parent)
+{}
+
+void
+TypeCheckTopLevelExternItem::Resolve (HIR::ExternalItem *item,
+ const HIR::ExternBlock &parent)
+{
+ TypeCheckTopLevelExternItem resolver (parent);
+ item->accept_vis (resolver);
+}
+
+void
+TypeCheckTopLevelExternItem::visit (HIR::ExternalStaticItem &item)
+{
+ TyTy::BaseType *actual_type
+ = TypeCheckType::Resolve (item.get_item_type ().get ());
+
+ context->insert_type (item.get_mappings (), actual_type);
+}
+
+void
+TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (function.has_generics ())
+ {
+ for (auto &generic_param : function.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ TyTy::BaseType *ret_type = nullptr;
+ if (!function.has_return_type ())
+ ret_type
+ = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
+ else
+ {
+ auto resolved
+ = TypeCheckType::Resolve (function.get_return_type ().get ());
+ if (resolved == nullptr)
+ {
+ rust_error_at (function.get_locus (),
+ "failed to resolve return type");
+ return;
+ }
+
+ ret_type = resolved->clone ();
+ ret_type->set_ref (
+ function.get_return_type ()->get_mappings ().get_hirid ());
+ }
+
+ std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
+ for (auto ¶m : function.get_function_params ())
+ {
+ // get the name as well required for later on
+ auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ());
+
+ // these are implicit mappings and not used
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ UNKNOWN_LOCAL_DEFID);
+
+ HIR::IdentifierPattern *param_pattern
+ = new HIR::IdentifierPattern (mapping, param.get_param_name (),
+ Location (), false, Mutability::Imm,
+ std::unique_ptr<HIR::Pattern> (nullptr));
+
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern,
+ param_tyty));
+
+ context->insert_type (param.get_mappings (), param_tyty);
+
+ // FIXME do we need error checking for patterns here?
+ // see https://github.com/Rust-GCC/gccrs/issues/995
+ }
+
+ uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG;
+ if (function.is_variadic ())
+ flags |= TyTy::FnType::FNTYPE_IS_VARADIC_FLAG;
+
+ RustIdent ident{
+ CanonicalPath::new_seg (function.get_mappings ().get_nodeid (),
+ function.get_item_name ()),
+ function.get_locus ()};
+
+ auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
+ function.get_mappings ().get_defid (),
+ function.get_item_name (), ident, flags,
+ parent.get_abi (), std::move (params),
+ ret_type, std::move (substitutions));
+
+ context->insert_type (function.get_mappings (), fnType);
+}
+
+TypeCheckTopLevelImplItem::TypeCheckTopLevelImplItem (
+ TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions)
+ : TypeCheckBase (), self (self), substitutions (substitutions)
+{}
+
+void
+TypeCheckTopLevelImplItem::Resolve (
+ HIR::ImplItem *item, TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions)
+{
+ TypeCheckTopLevelImplItem resolver (self, substitutions);
+ item->accept_vis (resolver);
+}
+
+void
+TypeCheckTopLevelImplItem::visit (HIR::TypeAlias &alias)
+{
+ TyTy::BaseType *actual_type
+ = TypeCheckType::Resolve (alias.get_type_aliased ().get ());
+
+ context->insert_type (alias.get_mappings (), actual_type);
+
+ for (auto &where_clause_item : alias.get_where_clause ().get_items ())
+ {
+ ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+ }
+}
+
+void
+TypeCheckTopLevelImplItem::visit (HIR::ConstantItem &constant)
+{
+ TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
+ TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
+
+ context->insert_type (constant.get_mappings (), type->unify (expr_type));
+}
+
+void
+TypeCheckTopLevelImplItem::visit (HIR::Function &function)
+{
+ if (function.has_generics ())
+ {
+ for (auto &generic_param : function.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ for (auto &where_clause_item : function.get_where_clause ().get_items ())
+ {
+ ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+ }
+
+ TyTy::BaseType *ret_type = nullptr;
+ if (!function.has_function_return_type ())
+ ret_type
+ = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
+ else
+ {
+ auto resolved
+ = TypeCheckType::Resolve (function.get_return_type ().get ());
+ if (resolved == nullptr)
+ {
+ rust_error_at (function.get_locus (),
+ "failed to resolve return type");
+ return;
+ }
+
+ ret_type = resolved->clone ();
+ ret_type->set_ref (
+ function.get_return_type ()->get_mappings ().get_hirid ());
+ }
+
+ std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
+ if (function.is_method ())
+ {
+ // these are implicit mappings and not used
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ UNKNOWN_LOCAL_DEFID);
+
+ // add the synthetic self param at the front, this is a placeholder for
+ // compilation to know parameter names. The types are ignored but we
+ // reuse the HIR identifier pattern which requires it
+ HIR::SelfParam &self_param = function.get_self_param ();
+ HIR::IdentifierPattern *self_pattern
+ = new HIR::IdentifierPattern (mapping, "self", self_param.get_locus (),
+ self_param.is_ref (),
+ self_param.get_mut (),
+ std::unique_ptr<HIR::Pattern> (nullptr));
+
+ // might have a specified type
+ TyTy::BaseType *self_type = nullptr;
+ if (self_param.has_type ())
+ {
+ std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
+ self_type = TypeCheckType::Resolve (specified_type.get ());
+ }
+ else
+ {
+ switch (self_param.get_self_kind ())
+ {
+ case HIR::SelfParam::IMM:
+ case HIR::SelfParam::MUT:
+ self_type = self->clone ();
+ break;
+
+ case HIR::SelfParam::IMM_REF:
+ self_type = new TyTy::ReferenceType (
+ self_param.get_mappings ().get_hirid (),
+ TyTy::TyVar (self->get_ref ()), Mutability::Imm);
+ break;
+
+ case HIR::SelfParam::MUT_REF:
+ self_type = new TyTy::ReferenceType (
+ self_param.get_mappings ().get_hirid (),
+ TyTy::TyVar (self->get_ref ()), Mutability::Mut);
+ break;
+
+ default:
+ gcc_unreachable ();
+ return;
+ }
+ }
+
+ context->insert_type (self_param.get_mappings (), self_type);
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type));
+ }
+
+ for (auto ¶m : function.get_function_params ())
+ {
+ // get the name as well required for later on
+ auto param_tyty = TypeCheckType::Resolve (param.get_type ());
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
+ param_tyty));
+
+ context->insert_type (param.get_mappings (), param_tyty);
+ TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
+ }
+
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok
+ = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+
+ RustIdent ident{*canonical_path, function.get_locus ()};
+ auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
+ function.get_mappings ().get_defid (),
+ function.get_function_name (), ident,
+ function.is_method ()
+ ? TyTy::FnType::FNTYPE_IS_METHOD_FLAG
+ : TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
+ ABI::RUST, std::move (params), ret_type,
+ std::move (substitutions));
+
+ context->insert_type (function.get_mappings (), fnType);
+}
+
+TypeCheckImplItem::TypeCheckImplItem (HIR::ImplBlock *parent,
+ TyTy::BaseType *self)
+ : TypeCheckBase (), parent (parent), self (self)
+{}
+
+void
+TypeCheckImplItem::Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
+ TyTy::BaseType *self)
+{
+ TypeCheckImplItem resolver (parent, self);
+ item->accept_vis (resolver);
+}
+
+void
+TypeCheckImplItem::visit (HIR::Function &function)
+{
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
+ {
+ rust_error_at (function.get_locus (), "failed to lookup function type");
+ return;
+ }
+
+ if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
+ {
+ rust_error_at (function.get_locus (),
+ "found invalid type for function [%s]",
+ lookup->as_string ().c_str ());
+ return;
+ }
+
+ // need to get the return type from this
+ TyTy::FnType *resolve_fn_type = static_cast<TyTy::FnType *> (lookup);
+ auto expected_ret_tyty = resolve_fn_type->get_return_type ();
+ context->push_return_type (TypeCheckContextItem (parent, &function),
+ expected_ret_tyty);
+
+ auto block_expr_ty
+ = TypeCheckExpr::Resolve (function.get_definition ().get ());
+
+ context->pop_return_type ();
+ expected_ret_tyty->unify (block_expr_ty);
+}
+
+void
+TypeCheckImplItem::visit (HIR::ConstantItem &const_item)
+{}
+
+void
+TypeCheckImplItem::visit (HIR::TypeAlias &type_alias)
+{}
+
+TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait (
+ HIR::ImplBlock *parent, TyTy::BaseType *self,
+ TyTy::TypeBoundPredicate &trait_reference,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions)
+ : TypeCheckImplItem (parent, self), trait_reference (trait_reference),
+ resolved_trait_item (TyTy::TypeBoundPredicateItem::error ()),
+ substitutions (substitutions)
+{
+ rust_assert (is_trait_impl_block ());
+}
+
+TyTy::TypeBoundPredicateItem
+TypeCheckImplItemWithTrait::Resolve (
+ HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
+ TyTy::TypeBoundPredicate &trait_reference,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions)
+{
+ TypeCheckImplItemWithTrait resolver (parent, self, trait_reference,
+ substitutions);
+ item->accept_vis (resolver);
+ return resolver.resolved_trait_item;
+}
+
+void
+TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant)
+{
+ // normal resolution of the item
+ TypeCheckImplItem::visit (constant);
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup))
+ return;
+
+ // map the impl item to the associated trait item
+ const auto tref = trait_reference.get ();
+ const TraitItemReference *raw_trait_item = nullptr;
+ bool found
+ = tref->lookup_trait_item_by_type (constant.get_identifier (),
+ TraitItemReference::TraitItemType::CONST,
+ &raw_trait_item);
+
+ // unknown trait item
+ if (!found || raw_trait_item->is_error ())
+ {
+ RichLocation r (constant.get_locus ());
+ r.add_range (trait_reference.get_locus ());
+ rust_error_at (r, "constant %<%s%> is not a member of trait %<%s%>",
+ constant.get_identifier ().c_str (),
+ trait_reference.get_name ().c_str ());
+ return;
+ }
+
+ // get the item from the predicate
+ resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
+ rust_assert (!resolved_trait_item.is_error ());
+
+ // merge the attributes
+ const HIR::TraitItem *hir_trait_item
+ = resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
+ merge_attributes (constant.get_outer_attrs (), *hir_trait_item);
+
+ // check the types are compatible
+ auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
+ if (!trait_item_type->can_eq (lookup, true))
+ {
+ RichLocation r (constant.get_locus ());
+ r.add_range (resolved_trait_item.get_locus ());
+
+ rust_error_at (
+ r, "constant %<%s%> has an incompatible type for trait %<%s%>",
+ constant.get_identifier ().c_str (),
+ trait_reference.get_name ().c_str ());
+ }
+}
+
+void
+TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
+{
+ // normal resolution of the item
+ TypeCheckImplItem::visit (type);
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
+ return;
+
+ // map the impl item to the associated trait item
+ const auto tref = trait_reference.get ();
+ const TraitItemReference *raw_trait_item = nullptr;
+ bool found
+ = tref->lookup_trait_item_by_type (type.get_new_type_name (),
+ TraitItemReference::TraitItemType::TYPE,
+ &raw_trait_item);
+
+ // unknown trait item
+ if (!found || raw_trait_item->is_error ())
+ {
+ RichLocation r (type.get_locus ());
+ r.add_range (trait_reference.get_locus ());
+ rust_error_at (r, "type alias %<%s%> is not a member of trait %<%s%>",
+ type.get_new_type_name ().c_str (),
+ trait_reference.get_name ().c_str ());
+ return;
+ }
+
+ // get the item from the predicate
+ resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
+ rust_assert (!resolved_trait_item.is_error ());
+
+ // merge the attributes
+ const HIR::TraitItem *hir_trait_item
+ = resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
+ merge_attributes (type.get_outer_attrs (), *hir_trait_item);
+
+ // check the types are compatible
+ auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
+ if (!trait_item_type->can_eq (lookup, true))
+ {
+ RichLocation r (type.get_locus ());
+ r.add_range (resolved_trait_item.get_locus ());
+
+ rust_error_at (
+ r, "type alias %<%s%> has an incompatible type for trait %<%s%>",
+ type.get_new_type_name ().c_str (),
+ trait_reference.get_name ().c_str ());
+ }
+
+ // its actually a projection, since we need a way to actually bind the
+ // generic substitutions to the type itself
+ TyTy::ProjectionType *projection
+ = new TyTy::ProjectionType (type.get_mappings ().get_hirid (), lookup, tref,
+ raw_trait_item->get_mappings ().get_defid (),
+ substitutions);
+
+ context->insert_type (type.get_mappings (), projection);
+ raw_trait_item->associated_type_set (projection);
+}
+
+void
+TypeCheckImplItemWithTrait::visit (HIR::Function &function)
+{
+ // we get the error checking from the base method here
+ TypeCheckImplItem::visit (function);
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
+ return;
+
+ // map the impl item to the associated trait item
+ const auto tref = trait_reference.get ();
+ const TraitItemReference *raw_trait_item = nullptr;
+ bool found
+ = tref->lookup_trait_item_by_type (function.get_function_name (),
+ TraitItemReference::TraitItemType::FN,
+ &raw_trait_item);
+
+ // unknown trait item
+ if (!found || raw_trait_item->is_error ())
+ {
+ RichLocation r (function.get_locus ());
+ r.add_range (trait_reference.get_locus ());
+ rust_error_at (r, "method %<%s%> is not a member of trait %<%s%>",
+ function.get_function_name ().c_str (),
+ trait_reference.get_name ().c_str ());
+ return;
+ }
+
+ // get the item from the predicate
+ resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
+ rust_assert (!resolved_trait_item.is_error ());
+
+ // merge the attributes
+ const HIR::TraitItem *hir_trait_item
+ = resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
+ merge_attributes (function.get_outer_attrs (), *hir_trait_item);
+
+ // check the types are compatible
+ auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
+ if (!trait_item_type->can_eq (lookup, true))
+ {
+ RichLocation r (function.get_locus ());
+ r.add_range (resolved_trait_item.get_locus ());
+
+ rust_error_at (r,
+ "method %<%s%> has an incompatible type for trait %<%s%>",
+ function.get_function_name ().c_str (),
+ trait_reference.get_name ().c_str ());
+ }
+}
+
+void
+TypeCheckImplItemWithTrait::merge_attributes (AST::AttrVec &impl_item_attrs,
+ const HIR::TraitItem &trait_item)
+{
+ for (const auto &attr : trait_item.get_outer_attrs ())
+ {
+ impl_item_attrs.push_back (attr);
+ }
+}
+
+bool
+TypeCheckImplItemWithTrait::is_trait_impl_block () const
+{
+ return !trait_reference.is_error ();
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
new file mode 100644
index 00000000000..f2f3faab9e0
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -0,0 +1,114 @@
+// 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_HIR_TYPE_CHECK_IMPLITEM_H
+#define RUST_HIR_TYPE_CHECK_IMPLITEM_H
+
+#include "rust-hir-type-check-base.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckTopLevelExternItem : public TypeCheckBase,
+ public HIR::HIRExternalItemVisitor
+{
+public:
+ static void Resolve (HIR::ExternalItem *item, const HIR::ExternBlock &parent);
+
+ void visit (HIR::ExternalStaticItem &item) override;
+ void visit (HIR::ExternalFunctionItem &function) override;
+
+private:
+ TypeCheckTopLevelExternItem (const HIR::ExternBlock &parent);
+
+ const HIR::ExternBlock &parent;
+};
+
+class TypeCheckTopLevelImplItem : public TypeCheckBase,
+ public HIR::HIRImplVisitor
+{
+public:
+ static void
+ Resolve (HIR::ImplItem *item, TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions);
+
+ void visit (HIR::TypeAlias &alias) override;
+ void visit (HIR::ConstantItem &constant) override;
+ void visit (HIR::Function &function) override;
+
+private:
+ TypeCheckTopLevelImplItem (
+ TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions);
+
+ TyTy::BaseType *self;
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+};
+
+class TypeCheckImplItem : public TypeCheckBase, public HIR::HIRImplVisitor
+{
+public:
+ static void Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
+ TyTy::BaseType *self);
+
+ void visit (HIR::Function &function) override;
+ void visit (HIR::ConstantItem &const_item) override;
+ void visit (HIR::TypeAlias &type_alias) override;
+
+protected:
+ TypeCheckImplItem (HIR::ImplBlock *parent, TyTy::BaseType *self);
+
+ HIR::ImplBlock *parent;
+ TyTy::BaseType *self;
+};
+
+class TypeCheckImplItemWithTrait : public TypeCheckImplItem
+{
+public:
+ static TyTy::TypeBoundPredicateItem
+ Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
+ TyTy::TypeBoundPredicate &trait_reference,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions);
+
+ void visit (HIR::ConstantItem &constant) override;
+ void visit (HIR::TypeAlias &type) override;
+ void visit (HIR::Function &function) override;
+
+protected:
+ // this allows us to inherit the must_use specified on a trait definition onto
+ // its implementation
+ void merge_attributes (AST::AttrVec &impl_item_attrs,
+ const HIR::TraitItem &trait_item);
+
+private:
+ TypeCheckImplItemWithTrait (
+ HIR::ImplBlock *parent, TyTy::BaseType *self,
+ TyTy::TypeBoundPredicate &trait_reference,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions);
+
+ bool is_trait_impl_block () const;
+
+ TyTy::TypeBoundPredicate &trait_reference;
+ TyTy::TypeBoundPredicateItem resolved_trait_item;
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_IMPLITEM_H
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc
new file mode 100644
index 00000000000..d31a6df4777
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -0,0 +1,237 @@
+// 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-hir-type-check-item.h"
+#include "rust-hir-full.h"
+#include "rust-hir-type-check-implitem.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-hir-type-check-stmt.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-trait-resolve.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCheckItem::TypeCheckItem () : TypeCheckBase () {}
+
+void
+TypeCheckItem::Resolve (HIR::Item &item)
+{
+ rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM);
+ HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item);
+
+ TypeCheckItem resolver;
+ vis_item.accept_vis (resolver);
+}
+
+void
+TypeCheckItem::visit (HIR::ImplBlock &impl_block)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (impl_block.has_generics ())
+ {
+ for (auto &generic_param : impl_block.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ TyTy::BaseType *l = nullptr;
+ bool ok = context->lookup_type (
+ generic_param->get_mappings ().get_hirid (), &l);
+ if (ok && l->get_kind () == TyTy::TypeKind::PARAM)
+ {
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param),
+ static_cast<TyTy::ParamType *> (l)));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ auto specified_bound = TyTy::TypeBoundPredicate::error ();
+ TraitReference *trait_reference = &TraitReference::error_node ();
+ if (impl_block.has_trait_ref ())
+ {
+ std::unique_ptr<HIR::TypePath> &ref = impl_block.get_trait_ref ();
+ trait_reference = TraitResolver::Resolve (*ref.get ());
+ rust_assert (!trait_reference->is_error ());
+
+ // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
+ // for example
+ specified_bound = get_predicate_from_bound (*ref.get ());
+ }
+
+ TyTy::BaseType *self = nullptr;
+ if (!context->lookup_type (
+ impl_block.get_type ()->get_mappings ().get_hirid (), &self))
+ {
+ rust_error_at (impl_block.get_locus (),
+ "failed to resolve Self for ImplBlock");
+ return;
+ }
+
+ // inherit the bounds
+ if (!specified_bound.is_error ())
+ self->inherit_bounds ({specified_bound});
+
+ // check for any unconstrained type-params
+ const TyTy::SubstitutionArgumentMappings trait_constraints
+ = specified_bound.get_substitution_arguments ();
+ const TyTy::SubstitutionArgumentMappings impl_constraints
+ = GetUsedSubstArgs::From (self);
+
+ bool impl_block_has_unconstrained_typarams
+ = check_for_unconstrained (substitutions, trait_constraints,
+ impl_constraints, self);
+ if (impl_block_has_unconstrained_typarams)
+ return;
+
+ // validate the impl items
+ bool is_trait_impl_block = !trait_reference->is_error ();
+ std::vector<const TraitItemReference *> trait_item_refs;
+ for (auto &impl_item : impl_block.get_impl_items ())
+ {
+ if (!is_trait_impl_block)
+ TypeCheckImplItem::Resolve (&impl_block, impl_item.get (), self);
+ else
+ {
+ auto trait_item_ref
+ = TypeCheckImplItemWithTrait::Resolve (&impl_block,
+ impl_item.get (), self,
+ specified_bound,
+ substitutions);
+ trait_item_refs.push_back (trait_item_ref.get_raw_item ());
+ }
+ }
+
+ bool impl_block_missing_trait_items
+ = is_trait_impl_block
+ && trait_reference->size () != trait_item_refs.size ();
+ if (impl_block_missing_trait_items)
+ {
+ // filter the missing impl_items
+ std::vector<std::reference_wrapper<const TraitItemReference>>
+ missing_trait_items;
+ for (const auto &trait_item_ref : trait_reference->get_trait_items ())
+ {
+ bool found = false;
+ for (auto implemented_trait_item : trait_item_refs)
+ {
+ std::string trait_item_name = trait_item_ref.get_identifier ();
+ std::string impl_item_name
+ = implemented_trait_item->get_identifier ();
+ found = trait_item_name.compare (impl_item_name) == 0;
+ if (found)
+ break;
+ }
+
+ bool is_required_trait_item = !trait_item_ref.is_optional ();
+ if (!found && is_required_trait_item)
+ missing_trait_items.push_back (trait_item_ref);
+ }
+
+ if (missing_trait_items.size () > 0)
+ {
+ std::string missing_items_buf;
+ RichLocation r (impl_block.get_locus ());
+ for (size_t i = 0; i < missing_trait_items.size (); i++)
+ {
+ bool has_more = (i + 1) < missing_trait_items.size ();
+ const TraitItemReference &missing_trait_item
+ = missing_trait_items.at (i);
+ missing_items_buf += missing_trait_item.get_identifier ()
+ + (has_more ? ", " : "");
+ r.add_range (missing_trait_item.get_locus ());
+ }
+
+ rust_error_at (r, "missing %s in implementation of trait %<%s%>",
+ missing_items_buf.c_str (),
+ trait_reference->get_name ().c_str ());
+ }
+ }
+
+ if (is_trait_impl_block)
+ {
+ trait_reference->clear_associated_types ();
+
+ AssociatedImplTrait associated (trait_reference, &impl_block, self,
+ context);
+ context->insert_associated_trait_impl (
+ impl_block.get_mappings ().get_hirid (), std::move (associated));
+ context->insert_associated_impl_mapping (
+ trait_reference->get_mappings ().get_hirid (), self,
+ impl_block.get_mappings ().get_hirid ());
+ }
+}
+
+void
+TypeCheckItem::visit (HIR::Function &function)
+{
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
+ {
+ rust_error_at (function.get_locus (), "failed to lookup function type");
+ return;
+ }
+
+ if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
+ {
+ rust_error_at (function.get_locus (),
+ "found invalid type for function [%s]",
+ lookup->as_string ().c_str ());
+ return;
+ }
+
+ // need to get the return type from this
+ TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (lookup);
+ auto expected_ret_tyty = resolved_fn_type->get_return_type ();
+ context->push_return_type (TypeCheckContextItem (&function),
+ expected_ret_tyty);
+
+ auto block_expr_ty
+ = TypeCheckExpr::Resolve (function.get_definition ().get ());
+
+ context->pop_return_type ();
+
+ if (block_expr_ty->get_kind () != TyTy::NEVER)
+ expected_ret_tyty->unify (block_expr_ty);
+}
+
+void
+TypeCheckItem::visit (HIR::Module &module)
+{
+ for (auto &item : module.get_items ())
+ TypeCheckItem::Resolve (*item.get ());
+}
+
+void
+TypeCheckItem::visit (HIR::Trait &trait)
+{
+ TraitResolver::Resolve (trait);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h
new file mode 100644
index 00000000000..ba4de19c9c7
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.h
@@ -0,0 +1,58 @@
+// 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_HIR_TYPE_CHECK_ITEM
+#define RUST_HIR_TYPE_CHECK_ITEM
+
+#include "rust-hir-type-check-base.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckItem : private TypeCheckBase, private HIR::HIRVisItemVisitor
+{
+public:
+ static void Resolve (HIR::Item &item);
+
+ void visit (HIR::ImplBlock &impl_block) override;
+ void visit (HIR::Function &function) override;
+ void visit (HIR::Module &module) override;
+ void visit (HIR::Trait &trait) override;
+
+ // FIXME - get rid of toplevel pass
+ void visit (HIR::TypeAlias &alias) override{};
+ void visit (HIR::TupleStruct &struct_decl) override{};
+ void visit (HIR::StructStruct &struct_decl) override{};
+ void visit (HIR::Enum &enum_decl) override{};
+ void visit (HIR::Union &union_decl) override{};
+ void visit (HIR::StaticItem &var) override{};
+ void visit (HIR::ConstantItem &constant) override{};
+ void visit (HIR::ExternBlock &extern_block) override{};
+
+ // nothing to do
+ void visit (HIR::ExternCrate &crate) override {}
+ void visit (HIR::UseDeclaration &use_decl) override {}
+
+private:
+ TypeCheckItem ();
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_ITEM
diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc
new file mode 100644
index 00000000000..84f3b6ea6e6
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc
@@ -0,0 +1,467 @@
+// 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-hir-type-check-expr.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-hir-trait-resolve.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
+{
+ HIR::QualifiedPathType qual_path_type = expr.get_path_type ();
+ TyTy::BaseType *root
+ = TypeCheckType::Resolve (qual_path_type.get_type ().get ());
+ if (root->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ if (!qual_path_type.has_as_clause ())
+ {
+ NodeId root_resolved_node_id = UNKNOWN_NODEID;
+ resolve_segments (root_resolved_node_id, expr.get_segments (), 0, root,
+ expr.get_mappings (), expr.get_locus ());
+ return;
+ }
+
+ // Resolve the trait now
+ std::unique_ptr<HIR::TypePath> &trait_path_ref = qual_path_type.get_trait ();
+ TraitReference *trait_ref = TraitResolver::Resolve (*trait_path_ref.get ());
+ if (trait_ref->is_error ())
+ return;
+
+ // does this type actually implement this type-bound?
+ if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
+ return;
+
+ // then we need to look at the next segment to create perform the correct
+ // projection type
+ if (expr.get_segments ().empty ())
+ return;
+
+ // get the predicate for the bound
+ auto specified_bound = get_predicate_from_bound (*trait_path_ref.get ());
+ if (specified_bound.is_error ())
+ return;
+
+ // inherit the bound
+ root->inherit_bounds ({specified_bound});
+
+ // setup the associated types
+ const TraitReference *specified_bound_ref = specified_bound.get ();
+ auto candidates = TypeBoundsProbe::Probe (root);
+ AssociatedImplTrait *associated_impl_trait = nullptr;
+ for (auto &probed_bound : candidates)
+ {
+ const TraitReference *bound_trait_ref = probed_bound.first;
+ const HIR::ImplBlock *associated_impl = probed_bound.second;
+
+ HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
+ AssociatedImplTrait *associated = nullptr;
+ bool found_impl_trait
+ = context->lookup_associated_trait_impl (impl_block_id, &associated);
+ if (found_impl_trait)
+ {
+ bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref);
+ bool found_self = associated->get_self ()->can_eq (root, false);
+ if (found_trait && found_self)
+ {
+ associated_impl_trait = associated;
+ break;
+ }
+ }
+ }
+
+ if (associated_impl_trait != nullptr)
+ {
+ associated_impl_trait->setup_associated_types (root, specified_bound);
+ }
+
+ // lookup the associated item from the specified bound
+ HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
+ HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment ();
+ TyTy::TypeBoundPredicateItem item
+ = specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
+ if (item.is_error ())
+ {
+ rust_error_at (item_seg.get_locus (), "unknown associated item");
+ return;
+ }
+
+ // infer the root type
+ infered = item.get_tyty_for_receiver (root);
+
+ // turbo-fish segment path::<ty>
+ if (item_seg.has_generic_args ())
+ {
+ if (!infered->can_substitute ())
+ {
+ rust_error_at (item_seg.get_locus (),
+ "substitutions not supported for %s",
+ infered->as_string ().c_str ());
+ infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ return;
+ }
+ infered = SubstMapper::Resolve (infered, expr.get_locus (),
+ &item_seg.get_generic_args ());
+ }
+
+ // continue on as a path-in-expression
+ const TraitItemReference *trait_item_ref = item.get_raw_item ();
+ NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
+ bool fully_resolved = expr.get_segments ().size () <= 1;
+
+ if (fully_resolved)
+ {
+ resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
+ root_resolved_node_id);
+ context->insert_receiver (expr.get_mappings ().get_hirid (), root);
+ return;
+ }
+
+ resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered,
+ expr.get_mappings (), expr.get_locus ());
+}
+
+void
+TypeCheckExpr::visit (HIR::PathInExpression &expr)
+{
+ NodeId resolved_node_id = UNKNOWN_NODEID;
+ size_t offset = -1;
+ TyTy::BaseType *tyseg = resolve_root_path (expr, &offset, &resolved_node_id);
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ if (tyseg->needs_generic_substitutions ())
+ {
+ tyseg = SubstMapper::InferSubst (tyseg, expr.get_locus ());
+ }
+
+ bool fully_resolved = offset == expr.get_segments ().size ();
+ if (fully_resolved)
+ {
+ infered = tyseg;
+ return;
+ }
+
+ resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg,
+ expr.get_mappings (), expr.get_locus ());
+}
+
+TyTy::BaseType *
+TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
+ NodeId *root_resolved_node_id)
+{
+ TyTy::BaseType *root_tyty = nullptr;
+ *offset = 0;
+ for (size_t i = 0; i < expr.get_num_segments (); i++)
+ {
+ HIR::PathExprSegment &seg = expr.get_segments ().at (i);
+
+ bool have_more_segments = (expr.get_num_segments () - 1 != i);
+ bool is_root = *offset == 0;
+ NodeId ast_node_id = seg.get_mappings ().get_nodeid ();
+
+ // then lookup the reference_node_id
+ NodeId ref_node_id = UNKNOWN_NODEID;
+ if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
+ {
+ resolver->lookup_resolved_type (ast_node_id, &ref_node_id);
+ }
+
+ // ref_node_id is the NodeId that the segments refers to.
+ if (ref_node_id == UNKNOWN_NODEID)
+ {
+ if (root_tyty != nullptr && *offset > 0)
+ {
+ // then we can let the impl path probe take over now
+ return root_tyty;
+ }
+
+ rust_error_at (seg.get_locus (),
+ "failed to type resolve root segment");
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+
+ // node back to HIR
+ HirId ref;
+ if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
+ {
+ rust_error_at (seg.get_locus (), "456 reverse lookup failure");
+ rust_debug_loc (seg.get_locus (),
+ "failure with [%s] mappings [%s] ref_node_id [%u]",
+ seg.as_string ().c_str (),
+ seg.get_mappings ().as_string ().c_str (),
+ ref_node_id);
+
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+
+ auto seg_is_module = (nullptr != mappings->lookup_module (ref));
+ auto seg_is_crate = mappings->is_local_hirid_crate (ref);
+ if (seg_is_module || seg_is_crate)
+ {
+ // A::B::C::this_is_a_module::D::E::F
+ // ^^^^^^^^^^^^^^^^
+ // Currently handling this.
+ if (have_more_segments)
+ {
+ (*offset)++;
+ continue;
+ }
+
+ // In the case of :
+ // A::B::C::this_is_a_module
+ // ^^^^^^^^^^^^^^^^
+ // This is an error, we are not expecting a module.
+ rust_error_at (seg.get_locus (), "expected value");
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+
+ TyTy::BaseType *lookup = nullptr;
+ if (!context->lookup_type (ref, &lookup))
+ {
+ if (is_root)
+ {
+ rust_error_at (seg.get_locus (),
+ "failed to resolve root segment");
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+ return root_tyty;
+ }
+
+ // if we have a previous segment type
+ if (root_tyty != nullptr)
+ {
+ // if this next segment needs substitution we must apply the
+ // previous type arguments
+ //
+ // such as: GenericStruct::<_>::new(123, 456)
+ if (lookup->needs_generic_substitutions ())
+ {
+ if (!root_tyty->needs_generic_substitutions ())
+ {
+ auto used_args_in_prev_segment
+ = GetUsedSubstArgs::From (root_tyty);
+ lookup
+ = SubstMapperInternal::Resolve (lookup,
+ used_args_in_prev_segment);
+ }
+ }
+ }
+
+ // turbo-fish segment path::<ty>
+ if (seg.has_generic_args ())
+ {
+ if (!lookup->can_substitute ())
+ {
+ rust_error_at (expr.get_locus (),
+ "substitutions not supported for %s",
+ root_tyty->as_string ().c_str ());
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+
+ lookup = SubstMapper::Resolve (lookup, expr.get_locus (),
+ &seg.get_generic_args ());
+ if (lookup->get_kind () == TyTy::TypeKind::ERROR)
+ return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ }
+
+ *root_resolved_node_id = ref_node_id;
+ *offset = *offset + 1;
+ root_tyty = lookup;
+ }
+
+ return root_tyty;
+}
+
+void
+TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
+ std::vector<HIR::PathExprSegment> &segments,
+ size_t offset, TyTy::BaseType *tyseg,
+ const Analysis::NodeMapping &expr_mappings,
+ Location expr_locus)
+{
+ NodeId resolved_node_id = root_resolved_node_id;
+ TyTy::BaseType *prev_segment = tyseg;
+ bool reciever_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
+
+ for (size_t i = offset; i < segments.size (); i++)
+ {
+ HIR::PathExprSegment &seg = segments.at (i);
+
+ bool probe_bounds = true;
+ bool probe_impls = !reciever_is_generic;
+ bool ignore_mandatory_trait_items = !reciever_is_generic;
+
+ // probe the path is done in two parts one where we search impls if no
+ // candidate is found then we search extensions from traits
+ auto candidates
+ = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls,
+ false, ignore_mandatory_trait_items);
+ if (candidates.size () == 0)
+ {
+ candidates
+ = PathProbeType::Probe (prev_segment, seg.get_segment (), false,
+ probe_bounds, ignore_mandatory_trait_items);
+
+ if (candidates.size () == 0)
+ {
+ rust_error_at (
+ seg.get_locus (),
+ "failed to resolve path segment using an impl Probe");
+ return;
+ }
+ }
+
+ if (candidates.size () > 1)
+ {
+ ReportMultipleCandidateError::Report (candidates, seg.get_segment (),
+ seg.get_locus ());
+ return;
+ }
+
+ auto &candidate = candidates.at (0);
+ prev_segment = tyseg;
+ tyseg = candidate.ty;
+
+ HIR::ImplBlock *associated_impl_block = nullptr;
+ if (candidate.is_enum_candidate ())
+ {
+ const TyTy::VariantDef *variant = candidate.item.enum_field.variant;
+
+ HirId variant_id = variant->get_id ();
+ HIR::Item *enum_item = mappings->lookup_hir_item (variant_id);
+ rust_assert (enum_item != nullptr);
+
+ resolved_node_id = enum_item->get_mappings ().get_nodeid ();
+
+ // insert the id of the variant we are resolved to
+ context->insert_variant_definition (expr_mappings.get_hirid (),
+ variant_id);
+ }
+ else if (candidate.is_impl_candidate ())
+ {
+ resolved_node_id
+ = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
+
+ associated_impl_block = candidate.item.impl.parent;
+ }
+ else
+ {
+ resolved_node_id
+ = candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
+
+ // lookup the associated-impl-trait
+ HIR::ImplBlock *impl = candidate.item.trait.impl;
+ if (impl != nullptr)
+ {
+ // get the associated impl block
+ associated_impl_block = impl;
+ }
+ }
+
+ if (associated_impl_block != nullptr)
+ {
+ // get the type of the parent Self
+ HirId impl_ty_id
+ = associated_impl_block->get_type ()->get_mappings ().get_hirid ();
+ TyTy::BaseType *impl_block_ty = nullptr;
+ bool ok = context->lookup_type (impl_ty_id, &impl_block_ty);
+ rust_assert (ok);
+
+ if (impl_block_ty->needs_generic_substitutions ())
+ impl_block_ty
+ = SubstMapper::InferSubst (impl_block_ty, seg.get_locus ());
+
+ prev_segment = prev_segment->unify (impl_block_ty);
+ }
+
+ if (tyseg->needs_generic_substitutions ())
+ {
+ if (!prev_segment->needs_generic_substitutions ())
+ {
+ auto used_args_in_prev_segment
+ = GetUsedSubstArgs::From (prev_segment);
+
+ if (!used_args_in_prev_segment.is_error ())
+ {
+ if (SubstMapperInternal::mappings_are_bound (
+ tyseg, used_args_in_prev_segment))
+ {
+ tyseg = SubstMapperInternal::Resolve (
+ tyseg, used_args_in_prev_segment);
+ }
+ }
+ }
+ }
+
+ if (seg.has_generic_args ())
+ {
+ if (!tyseg->can_substitute ())
+ {
+ rust_error_at (expr_locus, "substitutions not supported for %s",
+ tyseg->as_string ().c_str ());
+ return;
+ }
+
+ tyseg = SubstMapper::Resolve (tyseg, expr_locus,
+ &seg.get_generic_args ());
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+ else if (tyseg->needs_generic_substitutions () && !reciever_is_generic)
+ {
+ Location locus = seg.get_locus ();
+ tyseg = SubstMapper::InferSubst (tyseg, locus);
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+ }
+
+ rust_assert (resolved_node_id != UNKNOWN_NODEID);
+ if (tyseg->needs_generic_substitutions () && !reciever_is_generic)
+ {
+ Location locus = segments.back ().get_locus ();
+ tyseg = SubstMapper::InferSubst (tyseg, locus);
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+ }
+
+ context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
+
+ // name scope first
+ if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
+ {
+ resolver->insert_resolved_name (expr_mappings.get_nodeid (),
+ resolved_node_id);
+ }
+ // check the type scope
+ else if (resolver->get_type_scope ().decl_was_declared_here (
+ resolved_node_id))
+ {
+ resolver->insert_resolved_type (expr_mappings.get_nodeid (),
+ resolved_node_id);
+ }
+
+ infered = tyseg;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
new file mode 100644
index 00000000000..429511d0292
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -0,0 +1,416 @@
+// 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-hir-type-check-pattern.h"
+#include "rust-hir-type-check-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCheckPattern::TypeCheckPattern (TyTy::BaseType *parent)
+ : TypeCheckBase (), parent (parent), infered (nullptr)
+{}
+
+TyTy::BaseType *
+TypeCheckPattern::Resolve (HIR::Pattern *pattern, TyTy::BaseType *parent)
+{
+ TypeCheckPattern resolver (parent);
+ pattern->accept_vis (resolver);
+
+ if (resolver.infered == nullptr)
+ return new TyTy::ErrorType (pattern->get_pattern_mappings ().get_hirid ());
+
+ resolver.context->insert_type (pattern->get_pattern_mappings (),
+ resolver.infered);
+ return resolver.infered;
+}
+
+void
+TypeCheckPattern::visit (HIR::PathInExpression &pattern)
+{
+ infered = TypeCheckExpr::Resolve (&pattern);
+}
+
+void
+TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
+{
+ infered = TypeCheckExpr::Resolve (&pattern.get_path ());
+ if (infered->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
+ rust_assert (adt->number_of_variants () > 0);
+
+ TyTy::VariantDef *variant = adt->get_variants ().at (0);
+ if (adt->is_enum ())
+ {
+ HirId variant_id = UNKNOWN_HIRID;
+ bool ok = context->lookup_variant_definition (
+ pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
+ rust_assert (ok);
+
+ ok = adt->lookup_variant_by_id (variant_id, &variant);
+ rust_assert (ok);
+ }
+
+ // error[E0532]: expected tuple struct or tuple variant, found struct variant
+ // `Foo::D`
+ if (variant->get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
+ {
+ std::string variant_type
+ = TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
+
+ rust_error_at (
+ pattern.get_locus (),
+ "expected tuple struct or tuple variant, found %s variant %<%s::%s%>",
+ variant_type.c_str (), adt->get_name ().c_str (),
+ variant->get_identifier ().c_str ());
+ return;
+ }
+
+ // check the elements
+ // error[E0023]: this pattern has 2 fields, but the corresponding tuple
+ // variant has 1 field
+ // error[E0023]: this pattern has 0 fields, but the corresponding tuple
+ // variant has 1 field
+
+ std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items ();
+ switch (items->get_item_type ())
+ {
+ case HIR::TupleStructItems::RANGE: {
+ // TODO
+ gcc_unreachable ();
+ }
+ break;
+
+ case HIR::TupleStructItems::NO_RANGE: {
+ HIR::TupleStructItemsNoRange &items_no_range
+ = static_cast<HIR::TupleStructItemsNoRange &> (*items.get ());
+
+ if (items_no_range.get_patterns ().size () != variant->num_fields ())
+ {
+ rust_error_at (
+ pattern.get_locus (),
+ "this pattern has %lu fields but the corresponding "
+ "tuple variant has %lu field",
+ (unsigned long) items_no_range.get_patterns ().size (),
+ (unsigned long) variant->num_fields ());
+ // we continue on to try and setup the types as best we can for
+ // type checking
+ }
+
+ // iterate the fields and set them up, I wish we had ZIP
+ size_t i = 0;
+ for (auto &pattern : items_no_range.get_patterns ())
+ {
+ if (i >= variant->num_fields ())
+ break;
+
+ TyTy::StructFieldType *field = variant->get_field_at_index (i++);
+ TyTy::BaseType *fty = field->get_field_type ();
+
+ // setup the type on this pattern type
+ context->insert_type (pattern->get_pattern_mappings (), fty);
+ }
+ }
+ break;
+ }
+}
+
+void
+TypeCheckPattern::visit (HIR::StructPattern &pattern)
+{
+ infered = TypeCheckExpr::Resolve (&pattern.get_path ());
+ if (infered->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
+ rust_assert (adt->number_of_variants () > 0);
+
+ TyTy::VariantDef *variant = adt->get_variants ().at (0);
+ if (adt->is_enum ())
+ {
+ HirId variant_id = UNKNOWN_HIRID;
+ bool ok = context->lookup_variant_definition (
+ pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
+ rust_assert (ok);
+
+ ok = adt->lookup_variant_by_id (variant_id, &variant);
+ rust_assert (ok);
+ }
+
+ // error[E0532]: expected tuple struct or tuple variant, found struct variant
+ // `Foo::D`
+ if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT)
+ {
+ std::string variant_type
+ = TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
+ rust_error_at (pattern.get_locus (),
+ "expected struct variant, found %s variant %s",
+ variant_type.c_str (),
+ variant->get_identifier ().c_str ());
+ return;
+ }
+
+ // check the elements
+ // error[E0027]: pattern does not mention fields `x`, `y`
+ // error[E0026]: variant `Foo::D` does not have a field named `b`
+
+ std::vector<std::string> named_fields;
+ auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
+ for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
+ {
+ switch (field->get_item_type ())
+ {
+ case HIR::StructPatternField::ItemType::TUPLE_PAT: {
+ // TODO
+ gcc_unreachable ();
+ }
+ break;
+
+ case HIR::StructPatternField::ItemType::IDENT_PAT: {
+ // TODO
+ gcc_unreachable ();
+ }
+ break;
+
+ case HIR::StructPatternField::ItemType::IDENT: {
+ HIR::StructPatternFieldIdent &ident
+ = static_cast<HIR::StructPatternFieldIdent &> (*field.get ());
+
+ TyTy::StructFieldType *field = nullptr;
+ if (!variant->lookup_field (ident.get_identifier (), &field,
+ nullptr))
+ {
+ rust_error_at (ident.get_locus (),
+ "variant %s does not have a field named %s",
+ variant->get_identifier ().c_str (),
+ ident.get_identifier ().c_str ());
+ break;
+ }
+ named_fields.push_back (ident.get_identifier ());
+
+ // setup the type on this pattern
+ TyTy::BaseType *fty = field->get_field_type ();
+ context->insert_type (ident.get_mappings (), fty);
+ }
+ break;
+ }
+ }
+
+ if (named_fields.size () != variant->num_fields ())
+ {
+ std::map<std::string, bool> missing_names;
+
+ // populate with all fields
+ for (auto &field : variant->get_fields ())
+ missing_names[field->get_name ()] = true;
+
+ // then eliminate with named_fields
+ for (auto &named : named_fields)
+ missing_names.erase (named);
+
+ // then get the list of missing names
+ size_t i = 0;
+ std::string missing_fields_str;
+ for (auto it = missing_names.begin (); it != missing_names.end (); it++)
+ {
+ bool has_next = (i + 1) < missing_names.size ();
+ missing_fields_str += it->first + (has_next ? ", " : "");
+ i++;
+ }
+
+ rust_error_at (pattern.get_locus (), "pattern does not mention fields %s",
+ missing_fields_str.c_str ());
+ }
+}
+
+void
+TypeCheckPattern::visit (HIR::WildcardPattern &pattern)
+{
+ // wildcard patterns within the MatchArm's are simply just the same type as
+ // the parent
+ infered = parent->clone ();
+ infered->set_ref (pattern.get_pattern_mappings ().get_hirid ());
+}
+
+void
+TypeCheckPattern::visit (HIR::TuplePattern &pattern)
+{
+ std::unique_ptr<HIR::TuplePatternItems> items;
+ switch (pattern.get_items ()->get_pattern_type ())
+ {
+ case HIR::TuplePatternItems::TuplePatternItemType::MULTIPLE: {
+ HIR::TuplePatternItemsMultiple &ref
+ = *static_cast<HIR::TuplePatternItemsMultiple *> (
+ pattern.get_items ().get ());
+
+ std::vector<TyTy::TyVar> pattern_elems;
+ for (size_t i = 0; i < ref.get_patterns ().size (); i++)
+ {
+ auto &p = ref.get_patterns ()[i];
+ TyTy::BaseType *par_type = parent;
+ if (parent->get_kind () == TyTy::TUPLE)
+ {
+ TyTy::TupleType &par = *static_cast<TyTy::TupleType *> (parent);
+ par_type = par.get_field (i);
+ }
+
+ TyTy::BaseType *elem
+ = TypeCheckPattern::Resolve (p.get (), par_type);
+ pattern_elems.push_back (TyTy::TyVar (elem->get_ref ()));
+ }
+ infered
+ = new TyTy::TupleType (pattern.get_pattern_mappings ().get_hirid (),
+ pattern.get_locus (), pattern_elems);
+ }
+ break;
+
+ case HIR::TuplePatternItems::TuplePatternItemType::RANGED: {
+ // HIR::TuplePatternItemsRanged &ref
+ // = *static_cast<HIR::TuplePatternItemsRanged *> (
+ // pattern.get_items ().get ());
+ // TODO
+ gcc_unreachable ();
+ }
+ break;
+ }
+}
+
+void
+TypeCheckPattern::visit (HIR::LiteralPattern &pattern)
+{
+ infered = resolve_literal (pattern.get_pattern_mappings (),
+ pattern.get_literal (), pattern.get_locus ());
+}
+
+void
+TypeCheckPattern::visit (HIR::RangePattern &pattern)
+{
+ // Resolve the upper and lower bounds, and ensure they are compatible types
+ TyTy::BaseType *upper = nullptr, *lower = nullptr;
+
+ // TODO: It would be nice to factor this out into a helper since the logic for
+ // both bounds is exactly the same...
+ switch (pattern.get_upper_bound ()->get_bound_type ())
+ {
+ case HIR::RangePatternBound::RangePatternBoundType::LITERAL: {
+ HIR::RangePatternBoundLiteral &ref
+ = *static_cast<HIR::RangePatternBoundLiteral *> (
+ pattern.get_upper_bound ().get ());
+
+ HIR::Literal lit = ref.get_literal ();
+
+ upper = resolve_literal (pattern.get_pattern_mappings (), lit,
+ pattern.get_locus ());
+ }
+ break;
+
+ case HIR::RangePatternBound::RangePatternBoundType::PATH: {
+ HIR::RangePatternBoundPath &ref
+ = *static_cast<HIR::RangePatternBoundPath *> (
+ pattern.get_upper_bound ().get ());
+
+ upper = TypeCheckExpr::Resolve (&ref.get_path ());
+ }
+ break;
+
+ case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: {
+ HIR::RangePatternBoundQualPath &ref
+ = *static_cast<HIR::RangePatternBoundQualPath *> (
+ pattern.get_upper_bound ().get ());
+
+ upper = TypeCheckExpr::Resolve (&ref.get_qualified_path ());
+ }
+ break;
+ }
+
+ switch (pattern.get_lower_bound ()->get_bound_type ())
+ {
+ case HIR::RangePatternBound::RangePatternBoundType::LITERAL: {
+ HIR::RangePatternBoundLiteral &ref
+ = *static_cast<HIR::RangePatternBoundLiteral *> (
+ pattern.get_lower_bound ().get ());
+
+ HIR::Literal lit = ref.get_literal ();
+
+ lower = resolve_literal (pattern.get_pattern_mappings (), lit,
+ pattern.get_locus ());
+ }
+ break;
+
+ case HIR::RangePatternBound::RangePatternBoundType::PATH: {
+ HIR::RangePatternBoundPath &ref
+ = *static_cast<HIR::RangePatternBoundPath *> (
+ pattern.get_lower_bound ().get ());
+
+ lower = TypeCheckExpr::Resolve (&ref.get_path ());
+ }
+ break;
+
+ case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: {
+ HIR::RangePatternBoundQualPath &ref
+ = *static_cast<HIR::RangePatternBoundQualPath *> (
+ pattern.get_lower_bound ().get ());
+
+ lower = TypeCheckExpr::Resolve (&ref.get_qualified_path ());
+ }
+ break;
+ }
+
+ infered = upper->unify (lower);
+}
+
+void
+TypeCheckPattern::visit (HIR::IdentifierPattern &pattern)
+{
+ infered = parent;
+}
+
+void
+TypeCheckPattern::visit (HIR::GroupedPattern &pattern)
+{
+ // TODO
+ gcc_unreachable ();
+}
+
+void
+TypeCheckPattern::visit (HIR::QualifiedPathInExpression &pattern)
+{
+ // TODO
+ gcc_unreachable ();
+}
+
+void
+TypeCheckPattern::visit (HIR::ReferencePattern &pattern)
+{
+ // TODO
+ gcc_unreachable ();
+}
+
+void
+TypeCheckPattern::visit (HIR::SlicePattern &pattern)
+{
+ // TODO
+ gcc_unreachable ();
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.h b/gcc/rust/typecheck/rust-hir-type-check-pattern.h
new file mode 100644
index 00000000000..8af106033b7
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.h
@@ -0,0 +1,62 @@
+// 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_HIR_TYPE_CHECK_PATTERN
+#define RUST_HIR_TYPE_CHECK_PATTERN
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckPattern : public TypeCheckBase, public HIR::HIRPatternVisitor
+{
+public:
+ static TyTy::BaseType *Resolve (HIR::Pattern *pattern,
+ TyTy::BaseType *parent);
+
+ void visit (HIR::PathInExpression &pattern) override;
+ void visit (HIR::StructPattern &pattern) override;
+ void visit (HIR::TupleStructPattern &pattern) override;
+ void visit (HIR::WildcardPattern &pattern) override;
+ void visit (HIR::TuplePattern &pattern) override;
+ void visit (HIR::LiteralPattern &pattern) override;
+ void visit (HIR::RangePattern &pattern) override;
+ void visit (HIR::IdentifierPattern &pattern) override;
+ void visit (HIR::GroupedPattern &pattern) override;
+ void visit (HIR::QualifiedPathInExpression &pattern) override;
+ void visit (HIR::ReferencePattern &pattern) override;
+ void visit (HIR::SlicePattern &pattern) override;
+
+private:
+ TypeCheckPattern (TyTy::BaseType *parent);
+
+ static TyTy::BaseType *
+ typecheck_range_pattern_bound (HIR::RangePatternBound *bound,
+ Analysis::NodeMapping mappings,
+ Location locus);
+
+ TyTy::BaseType *parent;
+ TyTy::BaseType *infered;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_PATTERN
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc
new file mode 100644
index 00000000000..9f34ed49165
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc
@@ -0,0 +1,498 @@
+// 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-hir-type-check-stmt.h"
+#include "rust-hir-full.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-enumitem.h"
+#include "rust-hir-type-check-implitem.h"
+#include "rust-hir-type-check-pattern.h"
+
+namespace Rust {
+namespace Resolver {
+
+TyTy::BaseType *
+TypeCheckStmt::Resolve (HIR::Stmt *stmt)
+{
+ TypeCheckStmt resolver;
+ stmt->accept_vis (resolver);
+ return resolver.infered;
+}
+
+void
+TypeCheckStmt::visit (HIR::ExprStmtWithBlock &stmt)
+{
+ infered = TypeCheckExpr::Resolve (stmt.get_expr ());
+}
+
+void
+TypeCheckStmt::visit (HIR::ExprStmtWithoutBlock &stmt)
+{
+ infered = TypeCheckExpr::Resolve (stmt.get_expr ());
+}
+
+void
+TypeCheckStmt::visit (HIR::EmptyStmt &stmt)
+{
+ infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
+}
+
+void
+TypeCheckStmt::visit (HIR::ExternBlock &extern_block)
+{
+ for (auto &item : extern_block.get_extern_items ())
+ {
+ TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
+ }
+}
+
+void
+TypeCheckStmt::visit (HIR::ConstantItem &constant)
+{
+ TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
+ TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
+
+ infered = type->unify (expr_type);
+ context->insert_type (constant.get_mappings (), infered);
+}
+
+void
+TypeCheckStmt::visit (HIR::LetStmt &stmt)
+{
+ infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
+
+ const HIR::Pattern &stmt_pattern = *stmt.get_pattern ();
+ TyTy::BaseType *init_expr_ty = nullptr;
+ if (stmt.has_init_expr ())
+ {
+ init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ());
+ if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ init_expr_ty->append_reference (
+ stmt_pattern.get_pattern_mappings ().get_hirid ());
+ }
+
+ TyTy::BaseType *specified_ty = nullptr;
+ if (stmt.has_type ())
+ specified_ty = TypeCheckType::Resolve (stmt.get_type ());
+
+ // let x:i32 = 123;
+ if (specified_ty != nullptr && init_expr_ty != nullptr)
+ {
+ // FIXME use this result and look at the regressions
+ coercion_site (stmt.get_mappings ().get_hirid (), specified_ty,
+ init_expr_ty, stmt.get_locus ());
+ context->insert_type (stmt_pattern.get_pattern_mappings (), specified_ty);
+ }
+ else
+ {
+ // let x:i32;
+ if (specified_ty != nullptr)
+ {
+ context->insert_type (stmt_pattern.get_pattern_mappings (),
+ specified_ty);
+ }
+ // let x = 123;
+ else if (init_expr_ty != nullptr)
+ {
+ context->insert_type (stmt_pattern.get_pattern_mappings (),
+ init_expr_ty);
+ }
+ // let x;
+ else
+ {
+ context->insert_type (
+ stmt_pattern.get_pattern_mappings (),
+ new TyTy::InferType (
+ stmt_pattern.get_pattern_mappings ().get_hirid (),
+ TyTy::InferType::InferTypeKind::GENERAL, stmt.get_locus ()));
+ }
+ }
+}
+
+void
+TypeCheckStmt::visit (HIR::TupleStruct &struct_decl)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (struct_decl.has_generics ())
+ {
+ for (auto &generic_param : struct_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::StructFieldType *> fields;
+ size_t idx = 0;
+ for (auto &field : struct_decl.get_fields ())
+ {
+ TyTy::BaseType *field_type
+ = TypeCheckType::Resolve (field.get_field_type ().get ());
+ TyTy::StructFieldType *ty_field
+ = new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+ std::to_string (idx), field_type);
+ fields.push_back (ty_field);
+ context->insert_type (field.get_mappings (), ty_field->get_field_type ());
+ idx++;
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok = mappings->lookup_canonical_path (
+ struct_decl.get_mappings ().get_nodeid (), &canonical_path);
+ rust_assert (ok);
+ RustIdent ident{*canonical_path, struct_decl.get_locus ()};
+
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+ ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
+
+ // Process #[repr(...)] attribute, if any
+ const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
+ TyTy::ADTType::ReprOptions repr
+ = parse_repr_options (attrs, struct_decl.get_locus ());
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ struct_decl.get_identifier (), ident,
+ TyTy::ADTType::ADTKind::TUPLE_STRUCT,
+ std::move (variants), std::move (substitutions), repr);
+
+ context->insert_type (struct_decl.get_mappings (), type);
+ infered = type;
+}
+
+void
+TypeCheckStmt::visit (HIR::Enum &enum_decl)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (enum_decl.has_generics ())
+ {
+ for (auto &generic_param : enum_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::VariantDef *> variants;
+ int64_t discriminant_value = 0;
+ for (auto &variant : enum_decl.get_variants ())
+ {
+ TyTy::VariantDef *field_type
+ = TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
+
+ discriminant_value++;
+ variants.push_back (field_type);
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok
+ = mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+ RustIdent ident{*canonical_path, enum_decl.get_locus ()};
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ enum_decl.get_identifier (), ident,
+ TyTy::ADTType::ADTKind::ENUM, std::move (variants),
+ std::move (substitutions));
+
+ context->insert_type (enum_decl.get_mappings (), type);
+ infered = type;
+}
+
+void
+TypeCheckStmt::visit (HIR::StructStruct &struct_decl)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (struct_decl.has_generics ())
+ {
+ for (auto &generic_param : struct_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::StructFieldType *> fields;
+ for (auto &field : struct_decl.get_fields ())
+ {
+ TyTy::BaseType *field_type
+ = TypeCheckType::Resolve (field.get_field_type ().get ());
+ TyTy::StructFieldType *ty_field
+ = new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+ field.get_field_name (), field_type);
+ fields.push_back (ty_field);
+ context->insert_type (field.get_mappings (), ty_field->get_field_type ());
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok = mappings->lookup_canonical_path (
+ struct_decl.get_mappings ().get_nodeid (), &canonical_path);
+ rust_assert (ok);
+ RustIdent ident{*canonical_path, struct_decl.get_locus ()};
+
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+ ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
+
+ // Process #[repr(...)] attribute, if any
+ const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
+ TyTy::ADTType::ReprOptions repr
+ = parse_repr_options (attrs, struct_decl.get_locus ());
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ struct_decl.get_identifier (), ident,
+ TyTy::ADTType::ADTKind::STRUCT_STRUCT,
+ std::move (variants), std::move (substitutions), repr);
+
+ context->insert_type (struct_decl.get_mappings (), type);
+ infered = type;
+}
+
+void
+TypeCheckStmt::visit (HIR::Union &union_decl)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic_param : union_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::StructFieldType *> fields;
+ for (auto &variant : union_decl.get_variants ())
+ {
+ TyTy::BaseType *variant_type
+ = TypeCheckType::Resolve (variant.get_field_type ().get ());
+ TyTy::StructFieldType *ty_variant
+ = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+ variant.get_field_name (), variant_type);
+ fields.push_back (ty_variant);
+ context->insert_type (variant.get_mappings (),
+ ty_variant->get_field_type ());
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok
+ = mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+ RustIdent ident{*canonical_path, union_decl.get_locus ()};
+
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
+ ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ union_decl.get_identifier (), ident,
+ TyTy::ADTType::ADTKind::UNION, std::move (variants),
+ std::move (substitutions));
+
+ context->insert_type (union_decl.get_mappings (), type);
+ infered = type;
+}
+
+void
+TypeCheckStmt::visit (HIR::Function &function)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (function.has_generics ())
+ {
+ for (auto &generic_param : function.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ TyTy::BaseType *ret_type = nullptr;
+ if (!function.has_function_return_type ())
+ ret_type
+ = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
+ else
+ {
+ auto resolved
+ = TypeCheckType::Resolve (function.get_return_type ().get ());
+ if (resolved == nullptr)
+ {
+ rust_error_at (function.get_locus (),
+ "failed to resolve return type");
+ return;
+ }
+
+ ret_type = resolved->clone ();
+ ret_type->set_ref (
+ function.get_return_type ()->get_mappings ().get_hirid ());
+ }
+
+ std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
+ for (auto ¶m : function.get_function_params ())
+ {
+ // get the name as well required for later on
+ auto param_tyty = TypeCheckType::Resolve (param.get_type ());
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
+ param_tyty));
+
+ context->insert_type (param.get_mappings (), param_tyty);
+ TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok
+ = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+
+ RustIdent ident{*canonical_path, function.get_locus ()};
+ auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
+ function.get_mappings ().get_defid (),
+ function.get_function_name (), ident,
+ TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
+ std::move (params), ret_type,
+ std::move (substitutions));
+ context->insert_type (function.get_mappings (), fnType);
+
+ TyTy::FnType *resolved_fn_type = fnType;
+ auto expected_ret_tyty = resolved_fn_type->get_return_type ();
+ context->push_return_type (TypeCheckContextItem (&function),
+ expected_ret_tyty);
+
+ auto block_expr_ty
+ = TypeCheckExpr::Resolve (function.get_definition ().get ());
+
+ context->pop_return_type ();
+
+ if (block_expr_ty->get_kind () != TyTy::NEVER)
+ expected_ret_tyty->unify (block_expr_ty);
+
+ infered = fnType;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
new file mode 100644
index 00000000000..a79f17a59ce
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
@@ -0,0 +1,96 @@
+// 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_HIR_TYPE_CHECK_STMT
+#define RUST_HIR_TYPE_CHECK_STMT
+
+#include "rust-hir-type-check-base.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckStmt : private TypeCheckBase, private HIR::HIRStmtVisitor
+{
+public:
+ static TyTy::BaseType *Resolve (HIR::Stmt *stmt);
+
+ void visit (HIR::ExprStmtWithBlock &stmt) override;
+ void visit (HIR::ExprStmtWithoutBlock &stmt) override;
+ void visit (HIR::EmptyStmt &stmt) override;
+ void visit (HIR::ExternBlock &extern_block) override;
+ void visit (HIR::ConstantItem &constant) override;
+ void visit (HIR::LetStmt &stmt) override;
+ void visit (HIR::TupleStruct &struct_decl) override;
+ void visit (HIR::Enum &enum_decl) override;
+ void visit (HIR::StructStruct &struct_decl) override;
+ void visit (HIR::Union &union_decl) override;
+ void visit (HIR::Function &function) override;
+
+ void visit (HIR::EnumItemTuple &) override
+ { /* TODO? */
+ }
+ void visit (HIR::EnumItemStruct &) override
+ { /* TODO? */
+ }
+ void visit (HIR::EnumItem &item) override
+ { /* TODO? */
+ }
+ void visit (HIR::EnumItemDiscriminant &) override
+ { /* TODO? */
+ }
+ void visit (HIR::TypePathSegmentFunction &segment) override
+ { /* TODO? */
+ }
+ void visit (HIR::TypePath &path) override
+ { /* TODO? */
+ }
+ void visit (HIR::QualifiedPathInType &path) override
+ { /* TODO? */
+ }
+ void visit (HIR::Module &module) override
+ { /* TODO? */
+ }
+ void visit (HIR::ExternCrate &crate) override
+ { /* TODO? */
+ }
+ void visit (HIR::UseDeclaration &use_decl) override
+ { /* TODO? */
+ }
+ void visit (HIR::TypeAlias &type_alias) override
+ { /* TODO? */
+ }
+ void visit (HIR::StaticItem &static_item) override
+ { /* TODO? */
+ }
+ void visit (HIR::Trait &trait) override
+ { /* TODO? */
+ }
+ void visit (HIR::ImplBlock &impl) override
+ { /* TODO? */
+ }
+
+private:
+ TypeCheckStmt () : TypeCheckBase (), infered (nullptr) {}
+
+ TyTy::BaseType *infered;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_STMT
diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
new file mode 100644
index 00000000000..22af1aad4c3
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
@@ -0,0 +1,59 @@
+// 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_HIR_TYPE_CHECK_STRUCT_FIELD
+#define RUST_HIR_TYPE_CHECK_STRUCT_FIELD
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckStructExpr : public TypeCheckBase
+{
+public:
+ static TyTy::BaseType *Resolve (HIR::StructExprStructFields *expr);
+
+protected:
+ void resolve (HIR::StructExprStructFields &struct_expr);
+
+ void visit (HIR::StructExprFieldIdentifierValue &field);
+ void visit (HIR::StructExprFieldIndexValue &field);
+ void visit (HIR::StructExprFieldIdentifier &field);
+
+private:
+ TypeCheckStructExpr (HIR::Expr *e);
+
+ // result
+ TyTy::BaseType *resolved;
+
+ // internal state:
+ TyTy::ADTType *struct_path_resolved;
+ TyTy::VariantDef *variant;
+ TyTy::BaseType *resolved_field_value_expr;
+ std::set<std::string> fields_assigned;
+ std::map<size_t, HIR::StructExprField *> adtFieldIndexToField;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_STRUCT_FIELD
diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc
new file mode 100644
index 00000000000..b2261e8cdb3
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc
@@ -0,0 +1,340 @@
+// 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-hir-type-check.h"
+#include "rust-hir-full.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-struct-field.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr *e)
+ : TypeCheckBase (),
+ resolved (new TyTy::ErrorType (e->get_mappings ().get_hirid ())),
+ struct_path_resolved (nullptr),
+ variant (&TyTy::VariantDef::get_error_node ())
+{}
+
+TyTy::BaseType *
+TypeCheckStructExpr::Resolve (HIR::StructExprStructFields *expr)
+{
+ TypeCheckStructExpr resolver (expr);
+ resolver.resolve (*expr);
+ return resolver.resolved;
+}
+
+void
+TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
+{
+ TyTy::BaseType *struct_path_ty
+ = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ());
+ if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
+ {
+ rust_error_at (struct_expr.get_struct_name ().get_locus (),
+ "expected an ADT type for constructor");
+ return;
+ }
+
+ struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty);
+ TyTy::ADTType *struct_def = struct_path_resolved;
+ if (struct_expr.has_struct_base ())
+ {
+ TyTy::BaseType *base_resolved
+ = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ());
+ struct_def = static_cast<TyTy::ADTType *> (
+ struct_path_resolved->unify (base_resolved));
+ if (struct_def == nullptr)
+ {
+ rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (),
+ "incompatible types for base struct reference");
+ return;
+ }
+ }
+
+ // figure out the variant
+ if (struct_path_resolved->is_enum ())
+ {
+ // lookup variant id
+ HirId variant_id;
+ bool ok = context->lookup_variant_definition (
+ struct_expr.get_struct_name ().get_mappings ().get_hirid (),
+ &variant_id);
+ rust_assert (ok);
+
+ ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant);
+ rust_assert (ok);
+ }
+ else
+ {
+ rust_assert (struct_path_resolved->number_of_variants () == 1);
+ variant = struct_path_resolved->get_variants ().at (0);
+ }
+
+ std::vector<TyTy::StructFieldType *> infered_fields;
+ bool ok = true;
+
+ for (auto &field : struct_expr.get_fields ())
+ {
+ resolved_field_value_expr = nullptr;
+
+ switch (field->get_kind ())
+ {
+ case HIR::StructExprField::StructExprFieldKind::IDENTIFIER:
+ visit (static_cast<HIR::StructExprFieldIdentifier &> (*field.get ()));
+ break;
+
+ case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE:
+ visit (
+ static_cast<HIR::StructExprFieldIdentifierValue &> (*field.get ()));
+ break;
+
+ case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE:
+ visit (static_cast<HIR::StructExprFieldIndexValue &> (*field.get ()));
+ break;
+ }
+
+ if (resolved_field_value_expr == nullptr)
+ {
+ rust_fatal_error (field->get_locus (),
+ "failed to resolve type for field");
+ ok = false;
+ break;
+ }
+
+ context->insert_type (field->get_mappings (), resolved_field_value_expr);
+ }
+
+ // something failed setting up the fields
+ if (!ok)
+ {
+ rust_error_at (struct_expr.get_locus (),
+ "constructor type resolution failure");
+ return;
+ }
+
+ // check the arguments are all assigned and fix up the ordering
+ if (fields_assigned.size () != variant->num_fields ())
+ {
+ if (struct_def->is_union ())
+ {
+ if (fields_assigned.size () != 1 || struct_expr.has_struct_base ())
+ {
+ rust_error_at (
+ struct_expr.get_locus (),
+ "union must have exactly one field variant assigned");
+ return;
+ }
+ }
+ else if (!struct_expr.has_struct_base ())
+ {
+ rust_error_at (struct_expr.get_locus (),
+ "constructor is missing fields");
+ return;
+ }
+ else
+ {
+ // we have a struct base to assign the missing fields from.
+ // the missing fields can be implicit FieldAccessExprs for the value
+ std::set<std::string> missing_fields;
+ for (auto &field : variant->get_fields ())
+ {
+ auto it = fields_assigned.find (field->get_name ());
+ if (it == fields_assigned.end ())
+ missing_fields.insert (field->get_name ());
+ }
+
+ // we can generate FieldAccessExpr or TupleAccessExpr for the
+ // values of the missing fields.
+ for (auto &missing : missing_fields)
+ {
+ HIR::Expr *receiver
+ = struct_expr.struct_base->base_struct->clone_expr_impl ();
+
+ HIR::StructExprField *implicit_field = nullptr;
+
+ AST::AttrVec outer_attribs;
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (
+ crate_num,
+ struct_expr.struct_base->base_struct->get_mappings ()
+ .get_nodeid (),
+ mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
+
+ HIR::Expr *field_value = new HIR::FieldAccessExpr (
+ mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
+ std::move (outer_attribs),
+ struct_expr.struct_base->base_struct->get_locus ());
+
+ implicit_field = new HIR::StructExprFieldIdentifierValue (
+ mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
+ struct_expr.struct_base->base_struct->get_locus ());
+
+ size_t field_index;
+ bool ok = variant->lookup_field (missing, nullptr, &field_index);
+ rust_assert (ok);
+
+ adtFieldIndexToField[field_index] = implicit_field;
+ struct_expr.get_fields ().push_back (
+ std::unique_ptr<HIR::StructExprField> (implicit_field));
+ }
+ }
+ }
+
+ if (struct_def->is_union ())
+ {
+ // There is exactly one field in this constructor, we need to
+ // figure out the field index to make sure we initialize the
+ // right union field.
+ for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
+ {
+ if (adtFieldIndexToField[i])
+ {
+ struct_expr.union_index = i;
+ break;
+ }
+ }
+ rust_assert (struct_expr.union_index != -1);
+ }
+ else
+ {
+ // everything is ok, now we need to ensure all field values are ordered
+ // correctly. The GIMPLE backend uses a simple algorithm that assumes each
+ // assigned field in the constructor is in the same order as the field in
+ // the type
+ for (auto &field : struct_expr.get_fields ())
+ field.release ();
+
+ std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
+ for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
+ {
+ ordered_fields.push_back (
+ std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
+ }
+ struct_expr.set_fields_as_owner (std::move (ordered_fields));
+ }
+
+ resolved = struct_def;
+}
+
+void
+TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
+{
+ auto it = fields_assigned.find (field.field_name);
+ if (it != fields_assigned.end ())
+ {
+ rust_fatal_error (field.get_locus (), "used more than once");
+ return;
+ }
+
+ size_t field_index;
+ TyTy::StructFieldType *field_type;
+ bool ok = variant->lookup_field (field.field_name, &field_type, &field_index);
+ if (!ok)
+ {
+ rust_error_at (field.get_locus (), "unknown field");
+ return;
+ }
+
+ TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
+ resolved_field_value_expr
+ = coercion_site (field.get_mappings ().get_hirid (),
+ field_type->get_field_type (), value, field.get_locus ());
+ if (resolved_field_value_expr != nullptr)
+ {
+ fields_assigned.insert (field.field_name);
+ adtFieldIndexToField[field_index] = &field;
+ }
+}
+
+void
+TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
+{
+ std::string field_name (std::to_string (field.get_tuple_index ()));
+ auto it = fields_assigned.find (field_name);
+ if (it != fields_assigned.end ())
+ {
+ rust_fatal_error (field.get_locus (), "used more than once");
+ return;
+ }
+
+ size_t field_index;
+ TyTy::StructFieldType *field_type;
+ bool ok = variant->lookup_field (field_name, &field_type, &field_index);
+ if (!ok)
+ {
+ rust_error_at (field.get_locus (), "unknown field");
+ return;
+ }
+
+ TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
+ resolved_field_value_expr
+ = coercion_site (field.get_mappings ().get_hirid (),
+ field_type->get_field_type (), value, field.get_locus ());
+ if (resolved_field_value_expr != nullptr)
+ {
+ fields_assigned.insert (field_name);
+ adtFieldIndexToField[field_index] = &field;
+ }
+}
+
+void
+TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
+{
+ auto it = fields_assigned.find (field.get_field_name ());
+ if (it != fields_assigned.end ())
+ {
+ rust_fatal_error (field.get_locus (), "used more than once");
+ return;
+ }
+
+ size_t field_index;
+ TyTy::StructFieldType *field_type;
+ bool ok = variant->lookup_field (field.get_field_name (), &field_type,
+ &field_index);
+ if (!ok)
+ {
+ rust_error_at (field.get_locus (), "unknown field");
+ return;
+ }
+
+ // we can make the field look like a path expr to take advantage of existing
+ // code
+ Analysis::NodeMapping mappings_copy1 = field.get_mappings ();
+ Analysis::NodeMapping mappings_copy2 = field.get_mappings ();
+
+ HIR::PathIdentSegment ident_seg (field.get_field_name ());
+ HIR::PathExprSegment seg (mappings_copy1, ident_seg, field.get_locus (),
+ HIR::GenericArgs::create_empty ());
+ HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false,
+ {});
+ TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr);
+
+ resolved_field_value_expr
+ = coercion_site (field.get_mappings ().get_hirid (),
+ field_type->get_field_type (), value, field.get_locus ());
+ if (resolved_field_value_expr != nullptr)
+
+ {
+ fields_assigned.insert (field.get_field_name ());
+ adtFieldIndexToField[field_index] = &field;
+ }
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.cc b/gcc/rust/typecheck/rust-hir-type-check-toplevel.cc
new file mode 100644
index 00000000000..27f36b642fc
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.cc
@@ -0,0 +1,364 @@
+// 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-hir-type-check-toplevel.h"
+#include "rust-hir-type-check-enumitem.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-pattern.h"
+#include "rust-hir-type-check-implitem.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCheckTopLevel::TypeCheckTopLevel () : TypeCheckBase () {}
+
+void
+TypeCheckTopLevel::Resolve (HIR::Item &item)
+{
+ rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM);
+ HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item);
+
+ TypeCheckTopLevel resolver;
+ vis_item.accept_vis (resolver);
+}
+
+void
+TypeCheckTopLevel::visit (HIR::TypeAlias &alias)
+{
+ TyTy::BaseType *actual_type
+ = TypeCheckType::Resolve (alias.get_type_aliased ().get ());
+
+ context->insert_type (alias.get_mappings (), actual_type);
+
+ for (auto &where_clause_item : alias.get_where_clause ().get_items ())
+ {
+ ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+ }
+}
+
+void
+TypeCheckTopLevel::visit (HIR::TupleStruct &struct_decl)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (struct_decl.has_generics ())
+ resolve_generic_params (struct_decl.get_generic_params (), substitutions);
+
+ for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
+ {
+ ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+ }
+
+ std::vector<TyTy::StructFieldType *> fields;
+ size_t idx = 0;
+ for (auto &field : struct_decl.get_fields ())
+ {
+ TyTy::BaseType *field_type
+ = TypeCheckType::Resolve (field.get_field_type ().get ());
+ TyTy::StructFieldType *ty_field
+ = new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+ std::to_string (idx), field_type);
+ fields.push_back (ty_field);
+ context->insert_type (field.get_mappings (), ty_field->get_field_type ());
+ idx++;
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok = mappings->lookup_canonical_path (
+ struct_decl.get_mappings ().get_nodeid (), &canonical_path);
+ rust_assert (ok);
+ RustIdent ident{*canonical_path, struct_decl.get_locus ()};
+
+ // its a single variant ADT
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+ ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
+
+ // Process #[repr(X)] attribute, if any
+ const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
+ TyTy::ADTType::ReprOptions repr
+ = parse_repr_options (attrs, struct_decl.get_locus ());
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ struct_decl.get_identifier (), ident,
+ TyTy::ADTType::ADTKind::TUPLE_STRUCT,
+ std::move (variants), std::move (substitutions), repr);
+
+ context->insert_type (struct_decl.get_mappings (), type);
+}
+
+void
+TypeCheckTopLevel::visit (HIR::Module &module)
+{
+ for (auto &item : module.get_items ())
+ TypeCheckTopLevel::Resolve (*item.get ());
+}
+
+void
+TypeCheckTopLevel::visit (HIR::StructStruct &struct_decl)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (struct_decl.has_generics ())
+ resolve_generic_params (struct_decl.get_generic_params (), substitutions);
+
+ for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
+ {
+ ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+ }
+
+ std::vector<TyTy::StructFieldType *> fields;
+ for (auto &field : struct_decl.get_fields ())
+ {
+ TyTy::BaseType *field_type
+ = TypeCheckType::Resolve (field.get_field_type ().get ());
+ TyTy::StructFieldType *ty_field
+ = new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
+ field.get_field_name (), field_type);
+ fields.push_back (ty_field);
+ context->insert_type (field.get_mappings (), ty_field->get_field_type ());
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok = mappings->lookup_canonical_path (
+ struct_decl.get_mappings ().get_nodeid (), &canonical_path);
+ rust_assert (ok);
+ RustIdent ident{*canonical_path, struct_decl.get_locus ()};
+
+ // its a single variant ADT
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
+ ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
+
+ // Process #[repr(X)] attribute, if any
+ const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
+ TyTy::ADTType::ReprOptions repr
+ = parse_repr_options (attrs, struct_decl.get_locus ());
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ struct_decl.get_identifier (), ident,
+ TyTy::ADTType::ADTKind::STRUCT_STRUCT,
+ std::move (variants), std::move (substitutions), repr);
+
+ context->insert_type (struct_decl.get_mappings (), type);
+}
+
+void
+TypeCheckTopLevel::visit (HIR::Enum &enum_decl)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (enum_decl.has_generics ())
+ resolve_generic_params (enum_decl.get_generic_params (), substitutions);
+
+ std::vector<TyTy::VariantDef *> variants;
+ int64_t discriminant_value = 0;
+ for (auto &variant : enum_decl.get_variants ())
+ {
+ TyTy::VariantDef *field_type
+ = TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
+
+ discriminant_value++;
+ variants.push_back (field_type);
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok
+ = mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+ RustIdent ident{*canonical_path, enum_decl.get_locus ()};
+
+ // multi variant ADT
+ TyTy::BaseType *type
+ = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ enum_decl.get_identifier (), ident,
+ TyTy::ADTType::ADTKind::ENUM, std::move (variants),
+ std::move (substitutions));
+
+ context->insert_type (enum_decl.get_mappings (), type);
+}
+
+void
+TypeCheckTopLevel::visit (HIR::Union &union_decl)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (union_decl.has_generics ())
+ resolve_generic_params (union_decl.get_generic_params (), substitutions);
+
+ for (auto &where_clause_item : union_decl.get_where_clause ().get_items ())
+ {
+ ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+ }
+
+ std::vector<TyTy::StructFieldType *> fields;
+ for (auto &variant : union_decl.get_variants ())
+ {
+ TyTy::BaseType *variant_type
+ = TypeCheckType::Resolve (variant.get_field_type ().get ());
+ TyTy::StructFieldType *ty_variant
+ = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+ variant.get_field_name (), variant_type);
+ fields.push_back (ty_variant);
+ context->insert_type (variant.get_mappings (),
+ ty_variant->get_field_type ());
+ }
+
+ // get the path
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok
+ = mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+ RustIdent ident{*canonical_path, union_decl.get_locus ()};
+
+ // there is only a single variant
+ std::vector<TyTy::VariantDef *> variants;
+ variants.push_back (new TyTy::VariantDef (
+ union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
+ ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ union_decl.get_identifier (), ident,
+ TyTy::ADTType::ADTKind::UNION, std::move (variants),
+ std::move (substitutions));
+
+ context->insert_type (union_decl.get_mappings (), type);
+}
+
+void
+TypeCheckTopLevel::visit (HIR::StaticItem &var)
+{
+ TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ());
+ TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (var.get_expr ());
+
+ context->insert_type (var.get_mappings (), type->unify (expr_type));
+}
+
+void
+TypeCheckTopLevel::visit (HIR::ConstantItem &constant)
+{
+ TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
+ TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
+
+ context->insert_type (constant.get_mappings (), type->unify (expr_type));
+}
+
+void
+TypeCheckTopLevel::visit (HIR::Function &function)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (function.has_generics ())
+ resolve_generic_params (function.get_generic_params (), substitutions);
+
+ for (auto &where_clause_item : function.get_where_clause ().get_items ())
+ {
+ ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+ }
+
+ TyTy::BaseType *ret_type = nullptr;
+ if (!function.has_function_return_type ())
+ ret_type
+ = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
+ else
+ {
+ auto resolved
+ = TypeCheckType::Resolve (function.get_return_type ().get ());
+ if (resolved->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (function.get_locus (),
+ "failed to resolve return type");
+ return;
+ }
+
+ ret_type = resolved->clone ();
+ ret_type->set_ref (
+ function.get_return_type ()->get_mappings ().get_hirid ());
+ }
+
+ std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *>> params;
+ for (auto ¶m : function.get_function_params ())
+ {
+ // get the name as well required for later on
+ auto param_tyty = TypeCheckType::Resolve (param.get_type ());
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
+ param_tyty));
+
+ context->insert_type (param.get_mappings (), param_tyty);
+ TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
+ }
+
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok
+ = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+
+ RustIdent ident{*canonical_path, function.get_locus ()};
+ auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
+ function.get_mappings ().get_defid (),
+ function.get_function_name (), ident,
+ TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
+ std::move (params), ret_type,
+ std::move (substitutions));
+
+ context->insert_type (function.get_mappings (), fnType);
+}
+
+void
+TypeCheckTopLevel::visit (HIR::ImplBlock &impl_block)
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (impl_block.has_generics ())
+ resolve_generic_params (impl_block.get_generic_params (), substitutions);
+
+ for (auto &where_clause_item : impl_block.get_where_clause ().get_items ())
+ {
+ ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
+ }
+
+ auto self = TypeCheckType::Resolve (impl_block.get_type ().get ());
+ if (self->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ for (auto &impl_item : impl_block.get_impl_items ())
+ TypeCheckTopLevelImplItem::Resolve (impl_item.get (), self, substitutions);
+}
+
+void
+TypeCheckTopLevel::visit (HIR::ExternBlock &extern_block)
+{
+ for (auto &item : extern_block.get_extern_items ())
+ {
+ TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
+ }
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
new file mode 100644
index 00000000000..d0db07d7281
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
@@ -0,0 +1,56 @@
+// 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_HIR_TYPE_CHECK_TOPLEVEL
+#define RUST_HIR_TYPE_CHECK_TOPLEVEL
+
+#include "rust-hir-type-check-base.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckTopLevel : private TypeCheckBase, public HIR::HIRVisItemVisitor
+{
+public:
+ static void Resolve (HIR::Item &item);
+
+ void visit (HIR::Module &module) override;
+ void visit (HIR::Function &function) override;
+ void visit (HIR::TypeAlias &alias) override;
+ void visit (HIR::TupleStruct &struct_decl) override;
+ void visit (HIR::StructStruct &struct_decl) override;
+ void visit (HIR::Enum &enum_decl) override;
+ void visit (HIR::Union &union_decl) override;
+ void visit (HIR::StaticItem &var) override;
+ void visit (HIR::ConstantItem &constant) override;
+ void visit (HIR::ImplBlock &impl_block) override;
+ void visit (HIR::ExternBlock &extern_block) override;
+
+ // nothing to do
+ void visit (HIR::Trait &trait_block) override {}
+ void visit (HIR::ExternCrate &crate) override {}
+ void visit (HIR::UseDeclaration &use_decl) override {}
+
+private:
+ TypeCheckTopLevel ();
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_TOPLEVEL
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc
new file mode 100644
index 00000000000..3538d77b220
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -0,0 +1,838 @@
+// 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-hir-type-check-type.h"
+#include "rust-hir-trait-resolve.h"
+#include "rust-hir-type-check-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+HIR::GenericArgs
+TypeCheckResolveGenericArguments::resolve (HIR::TypePathSegment *segment)
+{
+ TypeCheckResolveGenericArguments resolver (segment->get_locus ());
+ switch (segment->get_type ())
+ {
+ case HIR::TypePathSegment::SegmentType::GENERIC:
+ resolver.visit (static_cast<HIR::TypePathSegmentGeneric &> (*segment));
+ break;
+
+ default:
+ break;
+ }
+ return resolver.args;
+}
+
+void
+TypeCheckResolveGenericArguments::visit (HIR::TypePathSegmentGeneric &generic)
+{
+ args = generic.get_generic_args ();
+}
+
+TyTy::BaseType *
+TypeCheckType::Resolve (HIR::Type *type)
+{
+ TypeCheckType resolver (type->get_mappings ().get_hirid ());
+ type->accept_vis (resolver);
+ rust_assert (resolver.translated != nullptr);
+ resolver.context->insert_type (type->get_mappings (), resolver.translated);
+ return resolver.translated;
+}
+
+void
+TypeCheckType::visit (HIR::BareFunctionType &fntype)
+{
+ TyTy::BaseType *return_type
+ = fntype.has_return_type ()
+ ? TypeCheckType::Resolve (fntype.get_return_type ().get ())
+ : TyTy::TupleType::get_unit_type (fntype.get_mappings ().get_hirid ());
+
+ std::vector<TyTy::TyVar> params;
+ for (auto ¶m : fntype.get_function_params ())
+ {
+ TyTy::BaseType *ptype = TypeCheckType::Resolve (param.get_type ().get ());
+ params.push_back (TyTy::TyVar (ptype->get_ref ()));
+ }
+
+ translated = new TyTy::FnPtr (fntype.get_mappings ().get_hirid (),
+ fntype.get_locus (), std::move (params),
+ TyTy::TyVar (return_type->get_ref ()));
+}
+
+void
+TypeCheckType::visit (HIR::TupleType &tuple)
+{
+ if (tuple.is_unit_type ())
+ {
+ auto unit_node_id = resolver->get_unit_type_node_id ();
+ if (!context->lookup_builtin (unit_node_id, &translated))
+ {
+ rust_error_at (tuple.get_locus (),
+ "failed to lookup builtin unit type");
+ }
+ return;
+ }
+
+ std::vector<TyTy::TyVar> fields;
+ for (auto &elem : tuple.get_elems ())
+ {
+ auto field_ty = TypeCheckType::Resolve (elem.get ());
+ fields.push_back (TyTy::TyVar (field_ty->get_ref ()));
+ }
+
+ translated = new TyTy::TupleType (tuple.get_mappings ().get_hirid (),
+ tuple.get_locus (), fields);
+}
+
+void
+TypeCheckType::visit (HIR::TypePath &path)
+{
+ // lookup the Node this resolves to
+ NodeId ref;
+ auto nid = path.get_mappings ().get_nodeid ();
+ bool is_fully_resolved = resolver->lookup_resolved_type (nid, &ref);
+
+ TyTy::BaseType *lookup = nullptr;
+ if (!is_fully_resolved)
+ {
+ // this can happen so we need to look up the root then resolve the
+ // remaining segments if possible
+ size_t offset = 0;
+ NodeId resolved_node_id = UNKNOWN_NODEID;
+ TyTy::BaseType *root
+ = resolve_root_path (path, &offset, &resolved_node_id);
+
+ rust_assert (root != nullptr);
+ if (root->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ translated
+ = resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (),
+ path.get_segments (), offset, root,
+ path.get_mappings (), path.get_locus ());
+ return;
+ }
+
+ HirId hir_lookup;
+ if (!context->lookup_type_by_node_id (ref, &hir_lookup))
+ {
+ rust_error_at (path.get_locus (), "failed to lookup HIR %d for node '%s'",
+ ref, path.as_string ().c_str ());
+ return;
+ }
+
+ if (!context->lookup_type (hir_lookup, &lookup))
+ {
+ rust_error_at (path.get_locus (), "failed to lookup HIR TyTy");
+ return;
+ }
+
+ TyTy::BaseType *path_type = lookup->clone ();
+ path_type->set_ref (path.get_mappings ().get_hirid ());
+
+ HIR::TypePathSegment *final_seg = path.get_final_segment ().get ();
+ HIR::GenericArgs args = TypeCheckResolveGenericArguments::resolve (final_seg);
+
+ bool is_big_self = final_seg->is_ident_only ()
+ && (final_seg->as_string ().compare ("Self") == 0);
+
+ if (path_type->needs_generic_substitutions ())
+ {
+ if (is_big_self)
+ {
+ translated = path_type;
+ return;
+ }
+
+ translated = SubstMapper::Resolve (path_type, path.get_locus (), &args);
+ }
+ else if (!args.is_empty ())
+ {
+ rust_error_at (path.get_locus (),
+ "TypePath %s declares generic arguments but "
+ "the type %s does not have any",
+ path.as_string ().c_str (),
+ path_type->as_string ().c_str ());
+ }
+ else
+ {
+ translated = path_type;
+ }
+}
+
+void
+TypeCheckType::visit (HIR::QualifiedPathInType &path)
+{
+ HIR::QualifiedPathType qual_path_type = path.get_path_type ();
+ TyTy::BaseType *root
+ = TypeCheckType::Resolve (qual_path_type.get_type ().get ());
+ if (root->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_debug_loc (path.get_locus (), "failed to resolve the root");
+ return;
+ }
+
+ if (!qual_path_type.has_as_clause ())
+ {
+ // then this is just a normal path-in-expression
+ NodeId root_resolved_node_id = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (
+ qual_path_type.get_type ()->get_mappings ().get_nodeid (),
+ &root_resolved_node_id);
+ rust_assert (ok);
+
+ translated = resolve_segments (root_resolved_node_id,
+ path.get_mappings ().get_hirid (),
+ path.get_segments (), 0, translated,
+ path.get_mappings (), path.get_locus ());
+
+ return;
+ }
+
+ // Resolve the trait now
+ TraitReference *trait_ref
+ = TraitResolver::Resolve (*qual_path_type.get_trait ().get ());
+ if (trait_ref->is_error ())
+ return;
+
+ // does this type actually implement this type-bound?
+ if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
+ {
+ rust_error_at (qual_path_type.get_locus (),
+ "root does not satisfy specified trait-bound");
+ return;
+ }
+
+ // get the predicate for the bound
+ auto specified_bound
+ = get_predicate_from_bound (*qual_path_type.get_trait ().get ());
+ if (specified_bound.is_error ())
+ return;
+
+ // inherit the bound
+ root->inherit_bounds ({specified_bound});
+
+ // setup the associated types
+ const TraitReference *specified_bound_ref = specified_bound.get ();
+ auto candidates = TypeBoundsProbe::Probe (root);
+ AssociatedImplTrait *associated_impl_trait = nullptr;
+ for (auto &probed_bound : candidates)
+ {
+ const TraitReference *bound_trait_ref = probed_bound.first;
+ const HIR::ImplBlock *associated_impl = probed_bound.second;
+
+ HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
+ AssociatedImplTrait *associated = nullptr;
+ bool found_impl_trait
+ = context->lookup_associated_trait_impl (impl_block_id, &associated);
+ if (found_impl_trait)
+ {
+ bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref);
+ bool found_self = associated->get_self ()->can_eq (root, false);
+ if (found_trait && found_self)
+ {
+ associated_impl_trait = associated;
+ break;
+ }
+ }
+ }
+
+ if (associated_impl_trait != nullptr)
+ {
+ associated_impl_trait->setup_associated_types (root, specified_bound);
+ }
+
+ // lookup the associated item from the specified bound
+ std::unique_ptr<HIR::TypePathSegment> &item_seg
+ = path.get_associated_segment ();
+ HIR::PathIdentSegment item_seg_identifier = item_seg->get_ident_segment ();
+ TyTy::TypeBoundPredicateItem item
+ = specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
+ if (item.is_error ())
+ {
+ rust_error_at (item_seg->get_locus (), "unknown associated item");
+ return;
+ }
+
+ // infer the root type
+ translated = item.get_tyty_for_receiver (root);
+
+ // turbo-fish segment path::<ty>
+ if (item_seg->get_type () == HIR::TypePathSegment::SegmentType::GENERIC)
+ {
+ HIR::TypePathSegmentGeneric &generic_seg
+ = static_cast<HIR::TypePathSegmentGeneric &> (*item_seg.get ());
+
+ // turbo-fish segment path::<ty>
+ if (generic_seg.has_generic_args ())
+ {
+ if (!translated->can_substitute ())
+ {
+ rust_error_at (item_seg->get_locus (),
+ "substitutions not supported for %s",
+ translated->as_string ().c_str ());
+ translated
+ = new TyTy::ErrorType (path.get_mappings ().get_hirid ());
+ return;
+ }
+ translated = SubstMapper::Resolve (translated, path.get_locus (),
+ &generic_seg.get_generic_args ());
+ }
+ }
+
+ // continue on as a path-in-expression
+ const TraitItemReference *trait_item_ref = item.get_raw_item ();
+ NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
+ bool fully_resolved = path.get_segments ().empty ();
+ if (fully_resolved)
+ {
+ resolver->insert_resolved_type (path.get_mappings ().get_nodeid (),
+ root_resolved_node_id);
+ context->insert_receiver (path.get_mappings ().get_hirid (), root);
+ return;
+ }
+
+ translated
+ = resolve_segments (root_resolved_node_id,
+ path.get_mappings ().get_hirid (), path.get_segments (),
+ 0, translated, path.get_mappings (), path.get_locus ());
+}
+
+TyTy::BaseType *
+TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
+ NodeId *root_resolved_node_id)
+{
+ TyTy::BaseType *root_tyty = nullptr;
+ *offset = 0;
+ for (size_t i = 0; i < path.get_num_segments (); i++)
+ {
+ std::unique_ptr<HIR::TypePathSegment> &seg = path.get_segments ().at (i);
+
+ bool have_more_segments = (path.get_num_segments () - 1 != i);
+ bool is_root = *offset == 0;
+ NodeId ast_node_id = seg->get_mappings ().get_nodeid ();
+
+ // then lookup the reference_node_id
+ NodeId ref_node_id = UNKNOWN_NODEID;
+ if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
+ {
+ resolver->lookup_resolved_type (ast_node_id, &ref_node_id);
+ }
+
+ // ref_node_id is the NodeId that the segments refers to.
+ if (ref_node_id == UNKNOWN_NODEID)
+ {
+ if (is_root)
+ {
+ rust_error_at (seg->get_locus (),
+ "unknown reference for resolved name: %<%s%>",
+ seg->get_ident_segment ().as_string ().c_str ());
+ return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
+ }
+ return root_tyty;
+ }
+
+ // node back to HIR
+ HirId ref = UNKNOWN_HIRID;
+ if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
+ {
+ if (is_root)
+ {
+ rust_error_at (seg->get_locus (), "789 reverse lookup failure");
+ rust_debug_loc (
+ seg->get_locus (),
+ "failure with [%s] mappings [%s] ref_node_id [%u]",
+ seg->as_string ().c_str (),
+ seg->get_mappings ().as_string ().c_str (), ref_node_id);
+
+ return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
+ }
+
+ return root_tyty;
+ }
+
+ auto seg_is_module = (nullptr != mappings->lookup_module (ref));
+ auto seg_is_crate = mappings->is_local_hirid_crate (ref);
+ if (seg_is_module || seg_is_crate)
+ {
+ // A::B::C::this_is_a_module::D::E::F
+ // ^^^^^^^^^^^^^^^^
+ // Currently handling this.
+ if (have_more_segments)
+ {
+ (*offset)++;
+ continue;
+ }
+
+ // In the case of :
+ // A::B::C::this_is_a_module
+ // ^^^^^^^^^^^^^^^^
+ // This is an error, we are not expecting a module.
+ rust_error_at (seg->get_locus (), "expected value");
+ return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
+ }
+
+ TyTy::BaseType *lookup = nullptr;
+ if (!context->lookup_type (ref, &lookup))
+ {
+ if (is_root)
+ {
+ rust_error_at (seg->get_locus (),
+ "failed to resolve root segment");
+ return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
+ }
+ return root_tyty;
+ }
+
+ // if we have a previous segment type
+ if (root_tyty != nullptr)
+ {
+ // if this next segment needs substitution we must apply the
+ // previous type arguments
+ //
+ // such as: GenericStruct::<_>::new(123, 456)
+ if (lookup->needs_generic_substitutions ())
+ {
+ if (!root_tyty->needs_generic_substitutions ())
+ {
+ auto used_args_in_prev_segment
+ = GetUsedSubstArgs::From (root_tyty);
+ lookup
+ = SubstMapperInternal::Resolve (lookup,
+ used_args_in_prev_segment);
+ }
+ }
+ }
+
+ // turbo-fish segment path::<ty>
+ if (seg->is_generic_segment ())
+ {
+ HIR::TypePathSegmentGeneric *generic_segment
+ = static_cast<HIR::TypePathSegmentGeneric *> (seg.get ());
+
+ if (!lookup->can_substitute ())
+ {
+ rust_error_at (seg->get_locus (),
+ "substitutions not supported for %s",
+ lookup->as_string ().c_str ());
+ return new TyTy::ErrorType (lookup->get_ref ());
+ }
+ lookup = SubstMapper::Resolve (lookup, path.get_locus (),
+ &generic_segment->get_generic_args ());
+ }
+
+ *root_resolved_node_id = ref_node_id;
+ *offset = *offset + 1;
+ root_tyty = lookup;
+ }
+
+ return root_tyty;
+}
+
+TyTy::BaseType *
+TypeCheckType::resolve_segments (
+ NodeId root_resolved_node_id, HirId expr_id,
+ std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset,
+ TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
+ Location expr_locus)
+{
+ NodeId resolved_node_id = root_resolved_node_id;
+ TyTy::BaseType *prev_segment = tyseg;
+ for (size_t i = offset; i < segments.size (); i++)
+ {
+ std::unique_ptr<HIR::TypePathSegment> &seg = segments.at (i);
+
+ bool reciever_is_generic
+ = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
+ bool probe_bounds = true;
+ bool probe_impls = !reciever_is_generic;
+ bool ignore_mandatory_trait_items = !reciever_is_generic;
+
+ // probe the path is done in two parts one where we search impls if no
+ // candidate is found then we search extensions from traits
+ auto candidates
+ = PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
+ probe_impls, false,
+ ignore_mandatory_trait_items);
+ if (candidates.size () == 0)
+ {
+ candidates
+ = PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
+ false, probe_bounds,
+ ignore_mandatory_trait_items);
+
+ if (candidates.size () == 0)
+ {
+ rust_error_at (
+ seg->get_locus (),
+ "failed to resolve path segment using an impl Probe");
+ return new TyTy::ErrorType (expr_id);
+ }
+ }
+
+ if (candidates.size () > 1)
+ {
+ ReportMultipleCandidateError::Report (candidates,
+ seg->get_ident_segment (),
+ seg->get_locus ());
+ return new TyTy::ErrorType (expr_id);
+ }
+
+ auto &candidate = candidates.at (0);
+ prev_segment = tyseg;
+ tyseg = candidate.ty;
+
+ if (candidate.is_impl_candidate ())
+ {
+ resolved_node_id
+ = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
+ }
+ else
+ {
+ resolved_node_id
+ = candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
+ }
+
+ if (seg->is_generic_segment ())
+ {
+ HIR::TypePathSegmentGeneric *generic_segment
+ = static_cast<HIR::TypePathSegmentGeneric *> (seg.get ());
+
+ if (!tyseg->can_substitute ())
+ {
+ rust_error_at (expr_locus, "substitutions not supported for %s",
+ tyseg->as_string ().c_str ());
+ return new TyTy::ErrorType (expr_id);
+ }
+
+ tyseg = SubstMapper::Resolve (tyseg, expr_locus,
+ &generic_segment->get_generic_args ());
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return new TyTy::ErrorType (expr_id);
+ }
+ }
+
+ context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
+ if (tyseg->needs_generic_substitutions ())
+ {
+ Location locus = segments.back ()->get_locus ();
+ if (!prev_segment->needs_generic_substitutions ())
+ {
+ auto used_args_in_prev_segment
+ = GetUsedSubstArgs::From (prev_segment);
+ if (!used_args_in_prev_segment.is_error ())
+ tyseg
+ = SubstMapperInternal::Resolve (tyseg, used_args_in_prev_segment);
+ }
+ else
+ {
+ tyseg = SubstMapper::InferSubst (tyseg, locus);
+ }
+
+ if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
+ return new TyTy::ErrorType (expr_id);
+ }
+
+ rust_assert (resolved_node_id != UNKNOWN_NODEID);
+
+ // lookup if the name resolver was able to canonically resolve this or not
+ NodeId path_resolved_id = UNKNOWN_NODEID;
+ if (resolver->lookup_resolved_name (expr_mappings.get_nodeid (),
+ &path_resolved_id))
+ {
+ rust_assert (path_resolved_id == resolved_node_id);
+ }
+ // check the type scope
+ else if (resolver->lookup_resolved_type (expr_mappings.get_nodeid (),
+ &path_resolved_id))
+ {
+ rust_assert (path_resolved_id == resolved_node_id);
+ }
+ else
+ {
+ // name scope first
+ if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
+ {
+ resolver->insert_resolved_name (expr_mappings.get_nodeid (),
+ resolved_node_id);
+ }
+ // check the type scope
+ else if (resolver->get_type_scope ().decl_was_declared_here (
+ resolved_node_id))
+ {
+ resolver->insert_resolved_type (expr_mappings.get_nodeid (),
+ resolved_node_id);
+ }
+ }
+
+ return tyseg;
+}
+
+void
+TypeCheckType::visit (HIR::TraitObjectType &type)
+{
+ std::vector<TyTy::TypeBoundPredicate> specified_bounds;
+ for (auto &bound : type.get_type_param_bounds ())
+ {
+ if (bound->get_bound_type ()
+ != HIR::TypeParamBound::BoundType::TRAITBOUND)
+ continue;
+
+ HIR::TypeParamBound &b = *bound.get ();
+ HIR::TraitBound &trait_bound = static_cast<HIR::TraitBound &> (b);
+
+ TyTy::TypeBoundPredicate predicate
+ = get_predicate_from_bound (trait_bound.get_path ());
+
+ if (!predicate.is_error ()
+ && predicate.is_object_safe (true, type.get_locus ()))
+ specified_bounds.push_back (std::move (predicate));
+ }
+
+ RustIdent ident{CanonicalPath::create_empty (), type.get_locus ()};
+ translated
+ = new TyTy::DynamicObjectType (type.get_mappings ().get_hirid (), ident,
+ std::move (specified_bounds));
+}
+
+void
+TypeCheckType::visit (HIR::ArrayType &type)
+{
+ auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ());
+ if (capacity_type->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ TyTy::BaseType *expected_ty = nullptr;
+ bool ok = context->lookup_builtin ("usize", &expected_ty);
+ rust_assert (ok);
+ context->insert_type (type.get_size_expr ()->get_mappings (), expected_ty);
+
+ auto unified = expected_ty->unify (capacity_type);
+ if (unified->get_kind () == TyTy::TypeKind::ERROR)
+ return;
+
+ TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ());
+ translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (),
+ type.get_locus (), *type.get_size_expr (),
+ TyTy::TyVar (base->get_ref ()));
+}
+
+void
+TypeCheckType::visit (HIR::SliceType &type)
+{
+ TyTy::BaseType *base
+ = TypeCheckType::Resolve (type.get_element_type ().get ());
+ translated
+ = new TyTy::SliceType (type.get_mappings ().get_hirid (), type.get_locus (),
+ TyTy::TyVar (base->get_ref ()));
+}
+void
+TypeCheckType::visit (HIR::ReferenceType &type)
+{
+ TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ());
+ translated
+ = new TyTy::ReferenceType (type.get_mappings ().get_hirid (),
+ TyTy::TyVar (base->get_ref ()), type.get_mut ());
+}
+
+void
+TypeCheckType::visit (HIR::RawPointerType &type)
+{
+ TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ());
+ translated
+ = new TyTy::PointerType (type.get_mappings ().get_hirid (),
+ TyTy::TyVar (base->get_ref ()), type.get_mut ());
+}
+
+void
+TypeCheckType::visit (HIR::InferredType &type)
+{
+ translated = new TyTy::InferType (type.get_mappings ().get_hirid (),
+ TyTy::InferType::InferTypeKind::GENERAL,
+ type.get_locus ());
+}
+
+void
+TypeCheckType::visit (HIR::NeverType &type)
+{
+ TyTy::BaseType *lookup = nullptr;
+ bool ok = context->lookup_builtin ("!", &lookup);
+ rust_assert (ok);
+
+ translated = lookup->clone ();
+}
+
+TyTy::ParamType *
+TypeResolveGenericParam::Resolve (HIR::GenericParam *param)
+{
+ TypeResolveGenericParam resolver;
+ switch (param->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::TYPE:
+ resolver.visit (static_cast<HIR::TypeParam &> (*param));
+ break;
+
+ case HIR::GenericParam::GenericKind::CONST:
+ resolver.visit (static_cast<HIR::ConstGenericParam &> (*param));
+ break;
+
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ resolver.visit (static_cast<HIR::LifetimeParam &> (*param));
+ break;
+ }
+ return resolver.resolved;
+}
+
+void
+TypeResolveGenericParam::visit (HIR::LifetimeParam ¶m)
+{
+ // nothing to do
+}
+
+void
+TypeResolveGenericParam::visit (HIR::ConstGenericParam ¶m)
+{
+ // TODO
+}
+
+void
+TypeResolveGenericParam::visit (HIR::TypeParam ¶m)
+{
+ if (param.has_type ())
+ TypeCheckType::Resolve (param.get_type ().get ());
+
+ std::vector<TyTy::TypeBoundPredicate> specified_bounds;
+ if (param.has_type_param_bounds ())
+ {
+ for (auto &bound : param.get_type_param_bounds ())
+ {
+ switch (bound->get_bound_type ())
+ {
+ case HIR::TypeParamBound::BoundType::TRAITBOUND: {
+ HIR::TraitBound *b
+ = static_cast<HIR::TraitBound *> (bound.get ());
+
+ TyTy::TypeBoundPredicate predicate
+ = get_predicate_from_bound (b->get_path ());
+ if (!predicate.is_error ())
+ specified_bounds.push_back (std::move (predicate));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ resolved
+ = new TyTy::ParamType (param.get_type_representation (), param.get_locus (),
+ param.get_mappings ().get_hirid (), param,
+ specified_bounds);
+}
+
+void
+ResolveWhereClauseItem::Resolve (HIR::WhereClauseItem &item)
+{
+ ResolveWhereClauseItem resolver;
+ switch (item.get_item_type ())
+ {
+ case HIR::WhereClauseItem::LIFETIME:
+ resolver.visit (static_cast<HIR::LifetimeWhereClauseItem &> (item));
+ break;
+
+ case HIR::WhereClauseItem::TYPE_BOUND:
+ resolver.visit (static_cast<HIR::TypeBoundWhereClauseItem &> (item));
+ break;
+ }
+}
+
+void
+ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &item)
+{}
+
+void
+ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item)
+{
+ auto &binding_type_path = item.get_bound_type ();
+ TyTy::BaseType *binding = TypeCheckType::Resolve (binding_type_path.get ());
+
+ std::vector<TyTy::TypeBoundPredicate> specified_bounds;
+ for (auto &bound : item.get_type_param_bounds ())
+ {
+ switch (bound->get_bound_type ())
+ {
+ case HIR::TypeParamBound::BoundType::TRAITBOUND: {
+ HIR::TraitBound *b = static_cast<HIR::TraitBound *> (bound.get ());
+
+ TyTy::TypeBoundPredicate predicate
+ = get_predicate_from_bound (b->get_path ());
+ if (!predicate.is_error ())
+ specified_bounds.push_back (std::move (predicate));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ binding->inherit_bounds (specified_bounds);
+
+ // When we apply these bounds we must lookup which type this binding
+ // resolves to, as this is the type which will be used during resolution
+ // of the block.
+ NodeId ast_node_id = binding_type_path->get_mappings ().get_nodeid ();
+
+ // then lookup the reference_node_id
+ NodeId ref_node_id = UNKNOWN_NODEID;
+ if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id))
+ {
+ // FIXME
+ rust_error_at (Location (),
+ "Failed to lookup type reference for node: %s",
+ binding_type_path->as_string ().c_str ());
+ return;
+ }
+
+ // node back to HIR
+ HirId ref;
+ if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
+ {
+ // FIXME
+ rust_error_at (Location (), "where-clause reverse lookup failure");
+ return;
+ }
+
+ // the base reference for this name _must_ have a type set
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (ref, &lookup))
+ {
+ rust_error_at (mappings->lookup_location (ref),
+ "Failed to resolve where-clause binding type: %s",
+ binding_type_path->as_string ().c_str ());
+ return;
+ }
+
+ // FIXME
+ // rust_assert (binding->is_equal (*lookup));
+ lookup->inherit_bounds (specified_bounds);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h
new file mode 100644
index 00000000000..90d5ddbb411
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.h
@@ -0,0 +1,130 @@
+// 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_HIR_TYPE_CHECK_TYPE
+#define RUST_HIR_TYPE_CHECK_TYPE
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+#include "rust-substitution-mapper.h"
+#include "rust-hir-path-probe.h"
+
+namespace Rust {
+namespace Resolver {
+
+// FIXME
+// This simply fetches the HIR:::GenericArgs from the base class. Check to see
+// if we can get rid of this class
+class TypeCheckResolveGenericArguments : public TypeCheckBase
+{
+public:
+ static HIR::GenericArgs resolve (HIR::TypePathSegment *segment);
+
+ void visit (HIR::TypePathSegmentGeneric &generic);
+
+private:
+ TypeCheckResolveGenericArguments (Location locus)
+ : TypeCheckBase (), args (HIR::GenericArgs::create_empty (locus))
+ {}
+
+ HIR::GenericArgs args;
+};
+
+class TypeCheckType : public TypeCheckBase, public HIR::HIRTypeVisitor
+{
+public:
+ static TyTy::BaseType *Resolve (HIR::Type *type);
+
+ void visit (HIR::BareFunctionType &fntype) override;
+ void visit (HIR::TupleType &tuple) override;
+ void visit (HIR::TypePath &path) override;
+ void visit (HIR::QualifiedPathInType &path) override;
+ void visit (HIR::ArrayType &type) override;
+ void visit (HIR::SliceType &type) override;
+ void visit (HIR::ReferenceType &type) override;
+ void visit (HIR::RawPointerType &type) override;
+ void visit (HIR::InferredType &type) override;
+ void visit (HIR::NeverType &type) override;
+ void visit (HIR::TraitObjectType &type) override;
+
+ void visit (HIR::TypePathSegmentFunction &segment) override
+ { /* TODO */
+ }
+ void visit (HIR::TraitBound &bound) override
+ { /* TODO */
+ }
+ void visit (HIR::ImplTraitType &type) override
+ { /* TODO */
+ }
+ void visit (HIR::ParenthesisedType &type) override
+ { /* TODO */
+ }
+ void visit (HIR::ImplTraitTypeOneBound &type) override
+ { /* TODO */
+ }
+
+private:
+ TypeCheckType (HirId id)
+ : TypeCheckBase (), translated (new TyTy::ErrorType (id))
+ {}
+
+ TyTy::BaseType *resolve_root_path (HIR::TypePath &path, size_t *offset,
+ NodeId *root_resolved_node_id);
+
+ TyTy::BaseType *resolve_segments (
+ NodeId root_resolved_node_id, HirId expr_id,
+ std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset,
+ TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
+ Location expr_locus);
+
+ TyTy::BaseType *translated;
+};
+
+class TypeResolveGenericParam : public TypeCheckBase
+{
+public:
+ static TyTy::ParamType *Resolve (HIR::GenericParam *param);
+
+protected:
+ void visit (HIR::TypeParam ¶m);
+ void visit (HIR::LifetimeParam ¶m);
+ void visit (HIR::ConstGenericParam ¶m);
+
+private:
+ TypeResolveGenericParam () : TypeCheckBase (), resolved (nullptr) {}
+
+ TyTy::ParamType *resolved;
+};
+
+class ResolveWhereClauseItem : public TypeCheckBase
+{
+public:
+ static void Resolve (HIR::WhereClauseItem &item);
+
+protected:
+ void visit (HIR::LifetimeWhereClauseItem &item);
+ void visit (HIR::TypeBoundWhereClauseItem &item);
+
+private:
+ ResolveWhereClauseItem () : TypeCheckBase () {}
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_TYPE
diff --git a/gcc/rust/typecheck/rust-hir-type-check-util.cc b/gcc/rust/typecheck/rust-hir-type-check-util.cc
new file mode 100644
index 00000000000..e25f431a507
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-util.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2021-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-hir-type-check-util.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+ImplTypeIterator::go ()
+{
+ for (auto &item : impl.get_impl_items ())
+ {
+ item->accept_vis (*this);
+ }
+}
+
+void
+ImplTypeIterator::visit (HIR::TypeAlias &alias)
+{
+ cb (alias);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-util.h b/gcc/rust/typecheck/rust-hir-type-check-util.h
new file mode 100644
index 00000000000..1a4b17a3303
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-util.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2021-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_HIR_TYPE_CHECK_UTIL_H
+#define RUST_HIR_TYPE_CHECK_UTIL_H
+
+#include "rust-system.h"
+#include "rust-hir-visitor.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ImplTypeIterator : public HIR::HIRFullVisitorBase
+{
+ using HIR::HIRFullVisitorBase::visit;
+
+public:
+ ImplTypeIterator (HIR::ImplBlock &impl,
+ std::function<void (HIR::TypeAlias &alias)> cb)
+ : impl (impl), cb (cb)
+ {}
+
+ void go ();
+
+ void visit (HIR::TypeAlias &alias) override;
+
+private:
+ HIR::ImplBlock &impl;
+ std::function<void (HIR::TypeAlias &alias)> cb;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK_UTIL_H
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
new file mode 100644
index 00000000000..c314585cd3d
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -0,0 +1,295 @@
+// 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-hir-type-check.h"
+#include "rust-hir-full.h"
+#include "rust-hir-type-check-toplevel.h"
+#include "rust-hir-type-check-item.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-pattern.h"
+#include "rust-hir-type-check-struct-field.h"
+#include "rust-hir-inherent-impl-overlap.h"
+
+extern bool
+saw_errors (void);
+
+namespace Rust {
+namespace Resolver {
+
+void
+TypeResolution::Resolve (HIR::Crate &crate)
+{
+ for (auto it = crate.items.begin (); it != crate.items.end (); it++)
+ TypeCheckTopLevel::Resolve (*it->get ());
+
+ if (saw_errors ())
+ return;
+
+ OverlappingImplItemPass::go ();
+ if (saw_errors ())
+ return;
+
+ for (auto it = crate.items.begin (); it != crate.items.end (); it++)
+ TypeCheckItem::Resolve (*it->get ());
+
+ if (saw_errors ())
+ return;
+
+ auto mappings = Analysis::Mappings::get ();
+ auto context = TypeCheckContext::get ();
+
+ // default inference variables if possible
+ context->iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool {
+ // nothing to do
+ if (ty->get_kind () != TyTy::TypeKind::INFER)
+ return true;
+
+ TyTy::InferType *infer_var = static_cast<TyTy::InferType *> (ty);
+ TyTy::BaseType *default_type;
+ bool ok = infer_var->default_type (&default_type);
+ if (!ok)
+ {
+ rust_error_at (mappings->lookup_location (id),
+ "type annotations needed");
+ return true;
+ }
+ else
+ {
+ auto result = ty->unify (default_type);
+ result->set_ref (id);
+ context->insert_type (
+ Analysis::NodeMapping (mappings->get_current_crate (), 0, id,
+ UNKNOWN_LOCAL_DEFID),
+ result);
+ }
+
+ return true;
+ });
+}
+
+// rust-hir-trait-ref.h
+
+TraitItemReference::TraitItemReference (
+ std::string identifier, bool optional, TraitItemType type,
+ HIR::TraitItem *hir_trait_item, TyTy::BaseType *self,
+ std::vector<TyTy::SubstitutionParamMapping> substitutions, Location locus)
+ : identifier (identifier), optional_flag (optional), type (type),
+ hir_trait_item (hir_trait_item),
+ inherited_substitutions (std::move (substitutions)), locus (locus),
+ self (self), context (TypeCheckContext::get ())
+{}
+
+TraitItemReference::TraitItemReference (TraitItemReference const &other)
+ : identifier (other.identifier), optional_flag (other.optional_flag),
+ type (other.type), hir_trait_item (other.hir_trait_item),
+ locus (other.locus), self (other.self), context (TypeCheckContext::get ())
+{
+ inherited_substitutions.clear ();
+ inherited_substitutions.reserve (other.inherited_substitutions.size ());
+ for (size_t i = 0; i < other.inherited_substitutions.size (); i++)
+ inherited_substitutions.push_back (
+ other.inherited_substitutions.at (i).clone ());
+}
+
+TraitItemReference &
+TraitItemReference::operator= (TraitItemReference const &other)
+{
+ identifier = other.identifier;
+ optional_flag = other.optional_flag;
+ type = other.type;
+ hir_trait_item = other.hir_trait_item;
+ self = other.self;
+ locus = other.locus;
+ context = other.context;
+
+ inherited_substitutions.clear ();
+ inherited_substitutions.reserve (other.inherited_substitutions.size ());
+ for (size_t i = 0; i < other.inherited_substitutions.size (); i++)
+ inherited_substitutions.push_back (
+ other.inherited_substitutions.at (i).clone ());
+
+ return *this;
+}
+
+TyTy::BaseType *
+TraitItemReference::get_type_from_typealias (/*const*/
+ HIR::TraitItemType &type) const
+{
+ TyTy::TyVar var (get_mappings ().get_hirid ());
+ return var.get_tyty ();
+}
+
+TyTy::BaseType *
+TraitItemReference::get_type_from_constant (
+ /*const*/ HIR::TraitItemConst &constant) const
+{
+ TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ());
+ if (constant.has_expr ())
+ {
+ TyTy::BaseType *expr
+ = TypeCheckExpr::Resolve (constant.get_expr ().get ());
+
+ return type->unify (expr);
+ }
+ return type;
+}
+
+TyTy::BaseType *
+TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const
+{
+ std::vector<TyTy::SubstitutionParamMapping> substitutions
+ = inherited_substitutions;
+
+ HIR::TraitFunctionDecl &function = fn.get_decl ();
+ if (function.has_generics ())
+ {
+ for (auto &generic_param : function.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ case HIR::GenericParam::GenericKind::CONST:
+ // FIXME: Skipping Lifetime and Const completely until better
+ // handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param), param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ TyTy::BaseType *ret_type = nullptr;
+ if (!function.has_return_type ())
+ ret_type = TyTy::TupleType::get_unit_type (fn.get_mappings ().get_hirid ());
+ else
+ {
+ auto resolved
+ = TypeCheckType::Resolve (function.get_return_type ().get ());
+ if (resolved->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (fn.get_locus (), "failed to resolve return type");
+ return get_error ();
+ }
+
+ ret_type = resolved->clone ();
+ ret_type->set_ref (
+ function.get_return_type ()->get_mappings ().get_hirid ());
+ }
+
+ std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
+ if (function.is_method ())
+ {
+ // these are implicit mappings and not used
+ auto mappings = Analysis::Mappings::get ();
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ UNKNOWN_LOCAL_DEFID);
+
+ // add the synthetic self param at the front, this is a placeholder
+ // for compilation to know parameter names. The types are ignored
+ // but we reuse the HIR identifier pattern which requires it
+ HIR::SelfParam &self_param = function.get_self ();
+ HIR::IdentifierPattern *self_pattern
+ = new HIR::IdentifierPattern (mapping, "self", self_param.get_locus (),
+ self_param.is_ref (),
+ self_param.is_mut () ? Mutability::Mut
+ : Mutability::Imm,
+ std::unique_ptr<HIR::Pattern> (nullptr));
+ // might have a specified type
+ TyTy::BaseType *self_type = nullptr;
+ if (self_param.has_type ())
+ {
+ std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
+ self_type = TypeCheckType::Resolve (specified_type.get ());
+ }
+ else
+ {
+ switch (self_param.get_self_kind ())
+ {
+ case HIR::SelfParam::IMM:
+ case HIR::SelfParam::MUT:
+ self_type = self->clone ();
+ break;
+
+ case HIR::SelfParam::IMM_REF:
+ self_type = new TyTy::ReferenceType (
+ self_param.get_mappings ().get_hirid (),
+ TyTy::TyVar (self->get_ref ()), Mutability::Imm);
+ break;
+
+ case HIR::SelfParam::MUT_REF:
+ self_type = new TyTy::ReferenceType (
+ self_param.get_mappings ().get_hirid (),
+ TyTy::TyVar (self->get_ref ()), Mutability::Mut);
+ break;
+
+ default:
+ gcc_unreachable ();
+ return nullptr;
+ }
+ }
+
+ context->insert_type (self_param.get_mappings (), self_type);
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type));
+ }
+
+ for (auto ¶m : function.get_function_params ())
+ {
+ // get the name as well required for later on
+ auto param_tyty = TypeCheckType::Resolve (param.get_type ());
+ params.push_back (
+ std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
+ param_tyty));
+
+ context->insert_type (param.get_mappings (), param_tyty);
+ TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
+ }
+
+ auto mappings = Analysis::Mappings::get ();
+ const CanonicalPath *canonical_path = nullptr;
+ bool ok = mappings->lookup_canonical_path (fn.get_mappings ().get_nodeid (),
+ &canonical_path);
+ rust_assert (ok);
+
+ RustIdent ident{*canonical_path, fn.get_locus ()};
+ auto resolved
+ = new TyTy::FnType (fn.get_mappings ().get_hirid (),
+ fn.get_mappings ().get_defid (),
+ function.get_function_name (), ident,
+ function.is_method ()
+ ? TyTy::FnType::FNTYPE_IS_METHOD_FLAG
+ : TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
+ ABI::RUST, std::move (params), ret_type, substitutions);
+
+ context->insert_type (fn.get_mappings (), resolved);
+ return resolved;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
new file mode 100644
index 00000000000..21694dd302b
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -0,0 +1,379 @@
+// 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_HIR_TYPE_CHECK
+#define RUST_HIR_TYPE_CHECK
+
+#include "rust-hir-full-decls.h"
+#include "rust-hir-map.h"
+#include "rust-tyty.h"
+#include "rust-hir-trait-ref.h"
+#include "rust-autoderef.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeCheckContextItem
+{
+public:
+ enum ItemType
+ {
+ ITEM,
+ IMPL_ITEM,
+ TRAIT_ITEM,
+ };
+
+ TypeCheckContextItem (HIR::Function *item)
+ : type (ItemType::ITEM), item (item)
+ {}
+
+ TypeCheckContextItem (HIR::ImplBlock *impl_block, HIR::Function *item)
+ : type (ItemType::IMPL_ITEM), item (impl_block, item)
+ {}
+
+ TypeCheckContextItem (HIR::TraitItemFunc *trait_item)
+ : type (ItemType::TRAIT_ITEM), item (trait_item)
+ {}
+
+ ItemType get_type () const { return type; }
+
+ HIR::Function *get_item ()
+ {
+ rust_assert (get_type () == ItemType::ITEM);
+ return item.item;
+ }
+
+ std::pair<HIR::ImplBlock *, HIR::Function *> &get_impl_item ()
+ {
+ rust_assert (get_type () == ItemType::IMPL_ITEM);
+ return item.impl_item;
+ };
+
+ HIR::TraitItemFunc *get_trait_item ()
+ {
+ rust_assert (get_type () == ItemType::TRAIT_ITEM);
+ return item.trait_item;
+ }
+
+private:
+ union Item
+ {
+ HIR::Function *item;
+ std::pair<HIR::ImplBlock *, HIR::Function *> impl_item;
+ HIR::TraitItemFunc *trait_item;
+
+ Item (HIR::Function *item) : item (item) {}
+
+ Item (HIR::ImplBlock *impl_block, HIR::Function *item)
+ : impl_item ({impl_block, item})
+ {}
+
+ Item (HIR::TraitItemFunc *trait_item) : trait_item (trait_item) {}
+ };
+
+ ItemType type;
+ Item item;
+};
+
+class TypeCheckContext
+{
+public:
+ static TypeCheckContext *get ();
+
+ ~TypeCheckContext ();
+
+ bool lookup_builtin (NodeId id, TyTy::BaseType **type);
+ bool lookup_builtin (std::string name, TyTy::BaseType **type);
+ void insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type);
+
+ void insert_type (const Analysis::NodeMapping &mappings,
+ TyTy::BaseType *type);
+ void insert_implicit_type (TyTy::BaseType *type);
+ bool lookup_type (HirId id, TyTy::BaseType **type) const;
+
+ void insert_implicit_type (HirId id, TyTy::BaseType *type);
+
+ void insert_type_by_node_id (NodeId ref, HirId id);
+ bool lookup_type_by_node_id (NodeId ref, HirId *id);
+
+ TyTy::BaseType *peek_return_type ();
+ TypeCheckContextItem &peek_context ();
+ void push_return_type (TypeCheckContextItem item,
+ TyTy::BaseType *return_type);
+ void pop_return_type ();
+
+ void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb)
+ {
+ for (auto it = resolved.begin (); it != resolved.end (); it++)
+ {
+ if (!cb (it->first, it->second))
+ return;
+ }
+ }
+
+ bool have_loop_context () const { return !loop_type_stack.empty (); }
+
+ void push_new_loop_context (HirId id, Location locus)
+ {
+ TyTy::BaseType *infer_var
+ = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL,
+ locus);
+ loop_type_stack.push_back (infer_var);
+ }
+
+ void push_new_while_loop_context (HirId id)
+ {
+ TyTy::BaseType *infer_var = new TyTy::ErrorType (id);
+ loop_type_stack.push_back (infer_var);
+ }
+
+ TyTy::BaseType *peek_loop_context () { return loop_type_stack.back (); }
+
+ TyTy::BaseType *pop_loop_context ()
+ {
+ auto back = peek_loop_context ();
+ loop_type_stack.pop_back ();
+ return back;
+ }
+
+ void swap_head_loop_context (TyTy::BaseType *val)
+ {
+ loop_type_stack.pop_back ();
+ loop_type_stack.push_back (val);
+ }
+
+ void insert_trait_reference (DefId id, TraitReference &&ref)
+ {
+ rust_assert (trait_context.find (id) == trait_context.end ());
+ trait_context.emplace (id, std::move (ref));
+ }
+
+ bool lookup_trait_reference (DefId id, TraitReference **ref)
+ {
+ auto it = trait_context.find (id);
+ if (it == trait_context.end ())
+ return false;
+
+ *ref = &it->second;
+ return true;
+ }
+
+ void insert_receiver (HirId id, TyTy::BaseType *t)
+ {
+ receiver_context[id] = t;
+ }
+
+ bool lookup_receiver (HirId id, TyTy::BaseType **ref)
+ {
+ auto it = receiver_context.find (id);
+ if (it == receiver_context.end ())
+ return false;
+
+ *ref = it->second;
+ return true;
+ }
+
+ void insert_associated_trait_impl (HirId id, AssociatedImplTrait &&associated)
+ {
+ rust_assert (associated_impl_traits.find (id)
+ == associated_impl_traits.end ());
+ associated_impl_traits.emplace (id, std::move (associated));
+ }
+
+ bool lookup_associated_trait_impl (HirId id, AssociatedImplTrait **associated)
+ {
+ auto it = associated_impl_traits.find (id);
+ if (it == associated_impl_traits.end ())
+ return false;
+
+ *associated = &it->second;
+ return true;
+ }
+
+ void insert_associated_type_mapping (HirId id, HirId mapping)
+ {
+ associated_type_mappings[id] = mapping;
+ }
+
+ void clear_associated_type_mapping (HirId id)
+ {
+ auto it = associated_type_mappings.find (id);
+ if (it != associated_type_mappings.end ())
+ associated_type_mappings.erase (it);
+ }
+
+ // lookup any associated type mappings, the out parameter of mapping is
+ // allowed to be nullptr which allows this interface to do a simple does exist
+ // check
+ bool lookup_associated_type_mapping (HirId id, HirId *mapping)
+ {
+ auto it = associated_type_mappings.find (id);
+ if (it == associated_type_mappings.end ())
+ return false;
+
+ if (mapping != nullptr)
+ *mapping = it->second;
+
+ return true;
+ }
+
+ void insert_associated_impl_mapping (HirId trait_id,
+ const TyTy::BaseType *impl_type,
+ HirId impl_id)
+ {
+ auto it = associated_traits_to_impls.find (trait_id);
+ if (it == associated_traits_to_impls.end ())
+ {
+ associated_traits_to_impls[trait_id] = {};
+ }
+
+ associated_traits_to_impls[trait_id].push_back ({impl_type, impl_id});
+ }
+
+ bool lookup_associated_impl_mapping_for_self (HirId trait_id,
+ const TyTy::BaseType *self,
+ HirId *mapping)
+ {
+ auto it = associated_traits_to_impls.find (trait_id);
+ if (it == associated_traits_to_impls.end ())
+ return false;
+
+ for (auto &item : it->second)
+ {
+ if (item.first->can_eq (self, false))
+ {
+ *mapping = item.second;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void insert_autoderef_mappings (HirId id,
+ std::vector<Adjustment> &&adjustments)
+ {
+ rust_assert (autoderef_mappings.find (id) == autoderef_mappings.end ());
+ autoderef_mappings.emplace (id, std::move (adjustments));
+ }
+
+ bool lookup_autoderef_mappings (HirId id,
+ std::vector<Adjustment> **adjustments)
+ {
+ auto it = autoderef_mappings.find (id);
+ if (it == autoderef_mappings.end ())
+ return false;
+
+ *adjustments = &it->second;
+ 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);
+ rust_assert (it == variants.end ());
+
+ variants[id] = variant;
+ }
+
+ bool lookup_variant_definition (HirId id, HirId *variant)
+ {
+ auto it = variants.find (id);
+ if (it == variants.end ())
+ return false;
+
+ *variant = it->second;
+ return true;
+ }
+
+ void insert_operator_overload (HirId id, TyTy::FnType *call_site)
+ {
+ auto it = operator_overloads.find (id);
+ rust_assert (it == operator_overloads.end ());
+
+ operator_overloads[id] = call_site;
+ }
+
+ bool lookup_operator_overload (HirId id, TyTy::FnType **call)
+ {
+ auto it = operator_overloads.find (id);
+ if (it == operator_overloads.end ())
+ return false;
+
+ *call = it->second;
+ return true;
+ }
+
+private:
+ TypeCheckContext ();
+
+ std::map<NodeId, HirId> node_id_refs;
+ std::map<HirId, TyTy::BaseType *> resolved;
+ std::vector<std::unique_ptr<TyTy::BaseType>> builtins;
+ std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>>
+ return_type_stack;
+ std::vector<TyTy::BaseType *> loop_type_stack;
+ std::map<DefId, TraitReference> trait_context;
+ std::map<HirId, TyTy::BaseType *> receiver_context;
+ std::map<HirId, AssociatedImplTrait> associated_impl_traits;
+
+ // trait-id -> list of < self-tyty:impl-id>
+ std::map<HirId, std::vector<std::pair<const TyTy::BaseType *, HirId>>>
+ associated_traits_to_impls;
+
+ std::map<HirId, HirId> associated_type_mappings;
+
+ // 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;
+
+ // variants
+ std::map<HirId, HirId> variants;
+};
+
+class TypeResolution
+{
+public:
+ static void Resolve (HIR::Crate &crate);
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_TYPE_CHECK
diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc b/gcc/rust/typecheck/rust-substitution-mapper.cc
new file mode 100644
index 00000000000..f80368a0339
--- /dev/null
+++ b/gcc/rust/typecheck/rust-substitution-mapper.cc
@@ -0,0 +1,77 @@
+// 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-substitution-mapper.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace Resolver {
+
+TyTy::BaseType *
+SubstMapperInternal::Resolve (TyTy::BaseType *base,
+ TyTy::SubstitutionArgumentMappings &mappings)
+{
+ auto context = TypeCheckContext::get ();
+
+ SubstMapperInternal mapper (base->get_ref (), mappings);
+ base->accept_vis (mapper);
+ rust_assert (mapper.resolved != nullptr);
+
+ // insert these new implict types into the context
+ TyTy::BaseType *unused = nullptr;
+ bool is_ty_available
+ = context->lookup_type (mapper.resolved->get_ty_ref (), &unused);
+ if (!is_ty_available)
+ {
+ context->insert_type (
+ Analysis::NodeMapping (0, 0, mapper.resolved->get_ty_ref (), 0),
+ mapper.resolved);
+ }
+ bool is_ref_available
+ = context->lookup_type (mapper.resolved->get_ref (), &unused);
+ if (!is_ref_available)
+ {
+ context->insert_type (Analysis::NodeMapping (0, 0,
+ mapper.resolved->get_ref (),
+ 0),
+ mapper.resolved);
+ }
+
+ return mapper.resolved;
+}
+
+bool
+SubstMapperInternal::mappings_are_bound (
+ TyTy::BaseType *tyseg, TyTy::SubstitutionArgumentMappings &mappings)
+{
+ if (tyseg->get_kind () == TyTy::TypeKind::ADT)
+ {
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyseg);
+ return adt->are_mappings_bound (mappings);
+ }
+ else if (tyseg->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (tyseg);
+ return fn->are_mappings_bound (mappings);
+ }
+
+ return false;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h
new file mode 100644
index 00000000000..028e10c0efe
--- /dev/null
+++ b/gcc/rust/typecheck/rust-substitution-mapper.h
@@ -0,0 +1,394 @@
+// 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_SUBSTITUTION_MAPPER_H
+#define RUST_SUBSTITUTION_MAPPER_H
+
+#include "rust-tyty.h"
+#include "rust-tyty-visitor.h"
+
+namespace Rust {
+namespace Resolver {
+
+class SubstMapper : public TyTy::TyVisitor
+{
+public:
+ static TyTy::BaseType *Resolve (TyTy::BaseType *base, Location locus,
+ HIR::GenericArgs *generics = nullptr)
+ {
+ SubstMapper mapper (base->get_ref (), generics, locus);
+ base->accept_vis (mapper);
+ rust_assert (mapper.resolved != nullptr);
+ return mapper.resolved;
+ }
+
+ static TyTy::BaseType *InferSubst (TyTy::BaseType *base, Location locus)
+ {
+ return SubstMapper::Resolve (base, locus, nullptr);
+ }
+
+ bool have_generic_args () const { return generics != nullptr; }
+
+ void visit (TyTy::FnType &type) override
+ {
+ TyTy::FnType *concrete = nullptr;
+ if (!have_generic_args ())
+ {
+ TyTy::BaseType *substs = type.infer_substitions (locus);
+ rust_assert (substs->get_kind () == TyTy::TypeKind::FNDEF);
+ concrete = static_cast<TyTy::FnType *> (substs);
+ }
+ else
+ {
+ TyTy::SubstitutionArgumentMappings mappings
+ = type.get_mappings_from_generic_args (*generics);
+ if (mappings.is_error ())
+ return;
+
+ concrete = type.handle_substitions (mappings);
+ }
+
+ if (concrete != nullptr)
+ resolved = concrete;
+ }
+
+ void visit (TyTy::ADTType &type) override
+ {
+ TyTy::ADTType *concrete = nullptr;
+ if (!have_generic_args ())
+ {
+ TyTy::BaseType *substs = type.infer_substitions (locus);
+ rust_assert (substs->get_kind () == TyTy::TypeKind::ADT);
+ concrete = static_cast<TyTy::ADTType *> (substs);
+ }
+ else
+ {
+ TyTy::SubstitutionArgumentMappings mappings
+ = type.get_mappings_from_generic_args (*generics);
+ if (mappings.is_error ())
+ return;
+
+ concrete = type.handle_substitions (mappings);
+ }
+
+ if (concrete != nullptr)
+ resolved = concrete;
+ }
+
+ void visit (TyTy::PlaceholderType &type) override
+ {
+ rust_assert (type.can_resolve ());
+ resolved = SubstMapper::Resolve (type.resolve (), locus, generics);
+ }
+
+ void visit (TyTy::ProjectionType &type) override
+ {
+ TyTy::ProjectionType *concrete = nullptr;
+ if (!have_generic_args ())
+ {
+ TyTy::BaseType *substs = type.infer_substitions (locus);
+ rust_assert (substs->get_kind () == TyTy::TypeKind::ADT);
+ concrete = static_cast<TyTy::ProjectionType *> (substs);
+ }
+ else
+ {
+ TyTy::SubstitutionArgumentMappings mappings
+ = type.get_mappings_from_generic_args (*generics);
+ if (mappings.is_error ())
+ return;
+
+ concrete = type.handle_substitions (mappings);
+ }
+
+ if (concrete != nullptr)
+ resolved = concrete;
+ }
+
+ // nothing to do for these
+ void visit (TyTy::InferType &) override { gcc_unreachable (); }
+ void visit (TyTy::TupleType &) override { gcc_unreachable (); }
+ void visit (TyTy::FnPtr &) override { gcc_unreachable (); }
+ void visit (TyTy::ArrayType &) override { gcc_unreachable (); }
+ void visit (TyTy::SliceType &) override { gcc_unreachable (); }
+ void visit (TyTy::BoolType &) override { gcc_unreachable (); }
+ void visit (TyTy::IntType &) override { gcc_unreachable (); }
+ void visit (TyTy::UintType &) override { gcc_unreachable (); }
+ void visit (TyTy::FloatType &) override { gcc_unreachable (); }
+ void visit (TyTy::USizeType &) override { gcc_unreachable (); }
+ void visit (TyTy::ISizeType &) override { gcc_unreachable (); }
+ void visit (TyTy::ErrorType &) override { gcc_unreachable (); }
+ void visit (TyTy::CharType &) override { gcc_unreachable (); }
+ void visit (TyTy::ReferenceType &) override { gcc_unreachable (); }
+ void visit (TyTy::PointerType &) override { gcc_unreachable (); }
+ void visit (TyTy::ParamType &) override { gcc_unreachable (); }
+ void visit (TyTy::StrType &) override { gcc_unreachable (); }
+ void visit (TyTy::NeverType &) override { gcc_unreachable (); }
+ void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
+ void visit (TyTy::ClosureType &) override { gcc_unreachable (); }
+
+private:
+ SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus)
+ : resolved (new TyTy::ErrorType (ref)), generics (generics), locus (locus)
+ {}
+
+ TyTy::BaseType *resolved;
+ HIR::GenericArgs *generics;
+ Location locus;
+};
+
+class SubstMapperInternal : public TyTy::TyVisitor
+{
+public:
+ static TyTy::BaseType *Resolve (TyTy::BaseType *base,
+ TyTy::SubstitutionArgumentMappings &mappings);
+
+ static bool mappings_are_bound (TyTy::BaseType *ty,
+ TyTy::SubstitutionArgumentMappings &mappings);
+
+ void visit (TyTy::FnType &type) override
+ {
+ TyTy::SubstitutionArgumentMappings adjusted
+ = type.adjust_mappings_for_this (mappings);
+ if (adjusted.is_error ())
+ return;
+
+ TyTy::BaseType *concrete = type.handle_substitions (adjusted);
+ if (concrete != nullptr)
+ resolved = concrete;
+ }
+
+ void visit (TyTy::ADTType &type) override
+ {
+ TyTy::SubstitutionArgumentMappings adjusted
+ = type.adjust_mappings_for_this (mappings);
+ if (adjusted.is_error ())
+ return;
+
+ TyTy::BaseType *concrete = type.handle_substitions (adjusted);
+ if (concrete != nullptr)
+ resolved = concrete;
+ }
+
+ // these don't support generic arguments but might contain a type param
+ void visit (TyTy::TupleType &type) override
+ {
+ resolved = type.handle_substitions (mappings);
+ }
+
+ void visit (TyTy::ReferenceType &type) override
+ {
+ resolved = type.handle_substitions (mappings);
+ }
+
+ void visit (TyTy::PointerType &type) override
+ {
+ resolved = type.handle_substitions (mappings);
+ }
+
+ void visit (TyTy::ParamType &type) override
+ {
+ resolved = type.handle_substitions (mappings);
+ }
+
+ void visit (TyTy::PlaceholderType &type) override
+ {
+ rust_assert (type.can_resolve ());
+ if (mappings.trait_item_mode ())
+ {
+ resolved = type.resolve ();
+ }
+ else
+ {
+ resolved = SubstMapperInternal::Resolve (type.resolve (), mappings);
+ }
+ }
+
+ void visit (TyTy::ProjectionType &type) override
+ {
+ resolved = type.handle_substitions (mappings);
+ }
+
+ void visit (TyTy::ClosureType &type) override
+ {
+ resolved = type.handle_substitions (mappings);
+ }
+
+ void visit (TyTy::ArrayType &type) override
+ {
+ resolved = type.handle_substitions (mappings);
+ }
+
+ void visit (TyTy::SliceType &type) override
+ {
+ resolved = type.handle_substitions (mappings);
+ }
+
+ // nothing to do for these
+ void visit (TyTy::InferType &type) override { resolved = type.clone (); }
+ void visit (TyTy::FnPtr &type) override { resolved = type.clone (); }
+ void visit (TyTy::BoolType &type) override { resolved = type.clone (); }
+ void visit (TyTy::IntType &type) override { resolved = type.clone (); }
+ void visit (TyTy::UintType &type) override { resolved = type.clone (); }
+ void visit (TyTy::FloatType &type) override { resolved = type.clone (); }
+ void visit (TyTy::USizeType &type) override { resolved = type.clone (); }
+ void visit (TyTy::ISizeType &type) override { resolved = type.clone (); }
+ void visit (TyTy::ErrorType &type) override { resolved = type.clone (); }
+ void visit (TyTy::CharType &type) override { resolved = type.clone (); }
+ void visit (TyTy::StrType &type) override { resolved = type.clone (); }
+ void visit (TyTy::NeverType &type) override { resolved = type.clone (); }
+ void visit (TyTy::DynamicObjectType &type) override
+ {
+ resolved = type.clone ();
+ }
+
+private:
+ SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings)
+ : resolved (new TyTy::ErrorType (ref)), mappings (mappings)
+ {}
+
+ TyTy::BaseType *resolved;
+ TyTy::SubstitutionArgumentMappings &mappings;
+};
+
+class SubstMapperFromExisting : public TyTy::TyVisitor
+{
+public:
+ static TyTy::BaseType *Resolve (TyTy::BaseType *concrete,
+ TyTy::BaseType *receiver)
+ {
+ rust_assert (concrete->get_kind () == receiver->get_kind ());
+
+ SubstMapperFromExisting mapper (concrete, receiver);
+ concrete->accept_vis (mapper);
+ return mapper.resolved;
+ }
+
+ void visit (TyTy::FnType &type) override
+ {
+ rust_assert (type.was_substituted ());
+
+ TyTy::FnType *to_sub = static_cast<TyTy::FnType *> (receiver);
+ resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
+ }
+
+ void visit (TyTy::ADTType &type) override
+ {
+ rust_assert (type.was_substituted ());
+
+ TyTy::ADTType *to_sub = static_cast<TyTy::ADTType *> (receiver);
+ resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
+ }
+
+ void visit (TyTy::ClosureType &type) override
+ {
+ rust_assert (type.was_substituted ());
+
+ TyTy::ClosureType *to_sub = static_cast<TyTy::ClosureType *> (receiver);
+ resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
+ }
+
+ void visit (TyTy::InferType &) override { gcc_unreachable (); }
+ void visit (TyTy::TupleType &) override { gcc_unreachable (); }
+ void visit (TyTy::FnPtr &) override { gcc_unreachable (); }
+ void visit (TyTy::ArrayType &) override { gcc_unreachable (); }
+ void visit (TyTy::SliceType &) override { gcc_unreachable (); }
+ void visit (TyTy::BoolType &) override { gcc_unreachable (); }
+ void visit (TyTy::IntType &) override { gcc_unreachable (); }
+ void visit (TyTy::UintType &) override { gcc_unreachable (); }
+ void visit (TyTy::FloatType &) override { gcc_unreachable (); }
+ void visit (TyTy::USizeType &) override { gcc_unreachable (); }
+ void visit (TyTy::ISizeType &) override { gcc_unreachable (); }
+ void visit (TyTy::ErrorType &) override { gcc_unreachable (); }
+ void visit (TyTy::CharType &) override { gcc_unreachable (); }
+ void visit (TyTy::ReferenceType &) override { gcc_unreachable (); }
+ void visit (TyTy::PointerType &) override { gcc_unreachable (); }
+ void visit (TyTy::ParamType &) override { gcc_unreachable (); }
+ void visit (TyTy::StrType &) override { gcc_unreachable (); }
+ void visit (TyTy::NeverType &) override { gcc_unreachable (); }
+ void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); }
+ void visit (TyTy::ProjectionType &) override { gcc_unreachable (); }
+ void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
+
+private:
+ SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver)
+ : concrete (concrete), receiver (receiver), resolved (nullptr)
+ {}
+
+ TyTy::BaseType *concrete;
+ TyTy::BaseType *receiver;
+
+ TyTy::BaseType *resolved;
+};
+
+class GetUsedSubstArgs : public TyTy::TyConstVisitor
+{
+public:
+ static TyTy::SubstitutionArgumentMappings From (const TyTy::BaseType *from)
+ {
+ GetUsedSubstArgs mapper;
+ from->accept_vis (mapper);
+ return mapper.args;
+ }
+
+ void visit (const TyTy::FnType &type) override
+ {
+ args = type.get_substitution_arguments ();
+ }
+
+ void visit (const TyTy::ADTType &type) override
+ {
+ args = type.get_substitution_arguments ();
+ }
+
+ void visit (const TyTy::ClosureType &type) override
+ {
+ args = type.get_substitution_arguments ();
+ }
+
+ void visit (const TyTy::InferType &) override {}
+ void visit (const TyTy::TupleType &) override {}
+ void visit (const TyTy::FnPtr &) override {}
+ void visit (const TyTy::ArrayType &) override {}
+ void visit (const TyTy::SliceType &) override {}
+ void visit (const TyTy::BoolType &) override {}
+ void visit (const TyTy::IntType &) override {}
+ void visit (const TyTy::UintType &) override {}
+ void visit (const TyTy::FloatType &) override {}
+ void visit (const TyTy::USizeType &) override {}
+ void visit (const TyTy::ISizeType &) override {}
+ void visit (const TyTy::ErrorType &) override {}
+ void visit (const TyTy::CharType &) override {}
+ void visit (const TyTy::ReferenceType &) override {}
+ void visit (const TyTy::PointerType &) override {}
+ void visit (const TyTy::ParamType &) override {}
+ void visit (const TyTy::StrType &) override {}
+ void visit (const TyTy::NeverType &) override {}
+ void visit (const TyTy::PlaceholderType &) override {}
+ void visit (const TyTy::ProjectionType &) override {}
+ void visit (const TyTy::DynamicObjectType &) override {}
+
+private:
+ GetUsedSubstArgs () : args (TyTy::SubstitutionArgumentMappings::error ()) {}
+
+ TyTy::SubstitutionArgumentMappings args;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_SUBSTITUTION_MAPPER_H
diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h
new file mode 100644
index 00000000000..ccf0f625e4b
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tycheck-dump.h
@@ -0,0 +1,239 @@
+// 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_TYCHECK_DUMP
+#define RUST_TYCHECK_DUMP
+
+#include "rust-hir-type-check-base.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class TypeResolverDump : private TypeCheckBase, private HIR::HIRFullVisitorBase
+{
+ using HIR::HIRFullVisitorBase::visit;
+
+public:
+ static void go (HIR::Crate &crate, std::ofstream &out)
+ {
+ TypeResolverDump dumper;
+ for (auto &item : crate.items)
+ {
+ item->accept_vis (dumper);
+ dumper.dump += "\n";
+ }
+
+ out << dumper.dump;
+ }
+
+ void visit (HIR::StructStruct &struct_decl) override
+ {
+ dump += indent () + "struct " + type_string (struct_decl.get_mappings ())
+ + "\n";
+ }
+
+ void visit (HIR::Union &union_decl) override
+ {
+ dump
+ += indent () + "union " + type_string (union_decl.get_mappings ()) + "\n";
+ }
+
+ void visit (HIR::TupleStruct &struct_decl) override
+ {
+ dump += indent () + "struct" + type_string (struct_decl.get_mappings ())
+ + "\n";
+ }
+
+ void visit (HIR::ImplBlock &impl_block) override
+ {
+ dump += indent () + "impl "
+ + type_string (impl_block.get_type ()->get_mappings ()) + " {\n";
+ indentation_level++;
+
+ for (auto &impl_item : impl_block.get_impl_items ())
+ {
+ impl_item->accept_vis (*this);
+ dump += "\n";
+ }
+
+ indentation_level--;
+ dump += indent () + "}\n";
+ }
+
+ void visit (HIR::ConstantItem &constant) override
+ {
+ dump += indent () + "constant " + constant.get_identifier () + ":"
+ + type_string (constant.get_mappings ()) + " = ";
+ constant.get_expr ()->accept_vis (*this);
+ dump += ";\n";
+ }
+
+ void visit (HIR::Function &function) override
+ {
+ dump += indent () + "fn " + function.get_function_name () + " "
+ + type_string (function.get_mappings ()) + "\n";
+ dump += indent () + "{\n";
+
+ HIR::BlockExpr *function_body = function.get_definition ().get ();
+ function_body->accept_vis (*this);
+
+ dump += indent () + "}\n";
+ }
+
+ void visit (HIR::BlockExpr &expr) override
+ {
+ dump += "{\n";
+ indentation_level++;
+
+ for (auto &s : expr.get_statements ())
+ {
+ dump += indent ();
+ s->accept_vis (*this);
+ dump += ";\n";
+ }
+
+ if (expr.has_expr ())
+ {
+ dump += indent ();
+ expr.expr->accept_vis (*this);
+ dump += ";\n";
+ }
+
+ indentation_level--;
+ dump += "}\n";
+ }
+
+ void visit (HIR::UnsafeBlockExpr &expr) override
+ {
+ dump += "unsafe ";
+ expr.get_block_expr ()->accept_vis (*this);
+ }
+
+ void visit (HIR::LetStmt &stmt) override
+ {
+ dump += "let " + stmt.get_pattern ()->as_string () + ":"
+ + type_string (stmt.get_pattern ()->get_pattern_mappings ());
+ if (stmt.has_init_expr ())
+ {
+ dump += " = ";
+ stmt.get_init_expr ()->accept_vis (*this);
+ }
+ }
+
+ void visit (HIR::ExprStmtWithBlock &stmt) override
+ {
+ stmt.get_expr ()->accept_vis (*this);
+ }
+
+ void visit (HIR::ExprStmtWithoutBlock &stmt) override
+ {
+ stmt.get_expr ()->accept_vis (*this);
+ }
+
+ void visit (HIR::AssignmentExpr &expr) override
+ {
+ expr.get_lhs ()->accept_vis (*this);
+ dump += " = ";
+ expr.get_rhs ()->accept_vis (*this);
+ }
+
+ void visit (HIR::LiteralExpr &expr) override
+ {
+ dump += expr.get_literal ().as_string () + ":"
+ + type_string (expr.get_mappings ());
+ }
+
+ void visit (HIR::ArrayExpr &expr) override
+ {
+ dump += type_string (expr.get_mappings ()) + ":[";
+
+ HIR::ArrayElems *elements = expr.get_internal_elements ();
+ elements->accept_vis (*this);
+
+ dump += "]";
+ }
+
+ void visit (HIR::ArrayElemsValues &elems) override
+ {
+ for (auto &elem : elems.get_values ())
+ {
+ elem->accept_vis (*this);
+ dump += ",";
+ }
+ }
+
+ void visit (HIR::GroupedExpr &expr) override
+ {
+ HIR::Expr *paren_expr = expr.get_expr_in_parens ().get ();
+ dump += "(";
+ paren_expr->accept_vis (*this);
+ dump += ")";
+ }
+
+ void visit (HIR::PathInExpression &expr) override
+ {
+ dump += type_string (expr.get_mappings ());
+ }
+
+ void visit (HIR::StructExprStructFields &expr) override
+ {
+ dump += "ctor: " + type_string (expr.get_mappings ());
+ }
+
+protected:
+ std::string type_string (const Analysis::NodeMapping &mappings)
+ {
+ TyTy::BaseType *lookup = nullptr;
+ if (!context->lookup_type (mappings.get_hirid (), &lookup))
+ return "<error>";
+
+ std::string buf = "[";
+ for (auto &ref : lookup->get_combined_refs ())
+ {
+ buf += std::to_string (ref);
+ buf += ", ";
+ }
+ buf += "]";
+
+ std::string repr = lookup->as_string ();
+ return "<" + repr + " HIRID: " + std::to_string (mappings.get_hirid ())
+ + " RF:" + std::to_string (lookup->get_ref ()) + " TF:"
+ + std::to_string (lookup->get_ty_ref ()) + +" - " + buf + ">";
+ }
+
+ std::string indent ()
+ {
+ std::string buf;
+ for (size_t i = 0; i < indentation_level; ++i)
+ buf += " ";
+
+ return buf;
+ }
+
+private:
+ TypeResolverDump () : TypeCheckBase (), indentation_level (0) {}
+
+ std::string dump;
+ size_t indentation_level;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_TYCHECK_DUMP
diff --git a/gcc/rust/typecheck/rust-tyctx.cc b/gcc/rust/typecheck/rust-tyctx.cc
new file mode 100644
index 00000000000..d8a49e8b9ea
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyctx.cc
@@ -0,0 +1,155 @@
+// 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-hir-type-check.h"
+
+namespace Rust {
+namespace Resolver {
+
+TypeCheckContext *
+TypeCheckContext::get ()
+{
+ static TypeCheckContext *instance;
+ if (instance == nullptr)
+ instance = new TypeCheckContext ();
+
+ return instance;
+}
+
+TypeCheckContext::TypeCheckContext () {}
+
+TypeCheckContext::~TypeCheckContext () {}
+
+bool
+TypeCheckContext::lookup_builtin (NodeId id, TyTy::BaseType **type)
+{
+ auto ref_it = node_id_refs.find (id);
+ if (ref_it == node_id_refs.end ())
+ return false;
+
+ auto it = resolved.find (ref_it->second);
+ if (it == resolved.end ())
+ return false;
+
+ *type = it->second;
+ return true;
+}
+
+bool
+TypeCheckContext::lookup_builtin (std::string name, TyTy::BaseType **type)
+{
+ for (auto &builtin : builtins)
+ {
+ if (name.compare (builtin->as_string ()) == 0)
+ {
+ *type = builtin.get ();
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+TypeCheckContext::insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type)
+{
+ node_id_refs[ref] = id;
+ resolved[id] = type;
+ builtins.push_back (std::unique_ptr<TyTy::BaseType> (type));
+}
+
+void
+TypeCheckContext::insert_type (const Analysis::NodeMapping &mappings,
+ TyTy::BaseType *type)
+{
+ rust_assert (type != nullptr);
+ NodeId ref = mappings.get_nodeid ();
+ HirId id = mappings.get_hirid ();
+ node_id_refs[ref] = id;
+ resolved[id] = type;
+}
+
+void
+TypeCheckContext::insert_implicit_type (TyTy::BaseType *type)
+{
+ rust_assert (type != nullptr);
+ resolved[type->get_ref ()] = type;
+}
+
+void
+TypeCheckContext::insert_implicit_type (HirId id, TyTy::BaseType *type)
+{
+ rust_assert (type != nullptr);
+ resolved[id] = type;
+}
+
+bool
+TypeCheckContext::lookup_type (HirId id, TyTy::BaseType **type) const
+{
+ auto it = resolved.find (id);
+ if (it == resolved.end ())
+ return false;
+
+ *type = it->second;
+ return true;
+}
+
+void
+TypeCheckContext::insert_type_by_node_id (NodeId ref, HirId id)
+{
+ rust_assert (node_id_refs.find (ref) == node_id_refs.end ());
+ node_id_refs[ref] = id;
+}
+
+bool
+TypeCheckContext::lookup_type_by_node_id (NodeId ref, HirId *id)
+{
+ auto it = node_id_refs.find (ref);
+ if (it == node_id_refs.end ())
+ return false;
+
+ *id = it->second;
+ return true;
+}
+
+TyTy::BaseType *
+TypeCheckContext::peek_return_type ()
+{
+ return return_type_stack.back ().second;
+}
+
+void
+TypeCheckContext::push_return_type (TypeCheckContextItem item,
+ TyTy::BaseType *return_type)
+{
+ return_type_stack.push_back ({std::move (item), return_type});
+}
+
+void
+TypeCheckContext::pop_return_type ()
+{
+ return_type_stack.pop_back ();
+}
+
+TypeCheckContextItem &
+TypeCheckContext::peek_context ()
+{
+ return return_type_stack.back ().first;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc
new file mode 100644
index 00000000000..7a1562ab544
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -0,0 +1,462 @@
+// Copyright (C) 2021-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-hir-type-bounds.h"
+#include "rust-hir-trait-resolve.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+TypeBoundsProbe::scan ()
+{
+ std::vector<std::pair<HIR::TypePath *, HIR::ImplBlock *>>
+ possible_trait_paths;
+ mappings->iterate_impl_blocks (
+ [&] (HirId id, HIR::ImplBlock *impl) mutable -> bool {
+ // we are filtering for trait-impl-blocks
+ if (!impl->has_trait_ref ())
+ return true;
+
+ TyTy::BaseType *impl_type = nullptr;
+ bool ok
+ = context->lookup_type (impl->get_type ()->get_mappings ().get_hirid (),
+ &impl_type);
+ if (!ok)
+ return true;
+
+ if (!receiver->can_eq (impl_type, false))
+ {
+ if (!impl_type->can_eq (receiver, false))
+ return true;
+ }
+
+ possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl});
+ return true;
+ });
+
+ for (auto &path : possible_trait_paths)
+ {
+ HIR::TypePath *trait_path = path.first;
+ TraitReference *trait_ref = TraitResolver::Resolve (*trait_path);
+
+ if (!trait_ref->is_error ())
+ trait_references.push_back ({trait_ref, path.second});
+ }
+}
+
+TraitReference *
+TypeCheckBase::resolve_trait_path (HIR::TypePath &path)
+{
+ return TraitResolver::Resolve (path);
+}
+
+TyTy::TypeBoundPredicate
+TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path)
+{
+ TraitReference *trait = resolve_trait_path (type_path);
+ if (trait->is_error ())
+ return TyTy::TypeBoundPredicate::error ();
+
+ TyTy::TypeBoundPredicate predicate (*trait, type_path.get_locus ());
+ HIR::GenericArgs args
+ = HIR::GenericArgs::create_empty (type_path.get_locus ());
+
+ auto &final_seg = type_path.get_final_segment ();
+ if (final_seg->is_generic_segment ())
+ {
+ auto final_generic_seg
+ = static_cast<HIR::TypePathSegmentGeneric *> (final_seg.get ());
+ if (final_generic_seg->has_generic_args ())
+ {
+ args = final_generic_seg->get_generic_args ();
+ }
+ }
+
+ if (predicate.requires_generic_args ())
+ {
+ // this is applying generic arguments to a trait reference
+ predicate.apply_generic_arguments (&args);
+ }
+
+ return predicate;
+}
+
+} // namespace Resolver
+
+namespace TyTy {
+
+TypeBoundPredicate::TypeBoundPredicate (
+ const Resolver::TraitReference &trait_reference, Location locus)
+ : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
+ reference (trait_reference.get_mappings ().get_defid ()), locus (locus),
+ error_flag (false)
+{
+ substitutions.clear ();
+ for (const auto &p : trait_reference.get_trait_substs ())
+ substitutions.push_back (p.clone ());
+
+ // we setup a dummy implict self argument
+ SubstitutionArg placeholder_self (&get_substs ().front (), nullptr);
+ used_arguments.get_mappings ().push_back (placeholder_self);
+}
+
+TypeBoundPredicate::TypeBoundPredicate (
+ DefId reference, std::vector<SubstitutionParamMapping> subst, Location locus)
+ : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
+ reference (reference), locus (locus), error_flag (false)
+{
+ substitutions.clear ();
+ for (const auto &p : subst)
+ substitutions.push_back (p.clone ());
+
+ // we setup a dummy implict self argument
+ SubstitutionArg placeholder_self (&get_substs ().front (), nullptr);
+ used_arguments.get_mappings ().push_back (placeholder_self);
+}
+
+TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other)
+ : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
+ reference (other.reference), locus (other.locus),
+ error_flag (other.error_flag)
+{
+ substitutions.clear ();
+ for (const auto &p : other.get_substs ())
+ substitutions.push_back (p.clone ());
+
+ std::vector<SubstitutionArg> mappings;
+ for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++)
+ {
+ const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i);
+ SubstitutionArg arg (oa);
+ mappings.push_back (std::move (arg));
+ }
+
+ // we need to remap the argument mappings based on this copied constructor
+ std::vector<SubstitutionArg> copied_arg_mappings;
+ size_t i = 0;
+ for (const auto &m : other.used_arguments.get_mappings ())
+ {
+ TyTy::BaseType *argument
+ = m.get_tyty () == nullptr ? nullptr : m.get_tyty ()->clone ();
+ SubstitutionArg c (&substitutions.at (i++), argument);
+ copied_arg_mappings.push_back (std::move (c));
+ }
+
+ used_arguments
+ = SubstitutionArgumentMappings (copied_arg_mappings,
+ other.used_arguments.get_locus ());
+}
+
+TypeBoundPredicate &
+TypeBoundPredicate::operator= (const TypeBoundPredicate &other)
+{
+ reference = other.reference;
+ locus = other.locus;
+ error_flag = other.error_flag;
+ used_arguments = SubstitutionArgumentMappings::error ();
+
+ substitutions.clear ();
+ for (const auto &p : other.get_substs ())
+ substitutions.push_back (p.clone ());
+
+ std::vector<SubstitutionArg> mappings;
+ for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++)
+ {
+ const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i);
+ SubstitutionArg arg (oa);
+ mappings.push_back (std::move (arg));
+ }
+
+ // we need to remap the argument mappings based on this copied constructor
+ std::vector<SubstitutionArg> copied_arg_mappings;
+ size_t i = 0;
+ for (const auto &m : other.used_arguments.get_mappings ())
+ {
+ TyTy::BaseType *argument
+ = m.get_tyty () == nullptr ? nullptr : m.get_tyty ()->clone ();
+ SubstitutionArg c (&substitutions.at (i++), argument);
+ copied_arg_mappings.push_back (std::move (c));
+ }
+
+ used_arguments
+ = SubstitutionArgumentMappings (copied_arg_mappings,
+ other.used_arguments.get_locus ());
+
+ return *this;
+}
+
+TypeBoundPredicate
+TypeBoundPredicate::error ()
+{
+ auto p = TypeBoundPredicate (UNKNOWN_DEFID, {}, Location ());
+ p.error_flag = true;
+ return p;
+}
+
+std::string
+TypeBoundPredicate::as_string () const
+{
+ return get ()->as_string () + subst_as_string ();
+}
+
+std::string
+TypeBoundPredicate::as_name () const
+{
+ return get ()->get_name () + subst_as_string ();
+}
+
+const Resolver::TraitReference *
+TypeBoundPredicate::get () const
+{
+ auto context = Resolver::TypeCheckContext::get ();
+
+ Resolver::TraitReference *ref = nullptr;
+ bool ok = context->lookup_trait_reference (reference, &ref);
+ rust_assert (ok);
+
+ return ref;
+}
+
+std::string
+TypeBoundPredicate::get_name () const
+{
+ return get ()->get_name ();
+}
+
+bool
+TypeBoundPredicate::is_object_safe (bool emit_error, Location locus) const
+{
+ const Resolver::TraitReference *trait = get ();
+ rust_assert (trait != nullptr);
+ return trait->is_object_safe (emit_error, locus);
+}
+
+void
+TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args)
+{
+ // we need to get the substitutions argument mappings but also remember that
+ // we have an implicit Self argument which we must be careful to respect
+ rust_assert (!used_arguments.is_empty ());
+ rust_assert (!substitutions.empty ());
+
+ // now actually perform a substitution
+ used_arguments = get_mappings_from_generic_args (*generic_args);
+
+ error_flag |= used_arguments.is_error ();
+ auto &subst_mappings = used_arguments;
+ for (auto &sub : get_substs ())
+ {
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok
+ = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
+ if (ok && arg.get_tyty () != nullptr)
+ sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
+ }
+}
+
+bool
+TypeBoundPredicate::contains_item (const std::string &search) const
+{
+ auto trait_ref = get ();
+ const Resolver::TraitItemReference *trait_item_ref = nullptr;
+ return trait_ref->lookup_trait_item (search, &trait_item_ref);
+}
+
+TypeBoundPredicateItem
+TypeBoundPredicate::lookup_associated_item (const std::string &search) const
+{
+ auto trait_ref = get ();
+ const Resolver::TraitItemReference *trait_item_ref = nullptr;
+ if (!trait_ref->lookup_trait_item (search, &trait_item_ref))
+ return TypeBoundPredicateItem::error ();
+
+ return TypeBoundPredicateItem (this, trait_item_ref);
+}
+
+TypeBoundPredicateItem
+TypeBoundPredicate::lookup_associated_item (
+ const Resolver::TraitItemReference *ref) const
+{
+ return lookup_associated_item (ref->get_identifier ());
+}
+
+BaseType *
+TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver)
+{
+ TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty ();
+ if (parent->get_substitution_arguments ().is_empty ())
+ return trait_item_tyty;
+
+ const Resolver::TraitItemReference *tref = get_raw_item ();
+ bool is_associated_type = tref->get_trait_item_type ();
+ if (is_associated_type)
+ return trait_item_tyty;
+
+ // set up the self mapping
+ SubstitutionArgumentMappings gargs = parent->get_substitution_arguments ();
+ rust_assert (!gargs.is_empty ());
+
+ // setup the adjusted mappings
+ std::vector<SubstitutionArg> adjusted_mappings;
+ for (size_t i = 0; i < gargs.get_mappings ().size (); i++)
+ {
+ auto &mapping = gargs.get_mappings ().at (i);
+
+ bool is_implicit_self = i == 0;
+ TyTy::BaseType *argument
+ = is_implicit_self ? receiver->clone () : mapping.get_tyty ();
+
+ SubstitutionArg arg (mapping.get_param_mapping (), argument);
+ adjusted_mappings.push_back (std::move (arg));
+ }
+
+ SubstitutionArgumentMappings adjusted (adjusted_mappings, gargs.get_locus (),
+ gargs.get_subst_cb (),
+ true /* trait-mode-flag */);
+ return Resolver::SubstMapperInternal::Resolve (trait_item_tyty, adjusted);
+}
+bool
+TypeBoundPredicate::is_error () const
+{
+ auto context = Resolver::TypeCheckContext::get ();
+
+ Resolver::TraitReference *ref = nullptr;
+ bool ok = context->lookup_trait_reference (reference, &ref);
+
+ return !ok || error_flag;
+}
+
+BaseType *
+TypeBoundPredicate::handle_substitions (
+ SubstitutionArgumentMappings subst_mappings)
+{
+ for (auto &sub : get_substs ())
+ {
+ if (sub.get_param_ty () == nullptr)
+ continue;
+
+ ParamType *p = sub.get_param_ty ();
+ BaseType *r = p->resolve ();
+ BaseType *s = Resolver::SubstMapperInternal::Resolve (r, subst_mappings);
+
+ p->set_ty_ref (s->get_ty_ref ());
+ }
+
+ // FIXME more error handling at some point
+ // used_arguments = subst_mappings;
+ // error_flag |= used_arguments.is_error ();
+
+ return nullptr;
+}
+
+bool
+TypeBoundPredicate::requires_generic_args () const
+{
+ if (is_error ())
+ return false;
+
+ return substitutions.size () > 1;
+}
+
+// trait item reference
+
+const Resolver::TraitItemReference *
+TypeBoundPredicateItem::get_raw_item () const
+{
+ return trait_item_ref;
+}
+
+bool
+TypeBoundPredicateItem::needs_implementation () const
+{
+ return !get_raw_item ()->is_optional ();
+}
+
+Location
+TypeBoundPredicateItem::get_locus () const
+{
+ return get_raw_item ()->get_locus ();
+}
+
+// TypeBoundsMappings
+
+TypeBoundsMappings::TypeBoundsMappings (
+ std::vector<TypeBoundPredicate> specified_bounds)
+ : specified_bounds (specified_bounds)
+{}
+
+std::vector<TypeBoundPredicate> &
+TypeBoundsMappings::get_specified_bounds ()
+{
+ return specified_bounds;
+}
+
+const std::vector<TypeBoundPredicate> &
+TypeBoundsMappings::get_specified_bounds () const
+{
+ return specified_bounds;
+}
+
+size_t
+TypeBoundsMappings::num_specified_bounds () const
+{
+ return specified_bounds.size ();
+}
+
+std::string
+TypeBoundsMappings::raw_bounds_as_string () const
+{
+ std::string buf;
+ for (size_t i = 0; i < specified_bounds.size (); i++)
+ {
+ const TypeBoundPredicate &b = specified_bounds.at (i);
+ bool has_next = (i + 1) < specified_bounds.size ();
+ buf += b.as_string () + (has_next ? " + " : "");
+ }
+ return buf;
+}
+
+std::string
+TypeBoundsMappings::bounds_as_string () const
+{
+ return "bounds:[" + raw_bounds_as_string () + "]";
+}
+
+std::string
+TypeBoundsMappings::raw_bounds_as_name () const
+{
+ std::string buf;
+ for (size_t i = 0; i < specified_bounds.size (); i++)
+ {
+ const TypeBoundPredicate &b = specified_bounds.at (i);
+ bool has_next = (i + 1) < specified_bounds.size ();
+ buf += b.as_name () + (has_next ? " + " : "");
+ }
+
+ return buf;
+}
+
+void
+TypeBoundsMappings::add_bound (TypeBoundPredicate predicate)
+{
+ specified_bounds.push_back (predicate);
+}
+
+} // namespace TyTy
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-call.cc b/gcc/rust/typecheck/rust-tyty-call.cc
new file mode 100644
index 00000000000..1ce82c943f5
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyty-call.cc
@@ -0,0 +1,263 @@
+// 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-tyty-call.h"
+#include "rust-hir-type-check-expr.h"
+
+namespace Rust {
+namespace TyTy {
+
+void
+TypeCheckCallExpr::visit (ADTType &type)
+{
+ rust_assert (!variant.is_error ());
+ if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
+ {
+ rust_error_at (
+ call.get_locus (),
+ "expected function, tuple struct or tuple variant, found struct %<%s%>",
+ type.get_name ().c_str ());
+ return;
+ }
+
+ if (call.num_params () != variant.num_fields ())
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) call.num_params (),
+ (unsigned long) variant.num_fields ());
+ return;
+ }
+
+ size_t i = 0;
+ for (auto &argument : call.get_arguments ())
+ {
+ StructFieldType *field = variant.get_field_at_index (i);
+ BaseType *field_tyty = field->get_field_type ();
+
+ BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get ());
+ if (arg->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (argument->get_locus (),
+ "failed to resolve argument type");
+ return;
+ }
+
+ auto res = Resolver::TypeCheckBase::coercion_site (
+ argument->get_mappings ().get_hirid (), field_tyty, arg,
+ argument->get_locus ());
+ if (res->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ return;
+ }
+
+ delete res;
+ i++;
+ }
+
+ if (i != call.num_params ())
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) i, (unsigned long) call.num_params ());
+ return;
+ }
+
+ resolved = type.clone ();
+}
+
+void
+TypeCheckCallExpr::visit (FnType &type)
+{
+ type.monomorphize ();
+ if (call.num_params () != type.num_params ())
+ {
+ if (type.is_varadic ())
+ {
+ if (call.num_params () < type.num_params ())
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) call.num_params (),
+ (unsigned long) type.num_params ());
+ return;
+ }
+ }
+ else
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) call.num_params (),
+ (unsigned long) type.num_params ());
+ return;
+ }
+ }
+
+ size_t i = 0;
+ for (auto &argument : call.get_arguments ())
+ {
+ auto argument_expr_tyty
+ = Resolver::TypeCheckExpr::Resolve (argument.get ());
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (
+ argument->get_locus (),
+ "failed to resolve type for argument expr in CallExpr");
+ return;
+ }
+
+ // it might be a varadic function
+ if (i < type.num_params ())
+ {
+ auto fnparam = type.param_at (i);
+ auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
+ argument->get_mappings ().get_hirid (), fnparam.second,
+ argument_expr_tyty, argument->get_locus ());
+ if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (argument->get_locus (),
+ "Type Resolution failure on parameter");
+ return;
+ }
+ }
+
+ i++;
+ }
+
+ if (i < call.num_params ())
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) i, (unsigned long) call.num_params ());
+ return;
+ }
+
+ type.monomorphize ();
+ resolved = type.get_return_type ()->clone ();
+}
+
+void
+TypeCheckCallExpr::visit (FnPtr &type)
+{
+ if (call.num_params () != type.num_params ())
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) call.num_params (),
+ (unsigned long) type.num_params ());
+ return;
+ }
+
+ size_t i = 0;
+ for (auto &argument : call.get_arguments ())
+ {
+ auto fnparam = type.param_at (i);
+ auto argument_expr_tyty
+ = Resolver::TypeCheckExpr::Resolve (argument.get ());
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (
+ argument->get_locus (),
+ "failed to resolve type for argument expr in CallExpr");
+ return;
+ }
+
+ auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
+ argument->get_mappings ().get_hirid (), fnparam, argument_expr_tyty,
+ argument->get_locus ());
+ if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (argument->get_locus (),
+ "Type Resolution failure on parameter");
+ return;
+ }
+
+ i++;
+ }
+
+ if (i != call.num_params ())
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) i, (unsigned long) call.num_params ());
+ return;
+ }
+
+ resolved = type.get_return_type ()->monomorphized_clone ();
+}
+
+// method call checker
+
+void
+TypeCheckMethodCallExpr::visit (FnType &type)
+{
+ type.get_self_type ()->unify (adjusted_self);
+
+ // +1 for the receiver self
+ size_t num_args_to_call = call.num_params () + 1;
+ if (num_args_to_call != type.num_params ())
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) call.num_params (),
+ (unsigned long) type.num_params ());
+ return;
+ }
+
+ size_t i = 1;
+ for (auto &argument : call.get_arguments ())
+ {
+ auto fnparam = type.param_at (i);
+ auto argument_expr_tyty
+ = Resolver::TypeCheckExpr::Resolve (argument.get ());
+ if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (
+ argument->get_locus (),
+ "failed to resolve type for argument expr in CallExpr");
+ return;
+ }
+
+ auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
+ argument->get_mappings ().get_hirid (), fnparam.second,
+ argument_expr_tyty, argument->get_locus ());
+ if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (argument->get_locus (),
+ "Type Resolution failure on parameter");
+ return;
+ }
+
+ i++;
+ }
+
+ if (i != num_args_to_call)
+ {
+ rust_error_at (call.get_locus (),
+ "unexpected number of arguments %lu expected %lu",
+ (unsigned long) i, (unsigned long) call.num_params ());
+ return;
+ }
+
+ type.monomorphize ();
+
+ resolved = type.get_return_type ()->monomorphized_clone ();
+}
+
+} // namespace TyTy
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h
new file mode 100644
index 00000000000..51817e6446d
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyty-call.h
@@ -0,0 +1,147 @@
+// 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_CALL
+#define RUST_TYTY_CALL
+
+#include "rust-diagnostics.h"
+#include "rust-hir-full.h"
+#include "rust-tyty-visitor.h"
+#include "rust-tyty.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace TyTy {
+
+class TypeCheckCallExpr : private TyVisitor
+{
+public:
+ static BaseType *go (BaseType *ref, HIR::CallExpr &call,
+ TyTy::VariantDef &variant,
+ Resolver::TypeCheckContext *context)
+ {
+ TypeCheckCallExpr checker (call, variant, context);
+ ref->accept_vis (checker);
+ return checker.resolved;
+ }
+
+ void visit (InferType &) override { gcc_unreachable (); }
+ void visit (TupleType &) override { gcc_unreachable (); }
+ void visit (ArrayType &) override { gcc_unreachable (); }
+ void visit (SliceType &) override { gcc_unreachable (); }
+ void visit (BoolType &) override { gcc_unreachable (); }
+ void visit (IntType &) override { gcc_unreachable (); }
+ void visit (UintType &) override { gcc_unreachable (); }
+ void visit (FloatType &) override { gcc_unreachable (); }
+ void visit (USizeType &) override { gcc_unreachable (); }
+ void visit (ISizeType &) override { gcc_unreachable (); }
+ void visit (ErrorType &) override { gcc_unreachable (); }
+ void visit (CharType &) override { gcc_unreachable (); }
+ void visit (ReferenceType &) override { gcc_unreachable (); }
+ void visit (PointerType &) override { gcc_unreachable (); }
+ void visit (ParamType &) override { gcc_unreachable (); }
+ void visit (StrType &) override { gcc_unreachable (); }
+ void visit (NeverType &) override { gcc_unreachable (); }
+ void visit (PlaceholderType &) override { gcc_unreachable (); }
+ void visit (ProjectionType &) override { gcc_unreachable (); }
+ void visit (DynamicObjectType &) override { gcc_unreachable (); }
+ void visit (ClosureType &type) override { gcc_unreachable (); }
+
+ // tuple-structs
+ void visit (ADTType &type) override;
+
+ // call fns
+ void visit (FnType &type) override;
+ void visit (FnPtr &type) override;
+
+private:
+ TypeCheckCallExpr (HIR::CallExpr &c, TyTy::VariantDef &variant,
+ Resolver::TypeCheckContext *context)
+ : resolved (new TyTy::ErrorType (c.get_mappings ().get_hirid ())), call (c),
+ variant (variant), context (context),
+ mappings (Analysis::Mappings::get ())
+ {}
+
+ BaseType *resolved;
+ HIR::CallExpr &call;
+ TyTy::VariantDef &variant;
+ Resolver::TypeCheckContext *context;
+ Analysis::Mappings *mappings;
+};
+
+class TypeCheckMethodCallExpr : private TyVisitor
+{
+public:
+ // Resolve the Method parameters and return back the return type
+ static BaseType *go (BaseType *ref, HIR::MethodCallExpr &call,
+ TyTy::BaseType *adjusted_self,
+ Resolver::TypeCheckContext *context)
+ {
+ TypeCheckMethodCallExpr checker (call, adjusted_self, context);
+ ref->accept_vis (checker);
+ return checker.resolved;
+ }
+
+ void visit (InferType &) override { gcc_unreachable (); }
+ void visit (TupleType &) override { gcc_unreachable (); }
+ void visit (ArrayType &) override { gcc_unreachable (); }
+ void visit (SliceType &) override { gcc_unreachable (); }
+ void visit (BoolType &) override { gcc_unreachable (); }
+ void visit (IntType &) override { gcc_unreachable (); }
+ void visit (UintType &) override { gcc_unreachable (); }
+ void visit (FloatType &) override { gcc_unreachable (); }
+ void visit (USizeType &) override { gcc_unreachable (); }
+ void visit (ISizeType &) override { gcc_unreachable (); }
+ void visit (ErrorType &) override { gcc_unreachable (); }
+ void visit (ADTType &) override { gcc_unreachable (); };
+ void visit (CharType &) override { gcc_unreachable (); }
+ void visit (ReferenceType &) override { gcc_unreachable (); }
+ void visit (PointerType &) override { gcc_unreachable (); }
+ void visit (ParamType &) override { gcc_unreachable (); }
+ void visit (StrType &) override { gcc_unreachable (); }
+ void visit (NeverType &) override { gcc_unreachable (); }
+ void visit (PlaceholderType &) override { gcc_unreachable (); }
+ void visit (ProjectionType &) override { gcc_unreachable (); }
+ void visit (DynamicObjectType &) override { gcc_unreachable (); }
+
+ // FIXME
+ void visit (FnPtr &type) override { gcc_unreachable (); }
+
+ // call fns
+ void visit (FnType &type) override;
+ void visit (ClosureType &type) override { gcc_unreachable (); }
+
+private:
+ TypeCheckMethodCallExpr (HIR::MethodCallExpr &c,
+ TyTy::BaseType *adjusted_self,
+ Resolver::TypeCheckContext *context)
+ : resolved (nullptr), call (c), adjusted_self (adjusted_self),
+ context (context), mappings (Analysis::Mappings::get ())
+ {}
+
+ BaseType *resolved;
+ HIR::MethodCallExpr &call;
+ TyTy::BaseType *adjusted_self;
+ Resolver::TypeCheckContext *context;
+ Analysis::Mappings *mappings;
+};
+
+} // namespace TyTy
+} // namespace Rust
+
+#endif // RUST_TYTY_CALL
diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h
new file mode 100644
index 00000000000..07d1dea7464
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyty-cmp.h
@@ -0,0 +1,1554 @@
+// 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_CMP_H
+#define RUST_TYTY_CMP_H
+
+#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 {
+
+class BaseCmp : public TyConstVisitor
+{
+public:
+ virtual bool can_eq (const BaseType *other)
+ {
+ if (other->get_kind () == TypeKind::PARAM)
+ {
+ const ParamType *p = static_cast<const ParamType *> (other);
+ other = p->resolve ();
+ }
+ if (other->get_kind () == TypeKind::PLACEHOLDER)
+ {
+ const PlaceholderType *p = static_cast<const PlaceholderType *> (other);
+ if (p->can_resolve ())
+ {
+ other = p->resolve ();
+ }
+ }
+ if (other->get_kind () == TypeKind::PROJECTION)
+ {
+ const ProjectionType *p = static_cast<const ProjectionType *> (other);
+ other = p->get ();
+ }
+
+ other->accept_vis (*this);
+ return ok;
+ }
+
+ virtual void visit (const TupleType &type) override
+ {
+ ok = false;
+
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const ADTType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const InferType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const FnType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const FnPtr &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const ArrayType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const SliceType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const BoolType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const IntType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const UintType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const USizeType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const ISizeType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const FloatType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const ErrorType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const CharType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const ReferenceType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const PointerType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const StrType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const NeverType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const ProjectionType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const PlaceholderType &type) override
+ {
+ // it is ok for types to can eq to a placeholder
+ ok = true;
+ }
+
+ virtual void visit (const ParamType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const DynamicObjectType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+ virtual void visit (const ClosureType &type) override
+ {
+ ok = false;
+ if (emit_error_flag)
+ {
+ 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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+ }
+
+protected:
+ BaseCmp (const BaseType *base, bool emit_errors)
+ : mappings (Analysis::Mappings::get ()),
+ context (Resolver::TypeCheckContext::get ()), ok (false),
+ emit_error_flag (emit_errors)
+ {}
+
+ Analysis::Mappings *mappings;
+ Resolver::TypeCheckContext *context;
+
+ bool ok;
+ bool emit_error_flag;
+
+private:
+ /* Returns a pointer to the ty that created this rule. */
+ virtual const BaseType *get_base () const = 0;
+};
+
+class InferCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ InferCmp (const InferType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const BoolType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const 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)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const 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)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const 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)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const 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)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const 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)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const ArrayType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const SliceType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const ADTType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const TupleType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const InferType &type) override
+ {
+ switch (base->get_infer_kind ())
+ {
+ case InferType::InferTypeKind::GENERAL:
+ ok = true;
+ return;
+
+ case InferType::InferTypeKind::INTEGRAL: {
+ if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL)
+ {
+ ok = true;
+ return;
+ }
+ else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL)
+ {
+ ok = true;
+ return;
+ }
+ }
+ break;
+
+ case InferType::InferTypeKind::FLOAT: {
+ if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT)
+ {
+ ok = true;
+ return;
+ }
+ else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL)
+ {
+ ok = true;
+ return;
+ }
+ }
+ break;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const CharType &type) override
+ {
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+ }
+
+ void visit (const ReferenceType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const PointerType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const ParamType &) override { ok = true; }
+
+ void visit (const DynamicObjectType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+ void visit (const ClosureType &type) override
+ {
+ bool is_valid
+ = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
+ if (is_valid)
+ {
+ ok = true;
+ return;
+ }
+
+ BaseCmp::visit (type);
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const InferType *base;
+};
+
+class FnCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ FnCmp (const FnType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL;
+ }
+
+ void visit (const FnType &type) override
+ {
+ if (base->num_params () != type.num_params ())
+ {
+ BaseCmp::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;
+
+ if (!a->can_eq (b, emit_error_flag))
+ {
+ emit_error_flag = false;
+ BaseCmp::visit (type);
+ return;
+ }
+ }
+
+ if (!base->get_return_type ()->can_eq (type.get_return_type (),
+ emit_error_flag))
+ {
+ emit_error_flag = false;
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const FnType *base;
+};
+
+class FnptrCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ FnptrCmp (const FnPtr *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+ void visit (const FnPtr &type) override
+ {
+ if (base->num_params () != type.num_params ())
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ auto this_ret_type = base->get_return_type ();
+ auto other_ret_type = type.get_return_type ();
+ if (!this_ret_type->can_eq (other_ret_type, emit_error_flag))
+ {
+ BaseCmp::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);
+ if (!this_param->can_eq (other_param, emit_error_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+ }
+
+ ok = true;
+ }
+
+ void visit (const FnType &type) override
+ {
+ if (base->num_params () != type.num_params ())
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ auto this_ret_type = base->get_return_type ();
+ auto other_ret_type = type.get_return_type ();
+ if (!this_ret_type->can_eq (other_ret_type, emit_error_flag))
+ {
+ BaseCmp::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;
+ if (!this_param->can_eq (other_param, emit_error_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const FnPtr *base;
+};
+
+class ClosureCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ ClosureCmp (const ClosureType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const ClosureType *base;
+};
+
+class ArrayCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ ArrayCmp (const ArrayType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const ArrayType &type) override
+ {
+ // check base type
+ const BaseType *base_element = base->get_element_type ();
+ const BaseType *other_element = type.get_element_type ();
+ if (!base_element->can_eq (other_element, emit_error_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const ArrayType *base;
+};
+
+class SliceCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ SliceCmp (const SliceType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const SliceType &type) override
+ {
+ // check base type
+ const BaseType *base_element = base->get_element_type ();
+ const BaseType *other_element = type.get_element_type ();
+ if (!base_element->can_eq (other_element, emit_error_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const SliceType *base;
+};
+
+class BoolCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ BoolCmp (const BoolType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const BoolType &type) override { ok = true; }
+
+ void visit (const InferType &type) override
+ {
+ ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const BoolType *base;
+};
+
+class IntCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ IntCmp (const IntType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT;
+ }
+
+ void visit (const IntType &type) override
+ {
+ ok = type.get_int_kind () == base->get_int_kind ();
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const IntType *base;
+};
+
+class UintCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ UintCmp (const UintType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT;
+ }
+
+ void visit (const UintType &type) override
+ {
+ ok = type.get_uint_kind () == base->get_uint_kind ();
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const UintType *base;
+};
+
+class FloatCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ FloatCmp (const FloatType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ ok = type.get_infer_kind () != InferType::InferTypeKind::INTEGRAL;
+ }
+
+ void visit (const FloatType &type) override
+ {
+ ok = type.get_float_kind () == base->get_float_kind ();
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const FloatType *base;
+};
+
+class ADTCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ ADTCmp (const ADTType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const ADTType &type) override
+ {
+ if (base->get_adt_kind () != type.get_adt_kind ())
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ if (base->get_identifier ().compare (type.get_identifier ()) != 0)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ if (base->number_of_variants () != type.number_of_variants ())
+ {
+ BaseCmp::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 ())
+ {
+ BaseCmp::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 ();
+
+ if (!this_field_ty->can_eq (other_field_ty, emit_error_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+ }
+ }
+
+ ok = true;
+ }
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const ADTType *base;
+};
+
+class TupleCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ TupleCmp (const TupleType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const TupleType &type) override
+ {
+ if (base->num_fields () != type.num_fields ())
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ for (size_t i = 0; i < base->num_fields (); i++)
+ {
+ BaseType *bo = base->get_field (i);
+ BaseType *fo = type.get_field (i);
+
+ if (!bo->can_eq (fo, emit_error_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+ }
+
+ ok = true;
+ }
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const TupleType *base;
+};
+
+class USizeCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ USizeCmp (const USizeType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT;
+ }
+
+ void visit (const USizeType &type) override { ok = true; }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const USizeType *base;
+};
+
+class ISizeCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ ISizeCmp (const ISizeType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT;
+ }
+
+ void visit (const ISizeType &type) override { ok = true; }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const ISizeType *base;
+};
+
+class CharCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ CharCmp (const CharType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const InferType &type) override
+ {
+ ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL;
+ }
+
+ void visit (const CharType &type) override { ok = true; }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const CharType *base;
+};
+
+class ReferenceCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ ReferenceCmp (const ReferenceType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const ReferenceType &type) override
+ {
+ auto base_type = base->get_base ();
+ auto other_base_type = type.get_base ();
+
+ bool mutability_match = base->is_mutable () == type.is_mutable ();
+ if (!mutability_match)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ if (!base_type->can_eq (other_base_type, emit_error_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const ReferenceType *base;
+};
+
+class PointerCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ PointerCmp (const PointerType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const PointerType &type) override
+ {
+ auto base_type = base->get_base ();
+ auto other_base_type = type.get_base ();
+
+ // 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)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ if (!base_type->can_eq (other_base_type, emit_error_flag))
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const PointerType *base;
+};
+
+class ParamCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ ParamCmp (const ParamType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), 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
+ bool can_eq (const BaseType *other) override
+ {
+ if (!base->can_resolve ())
+ return BaseCmp::can_eq (other);
+
+ auto lookup = base->resolve ();
+ return lookup->can_eq (other, emit_error_flag);
+ }
+
+ // imagine the case where we have:
+ // struct Foo<T>(T);
+ // Then we declare a generic impl block
+ // impl <X>Foo<X> { ... }
+ // both of these types are compatible so we mostly care about the number of
+ // generic arguments
+ void visit (const ParamType &) override { ok = true; }
+
+ void visit (const InferType &) override { ok = true; }
+
+ void visit (const FnType &) override { ok = true; }
+
+ void visit (const FnPtr &) override { ok = true; }
+
+ void visit (const ADTType &) override { ok = true; }
+
+ void visit (const ArrayType &) override { ok = true; }
+
+ void visit (const SliceType &) override { ok = true; }
+
+ void visit (const BoolType &) override { ok = true; }
+
+ void visit (const IntType &) override { ok = true; }
+
+ void visit (const UintType &) override { ok = true; }
+
+ void visit (const USizeType &) override { ok = true; }
+
+ void visit (const ISizeType &) override { ok = true; }
+
+ void visit (const FloatType &) override { ok = true; }
+
+ void visit (const CharType &) override { ok = true; }
+
+ void visit (const ReferenceType &) override { ok = true; }
+
+ void visit (const PointerType &) override { ok = true; }
+
+ void visit (const StrType &) override { ok = true; }
+
+ void visit (const NeverType &) override { ok = true; }
+
+ void visit (const DynamicObjectType &) override { ok = true; }
+
+ void visit (const PlaceholderType &type) override
+ {
+ ok = base->get_symbol ().compare (type.get_symbol ()) == 0;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const ParamType *base;
+};
+
+class StrCmp : public BaseCmp
+{
+ // FIXME we will need a enum for the StrType like ByteBuf etc..
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ StrCmp (const StrType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const StrType &type) override { ok = true; }
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const StrType *base;
+};
+
+class NeverCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ NeverCmp (const NeverType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const NeverType &type) override { ok = true; }
+
+ void visit (const InferType &type) override
+ {
+ if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ ok = true;
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+ const NeverType *base;
+};
+
+class PlaceholderCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ PlaceholderCmp (const PlaceholderType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ bool can_eq (const BaseType *other) override
+ {
+ if (!base->can_resolve ())
+ return BaseCmp::can_eq (other);
+
+ BaseType *lookup = base->resolve ();
+ return lookup->can_eq (other, emit_error_flag);
+ }
+
+ void visit (const TupleType &) override { ok = true; }
+
+ void visit (const ADTType &) override { ok = true; }
+
+ void visit (const InferType &) override { ok = true; }
+
+ void visit (const FnType &) override { ok = true; }
+
+ void visit (const FnPtr &) override { ok = true; }
+
+ void visit (const ArrayType &) override { ok = true; }
+
+ void visit (const BoolType &) override { ok = true; }
+
+ void visit (const IntType &) override { ok = true; }
+
+ void visit (const UintType &) override { ok = true; }
+
+ void visit (const USizeType &) override { ok = true; }
+
+ void visit (const ISizeType &) override { ok = true; }
+
+ void visit (const FloatType &) override { ok = true; }
+
+ void visit (const ErrorType &) override { ok = true; }
+
+ void visit (const CharType &) override { ok = true; }
+
+ void visit (const ReferenceType &) override { ok = true; }
+
+ void visit (const ParamType &) override { ok = true; }
+
+ void visit (const StrType &) override { ok = true; }
+
+ void visit (const NeverType &) override { ok = true; }
+
+ void visit (const SliceType &) override { ok = true; }
+
+private:
+ const BaseType *get_base () const override { return base; }
+
+ const PlaceholderType *base;
+};
+
+class DynamicCmp : public BaseCmp
+{
+ using Rust::TyTy::BaseCmp::visit;
+
+public:
+ DynamicCmp (const DynamicObjectType *base, bool emit_errors)
+ : BaseCmp (base, emit_errors), base (base)
+ {}
+
+ void visit (const DynamicObjectType &type) override
+ {
+ if (base->num_specified_bounds () != type.num_specified_bounds ())
+ {
+ BaseCmp::visit (type);
+ return;
+ }
+
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ ok = base->bounds_compatible (type, ref_locus, false);
+ }
+
+private:
+ const BaseType *get_base () const override { return base; }
+
+ const DynamicObjectType *base;
+};
+
+} // namespace TyTy
+} // namespace Rust
+
+#endif // RUST_TYTY_CMP_H
diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h
new file mode 100644
index 00000000000..77d912a5921
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyty-rules.h
@@ -0,0 +1,1584 @@
+// 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 &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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%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, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
+
+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) {}
+
+ // TODO
+
+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-visitor.h b/gcc/rust/typecheck/rust-tyty-visitor.h
new file mode 100644
index 00000000000..464e70d39d7
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyty-visitor.h
@@ -0,0 +1,88 @@
+// 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_VISITOR
+#define RUST_TYTY_VISITOR
+
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace TyTy {
+
+class TyVisitor
+{
+public:
+ virtual void visit (InferType &type) = 0;
+ virtual void visit (ADTType &type) = 0;
+ virtual void visit (TupleType &type) = 0;
+ virtual void visit (FnType &type) = 0;
+ virtual void visit (FnPtr &type) = 0;
+ virtual void visit (ArrayType &type) = 0;
+ virtual void visit (SliceType &type) = 0;
+ virtual void visit (BoolType &type) = 0;
+ virtual void visit (IntType &type) = 0;
+ virtual void visit (UintType &type) = 0;
+ virtual void visit (FloatType &type) = 0;
+ virtual void visit (USizeType &type) = 0;
+ virtual void visit (ISizeType &type) = 0;
+ virtual void visit (ErrorType &type) = 0;
+ virtual void visit (CharType &type) = 0;
+ virtual void visit (ReferenceType &type) = 0;
+ virtual void visit (PointerType &type) = 0;
+ virtual void visit (ParamType &type) = 0;
+ virtual void visit (StrType &type) = 0;
+ virtual void visit (NeverType &type) = 0;
+ virtual void visit (PlaceholderType &type) = 0;
+ virtual void visit (ProjectionType &type) = 0;
+ virtual void visit (DynamicObjectType &type) = 0;
+ virtual void visit (ClosureType &type) = 0;
+};
+
+class TyConstVisitor
+{
+public:
+ virtual void visit (const InferType &type) = 0;
+ virtual void visit (const ADTType &type) = 0;
+ virtual void visit (const TupleType &type) = 0;
+ virtual void visit (const FnType &type) = 0;
+ virtual void visit (const FnPtr &type) = 0;
+ virtual void visit (const ArrayType &type) = 0;
+ virtual void visit (const SliceType &type) = 0;
+ virtual void visit (const BoolType &type) = 0;
+ virtual void visit (const IntType &type) = 0;
+ virtual void visit (const UintType &type) = 0;
+ virtual void visit (const FloatType &type) = 0;
+ virtual void visit (const USizeType &type) = 0;
+ virtual void visit (const ISizeType &type) = 0;
+ virtual void visit (const ErrorType &type) = 0;
+ virtual void visit (const CharType &type) = 0;
+ virtual void visit (const ReferenceType &type) = 0;
+ virtual void visit (const PointerType &type) = 0;
+ virtual void visit (const ParamType &type) = 0;
+ virtual void visit (const StrType &type) = 0;
+ virtual void visit (const NeverType &type) = 0;
+ virtual void visit (const PlaceholderType &type) = 0;
+ virtual void visit (const ProjectionType &type) = 0;
+ virtual void visit (const DynamicObjectType &type) = 0;
+ virtual void visit (const ClosureType &type) = 0;
+};
+
+} // namespace TyTy
+} // namespace Rust
+
+#endif // RUST_TYTY_VISITOR
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
new file mode 100644
index 00000000000..3c2c6786940
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -0,0 +1,2885 @@
+// 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-tyty.h"
+#include "rust-tyty-visitor.h"
+#include "rust-tyty-call.h"
+#include "rust-hir-type-check-expr.h"
+#include "rust-hir-type-check-type.h"
+#include "rust-tyty-rules.h"
+#include "rust-tyty-cmp.h"
+#include "rust-hir-map.h"
+#include "rust-substitution-mapper.h"
+#include "rust-hir-trait-ref.h"
+#include "rust-hir-type-bounds.h"
+
+namespace Rust {
+namespace TyTy {
+
+std::string
+TypeKindFormat::to_string (TypeKind kind)
+{
+ switch (kind)
+ {
+ case TypeKind::INFER:
+ return "Infer";
+
+ case TypeKind::ADT:
+ return "ADT";
+
+ case TypeKind::STR:
+ return "STR";
+
+ case TypeKind::REF:
+ return "REF";
+
+ case TypeKind::POINTER:
+ return "POINTER";
+
+ case TypeKind::PARAM:
+ return "PARAM";
+
+ case TypeKind::ARRAY:
+ return "ARRAY";
+
+ case TypeKind::SLICE:
+ return "SLICE";
+
+ case TypeKind::FNDEF:
+ return "FnDef";
+
+ case TypeKind::FNPTR:
+ return "FnPtr";
+
+ case TypeKind::TUPLE:
+ return "Tuple";
+
+ case TypeKind::BOOL:
+ return "Bool";
+
+ case TypeKind::CHAR:
+ return "Char";
+
+ case TypeKind::INT:
+ return "Int";
+
+ case TypeKind::UINT:
+ return "Uint";
+
+ case TypeKind::FLOAT:
+ return "Float";
+
+ case TypeKind::USIZE:
+ return "Usize";
+
+ case TypeKind::ISIZE:
+ return "Isize";
+
+ case TypeKind::NEVER:
+ return "Never";
+
+ case TypeKind::PLACEHOLDER:
+ return "Placeholder";
+
+ case TypeKind::PROJECTION:
+ return "Projection";
+
+ case TypeKind::DYNAMIC:
+ return "Dynamic";
+
+ case TypeKind::CLOSURE:
+ return "Closure";
+
+ case TypeKind::ERROR:
+ return "ERROR";
+ }
+ gcc_unreachable ();
+}
+
+bool
+is_primitive_type_kind (TypeKind kind)
+{
+ switch (kind)
+ {
+ case TypeKind::BOOL:
+ case TypeKind::CHAR:
+ case TypeKind::INT:
+ case TypeKind::UINT:
+ case TypeKind::ISIZE:
+ case TypeKind::USIZE:
+ case TypeKind::FLOAT:
+ case TypeKind::NEVER:
+ case TypeKind::STR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool
+BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const
+{
+ const Resolver::TraitReference *query = predicate.get ();
+ for (auto &bound : specified_bounds)
+ {
+ const Resolver::TraitReference *item = bound.get ();
+ bool found = item->get_mappings ().get_defid ()
+ == query->get_mappings ().get_defid ();
+ if (found)
+ return true;
+ }
+
+ auto probed = Resolver::TypeBoundsProbe::Probe (this);
+ for (auto &b : probed)
+ {
+ const Resolver::TraitReference *bound = b.first;
+ bool found = bound->get_mappings ().get_defid ()
+ == query->get_mappings ().get_defid ();
+ if (found)
+ return true;
+ }
+
+ return false;
+}
+
+bool
+BaseType::bounds_compatible (const BaseType &other, Location locus,
+ bool emit_error) const
+{
+ std::vector<std::reference_wrapper<const TypeBoundPredicate>>
+ unsatisfied_bounds;
+ for (auto &bound : get_specified_bounds ())
+ {
+ if (!other.satisfies_bound (bound))
+ unsatisfied_bounds.push_back (bound);
+ }
+
+ // lets emit a single error for this
+ if (unsatisfied_bounds.size () > 0)
+ {
+ RichLocation r (locus);
+ std::string missing_preds;
+ for (size_t i = 0; i < unsatisfied_bounds.size (); i++)
+ {
+ const TypeBoundPredicate &pred = unsatisfied_bounds.at (i);
+ r.add_range (pred.get_locus ());
+ missing_preds += pred.get_name ();
+
+ bool have_next = (i + 1) < unsatisfied_bounds.size ();
+ if (have_next)
+ missing_preds += ", ";
+ }
+
+ if (emit_error)
+ {
+ rust_error_at (r,
+ "bounds not satisfied for %s %<%s%> is not satisfied",
+ other.get_name ().c_str (), missing_preds.c_str ());
+ // rust_assert (!emit_error);
+ }
+ }
+
+ return unsatisfied_bounds.size () == 0;
+}
+
+void
+BaseType::inherit_bounds (const BaseType &other)
+{
+ inherit_bounds (other.get_specified_bounds ());
+}
+
+void
+BaseType::inherit_bounds (
+ const std::vector<TyTy::TypeBoundPredicate> &specified_bounds)
+{
+ // FIXME
+ // 1. This needs to union the bounds
+ // 2. Do some checking for trait polarity to ensure compatibility
+ for (auto &bound : specified_bounds)
+ {
+ add_bound (bound);
+ }
+}
+
+const BaseType *
+BaseType::get_root () const
+{
+ // FIXME this needs to be it its own visitor class with a vector adjustments
+ const TyTy::BaseType *root = this;
+ if (get_kind () == TyTy::REF)
+ {
+ const ReferenceType *r = static_cast<const ReferenceType *> (root);
+ root = r->get_base ()->get_root ();
+ }
+ else if (get_kind () == TyTy::POINTER)
+ {
+ const PointerType *r = static_cast<const PointerType *> (root);
+ root = r->get_base ()->get_root ();
+ }
+
+ // these are an unsize
+ else if (get_kind () == TyTy::SLICE)
+ {
+ const SliceType *r = static_cast<const SliceType *> (root);
+ root = r->get_element_type ()->get_root ();
+ }
+ // else if (get_kind () == TyTy::ARRAY)
+ // {
+ // const ArrayType *r = static_cast<const ArrayType *> (root);
+ // root = r->get_element_type ()->get_root ();
+ // }
+
+ return root;
+}
+
+const BaseType *
+BaseType::destructure () const
+{
+ int recurisve_ops = 0;
+ const 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: {
+ const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (x);
+ x = p->resolve ();
+ }
+ break;
+
+ case TyTy::TypeKind::PLACEHOLDER: {
+ const TyTy::PlaceholderType *p
+ = static_cast<const TyTy::PlaceholderType *> (x);
+ rust_assert (p->can_resolve ());
+ x = p->resolve ();
+ }
+ break;
+
+ case TyTy::TypeKind::PROJECTION: {
+ const TyTy::ProjectionType *p
+ = static_cast<const TyTy::ProjectionType *> (x);
+ x = p->get ();
+ }
+ break;
+
+ default:
+ return x;
+ }
+ }
+
+ return x;
+}
+
+TyVar::TyVar (HirId ref) : ref (ref)
+{
+ // ensure this reference is defined within the context
+ auto context = Resolver::TypeCheckContext::get ();
+ BaseType *lookup = nullptr;
+ bool ok = context->lookup_type (ref, &lookup);
+ rust_assert (ok);
+}
+
+BaseType *
+TyVar::get_tyty () const
+{
+ auto context = Resolver::TypeCheckContext::get ();
+ BaseType *lookup = nullptr;
+ bool ok = context->lookup_type (ref, &lookup);
+ rust_assert (ok);
+ return lookup;
+}
+
+TyVar
+TyVar::get_implicit_infer_var (Location locus)
+{
+ auto mappings = Analysis::Mappings::get ();
+ auto context = Resolver::TypeCheckContext::get ();
+
+ InferType *infer = new InferType (mappings->get_next_hir_id (),
+ InferType::InferTypeKind::GENERAL, locus);
+ context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (),
+ UNKNOWN_NODEID,
+ infer->get_ref (),
+ UNKNOWN_LOCAL_DEFID),
+ infer);
+ mappings->insert_location (infer->get_ref (), locus);
+
+ return TyVar (infer->get_ref ());
+}
+
+TyVar
+TyVar::subst_covariant_var (TyTy::BaseType *orig, TyTy::BaseType *subst)
+{
+ if (orig->get_kind () != TyTy::TypeKind::PARAM)
+ return TyVar (subst->get_ty_ref ());
+ else if (subst->get_kind () == TyTy::TypeKind::PARAM)
+ {
+ TyTy::ParamType *p = static_cast<TyTy::ParamType *> (subst);
+ if (p->resolve ()->get_kind () == TyTy::TypeKind::PARAM)
+ {
+ return TyVar (subst->get_ty_ref ());
+ }
+ }
+
+ return TyVar (subst->get_ref ());
+}
+
+TyVar
+TyVar::clone () const
+{
+ TyTy::BaseType *c = get_tyty ()->clone ();
+ return TyVar (c->get_ref ());
+}
+
+TyVar
+TyVar::monomorphized_clone () const
+{
+ auto mappings = Analysis::Mappings::get ();
+ auto context = Resolver::TypeCheckContext::get ();
+
+ // this needs a new hirid
+ TyTy::BaseType *c = get_tyty ()->monomorphized_clone ();
+ c->set_ref (mappings->get_next_hir_id ());
+
+ // insert it
+ context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (),
+ UNKNOWN_NODEID, c->get_ref (),
+ UNKNOWN_LOCAL_DEFID),
+ c);
+
+ 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)
+{
+ vis.visit (*this);
+}
+
+void
+InferType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+InferType::as_string () const
+{
+ switch (infer_kind)
+ {
+ case GENERAL:
+ return "T?";
+ case INTEGRAL:
+ return "<integer>";
+ case FLOAT:
+ return "<float>";
+ }
+ 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
+{
+ InferCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+InferType::clone () const
+{
+ // clones for inference variables are special in that they _must_ exist within
+ // the type check context and we must ensure we don't loose the chain
+ // otherwise we will end up in the missing type annotations case
+ //
+ // This means we cannot simply take over the same reference we must generate a
+ // new ref just like the get_implicit_infer_var code then we can setup the
+ // chain of references accordingly to ensure we don't loose the ability to
+ // update the inference variables when we solve the type
+
+ auto mappings = Analysis::Mappings::get ();
+ auto context = Resolver::TypeCheckContext::get ();
+
+ InferType *clone
+ = new InferType (mappings->get_next_hir_id (), get_infer_kind (),
+ get_ident ().locus, get_combined_refs ());
+
+ context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (),
+ UNKNOWN_NODEID,
+ clone->get_ref (),
+ UNKNOWN_LOCAL_DEFID),
+ clone);
+ mappings->insert_location (clone->get_ref (),
+ mappings->lookup_location (get_ref ()));
+
+ // setup the chain to reference this
+ clone->append_reference (get_ref ());
+
+ return clone;
+}
+
+BaseType *
+InferType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+bool
+InferType::default_type (BaseType **type) const
+{
+ auto context = Resolver::TypeCheckContext::get ();
+ bool ok = false;
+ switch (infer_kind)
+ {
+ case GENERAL:
+ return false;
+
+ case INTEGRAL: {
+ ok = context->lookup_builtin ("i32", type);
+ rust_assert (ok);
+ return ok;
+ }
+
+ case FLOAT: {
+ ok = context->lookup_builtin ("f64", type);
+ rust_assert (ok);
+ return ok;
+ }
+ }
+ return false;
+}
+
+void
+ErrorType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+ErrorType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ return get_kind () == other->get_kind ();
+}
+
+BaseType *
+ErrorType::clone () const
+{
+ return new ErrorType (get_ref (), get_ty_ref (), get_combined_refs ());
+}
+
+BaseType *
+ErrorType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+std::string
+StructFieldType::as_string () const
+{
+ return name + ":" + get_field_type ()->debug_str ();
+}
+
+bool
+StructFieldType::is_equal (const StructFieldType &other) const
+{
+ bool names_eq = get_name ().compare (other.get_name ()) == 0;
+
+ TyTy::BaseType *o = other.get_field_type ();
+ if (o->get_kind () == TypeKind::PARAM)
+ {
+ ParamType *op = static_cast<ParamType *> (o);
+ o = op->resolve ();
+ }
+
+ bool types_eq = get_field_type ()->is_equal (*o);
+
+ return names_eq && types_eq;
+}
+
+StructFieldType *
+StructFieldType::clone () const
+{
+ return new StructFieldType (get_ref (), get_name (),
+ get_field_type ()->clone ());
+}
+
+StructFieldType *
+StructFieldType::monomorphized_clone () const
+{
+ return new StructFieldType (get_ref (), get_name (),
+ get_field_type ()->monomorphized_clone ());
+}
+
+bool
+SubstitutionParamMapping::need_substitution () const
+{
+ if (!param->can_resolve ())
+ return true;
+
+ auto resolved = param->resolve ();
+ return !resolved->is_concrete ();
+}
+
+bool
+SubstitutionParamMapping::fill_param_ty (
+ SubstitutionArgumentMappings &subst_mappings, Location locus)
+{
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (get_param_ty (), &arg);
+ if (!ok)
+ return true;
+
+ TyTy::BaseType &type = *arg.get_tyty ();
+ if (type.get_kind () == TyTy::TypeKind::INFER)
+ {
+ type.inherit_bounds (*param);
+ }
+ else
+ {
+ if (!param->bounds_compatible (type, locus, true))
+ return false;
+ }
+
+ if (type.get_kind () == TypeKind::PARAM)
+ {
+ // delete param;
+ param = static_cast<ParamType *> (type.clone ());
+ }
+ else
+ {
+ // check the substitution is compatible with bounds
+ if (!param->bounds_compatible (type, locus, true))
+ return false;
+
+ // recursively pass this down to all HRTB's
+ for (auto &bound : param->get_specified_bounds ())
+ bound.handle_substitions (subst_mappings);
+
+ param->set_ty_ref (type.get_ref ());
+ }
+
+ return true;
+}
+
+void
+SubstitutionParamMapping::override_context ()
+{
+ if (!param->can_resolve ())
+ return;
+
+ auto mappings = Analysis::Mappings::get ();
+ auto context = Resolver::TypeCheckContext::get ();
+
+ context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (),
+ UNKNOWN_NODEID,
+ param->get_ref (),
+ UNKNOWN_LOCAL_DEFID),
+ param->resolve ());
+}
+
+SubstitutionArgumentMappings
+SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args)
+{
+ if (args.get_binding_args ().size () > 0)
+ {
+ RichLocation r (args.get_locus ());
+ for (auto &binding : args.get_binding_args ())
+ r.add_range (binding.get_locus ());
+
+ rust_error_at (r, "associated type bindings are not allowed here");
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ // for inherited arguments
+ size_t offs = used_arguments.size ();
+ if (args.get_type_args ().size () + offs > substitutions.size ())
+ {
+ RichLocation r (args.get_locus ());
+ r.add_range (substitutions.front ().get_param_locus ());
+
+ rust_error_at (
+ r,
+ "generic item takes at most %lu type arguments but %lu were supplied",
+ (unsigned long) substitutions.size (),
+ (unsigned long) args.get_type_args ().size ());
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ if (args.get_type_args ().size () + offs < min_required_substitutions ())
+ {
+ RichLocation r (args.get_locus ());
+ r.add_range (substitutions.front ().get_param_locus ());
+
+ rust_error_at (
+ r,
+ "generic item takes at least %lu type arguments but %lu were supplied",
+ (unsigned long) (min_required_substitutions () - offs),
+ (unsigned long) args.get_type_args ().size ());
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ std::vector<SubstitutionArg> mappings = used_arguments.get_mappings ();
+ for (auto &arg : args.get_type_args ())
+ {
+ BaseType *resolved = Resolver::TypeCheckType::Resolve (arg.get ());
+ if (resolved == nullptr || resolved->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (args.get_locus (), "failed to resolve type arguments");
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ SubstitutionArg subst_arg (&substitutions.at (offs), resolved);
+ offs++;
+ mappings.push_back (std::move (subst_arg));
+ }
+
+ // we must need to fill out defaults
+ size_t left_over
+ = num_required_substitutions () - min_required_substitutions ();
+ if (left_over > 0)
+ {
+ for (size_t offs = mappings.size (); offs < substitutions.size (); offs++)
+ {
+ SubstitutionParamMapping ¶m = substitutions.at (offs);
+ rust_assert (param.param_has_default_ty ());
+
+ BaseType *resolved = param.get_default_ty ();
+ if (resolved->get_kind () == TypeKind::ERROR)
+ return SubstitutionArgumentMappings::error ();
+
+ // this resolved default might already contain default parameters
+ if (resolved->contains_type_parameters ())
+ {
+ SubstitutionArgumentMappings intermediate (mappings,
+ args.get_locus ());
+ resolved = Resolver::SubstMapperInternal::Resolve (resolved,
+ intermediate);
+
+ if (resolved->get_kind () == TypeKind::ERROR)
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ SubstitutionArg subst_arg (¶m, resolved);
+ mappings.push_back (std::move (subst_arg));
+ }
+ }
+
+ return SubstitutionArgumentMappings (mappings, args.get_locus ());
+}
+
+SubstitutionArgumentMappings
+SubstitutionRef::adjust_mappings_for_this (
+ SubstitutionArgumentMappings &mappings)
+{
+ std::vector<SubstitutionArg> resolved_mappings;
+ for (size_t i = 0; i < substitutions.size (); i++)
+ {
+ auto &subst = substitutions.at (i);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ if (mappings.size () == substitutions.size ())
+ {
+ mappings.get_argument_at (i, &arg);
+ }
+ else
+ {
+ if (subst.needs_substitution ())
+ {
+ // get from passed in mappings
+ mappings.get_argument_for_symbol (subst.get_param_ty (), &arg);
+ }
+ else
+ {
+ // we should already have this somewhere
+ used_arguments.get_argument_for_symbol (subst.get_param_ty (),
+ &arg);
+ }
+ }
+
+ bool ok = !arg.is_error ();
+ if (ok)
+ {
+ SubstitutionArg adjusted (&subst, arg.get_tyty ());
+ resolved_mappings.push_back (std::move (adjusted));
+ }
+ }
+
+ if (resolved_mappings.empty ())
+ return SubstitutionArgumentMappings::error ();
+
+ return SubstitutionArgumentMappings (resolved_mappings, mappings.get_locus (),
+ mappings.get_subst_cb (),
+ mappings.trait_item_mode ());
+}
+
+bool
+SubstitutionRef::are_mappings_bound (SubstitutionArgumentMappings &mappings)
+{
+ std::vector<SubstitutionArg> resolved_mappings;
+ for (size_t i = 0; i < substitutions.size (); i++)
+ {
+ auto &subst = substitutions.at (i);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ if (mappings.size () == substitutions.size ())
+ {
+ mappings.get_argument_at (i, &arg);
+ }
+ else
+ {
+ if (subst.needs_substitution ())
+ {
+ // get from passed in mappings
+ mappings.get_argument_for_symbol (subst.get_param_ty (), &arg);
+ }
+ else
+ {
+ // we should already have this somewhere
+ used_arguments.get_argument_for_symbol (subst.get_param_ty (),
+ &arg);
+ }
+ }
+
+ bool ok = !arg.is_error ();
+ if (ok)
+ {
+ SubstitutionArg adjusted (&subst, arg.get_tyty ());
+ resolved_mappings.push_back (std::move (adjusted));
+ }
+ }
+
+ return !resolved_mappings.empty ();
+}
+
+// this function assumes that the mappings being passed are for the same type as
+// this new substitution reference so ordering matters here
+SubstitutionArgumentMappings
+SubstitutionRef::solve_mappings_from_receiver_for_self (
+ SubstitutionArgumentMappings &mappings) const
+{
+ std::vector<SubstitutionArg> resolved_mappings;
+
+ rust_assert (mappings.size () == get_num_substitutions ());
+ for (size_t i = 0; i < get_num_substitutions (); i++)
+ {
+ const SubstitutionParamMapping ¶m_mapping = substitutions.at (i);
+ SubstitutionArg &arg = mappings.get_mappings ().at (i);
+
+ if (param_mapping.needs_substitution ())
+ {
+ SubstitutionArg adjusted (¶m_mapping, arg.get_tyty ());
+ resolved_mappings.push_back (std::move (adjusted));
+ }
+ }
+
+ return SubstitutionArgumentMappings (resolved_mappings,
+ mappings.get_locus ());
+}
+
+SubstitutionArgumentMappings
+SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref,
+ SubstitutionRef &to)
+{
+ rust_assert (!ref.needs_substitution ());
+ rust_assert (needs_substitution ());
+ rust_assert (get_num_substitutions () == ref.get_num_substitutions ());
+
+ Location locus = used_arguments.get_locus ();
+ std::vector<SubstitutionArg> resolved_mappings;
+
+ std::map<HirId, std::pair<ParamType *, BaseType *>> substs;
+ for (size_t i = 0; i < get_num_substitutions (); i++)
+ {
+ SubstitutionParamMapping &a = substitutions.at (i);
+ SubstitutionParamMapping &b = ref.substitutions.at (i);
+
+ if (a.need_substitution ())
+ {
+ const BaseType *root = a.get_param_ty ()->resolve ()->get_root ();
+ rust_assert (root->get_kind () == TyTy::TypeKind::PARAM);
+ const ParamType *p = static_cast<const TyTy::ParamType *> (root);
+
+ substs[p->get_ty_ref ()] = {static_cast<ParamType *> (p->clone ()),
+ b.get_param_ty ()->resolve ()};
+ }
+ }
+
+ for (auto it = substs.begin (); it != substs.end (); it++)
+ {
+ HirId param_id = it->first;
+ BaseType *arg = it->second.second;
+
+ const SubstitutionParamMapping *associate_param = nullptr;
+ for (SubstitutionParamMapping &p : to.substitutions)
+ {
+ if (p.get_param_ty ()->get_ty_ref () == param_id)
+ {
+ associate_param = &p;
+ break;
+ }
+ }
+
+ rust_assert (associate_param != nullptr);
+ SubstitutionArg argument (associate_param, arg);
+ resolved_mappings.push_back (std::move (argument));
+ }
+
+ return SubstitutionArgumentMappings (resolved_mappings, locus);
+}
+
+bool
+SubstitutionRef::monomorphize ()
+{
+ auto context = Resolver::TypeCheckContext::get ();
+ for (const auto &subst : get_substs ())
+ {
+ const TyTy::ParamType *pty = subst.get_param_ty ();
+
+ if (!pty->can_resolve ())
+ continue;
+
+ const TyTy::BaseType *binding = pty->resolve ();
+ if (binding->get_kind () == TyTy::TypeKind::PARAM)
+ continue;
+
+ for (const auto &bound : pty->get_specified_bounds ())
+ {
+ const Resolver::TraitReference *specified_bound_ref = bound.get ();
+
+ // setup any associated type mappings for the specified bonds and this
+ // type
+ auto candidates = Resolver::TypeBoundsProbe::Probe (binding);
+
+ Resolver::AssociatedImplTrait *associated_impl_trait = nullptr;
+ for (auto &probed_bound : candidates)
+ {
+ const Resolver::TraitReference *bound_trait_ref
+ = probed_bound.first;
+ const HIR::ImplBlock *associated_impl = probed_bound.second;
+
+ HirId impl_block_id
+ = associated_impl->get_mappings ().get_hirid ();
+ Resolver::AssociatedImplTrait *associated = nullptr;
+ bool found_impl_trait
+ = context->lookup_associated_trait_impl (impl_block_id,
+ &associated);
+ if (found_impl_trait)
+ {
+ bool found_trait
+ = specified_bound_ref->is_equal (*bound_trait_ref);
+ bool found_self
+ = associated->get_self ()->can_eq (binding, false);
+ if (found_trait && found_self)
+ {
+ associated_impl_trait = associated;
+ break;
+ }
+ }
+ }
+
+ if (associated_impl_trait != nullptr)
+ {
+ associated_impl_trait->setup_associated_types (binding, bound);
+ }
+ }
+ }
+
+ return true;
+}
+
+void
+ADTType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+ADTType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+ADTType::as_string () const
+{
+ std::string variants_buffer;
+ for (size_t i = 0; i < number_of_variants (); ++i)
+ {
+ TyTy::VariantDef *variant = variants.at (i);
+ variants_buffer += variant->as_string ();
+ if ((i + 1) < number_of_variants ())
+ variants_buffer += ", ";
+ }
+
+ 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
+{
+ ADTCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+ADTType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ auto other2 = static_cast<const ADTType &> (other);
+ if (get_adt_kind () != other2.get_adt_kind ())
+ return false;
+
+ if (number_of_variants () != other2.number_of_variants ())
+ return false;
+
+ if (has_subsititions_defined () != other2.has_subsititions_defined ())
+ return false;
+
+ if (has_subsititions_defined ())
+ {
+ if (get_num_substitutions () != other2.get_num_substitutions ())
+ return false;
+
+ for (size_t i = 0; i < get_num_substitutions (); i++)
+ {
+ const SubstitutionParamMapping &a = substitutions.at (i);
+ const SubstitutionParamMapping &b = other2.substitutions.at (i);
+
+ const ParamType *aa = a.get_param_ty ();
+ const ParamType *bb = b.get_param_ty ();
+ BaseType *aaa = aa->resolve ();
+ BaseType *bbb = bb->resolve ();
+ if (!aaa->is_equal (*bbb))
+ return false;
+ }
+ }
+
+ for (size_t i = 0; i < number_of_variants (); i++)
+ {
+ const TyTy::VariantDef *a = get_variants ().at (i);
+ const TyTy::VariantDef *b = other2.get_variants ().at (i);
+
+ if (!a->is_equal (*b))
+ return false;
+ }
+
+ return true;
+}
+
+BaseType *
+ADTType::clone () const
+{
+ std::vector<VariantDef *> cloned_variants;
+ for (auto &variant : variants)
+ cloned_variants.push_back (variant->clone ());
+
+ return new ADTType (get_ref (), get_ty_ref (), identifier, ident,
+ get_adt_kind (), cloned_variants, clone_substs (),
+ get_repr_options (), used_arguments,
+ get_combined_refs ());
+}
+
+BaseType *
+ADTType::monomorphized_clone () const
+{
+ std::vector<VariantDef *> cloned_variants;
+ for (auto &variant : variants)
+ cloned_variants.push_back (variant->monomorphized_clone ());
+
+ return new ADTType (get_ref (), get_ty_ref (), identifier, ident,
+ get_adt_kind (), cloned_variants, clone_substs (),
+ get_repr_options (), used_arguments,
+ get_combined_refs ());
+}
+
+static bool
+handle_substitions (SubstitutionArgumentMappings &subst_mappings,
+ StructFieldType *field)
+{
+ auto fty = field->get_field_type ();
+ bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
+ if (is_param_ty)
+ {
+ ParamType *p = static_cast<ParamType *> (fty);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
+ if (ok)
+ {
+ auto argt = arg.get_tyty ();
+ bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
+ bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
+
+ if (arg_is_param || arg_is_concrete)
+ {
+ auto new_field = argt->clone ();
+ new_field->set_ref (fty->get_ref ());
+ field->set_field_type (new_field);
+ }
+ else
+ {
+ field->get_field_type ()->set_ty_ref (argt->get_ref ());
+ }
+ }
+ }
+ else if (fty->has_subsititions_defined () || fty->contains_type_parameters ())
+ {
+ BaseType *concrete
+ = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
+
+ if (concrete->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (subst_mappings.get_locus (),
+ "Failed to resolve field substitution type: %s",
+ fty->as_string ().c_str ());
+ return false;
+ }
+
+ auto new_field = concrete->clone ();
+ new_field->set_ref (fty->get_ref ());
+ field->set_field_type (new_field);
+ }
+
+ return true;
+}
+
+ADTType *
+ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings)
+{
+ ADTType *adt = static_cast<ADTType *> (clone ());
+ adt->set_ty_ref (mappings->get_next_hir_id ());
+ adt->used_arguments = subst_mappings;
+
+ for (auto &sub : adt->get_substs ())
+ {
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok
+ = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
+ if (ok)
+ sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
+ }
+
+ for (auto &variant : adt->get_variants ())
+ {
+ if (variant->is_dataless_variant ())
+ continue;
+
+ for (auto &field : variant->get_fields ())
+ {
+ bool ok = ::Rust::TyTy::handle_substitions (subst_mappings, field);
+ if (!ok)
+ return adt;
+ }
+ }
+
+ return adt;
+}
+
+void
+TupleType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+TupleType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+TupleType::as_string () const
+{
+ std::string fields_buffer;
+ for (const TyVar &field : get_fields ())
+ {
+ fields_buffer += field.get_tyty ()->as_string ();
+ fields_buffer += ", ";
+ }
+ return "(" + fields_buffer + ")";
+}
+
+BaseType *
+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
+{
+ TupleCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+TupleType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ auto other2 = static_cast<const TupleType &> (other);
+ if (num_fields () != other2.num_fields ())
+ return false;
+
+ for (size_t i = 0; i < num_fields (); i++)
+ {
+ if (!get_field (i)->is_equal (*other2.get_field (i)))
+ return false;
+ }
+ return true;
+}
+
+BaseType *
+TupleType::clone () const
+{
+ std::vector<TyVar> cloned_fields;
+ for (const auto &f : fields)
+ cloned_fields.push_back (f.clone ());
+
+ return new TupleType (get_ref (), get_ty_ref (), get_ident ().locus,
+ cloned_fields, get_combined_refs ());
+}
+
+BaseType *
+TupleType::monomorphized_clone () const
+{
+ std::vector<TyVar> cloned_fields;
+ for (const auto &f : fields)
+ cloned_fields.push_back (f.monomorphized_clone ());
+
+ return new TupleType (get_ref (), get_ty_ref (), get_ident ().locus,
+ cloned_fields, get_combined_refs ());
+}
+
+TupleType *
+TupleType::handle_substitions (SubstitutionArgumentMappings mappings)
+{
+ auto mappings_table = Analysis::Mappings::get ();
+
+ TupleType *tuple = static_cast<TupleType *> (clone ());
+ tuple->set_ref (mappings_table->get_next_hir_id ());
+ tuple->set_ty_ref (mappings_table->get_next_hir_id ());
+
+ for (size_t i = 0; i < tuple->fields.size (); i++)
+ {
+ TyVar &field = fields.at (i);
+ if (field.get_tyty ()->contains_type_parameters ())
+ {
+ BaseType *concrete
+ = Resolver::SubstMapperInternal::Resolve (field.get_tyty (),
+ mappings);
+ tuple->fields[i]
+ = TyVar::subst_covariant_var (field.get_tyty (), concrete);
+ }
+ }
+
+ return tuple;
+}
+
+void
+FnType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+FnType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+FnType::as_string () const
+{
+ std::string params_str = "";
+ for (auto ¶m : params)
+ {
+ auto pattern = param.first;
+ auto ty = param.second;
+ params_str += pattern->as_string () + " " + ty->as_string ();
+ params_str += ",";
+ }
+
+ std::string ret_str = type->as_string ();
+ 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
+{
+ FnCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+FnType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ auto other2 = static_cast<const FnType &> (other);
+ if (get_identifier ().compare (other2.get_identifier ()) != 0)
+ return false;
+
+ if (!get_return_type ()->is_equal (*other2.get_return_type ()))
+ return false;
+
+ if (has_subsititions_defined () != other2.has_subsititions_defined ())
+ return false;
+
+ if (has_subsititions_defined ())
+ {
+ if (get_num_substitutions () != other2.get_num_substitutions ())
+ return false;
+
+ const FnType &ofn = static_cast<const FnType &> (other);
+ for (size_t i = 0; i < get_num_substitutions (); i++)
+ {
+ const SubstitutionParamMapping &a = get_substs ().at (i);
+ const SubstitutionParamMapping &b = ofn.get_substs ().at (i);
+
+ const ParamType *pa = a.get_param_ty ();
+ const ParamType *pb = b.get_param_ty ();
+
+ if (!pa->is_equal (*pb))
+ return false;
+ }
+ }
+
+ if (num_params () != other2.num_params ())
+ return false;
+
+ for (size_t i = 0; i < num_params (); i++)
+ {
+ auto lhs = param_at (i).second;
+ auto rhs = other2.param_at (i).second;
+ if (!lhs->is_equal (*rhs))
+ return false;
+ }
+ return true;
+}
+
+BaseType *
+FnType::clone () const
+{
+ std::vector<std::pair<HIR::Pattern *, BaseType *>> cloned_params;
+ for (auto &p : params)
+ cloned_params.push_back ({p.first, p.second->clone ()});
+
+ return new FnType (get_ref (), get_ty_ref (), get_id (), get_identifier (),
+ ident, flags, abi, std::move (cloned_params),
+ get_return_type ()->clone (), clone_substs (),
+ get_combined_refs ());
+}
+
+BaseType *
+FnType::monomorphized_clone () const
+{
+ std::vector<std::pair<HIR::Pattern *, BaseType *>> cloned_params;
+ for (auto &p : params)
+ cloned_params.push_back ({p.first, p.second->monomorphized_clone ()});
+
+ return new FnType (get_ref (), get_ty_ref (), get_id (), get_identifier (),
+ ident, flags, abi, std::move (cloned_params),
+ get_return_type ()->clone (), clone_substs (),
+ get_combined_refs ());
+}
+
+FnType *
+FnType::handle_substitions (SubstitutionArgumentMappings subst_mappings)
+{
+ FnType *fn = static_cast<FnType *> (clone ());
+ fn->set_ty_ref (mappings->get_next_hir_id ());
+ fn->used_arguments = subst_mappings;
+
+ for (auto &sub : fn->get_substs ())
+ {
+ SubstitutionArg arg = SubstitutionArg::error ();
+
+ bool ok
+ = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
+ if (ok)
+ {
+ sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
+ }
+ }
+
+ auto fty = fn->get_return_type ();
+ bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
+ if (is_param_ty)
+ {
+ ParamType *p = static_cast<ParamType *> (fty);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
+ if (ok)
+ {
+ auto argt = arg.get_tyty ();
+ bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
+ bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
+
+ if (arg_is_param || arg_is_concrete)
+ {
+ auto new_field = argt->clone ();
+ new_field->set_ref (fty->get_ref ());
+ fn->type = new_field;
+ }
+ else
+ {
+ fty->set_ty_ref (argt->get_ref ());
+ }
+ }
+ }
+ else if (fty->needs_generic_substitutions ()
+ || fty->contains_type_parameters ())
+ {
+ BaseType *concrete
+ = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
+
+ if (concrete == nullptr || concrete->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (subst_mappings.get_locus (),
+ "Failed to resolve field substitution type: %s",
+ fty->as_string ().c_str ());
+ return nullptr;
+ }
+
+ auto new_field = concrete->clone ();
+ new_field->set_ref (fty->get_ref ());
+ fn->type = new_field;
+ }
+
+ for (auto ¶m : fn->get_params ())
+ {
+ auto fty = param.second;
+
+ bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
+ if (is_param_ty)
+ {
+ ParamType *p = static_cast<ParamType *> (fty);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
+ if (ok)
+ {
+ auto argt = arg.get_tyty ();
+ bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
+ bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
+
+ if (arg_is_param || arg_is_concrete)
+ {
+ auto new_field = argt->clone ();
+ new_field->set_ref (fty->get_ref ());
+ param.second = new_field;
+ }
+ else
+ {
+ fty->set_ty_ref (argt->get_ref ());
+ }
+ }
+ }
+ else if (fty->has_subsititions_defined ()
+ || fty->contains_type_parameters ())
+ {
+ BaseType *concrete
+ = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
+
+ if (concrete == nullptr
+ || concrete->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (subst_mappings.get_locus (),
+ "Failed to resolve field substitution type: %s",
+ fty->as_string ().c_str ());
+ return nullptr;
+ }
+
+ auto new_field = concrete->clone ();
+ new_field->set_ref (fty->get_ref ());
+ param.second = new_field;
+ }
+ }
+
+ return fn;
+}
+
+void
+FnPtr::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+FnPtr::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+FnPtr::as_string () const
+{
+ std::string params_str;
+
+ auto ¶ms = get_params ();
+ for (auto &p : params)
+ {
+ params_str += p.get_tyty ()->as_string () + " ,";
+ }
+
+ 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
+{
+ FnptrCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+FnPtr::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ auto other2 = static_cast<const FnPtr &> (other);
+ auto this_ret_type = get_return_type ();
+ auto other_ret_type = other2.get_return_type ();
+ if (this_ret_type->is_equal (*other_ret_type))
+ return false;
+
+ if (num_params () != other2.num_params ())
+ return false;
+
+ for (size_t i = 0; i < num_params (); i++)
+ {
+ if (!param_at (i)->is_equal (*other2.param_at (i)))
+ return false;
+ }
+ return true;
+}
+
+BaseType *
+FnPtr::clone () const
+{
+ std::vector<TyVar> cloned_params;
+ for (auto &p : params)
+ cloned_params.push_back (TyVar (p.get_ref ()));
+
+ return new FnPtr (get_ref (), get_ty_ref (), ident.locus,
+ std::move (cloned_params), result_type,
+ get_combined_refs ());
+}
+
+BaseType *
+FnPtr::monomorphized_clone () const
+{
+ std::vector<TyVar> cloned_params;
+ for (auto &p : params)
+ cloned_params.push_back (p.monomorphized_clone ());
+
+ return new FnPtr (get_ref (), get_ty_ref (), ident.locus,
+ std::move (cloned_params), result_type,
+ get_combined_refs ());
+}
+
+void
+ClosureType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+ClosureType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+ClosureType::as_string () const
+{
+ return "TODO";
+}
+
+BaseType *
+ClosureType::unify (BaseType *other)
+{
+ ClosureRules r (this);
+ return r.unify (other);
+}
+
+bool
+ClosureType::can_eq (const BaseType *other, bool emit_errors) const
+{
+ ClosureCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+ClosureType::is_equal (const BaseType &other) const
+{
+ gcc_unreachable ();
+ return false;
+}
+
+BaseType *
+ClosureType::clone () const
+{
+ return new ClosureType (get_ref (), get_ty_ref (), ident, id, parameter_types,
+ result_type, clone_substs (), get_combined_refs ());
+}
+
+BaseType *
+ClosureType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+ClosureType *
+ClosureType::handle_substitions (SubstitutionArgumentMappings mappings)
+{
+ gcc_unreachable ();
+ return nullptr;
+}
+
+void
+ArrayType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+ArrayType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ ArrayCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+ArrayType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ auto other2 = static_cast<const ArrayType &> (other);
+
+ auto this_element_type = get_element_type ();
+ auto other_element_type = other2.get_element_type ();
+
+ return this_element_type->is_equal (*other_element_type);
+}
+
+BaseType *
+ArrayType::get_element_type () const
+{
+ return element_type.get_tyty ();
+}
+
+BaseType *
+ArrayType::clone () const
+{
+ return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity_expr,
+ element_type, get_combined_refs ());
+}
+
+BaseType *
+ArrayType::monomorphized_clone () const
+{
+ return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity_expr,
+ element_type.monomorphized_clone (),
+ get_combined_refs ());
+}
+
+ArrayType *
+ArrayType::handle_substitions (SubstitutionArgumentMappings mappings)
+{
+ auto mappings_table = Analysis::Mappings::get ();
+
+ ArrayType *ref = static_cast<ArrayType *> (clone ());
+ ref->set_ty_ref (mappings_table->get_next_hir_id ());
+
+ // might be &T or &ADT so this needs to be recursive
+ auto base = ref->get_element_type ();
+ BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
+ ref->element_type = TyVar::subst_covariant_var (base, concrete);
+
+ return ref;
+}
+
+void
+SliceType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+SliceType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ SliceCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+SliceType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ auto other2 = static_cast<const SliceType &> (other);
+
+ auto this_element_type = get_element_type ();
+ auto other_element_type = other2.get_element_type ();
+
+ return this_element_type->is_equal (*other_element_type);
+}
+
+BaseType *
+SliceType::get_element_type () const
+{
+ return element_type.get_tyty ();
+}
+
+BaseType *
+SliceType::clone () const
+{
+ return new SliceType (get_ref (), get_ty_ref (), ident.locus,
+ element_type.clone (), get_combined_refs ());
+}
+
+BaseType *
+SliceType::monomorphized_clone () const
+{
+ return new SliceType (get_ref (), get_ty_ref (), ident.locus,
+ element_type.monomorphized_clone (),
+ get_combined_refs ());
+}
+
+SliceType *
+SliceType::handle_substitions (SubstitutionArgumentMappings mappings)
+{
+ auto mappings_table = Analysis::Mappings::get ();
+
+ SliceType *ref = static_cast<SliceType *> (clone ());
+ ref->set_ty_ref (mappings_table->get_next_hir_id ());
+
+ // might be &T or &ADT so this needs to be recursive
+ auto base = ref->get_element_type ();
+ BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
+ ref->element_type = TyVar::subst_covariant_var (base, concrete);
+
+ return ref;
+}
+
+void
+BoolType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+BoolType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ BoolCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+BoolType::clone () const
+{
+ return new BoolType (get_ref (), get_ty_ref (), get_combined_refs ());
+}
+
+BaseType *
+BoolType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+void
+IntType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+IntType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+IntType::as_string () const
+{
+ switch (int_kind)
+ {
+ case I8:
+ return "i8";
+ case I16:
+ return "i16";
+ case I32:
+ return "i32";
+ case I64:
+ return "i64";
+ case I128:
+ return "i128";
+ }
+ gcc_unreachable ();
+ 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
+{
+ IntCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+IntType::clone () const
+{
+ return new IntType (get_ref (), get_ty_ref (), get_int_kind (),
+ get_combined_refs ());
+}
+
+BaseType *
+IntType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+bool
+IntType::is_equal (const BaseType &other) const
+{
+ if (!BaseType::is_equal (other))
+ return false;
+
+ const IntType &o = static_cast<const IntType &> (other);
+ return get_int_kind () == o.get_int_kind ();
+}
+
+void
+UintType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+UintType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+UintType::as_string () const
+{
+ switch (uint_kind)
+ {
+ case U8:
+ return "u8";
+ case U16:
+ return "u16";
+ case U32:
+ return "u32";
+ case U64:
+ return "u64";
+ case U128:
+ return "u128";
+ }
+ gcc_unreachable ();
+ 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
+{
+ UintCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+UintType::clone () const
+{
+ return new UintType (get_ref (), get_ty_ref (), get_uint_kind (),
+ get_combined_refs ());
+}
+
+BaseType *
+UintType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+bool
+UintType::is_equal (const BaseType &other) const
+{
+ if (!BaseType::is_equal (other))
+ return false;
+
+ const UintType &o = static_cast<const UintType &> (other);
+ return get_uint_kind () == o.get_uint_kind ();
+}
+
+void
+FloatType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+FloatType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+FloatType::as_string () const
+{
+ switch (float_kind)
+ {
+ case F32:
+ return "f32";
+ case F64:
+ return "f64";
+ }
+ gcc_unreachable ();
+ 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
+{
+ FloatCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+FloatType::clone () const
+{
+ return new FloatType (get_ref (), get_ty_ref (), get_float_kind (),
+ get_combined_refs ());
+}
+
+BaseType *
+FloatType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+bool
+FloatType::is_equal (const BaseType &other) const
+{
+ if (!BaseType::is_equal (other))
+ return false;
+
+ const FloatType &o = static_cast<const FloatType &> (other);
+ return get_float_kind () == o.get_float_kind ();
+}
+
+void
+USizeType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+USizeType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ USizeCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+USizeType::clone () const
+{
+ return new USizeType (get_ref (), get_ty_ref (), get_combined_refs ());
+}
+
+BaseType *
+USizeType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+void
+ISizeType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+ISizeType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ ISizeCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+ISizeType::clone () const
+{
+ return new ISizeType (get_ref (), get_ty_ref (), get_combined_refs ());
+}
+
+BaseType *
+ISizeType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+void
+CharType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+CharType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ CharCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+CharType::clone () const
+{
+ return new CharType (get_ref (), get_ty_ref (), get_combined_refs ());
+}
+
+BaseType *
+CharType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+void
+ReferenceType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+ReferenceType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+ReferenceType::as_string () const
+{
+ return std::string ("&") + (is_mutable () ? "mut" : "") + " "
+ + get_base ()->as_string ();
+}
+
+BaseType *
+ReferenceType::unify (BaseType *other)
+{
+ ReferenceRules r (this);
+ return r.unify (other);
+}
+
+bool
+ReferenceType::can_eq (const BaseType *other, bool emit_errors) const
+{
+ ReferenceCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+ReferenceType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ auto other2 = static_cast<const ReferenceType &> (other);
+ if (mutability () != other2.mutability ())
+ return false;
+
+ return get_base ()->is_equal (*other2.get_base ());
+}
+
+BaseType *
+ReferenceType::get_base () const
+{
+ return base.get_tyty ();
+}
+
+BaseType *
+ReferenceType::clone () const
+{
+ return new ReferenceType (get_ref (), get_ty_ref (), base, mutability (),
+ get_combined_refs ());
+}
+
+BaseType *
+ReferenceType::monomorphized_clone () const
+{
+ return new ReferenceType (get_ref (), get_ty_ref (),
+ base.monomorphized_clone (), mutability (),
+ get_combined_refs ());
+}
+
+ReferenceType *
+ReferenceType::handle_substitions (SubstitutionArgumentMappings mappings)
+{
+ auto mappings_table = Analysis::Mappings::get ();
+
+ ReferenceType *ref = static_cast<ReferenceType *> (clone ());
+ ref->set_ty_ref (mappings_table->get_next_hir_id ());
+
+ // might be &T or &ADT so this needs to be recursive
+ auto base = ref->get_base ();
+ BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
+ ref->base = TyVar::subst_covariant_var (base, concrete);
+
+ return ref;
+}
+
+void
+PointerType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+PointerType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+PointerType::as_string () const
+{
+ return std::string ("* ") + (is_mutable () ? "mut" : "const") + " "
+ + get_base ()->as_string ();
+}
+
+BaseType *
+PointerType::unify (BaseType *other)
+{
+ PointerRules r (this);
+ return r.unify (other);
+}
+
+bool
+PointerType::can_eq (const BaseType *other, bool emit_errors) const
+{
+ PointerCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+PointerType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ auto other2 = static_cast<const PointerType &> (other);
+ if (mutability () != other2.mutability ())
+ return false;
+
+ return get_base ()->is_equal (*other2.get_base ());
+}
+
+BaseType *
+PointerType::get_base () const
+{
+ return base.get_tyty ();
+}
+
+BaseType *
+PointerType::clone () const
+{
+ return new PointerType (get_ref (), get_ty_ref (), base, mutability (),
+ get_combined_refs ());
+}
+
+BaseType *
+PointerType::monomorphized_clone () const
+{
+ return new PointerType (get_ref (), get_ty_ref (),
+ base.monomorphized_clone (), mutability (),
+ get_combined_refs ());
+}
+
+PointerType *
+PointerType::handle_substitions (SubstitutionArgumentMappings mappings)
+{
+ auto mappings_table = Analysis::Mappings::get ();
+
+ PointerType *ref = static_cast<PointerType *> (clone ());
+ ref->set_ty_ref (mappings_table->get_next_hir_id ());
+
+ // might be &T or &ADT so this needs to be recursive
+ auto base = ref->get_base ();
+ BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
+ ref->base = TyVar::subst_covariant_var (base, concrete);
+
+ return ref;
+}
+
+void
+ParamType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+ParamType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+ParamType::as_string () const
+{
+ if (!can_resolve ())
+ {
+ return get_symbol () + " REF: " + std::to_string (get_ref ());
+ }
+
+ BaseType *lookup = resolve ();
+ return get_symbol () + "=" + lookup->as_string ();
+}
+
+std::string
+ParamType::get_name () const
+{
+ if (!can_resolve ())
+ return get_symbol ();
+
+ 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
+{
+ ParamCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+ParamType::clone () const
+{
+ return new ParamType (get_symbol (), ident.locus, get_ref (), get_ty_ref (),
+ param, get_specified_bounds (), get_combined_refs ());
+}
+
+BaseType *
+ParamType::monomorphized_clone () const
+{
+ return resolve ()->clone ();
+}
+
+std::string
+ParamType::get_symbol () const
+{
+ return symbol;
+}
+
+BaseType *
+ParamType::resolve () const
+{
+ TyVar var (get_ty_ref ());
+ BaseType *r = var.get_tyty ();
+
+ while (r->get_kind () == TypeKind::PARAM)
+ {
+ ParamType *rr = static_cast<ParamType *> (r);
+ if (!rr->can_resolve ())
+ break;
+
+ TyVar v (rr->get_ty_ref ());
+ r = v.get_tyty ();
+ }
+
+ if (r->get_kind () == TypeKind::PARAM && (r->get_ref () == r->get_ty_ref ()))
+ return TyVar (r->get_ty_ref ()).get_tyty ();
+
+ return r;
+}
+
+bool
+ParamType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ {
+ if (!can_resolve ())
+ return false;
+
+ return resolve ()->is_equal (other);
+ }
+
+ auto other2 = static_cast<const ParamType &> (other);
+ if (can_resolve () != other2.can_resolve ())
+ return false;
+
+ if (can_resolve ())
+ return resolve ()->can_eq (other2.resolve (), false);
+
+ return get_symbol ().compare (other2.get_symbol ()) == 0;
+}
+
+ParamType *
+ParamType::handle_substitions (SubstitutionArgumentMappings subst_mappings)
+{
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (this, &arg);
+ if (!ok || arg.is_error ())
+ return this;
+
+ ParamType *p = static_cast<ParamType *> (clone ());
+ subst_mappings.on_param_subst (*p, arg);
+
+ // there are two cases one where we substitute directly to a new PARAM and
+ // otherwise
+ if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM)
+ {
+ p->set_ty_ref (arg.get_tyty ()->get_ref ());
+ return p;
+ }
+
+ // this is the new subst that this needs to pass
+ p->set_ref (mappings->get_next_hir_id ());
+ p->set_ty_ref (arg.get_tyty ()->get_ref ());
+
+ return p;
+}
+
+BaseType *
+StrType::clone () const
+{
+ return new StrType (get_ref (), get_ty_ref (), get_combined_refs ());
+}
+
+BaseType *
+StrType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+void
+StrType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+StrType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ StrCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+bool
+StrType::is_equal (const BaseType &other) const
+{
+ return get_kind () == other.get_kind ();
+}
+
+void
+NeverType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+NeverType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ NeverCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+NeverType::clone () const
+{
+ return new NeverType (get_ref (), get_ty_ref (), get_combined_refs ());
+}
+
+BaseType *
+NeverType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+// placeholder type
+
+void
+PlaceholderType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+PlaceholderType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+PlaceholderType::as_string () const
+{
+ return "<placeholder:" + (can_resolve () ? resolve ()->as_string () : "")
+ + ">";
+}
+
+BaseType *
+PlaceholderType::unify (BaseType *other)
+{
+ PlaceholderRules r (this);
+ return r.unify (other);
+}
+
+bool
+PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const
+{
+ PlaceholderCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+PlaceholderType::clone () const
+{
+ return new PlaceholderType (get_symbol (), get_ref (), get_ty_ref (),
+ get_combined_refs ());
+}
+
+BaseType *
+PlaceholderType::monomorphized_clone () const
+{
+ if (can_resolve ())
+ return resolve ()->monomorphized_clone ();
+
+ return clone ();
+}
+
+void
+PlaceholderType::set_associated_type (HirId ref)
+{
+ auto context = Resolver::TypeCheckContext::get ();
+ context->insert_associated_type_mapping (get_ty_ref (), ref);
+}
+
+void
+PlaceholderType::clear_associated_type ()
+{
+ auto context = Resolver::TypeCheckContext::get ();
+ context->clear_associated_type_mapping (get_ty_ref ());
+}
+
+bool
+PlaceholderType::can_resolve () const
+{
+ auto context = Resolver::TypeCheckContext::get ();
+ return context->lookup_associated_type_mapping (get_ty_ref (), nullptr);
+}
+
+BaseType *
+PlaceholderType::resolve () const
+{
+ auto context = Resolver::TypeCheckContext::get ();
+
+ HirId mapping;
+ bool ok = context->lookup_associated_type_mapping (get_ty_ref (), &mapping);
+ rust_assert (ok);
+
+ return TyVar (mapping).get_tyty ();
+}
+
+bool
+PlaceholderType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ {
+ if (!can_resolve ())
+ return false;
+
+ return resolve ()->is_equal (other);
+ }
+
+ auto other2 = static_cast<const PlaceholderType &> (other);
+ return get_symbol ().compare (other2.get_symbol ()) == 0;
+}
+
+// Projection type
+
+void
+ProjectionType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+ProjectionType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ return base->can_eq (other, emit_errors);
+}
+
+BaseType *
+ProjectionType::clone () const
+{
+ return new ProjectionType (get_ref (), get_ty_ref (), base->clone (), trait,
+ item, clone_substs (), used_arguments,
+ get_combined_refs ());
+}
+
+BaseType *
+ProjectionType::monomorphized_clone () const
+{
+ return get ()->monomorphized_clone ();
+}
+
+ProjectionType *
+ProjectionType::handle_substitions (SubstitutionArgumentMappings subst_mappings)
+{
+ // // do we really need to substitute this?
+ // if (base->needs_generic_substitutions () || base->contains_type_parameters
+ // ())
+ // {
+ // return this;
+ // }
+
+ ProjectionType *projection = static_cast<ProjectionType *> (clone ());
+ projection->set_ty_ref (mappings->get_next_hir_id ());
+ projection->used_arguments = subst_mappings;
+
+ auto context = Resolver::TypeCheckContext::get ();
+ context->insert_implicit_type (projection->get_ty_ref (), projection);
+
+ for (auto &sub : projection->get_substs ())
+ {
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok
+ = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
+ if (ok)
+ sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
+ }
+
+ auto fty = projection->base;
+ bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
+ if (is_param_ty)
+ {
+ ParamType *p = static_cast<ParamType *> (fty);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
+ if (ok)
+ {
+ auto argt = arg.get_tyty ();
+ bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
+ bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
+
+ if (arg_is_param || arg_is_concrete)
+ {
+ auto new_field = argt->clone ();
+ new_field->set_ref (fty->get_ref ());
+ projection->base = new_field;
+ }
+ else
+ {
+ fty->set_ty_ref (argt->get_ref ());
+ }
+ }
+ }
+ else if (fty->needs_generic_substitutions ()
+ || fty->contains_type_parameters ())
+ {
+ BaseType *concrete
+ = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
+
+ if (concrete == nullptr || concrete->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (subst_mappings.get_locus (),
+ "Failed to resolve field substitution type: %s",
+ fty->as_string ().c_str ());
+ return nullptr;
+ }
+
+ projection->base = concrete;
+ }
+
+ return projection;
+}
+
+void
+DynamicObjectType::accept_vis (TyVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+DynamicObjectType::accept_vis (TyConstVisitor &vis) const
+{
+ vis.visit (*this);
+}
+
+std::string
+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
+{
+ DynamicCmp r (this, emit_errors);
+ return r.can_eq (other);
+}
+
+BaseType *
+DynamicObjectType::clone () const
+{
+ return new DynamicObjectType (get_ref (), get_ty_ref (), ident,
+ specified_bounds, get_combined_refs ());
+}
+
+BaseType *
+DynamicObjectType::monomorphized_clone () const
+{
+ return clone ();
+}
+
+std::string
+DynamicObjectType::get_name () const
+{
+ return "dyn [" + raw_bounds_as_name () + "]";
+}
+
+bool
+DynamicObjectType::is_equal (const BaseType &other) const
+{
+ if (get_kind () != other.get_kind ())
+ return false;
+
+ if (num_specified_bounds () != other.num_specified_bounds ())
+ return false;
+
+ return bounds_compatible (other, Location (), false);
+}
+
+const std::vector<
+ std::pair<const Resolver::TraitItemReference *, const TypeBoundPredicate *>>
+DynamicObjectType::get_object_items () const
+{
+ std::vector<
+ std::pair<const Resolver::TraitItemReference *, const TypeBoundPredicate *>>
+ items;
+ for (auto &bound : get_specified_bounds ())
+ {
+ const Resolver::TraitReference *trait = bound.get ();
+ for (auto &item : trait->get_trait_items ())
+ {
+ if (item.get_trait_item_type ()
+ == Resolver::TraitItemReference::TraitItemType::FN
+ && item.is_object_safe ())
+ items.push_back ({&item, &bound});
+ }
+
+ for (auto &super_trait : trait->get_super_traits ())
+ {
+ for (auto &item : super_trait->get_trait_items ())
+ {
+ if (item.get_trait_item_type ()
+ == Resolver::TraitItemReference::TraitItemType::FN
+ && item.is_object_safe ())
+ items.push_back ({&item, &bound});
+ }
+ }
+ }
+ return items;
+}
+
+} // namespace TyTy
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
new file mode 100644
index 00000000000..c47921d44d7
--- /dev/null
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -0,0 +1,2533 @@
+// 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
+#define RUST_TYTY
+
+#include "rust-hir-map.h"
+#include "rust-hir-full.h"
+#include "rust-diagnostics.h"
+#include "rust-abi.h"
+#include "rust-common.h"
+#include "rust-identifier.h"
+
+namespace Rust {
+
+namespace Resolver {
+class TraitReference;
+class TraitItemReference;
+class AssociatedImplTrait;
+} // namespace Resolver
+
+namespace TyTy {
+
+// https://rustc-dev-guide.rust-lang.org/type-inference.html#inference-variables
+// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variants
+enum TypeKind
+{
+ INFER,
+ ADT,
+ STR,
+ REF,
+ POINTER,
+ PARAM,
+ ARRAY,
+ SLICE,
+ FNDEF,
+ FNPTR,
+ TUPLE,
+ BOOL,
+ CHAR,
+ INT,
+ UINT,
+ FLOAT,
+ USIZE,
+ ISIZE,
+ NEVER,
+ PLACEHOLDER,
+ PROJECTION,
+ DYNAMIC,
+ CLOSURE,
+ // there are more to add...
+ ERROR
+};
+
+extern bool
+is_primitive_type_kind (TypeKind kind);
+
+class TypeKindFormat
+{
+public:
+ static std::string to_string (TypeKind kind);
+};
+
+class BaseType;
+class TypeBoundPredicate;
+class TypeBoundPredicateItem
+{
+public:
+ TypeBoundPredicateItem (const TypeBoundPredicate *parent,
+ const Resolver::TraitItemReference *trait_item_ref)
+ : parent (parent), trait_item_ref (trait_item_ref)
+ {}
+
+ static TypeBoundPredicateItem error ()
+ {
+ return TypeBoundPredicateItem (nullptr, nullptr);
+ }
+
+ bool is_error () const
+ {
+ return parent == nullptr || trait_item_ref == nullptr;
+ }
+
+ BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver);
+
+ const Resolver::TraitItemReference *get_raw_item () const;
+
+ bool needs_implementation () const;
+
+ const TypeBoundPredicate *get_parent () const { return parent; }
+
+ Location get_locus () const;
+
+private:
+ const TypeBoundPredicate *parent;
+ const Resolver::TraitItemReference *trait_item_ref;
+};
+
+class TypeBoundsMappings
+{
+protected:
+ TypeBoundsMappings (std::vector<TypeBoundPredicate> specified_bounds);
+
+public:
+ std::vector<TypeBoundPredicate> &get_specified_bounds ();
+
+ const std::vector<TypeBoundPredicate> &get_specified_bounds () const;
+
+ size_t num_specified_bounds () const;
+
+ std::string raw_bounds_as_string () const;
+
+ std::string bounds_as_string () const;
+
+ std::string raw_bounds_as_name () const;
+
+protected:
+ void add_bound (TypeBoundPredicate predicate);
+
+ std::vector<TypeBoundPredicate> specified_bounds;
+};
+
+class TyVisitor;
+class TyConstVisitor;
+class BaseType : public TypeBoundsMappings
+{
+public:
+ virtual ~BaseType () {}
+
+ HirId get_ref () const { return ref; }
+
+ void set_ref (HirId id)
+ {
+ if (id != ref)
+ append_reference (ref);
+ ref = id;
+ }
+
+ HirId get_ty_ref () const { return ty_ref; }
+
+ void set_ty_ref (HirId id) { ty_ref = id; }
+
+ virtual void accept_vis (TyVisitor &vis) = 0;
+
+ virtual void accept_vis (TyConstVisitor &vis) const = 0;
+
+ virtual std::string as_string () const = 0;
+
+ 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
+ //
+ // fn foo<T>() -> T { ... }
+ // fn foo() -> i32 { ... }
+ //
+ // when the function has been substituted they can be considered equal.
+ //
+ // It can also be used to optional emit errors for trait item compatibility
+ // checks
+ virtual bool can_eq (const BaseType *other, bool emit_errors) const = 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
+ // 2. (For functions) have the same signature
+ virtual bool is_equal (const BaseType &other) const
+ {
+ return get_kind () == other.get_kind ();
+ }
+
+ bool satisfies_bound (const TypeBoundPredicate &predicate) const;
+
+ bool bounds_compatible (const BaseType &other, Location locus,
+ bool emit_error) const;
+
+ void inherit_bounds (const BaseType &other);
+
+ void inherit_bounds (
+ const std::vector<TyTy::TypeBoundPredicate> &specified_bounds);
+
+ virtual bool is_unit () const { return false; }
+
+ virtual bool is_concrete () const = 0;
+
+ TypeKind get_kind () const { return kind; }
+
+ /* Returns a pointer to a clone of this. The caller is responsible for
+ * releasing the memory of the returned ty. */
+ virtual BaseType *clone () const = 0;
+
+ // TODO
+ virtual BaseType *monomorphized_clone () const = 0;
+
+ // get_combined_refs returns the chain of node refs involved in unification
+ std::set<HirId> get_combined_refs () const { return combined; }
+
+ void append_reference (HirId id) { combined.insert (id); }
+
+ virtual bool supports_substitutions () const { return false; }
+
+ virtual bool has_subsititions_defined () const { return false; }
+
+ virtual bool can_substitute () const
+ {
+ return supports_substitutions () && has_subsititions_defined ();
+ }
+
+ virtual bool needs_generic_substitutions () const { return false; }
+
+ bool contains_type_parameters () const { return !is_concrete (); }
+
+ std::string mappings_str () const
+ {
+ std::string buffer = "Ref: " + std::to_string (get_ref ())
+ + " TyRef: " + std::to_string (get_ty_ref ());
+ buffer += "[";
+ for (auto &ref : combined)
+ buffer += std::to_string (ref) + ",";
+ buffer += "]";
+ return "(" + buffer + ")";
+ }
+
+ std::string debug_str () const
+ {
+ return TypeKindFormat::to_string (get_kind ()) + ":" + as_string () + ":"
+ + mappings_str () + ":" + bounds_as_string ();
+ }
+
+ void debug () const
+ {
+ rust_debug ("[%p] %s", static_cast<const void *> (this),
+ debug_str ().c_str ());
+ }
+
+ // FIXME this will eventually go away
+ const BaseType *get_root () const;
+
+ // This will get the monomorphized type from Params, Placeholders or
+ // Projections if available or error
+ const BaseType *destructure () const;
+
+ const RustIdent &get_ident () const { return ident; }
+
+ Location get_locus () const { return ident.locus; }
+
+protected:
+ BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
+ std::set<HirId> refs = std::set<HirId> ())
+ : TypeBoundsMappings ({}), kind (kind), ref (ref), ty_ref (ty_ref),
+ combined (refs), ident (ident), mappings (Analysis::Mappings::get ())
+ {}
+
+ BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
+ std::vector<TypeBoundPredicate> specified_bounds,
+ std::set<HirId> refs = std::set<HirId> ())
+ : TypeBoundsMappings (specified_bounds), kind (kind), ref (ref),
+ ty_ref (ty_ref), combined (refs), ident (ident),
+ mappings (Analysis::Mappings::get ())
+ {}
+
+ TypeKind kind;
+ HirId ref;
+ HirId ty_ref;
+ std::set<HirId> combined;
+ RustIdent ident;
+
+ Analysis::Mappings *mappings;
+};
+
+// this is a placeholder for types that can change like inference variables
+class TyVar
+{
+public:
+ explicit TyVar (HirId ref);
+
+ HirId get_ref () const { return ref; }
+
+ BaseType *get_tyty () const;
+
+ TyVar clone () const;
+
+ TyVar monomorphized_clone () const;
+
+ static TyVar get_implicit_infer_var (Location locus);
+
+ static TyVar subst_covariant_var (TyTy::BaseType *orig,
+ TyTy::BaseType *subst);
+
+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:
+ enum InferTypeKind
+ {
+ GENERAL,
+ INTEGRAL,
+ FLOAT
+ };
+
+ InferType (HirId ref, InferTypeKind infer_kind, Location locus,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::INFER,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ infer_kind (infer_kind)
+ {}
+
+ InferType (HirId ref, HirId ty_ref, InferTypeKind infer_kind, Location locus,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::INFER,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ infer_kind (infer_kind)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+ BaseType *monomorphized_clone () const final override;
+
+ InferTypeKind get_infer_kind () const { return infer_kind; }
+
+ std::string get_name () const override final { return as_string (); }
+
+ bool default_type (BaseType **type) const;
+
+ bool is_concrete () const final override { return true; }
+
+private:
+ InferTypeKind infer_kind;
+};
+
+class ErrorType : public BaseType
+{
+public:
+ ErrorType (HirId ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::ERROR,
+ {Resolver::CanonicalPath::create_empty (), Location ()}, refs)
+ {}
+
+ ErrorType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::ERROR,
+ {Resolver::CanonicalPath::create_empty (), Location ()}, refs)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ bool is_unit () const override { return true; }
+
+ 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;
+ BaseType *monomorphized_clone () const final override;
+
+ std::string get_name () const override final { return as_string (); }
+
+ bool is_concrete () const final override { return false; }
+};
+
+class SubstitutionArgumentMappings;
+class ParamType : public BaseType
+{
+public:
+ ParamType (std::string symbol, Location locus, HirId ref,
+ HIR::GenericParam ¶m,
+ std::vector<TypeBoundPredicate> specified_bounds,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::PARAM,
+ {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
+ locus},
+ specified_bounds, refs),
+ symbol (symbol), param (param)
+ {}
+
+ ParamType (std::string symbol, Location locus, HirId ref, HirId ty_ref,
+ HIR::GenericParam ¶m,
+ std::vector<TypeBoundPredicate> specified_bounds,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::PARAM,
+ {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
+ locus},
+ specified_bounds, refs),
+ symbol (symbol), param (param)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+ BaseType *monomorphized_clone () const final override;
+
+ std::string get_symbol () const;
+
+ HIR::GenericParam &get_generic_param () { return param; }
+
+ bool can_resolve () const { return get_ref () != get_ty_ref (); }
+
+ BaseType *resolve () const;
+
+ std::string get_name () const override final;
+
+ bool is_equal (const BaseType &other) const override;
+
+ bool is_concrete () const override final
+ {
+ auto r = resolve ();
+ if (r == this)
+ return false;
+
+ return r->is_concrete ();
+ }
+
+ ParamType *handle_substitions (SubstitutionArgumentMappings mappings);
+
+private:
+ std::string symbol;
+ HIR::GenericParam ¶m;
+};
+
+class StructFieldType
+{
+public:
+ StructFieldType (HirId ref, std::string name, BaseType *ty)
+ : ref (ref), name (name), ty (ty)
+ {}
+
+ HirId get_ref () const { return ref; }
+
+ std::string as_string () const;
+
+ bool is_equal (const StructFieldType &other) const;
+
+ std::string get_name () const { return name; }
+
+ BaseType *get_field_type () const { return ty; }
+
+ void set_field_type (BaseType *fty) { ty = fty; }
+
+ StructFieldType *clone () const;
+
+ StructFieldType *monomorphized_clone () const;
+
+ bool is_concrete () const { return ty->is_concrete (); }
+
+ void debug () const { rust_debug ("%s", as_string ().c_str ()); }
+
+private:
+ HirId ref;
+ std::string name;
+ BaseType *ty;
+};
+
+class TupleType : public BaseType
+{
+public:
+ TupleType (HirId ref, Location locus,
+ std::vector<TyVar> fields = std::vector<TyVar> (),
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::TUPLE,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ fields (fields)
+ {}
+
+ TupleType (HirId ref, HirId ty_ref, Location locus,
+ std::vector<TyVar> fields = std::vector<TyVar> (),
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::TUPLE,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ fields (fields)
+ {}
+
+ static TupleType *get_unit_type (HirId ref)
+ {
+ return new TupleType (ref, Linemap::predeclared_location ());
+ }
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ bool is_unit () const override { return this->fields.empty (); }
+
+ 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;
+
+ size_t num_fields () const { return fields.size (); }
+
+ BaseType *get_field (size_t index) const;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_concrete () const override final
+ {
+ for (size_t i = 0; i < num_fields (); i++)
+ {
+ if (!get_field (i)->is_concrete ())
+ return false;
+ }
+ return true;
+ }
+
+ const std::vector<TyVar> &get_fields () const { return fields; }
+
+ std::string get_name () const override final { return as_string (); }
+
+ TupleType *handle_substitions (SubstitutionArgumentMappings mappings);
+
+private:
+ std::vector<TyVar> fields;
+};
+
+class SubstitutionParamMapping
+{
+public:
+ SubstitutionParamMapping (const HIR::TypeParam &generic, ParamType *param)
+ : generic (generic), param (param)
+ {}
+
+ SubstitutionParamMapping (const SubstitutionParamMapping &other)
+ : generic (other.generic), param (other.param)
+ {}
+
+ std::string as_string () const
+ {
+ if (param == nullptr)
+ return "nullptr";
+
+ return param->get_name ();
+ }
+
+ bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings,
+ Location locus);
+
+ SubstitutionParamMapping clone () const
+ {
+ return SubstitutionParamMapping (generic, static_cast<ParamType *> (
+ param->clone ()));
+ }
+
+ ParamType *get_param_ty () { return param; }
+
+ const ParamType *get_param_ty () const { return param; }
+
+ const HIR::TypeParam &get_generic_param () { return generic; };
+
+ // this is used for the backend to override the HirId ref of the param to
+ // what the concrete type is for the rest of the context
+ void override_context ();
+
+ bool needs_substitution () const
+ {
+ return !(get_param_ty ()->is_concrete ());
+ }
+
+ Location get_param_locus () const { return generic.get_locus (); }
+
+ bool param_has_default_ty () const { return generic.has_type (); }
+
+ BaseType *get_default_ty () const
+ {
+ TyVar var (generic.get_type_mappings ().get_hirid ());
+ return var.get_tyty ();
+ }
+
+ bool need_substitution () const;
+
+private:
+ const HIR::TypeParam &generic;
+ ParamType *param;
+};
+
+class SubstitutionArg
+{
+public:
+ SubstitutionArg (const SubstitutionParamMapping *param, BaseType *argument)
+ : param (param), argument (argument)
+ {}
+
+ // FIXME
+ // the copy constructors need removed - they are unsafe see
+ // TypeBoundPredicate
+ SubstitutionArg (const SubstitutionArg &other)
+ : param (other.param), argument (other.argument)
+ {}
+
+ SubstitutionArg &operator= (const SubstitutionArg &other)
+ {
+ param = other.param;
+ argument = other.argument;
+ return *this;
+ }
+
+ BaseType *get_tyty () { return argument; }
+
+ const BaseType *get_tyty () const { return argument; }
+
+ const SubstitutionParamMapping *get_param_mapping () const { return param; }
+
+ static SubstitutionArg error () { return SubstitutionArg (nullptr, nullptr); }
+
+ bool is_error () const { return param == nullptr || argument == nullptr; }
+
+ bool is_conrete () const
+ {
+ if (argument != nullptr)
+ return true;
+
+ if (argument->get_kind () == TyTy::TypeKind::PARAM)
+ return false;
+
+ return argument->is_concrete ();
+ }
+
+ std::string as_string () const
+ {
+ return param->as_string ()
+ + (argument != nullptr ? ":" + argument->as_string () : "");
+ }
+
+private:
+ const SubstitutionParamMapping *param;
+ BaseType *argument;
+};
+
+typedef std::function<void (const ParamType &, const SubstitutionArg &)>
+ ParamSubstCb;
+class SubstitutionArgumentMappings
+{
+public:
+ SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings,
+ Location locus,
+ ParamSubstCb param_subst_cb = nullptr,
+ bool trait_item_flag = false)
+ : mappings (mappings), locus (locus), param_subst_cb (param_subst_cb),
+ trait_item_flag (trait_item_flag)
+ {}
+
+ SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other)
+ : mappings (other.mappings), locus (other.locus),
+ param_subst_cb (other.param_subst_cb),
+ trait_item_flag (other.trait_item_flag)
+ {}
+
+ SubstitutionArgumentMappings &
+ operator= (const SubstitutionArgumentMappings &other)
+ {
+ mappings = other.mappings;
+ locus = other.locus;
+ param_subst_cb = other.param_subst_cb;
+ trait_item_flag = other.trait_item_flag;
+
+ return *this;
+ }
+
+ static SubstitutionArgumentMappings error ()
+ {
+ return SubstitutionArgumentMappings ({}, Location (), nullptr, false);
+ }
+
+ bool is_error () const { return mappings.size () == 0; }
+
+ bool get_argument_for_symbol (const ParamType *param_to_find,
+ SubstitutionArg *argument)
+ {
+ for (auto &mapping : mappings)
+ {
+ const SubstitutionParamMapping *param = mapping.get_param_mapping ();
+ const ParamType *p = param->get_param_ty ();
+
+ if (p->get_symbol ().compare (param_to_find->get_symbol ()) == 0)
+ {
+ *argument = mapping;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool get_argument_at (size_t index, SubstitutionArg *argument)
+ {
+ if (index > mappings.size ())
+ return false;
+
+ *argument = mappings.at (index);
+ return true;
+ }
+
+ // is_concrete means if the used args is non error, ie: non empty this will
+ // verify if actual real types have been put in place of are they still
+ // ParamTy
+ bool is_concrete () const
+ {
+ for (auto &mapping : mappings)
+ {
+ if (!mapping.is_conrete ())
+ return false;
+ }
+ return true;
+ }
+
+ Location get_locus () const { return locus; }
+
+ size_t size () const { return mappings.size (); }
+
+ bool is_empty () const { return size () == 0; }
+
+ std::vector<SubstitutionArg> &get_mappings () { return mappings; }
+
+ const std::vector<SubstitutionArg> &get_mappings () const { return mappings; }
+
+ std::string as_string () const
+ {
+ std::string buffer;
+ for (auto &mapping : mappings)
+ {
+ buffer += mapping.as_string () + ", ";
+ }
+ return "<" + buffer + ">";
+ }
+
+ void on_param_subst (const ParamType &p, const SubstitutionArg &a) const
+ {
+ if (param_subst_cb == nullptr)
+ return;
+
+ param_subst_cb (p, a);
+ }
+
+ ParamSubstCb get_subst_cb () const { return param_subst_cb; }
+
+ bool trait_item_mode () const { return trait_item_flag; }
+
+private:
+ std::vector<SubstitutionArg> mappings;
+ Location locus;
+ ParamSubstCb param_subst_cb;
+ bool trait_item_flag;
+};
+
+class SubstitutionRef
+{
+public:
+ SubstitutionRef (std::vector<SubstitutionParamMapping> substitutions,
+ SubstitutionArgumentMappings arguments)
+ : substitutions (substitutions), used_arguments (arguments)
+ {}
+
+ bool has_substitutions () const { return substitutions.size () > 0; }
+
+ std::string subst_as_string () const
+ {
+ std::string buffer;
+ for (size_t i = 0; i < substitutions.size (); i++)
+ {
+ const SubstitutionParamMapping &sub = substitutions.at (i);
+ buffer += sub.as_string ();
+
+ if ((i + 1) < substitutions.size ())
+ buffer += ", ";
+ }
+
+ return buffer.empty () ? "" : "<" + buffer + ">";
+ }
+
+ size_t get_num_substitutions () const { return substitutions.size (); }
+
+ std::vector<SubstitutionParamMapping> &get_substs () { return substitutions; }
+
+ const std::vector<SubstitutionParamMapping> &get_substs () const
+ {
+ return substitutions;
+ }
+
+ std::vector<SubstitutionParamMapping> clone_substs () const
+ {
+ std::vector<SubstitutionParamMapping> clone;
+
+ for (auto &sub : substitutions)
+ clone.push_back (sub.clone ());
+
+ return clone;
+ }
+
+ void override_context ()
+ {
+ for (auto &sub : substitutions)
+ {
+ sub.override_context ();
+ }
+ }
+
+ bool needs_substitution () const
+ {
+ for (auto &sub : substitutions)
+ {
+ if (sub.need_substitution ())
+ return true;
+ }
+ return false;
+ }
+
+ bool was_substituted () const { return !needs_substitution (); }
+
+ SubstitutionArgumentMappings get_substitution_arguments () const
+ {
+ return used_arguments;
+ }
+
+ // this is the count of type params that are not substituted fuly
+ size_t num_required_substitutions () const
+ {
+ size_t n = 0;
+ for (auto &p : substitutions)
+ {
+ if (p.needs_substitution ())
+ n++;
+ }
+ return n;
+ }
+
+ // this is the count of type params that need substituted taking into account
+ // possible defaults
+ size_t min_required_substitutions () const
+ {
+ size_t n = 0;
+ for (auto &p : substitutions)
+ {
+ if (p.needs_substitution () && !p.param_has_default_ty ())
+ n++;
+ }
+ return n;
+ }
+
+ // We are trying to subst <i32, f32> into Struct Foo<X,Y> {}
+ // in the case of Foo<i32,f32>{...}
+ //
+ // the substitions we have here define X,Y but the arguments have no bindings
+ // so its a matter of ordering
+ SubstitutionArgumentMappings
+ get_mappings_from_generic_args (HIR::GenericArgs &args);
+
+ // Recursive substitutions
+ // Foo <A,B> { a:A, b: B}; Bar <X,Y,Z>{a:X, b: Foo<Y,Z>}
+ //
+ // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo
+ // Which binds to A,B
+ SubstitutionArgumentMappings
+ adjust_mappings_for_this (SubstitutionArgumentMappings &mappings);
+
+ // Are the mappings here actually bound to this type. For example imagine the
+ // case:
+ //
+ // struct Foo<T>(T);
+ // impl<T> Foo<T> {
+ // fn test(self) { ... }
+ // }
+ //
+ // In this case we have a generic ADT of Foo and an impl block of a generic T
+ // on Foo for the Self type. When we it comes to path resolution we can have:
+ //
+ // Foo::<i32>::test()
+ //
+ // This means the first segment of Foo::<i32> returns the ADT Foo<i32> not the
+ // Self ADT bound to the T from the impl block. This means when it comes to
+ // the next segment of test which resolves to the function we need to check
+ // wether the arguments in the struct definition of foo can be bound here
+ // before substituting the previous segments type here. This functions acts as
+ // a guard for the solve_mappings_from_receiver_for_self to handle the case
+ // where arguments are not bound. This is important for this next case:
+ //
+ // struct Baz<A, B>(A, B);
+ // impl Baz<i32, f32> {
+ // fn test<X>(a: X) -> X {
+ // a
+ // }
+ // }
+ //
+ // In this case Baz has been already substituted for the impl's Self to become
+ // ADT<i32, f32> so that the function test only has 1 generic argument of X.
+ // The path for this will be:
+ //
+ // Baz::test::<_>(123)
+ //
+ // So the first segment here will be Baz<_, _> to try and infer the arguments
+ // which will be taken from the impl's Self type in this case since it is
+ // already substituted and like the previous case the check to see if we need
+ // to inherit the previous segments generic arguments takes place but the
+ // generic arguments are not bound to this type as they have already been
+ // substituted.
+ //
+ // Its important to remember from the first example the FnType actually looks
+ // like:
+ //
+ // fn <T>test(self :Foo<T>(T))
+ //
+ // As the generic parameters are "bound" to each of the items in the impl
+ // block. So this check is about wether the arguments we have here can
+ // actually be bound to this type.
+ bool are_mappings_bound (SubstitutionArgumentMappings &mappings);
+
+ // struct Foo<A, B>(A, B);
+ //
+ // impl<T> Foo<T, f32>;
+ // -> fn test<X>(self, a: X) -> X
+ //
+ // We might invoke this via:
+ //
+ // a = Foo(123, 456f32);
+ // b = a.test::<bool>(false);
+ //
+ // we need to figure out relevant generic arguemts for self to apply to the
+ // fntype
+ SubstitutionArgumentMappings solve_mappings_from_receiver_for_self (
+ SubstitutionArgumentMappings &mappings) const;
+
+ // TODO comment
+ SubstitutionArgumentMappings
+ solve_missing_mappings_from_this (SubstitutionRef &ref, SubstitutionRef &to);
+
+ // TODO comment
+ BaseType *infer_substitions (Location locus)
+ {
+ std::vector<SubstitutionArg> args;
+ std::map<std::string, BaseType *> argument_mappings;
+ for (auto &p : get_substs ())
+ {
+ if (p.needs_substitution ())
+ {
+ const std::string &symbol = p.get_param_ty ()->get_symbol ();
+ auto it = argument_mappings.find (symbol);
+ if (it == argument_mappings.end ())
+ {
+ TyVar infer_var = TyVar::get_implicit_infer_var (locus);
+ args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
+ argument_mappings[symbol] = infer_var.get_tyty ();
+ }
+ else
+ {
+ args.push_back (SubstitutionArg (&p, it->second));
+ }
+ }
+ else
+ {
+ args.push_back (
+ SubstitutionArg (&p, p.get_param_ty ()->resolve ()));
+ }
+ }
+
+ SubstitutionArgumentMappings infer_arguments (std::move (args), locus);
+ return handle_substitions (std::move (infer_arguments));
+ }
+
+ // TODO comment
+ bool monomorphize ();
+
+ // TODO comment
+ virtual BaseType *handle_substitions (SubstitutionArgumentMappings mappings)
+ = 0;
+
+ SubstitutionArgumentMappings get_used_arguments () const
+ {
+ return used_arguments;
+ }
+
+protected:
+ std::vector<SubstitutionParamMapping> substitutions;
+ SubstitutionArgumentMappings used_arguments;
+};
+
+class TypeBoundPredicate : public SubstitutionRef
+{
+public:
+ TypeBoundPredicate (const Resolver::TraitReference &trait_reference,
+ Location locus);
+
+ TypeBoundPredicate (DefId reference,
+ std::vector<SubstitutionParamMapping> substitutions,
+ Location locus);
+
+ TypeBoundPredicate (const TypeBoundPredicate &other);
+
+ TypeBoundPredicate &operator= (const TypeBoundPredicate &other);
+
+ static TypeBoundPredicate error ();
+
+ std::string as_string () const;
+
+ std::string as_name () const;
+
+ const Resolver::TraitReference *get () const;
+
+ Location get_locus () const { return locus; }
+
+ std::string get_name () const;
+
+ // check that this predicate is object-safe see:
+ // https://doc.rust-lang.org/reference/items/traits.html#object-safety
+ bool is_object_safe (bool emit_error, Location locus) const;
+
+ void apply_generic_arguments (HIR::GenericArgs *generic_args);
+
+ bool contains_item (const std::string &search) const;
+
+ TypeBoundPredicateItem
+ lookup_associated_item (const std::string &search) const;
+
+ TypeBoundPredicateItem
+ lookup_associated_item (const Resolver::TraitItemReference *ref) const;
+
+ // WARNING THIS WILL ALWAYS RETURN NULLPTR
+ BaseType *
+ handle_substitions (SubstitutionArgumentMappings mappings) override final;
+
+ bool is_error () const;
+
+ bool requires_generic_args () const;
+
+private:
+ DefId reference;
+ Location locus;
+ bool error_flag;
+};
+
+// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.VariantDef.html
+class VariantDef
+{
+public:
+ enum VariantType
+ {
+ NUM,
+ TUPLE,
+ STRUCT
+ };
+
+ static std::string variant_type_string (VariantType type)
+ {
+ switch (type)
+ {
+ case NUM:
+ return "enumeral";
+ case TUPLE:
+ return "tuple";
+ case STRUCT:
+ return "struct";
+ }
+ gcc_unreachable ();
+ return "";
+ }
+
+ VariantDef (HirId id, std::string identifier, RustIdent ident,
+ HIR::Expr *discriminant)
+ : id (id), identifier (identifier), ident (ident),
+ discriminant (discriminant)
+
+ {
+ type = VariantType::NUM;
+ fields = {};
+ }
+
+ VariantDef (HirId id, std::string identifier, RustIdent ident,
+ VariantType type, HIR::Expr *discriminant,
+ std::vector<StructFieldType *> fields)
+ : id (id), identifier (identifier), ident (ident), type (type),
+ discriminant (discriminant), fields (fields)
+ {
+ rust_assert (
+ (type == VariantType::NUM && fields.empty ())
+ || (type == VariantType::TUPLE || type == VariantType::STRUCT));
+ }
+
+ VariantDef (const VariantDef &other)
+ : id (other.id), identifier (other.identifier), ident (other.ident),
+ type (other.type), discriminant (other.discriminant),
+ fields (other.fields)
+ {}
+
+ VariantDef &operator= (const VariantDef &other)
+ {
+ id = other.id;
+ identifier = other.identifier;
+ type = other.type;
+ discriminant = other.discriminant;
+ fields = other.fields;
+ ident = other.ident;
+
+ return *this;
+ }
+
+ static VariantDef &get_error_node ()
+ {
+ static VariantDef node
+ = VariantDef (UNKNOWN_HIRID, "",
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::unknown_location ()},
+ nullptr);
+
+ return node;
+ }
+
+ bool is_error () const { return get_id () == UNKNOWN_HIRID; }
+
+ HirId get_id () const { return id; }
+
+ VariantType get_variant_type () const { return type; }
+ bool is_data_variant () const { return type != VariantType::NUM; }
+ bool is_dataless_variant () const { return type == VariantType::NUM; }
+
+ std::string get_identifier () const { return identifier; }
+
+ size_t num_fields () const { return fields.size (); }
+ StructFieldType *get_field_at_index (size_t index)
+ {
+ rust_assert (index < fields.size ());
+ return fields.at (index);
+ }
+
+ std::vector<StructFieldType *> &get_fields ()
+ {
+ rust_assert (type != NUM);
+ return fields;
+ }
+
+ bool lookup_field (const std::string &lookup, StructFieldType **field_lookup,
+ size_t *index) const
+ {
+ size_t i = 0;
+ for (auto &field : fields)
+ {
+ if (field->get_name ().compare (lookup) == 0)
+ {
+ if (index != nullptr)
+ *index = i;
+
+ if (field_lookup != nullptr)
+ *field_lookup = field;
+
+ return true;
+ }
+ i++;
+ }
+ return false;
+ }
+
+ HIR::Expr *get_discriminant () const
+ {
+ rust_assert (discriminant != nullptr);
+ return discriminant;
+ }
+
+ std::string as_string () const
+ {
+ if (type == VariantType::NUM)
+ return identifier + " = " + discriminant->as_string ();
+
+ std::string buffer;
+ for (size_t i = 0; i < fields.size (); ++i)
+ {
+ buffer += fields.at (i)->as_string ();
+ if ((i + 1) < fields.size ())
+ buffer += ", ";
+ }
+
+ if (type == VariantType::TUPLE)
+ return identifier + " (" + buffer + ")";
+ else
+ return identifier + " {" + buffer + "}";
+ }
+
+ bool is_equal (const VariantDef &other) const
+ {
+ if (type != other.type)
+ return false;
+
+ if (identifier.compare (other.identifier) != 0)
+ return false;
+
+ if (discriminant != other.discriminant)
+ return false;
+
+ if (fields.size () != other.fields.size ())
+ return false;
+
+ for (size_t i = 0; i < fields.size (); i++)
+ {
+ if (!fields.at (i)->is_equal (*other.fields.at (i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ VariantDef *clone () const
+ {
+ std::vector<StructFieldType *> cloned_fields;
+ for (auto &f : fields)
+ cloned_fields.push_back ((StructFieldType *) f->clone ());
+
+ return new VariantDef (id, identifier, ident, type, discriminant,
+ cloned_fields);
+ }
+
+ VariantDef *monomorphized_clone () const
+ {
+ std::vector<StructFieldType *> cloned_fields;
+ for (auto &f : fields)
+ cloned_fields.push_back ((StructFieldType *) f->monomorphized_clone ());
+
+ return new VariantDef (id, identifier, ident, type, discriminant,
+ cloned_fields);
+ }
+
+ const RustIdent &get_ident () const { return ident; }
+
+private:
+ HirId id;
+ std::string identifier;
+ RustIdent ident;
+ VariantType type;
+ // can either be a structure or a discriminant value
+ HIR::Expr *discriminant;
+ std::vector<StructFieldType *> fields;
+};
+
+class ADTType : public BaseType, public SubstitutionRef
+{
+public:
+ enum ADTKind
+ {
+ STRUCT_STRUCT,
+ TUPLE_STRUCT,
+ UNION,
+ ENUM
+ };
+
+ // Representation options, specified via attributes e.g. #[repr(packed)]
+ struct ReprOptions
+ {
+ // bool is_c;
+ // bool is_transparent;
+ //...
+
+ // For align and pack: 0 = unspecified. Nonzero = byte alignment.
+ // It is an error for both to be nonzero, this should be caught when
+ // parsing the #[repr] attribute.
+ unsigned char align = 0;
+ unsigned char pack = 0;
+ };
+
+ ADTType (HirId ref, std::string identifier, RustIdent ident, ADTKind adt_kind,
+ std::vector<VariantDef *> variants,
+ std::vector<SubstitutionParamMapping> subst_refs,
+ SubstitutionArgumentMappings generic_arguments
+ = SubstitutionArgumentMappings::error (),
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::ADT, ident, refs),
+ SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
+ identifier (identifier), variants (variants), adt_kind (adt_kind)
+ {}
+
+ ADTType (HirId ref, HirId ty_ref, std::string identifier, RustIdent ident,
+ ADTKind adt_kind, std::vector<VariantDef *> variants,
+ std::vector<SubstitutionParamMapping> subst_refs,
+ SubstitutionArgumentMappings generic_arguments
+ = SubstitutionArgumentMappings::error (),
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs),
+ SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
+ identifier (identifier), variants (variants), adt_kind (adt_kind)
+ {}
+
+ ADTType (HirId ref, HirId ty_ref, std::string identifier, RustIdent ident,
+ ADTKind adt_kind, std::vector<VariantDef *> variants,
+ std::vector<SubstitutionParamMapping> subst_refs, ReprOptions repr,
+ SubstitutionArgumentMappings generic_arguments
+ = SubstitutionArgumentMappings::error (),
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs),
+ SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
+ identifier (identifier), variants (variants), adt_kind (adt_kind),
+ repr (repr)
+ {}
+
+ ADTKind get_adt_kind () const { return adt_kind; }
+ ReprOptions get_repr_options () const { return repr; }
+
+ bool is_struct_struct () const { return adt_kind == STRUCT_STRUCT; }
+ bool is_tuple_struct () const { return adt_kind == TUPLE_STRUCT; }
+ bool is_union () const { return adt_kind == UNION; }
+ bool is_enum () const { return adt_kind == ENUM; }
+
+ bool is_unit () const override
+ {
+ if (number_of_variants () == 0)
+ return true;
+
+ if (number_of_variants () == 1)
+ return variants.at (0)->num_fields () == 0;
+
+ return false;
+ }
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ std::string get_identifier () const { return identifier; }
+
+ std::string get_name () const override final
+ {
+ return identifier + subst_as_string ();
+ }
+
+ bool is_concrete () const override final
+ {
+ for (auto &variant : variants)
+ {
+ for (auto &field : variant->get_fields ())
+ {
+ if (!field->is_concrete ())
+ return false;
+ }
+ }
+ return true;
+ }
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool needs_generic_substitutions () const override final
+ {
+ return needs_substitution ();
+ }
+
+ bool supports_substitutions () const override final { return true; }
+
+ bool has_subsititions_defined () const override final
+ {
+ return has_substitutions ();
+ }
+
+ size_t number_of_variants () const { return variants.size (); }
+
+ std::vector<VariantDef *> &get_variants () { return variants; }
+ const std::vector<VariantDef *> &get_variants () const { return variants; }
+
+ bool lookup_variant (const std::string &lookup,
+ VariantDef **found_variant) const
+ {
+ for (auto &variant : variants)
+ {
+ if (variant->get_identifier ().compare (lookup) == 0)
+ {
+ *found_variant = variant;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool lookup_variant_by_id (HirId id, VariantDef **found_variant,
+ int *index = nullptr) const
+ {
+ int i = 0;
+ for (auto &variant : variants)
+ {
+ if (variant->get_id () == id)
+ {
+ if (index != nullptr)
+ *index = i;
+
+ *found_variant = variant;
+ return true;
+ }
+ i++;
+ }
+ return false;
+ }
+
+ ADTType *
+ handle_substitions (SubstitutionArgumentMappings mappings) override final;
+
+private:
+ std::string identifier;
+ std::vector<VariantDef *> variants;
+ ADTType::ADTKind adt_kind;
+ ReprOptions repr;
+};
+
+class FnType : public BaseType, public SubstitutionRef
+{
+public:
+ static const uint8_t FNTYPE_DEFAULT_FLAGS = 0x00;
+ static const uint8_t FNTYPE_IS_METHOD_FLAG = 0x01;
+ static const uint8_t FNTYPE_IS_EXTERN_FLAG = 0x02;
+ static const uint8_t FNTYPE_IS_VARADIC_FLAG = 0X04;
+
+ FnType (HirId ref, DefId id, std::string identifier, RustIdent ident,
+ uint8_t flags, ABI abi,
+ std::vector<std::pair<HIR::Pattern *, BaseType *>> params,
+ BaseType *type, std::vector<SubstitutionParamMapping> subst_refs,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::FNDEF, ident, refs),
+ SubstitutionRef (std::move (subst_refs),
+ SubstitutionArgumentMappings::error ()),
+ params (std::move (params)), type (type), flags (flags),
+ identifier (identifier), id (id), abi (abi)
+ {
+ LocalDefId local_def_id = id.localDefId;
+ rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID);
+ }
+
+ FnType (HirId ref, HirId ty_ref, DefId id, std::string identifier,
+ RustIdent ident, uint8_t flags, ABI abi,
+ std::vector<std::pair<HIR::Pattern *, BaseType *>> params,
+ BaseType *type, std::vector<SubstitutionParamMapping> subst_refs,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::FNDEF, ident, refs),
+ SubstitutionRef (std::move (subst_refs),
+ SubstitutionArgumentMappings::error ()),
+ params (params), type (type), flags (flags), identifier (identifier),
+ id (id), abi (abi)
+ {
+ LocalDefId local_def_id = id.localDefId;
+ rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID);
+ }
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ std::string as_string () const override;
+
+ std::string get_name () const override final { return as_string (); }
+
+ 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;
+
+ size_t num_params () const { return params.size (); }
+
+ bool is_method () const
+ {
+ if (num_params () == 0)
+ return false;
+
+ return (flags & FNTYPE_IS_METHOD_FLAG) != 0;
+ }
+
+ bool is_extern () const { return (flags & FNTYPE_IS_EXTERN_FLAG) != 0; }
+
+ bool is_varadic () const { return (flags & FNTYPE_IS_VARADIC_FLAG) != 0; }
+
+ DefId get_id () const { return id; }
+
+ // get the Self type for the method
+ BaseType *get_self_type () const
+ {
+ rust_assert (is_method ());
+ return param_at (0).second;
+ }
+
+ bool is_concrete () const override final
+ {
+ for (const auto ¶m : params)
+ {
+ const BaseType *p = param.second;
+ if (!p->is_concrete ())
+ return false;
+ }
+ return get_return_type ()->is_concrete ();
+ }
+
+ std::vector<std::pair<HIR::Pattern *, BaseType *>> &get_params ()
+ {
+ return params;
+ }
+
+ const std::vector<std::pair<HIR::Pattern *, BaseType *>> &get_params () const
+ {
+ return params;
+ }
+
+ std::pair<HIR::Pattern *, BaseType *> ¶m_at (size_t idx)
+ {
+ return params.at (idx);
+ }
+
+ const std::pair<HIR::Pattern *, BaseType *> ¶m_at (size_t idx) const
+ {
+ return params.at (idx);
+ }
+
+ BaseType *get_return_type () const { return type; }
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool needs_generic_substitutions () const override final
+ {
+ return needs_substitution ();
+ }
+
+ bool supports_substitutions () const override final { return true; }
+
+ bool has_subsititions_defined () const override final
+ {
+ return has_substitutions ();
+ }
+
+ FnType *
+ handle_substitions (SubstitutionArgumentMappings mappings) override final;
+
+ ABI get_abi () const { return abi; }
+
+private:
+ std::vector<std::pair<HIR::Pattern *, BaseType *>> params;
+ BaseType *type;
+ uint8_t flags;
+ std::string identifier;
+ DefId id;
+ ABI abi;
+};
+
+class FnPtr : public BaseType
+{
+public:
+ FnPtr (HirId ref, Location locus, std::vector<TyVar> params,
+ TyVar result_type, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::FNPTR,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ params (std::move (params)), result_type (result_type)
+ {}
+
+ FnPtr (HirId ref, HirId ty_ref, Location locus, std::vector<TyVar> params,
+ TyVar result_type, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::FNPTR,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ params (params), result_type (result_type)
+ {}
+
+ std::string get_name () const override final { return as_string (); }
+
+ BaseType *get_return_type () const { return result_type.get_tyty (); }
+
+ size_t num_params () const { return params.size (); }
+
+ BaseType *param_at (size_t idx) const { return params.at (idx).get_tyty (); }
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ void iterate_params (std::function<bool (BaseType *)> cb) const
+ {
+ for (auto &p : params)
+ {
+ if (!cb (p.get_tyty ()))
+ return;
+ }
+ }
+
+ std::vector<TyVar> &get_params () { return params; }
+ const std::vector<TyVar> &get_params () const { return params; }
+
+ bool is_concrete () const override final
+ {
+ for (auto &p : params)
+ {
+ if (!p.get_tyty ()->is_concrete ())
+ return false;
+ }
+ return result_type.get_tyty ()->is_concrete ();
+ }
+
+private:
+ std::vector<TyVar> params;
+ TyVar result_type;
+};
+
+class ClosureType : public BaseType, public SubstitutionRef
+{
+public:
+ ClosureType (HirId ref, DefId id, RustIdent ident,
+ std::vector<TyVar> parameter_types, TyVar result_type,
+ std::vector<SubstitutionParamMapping> subst_refs,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::CLOSURE, ident, refs),
+ SubstitutionRef (std::move (subst_refs),
+ SubstitutionArgumentMappings::error ()),
+ parameter_types (std::move (parameter_types)),
+ result_type (std::move (result_type)), id (id)
+ {
+ LocalDefId local_def_id = id.localDefId;
+ rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID);
+ }
+
+ ClosureType (HirId ref, HirId ty_ref, RustIdent ident, DefId id,
+ std::vector<TyVar> parameter_types, TyVar result_type,
+ std::vector<SubstitutionParamMapping> subst_refs,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::CLOSURE, ident, refs),
+ SubstitutionRef (std::move (subst_refs),
+ SubstitutionArgumentMappings::error ()),
+ parameter_types (std::move (parameter_types)),
+ result_type (std::move (result_type)), id (id)
+ {
+ LocalDefId local_def_id = id.localDefId;
+ rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID);
+ }
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_concrete () const override final
+ {
+ for (auto ¶m : parameter_types)
+ {
+ auto p = param.get_tyty ();
+ if (!p->is_concrete ())
+ return false;
+ }
+ return result_type.get_tyty ()->is_concrete ();
+ }
+
+ bool needs_generic_substitutions () const override final
+ {
+ return needs_substitution ();
+ }
+
+ bool supports_substitutions () const override final { return true; }
+
+ bool has_subsititions_defined () const override final
+ {
+ return has_substitutions ();
+ }
+
+ ClosureType *
+ handle_substitions (SubstitutionArgumentMappings mappings) override final;
+
+private:
+ std::vector<TyVar> parameter_types;
+ TyVar result_type;
+ DefId id;
+};
+
+class ArrayType : public BaseType
+{
+public:
+ ArrayType (HirId ref, Location locus, HIR::Expr &capacity_expr, TyVar base,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::ARRAY,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ element_type (base), capacity_expr (capacity_expr)
+ {}
+
+ ArrayType (HirId ref, HirId ty_ref, Location locus, HIR::Expr &capacity_expr,
+ TyVar base, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::ARRAY,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ element_type (base), capacity_expr (capacity_expr)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *get_element_type () const;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_concrete () const final override
+ {
+ return get_element_type ()->is_concrete ();
+ }
+
+ HIR::Expr &get_capacity_expr () const { return capacity_expr; }
+
+ ArrayType *handle_substitions (SubstitutionArgumentMappings mappings);
+
+private:
+ TyVar element_type;
+ HIR::Expr &capacity_expr;
+};
+
+class SliceType : public BaseType
+{
+public:
+ SliceType (HirId ref, Location locus, TyVar base,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::SLICE,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ element_type (base)
+ {}
+
+ SliceType (HirId ref, HirId ty_ref, Location locus, TyVar base,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::SLICE,
+ {Resolver::CanonicalPath::create_empty (), locus}, refs),
+ element_type (base)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *get_element_type () const;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_concrete () const final override
+ {
+ return get_element_type ()->is_concrete ();
+ }
+
+ SliceType *handle_substitions (SubstitutionArgumentMappings mappings);
+
+private:
+ TyVar element_type;
+};
+
+class BoolType : public BaseType
+{
+public:
+ BoolType (HirId ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::BOOL,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ BoolType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::BOOL,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+ bool is_concrete () const override final { return true; }
+};
+
+class IntType : public BaseType
+{
+public:
+ enum IntKind
+ {
+ I8,
+ I16,
+ I32,
+ I64,
+ I128
+ };
+
+ IntType (HirId ref, IntKind kind, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::INT,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ int_kind (kind)
+ {}
+
+ IntType (HirId ref, HirId ty_ref, IntKind kind,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::INT,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ int_kind (kind)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ IntKind get_int_kind () const { return int_kind; }
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_equal (const BaseType &other) const override;
+ bool is_concrete () const override final { return true; }
+
+private:
+ IntKind int_kind;
+};
+
+class UintType : public BaseType
+{
+public:
+ enum UintKind
+ {
+ U8,
+ U16,
+ U32,
+ U64,
+ U128
+ };
+
+ UintType (HirId ref, UintKind kind, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::UINT,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ uint_kind (kind)
+ {}
+
+ UintType (HirId ref, HirId ty_ref, UintKind kind,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::UINT,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ uint_kind (kind)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ UintKind get_uint_kind () const { return uint_kind; }
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_equal (const BaseType &other) const override;
+ bool is_concrete () const override final { return true; }
+
+private:
+ UintKind uint_kind;
+};
+
+class FloatType : public BaseType
+{
+public:
+ enum FloatKind
+ {
+ F32,
+ F64
+ };
+
+ FloatType (HirId ref, FloatKind kind,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::FLOAT,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ float_kind (kind)
+ {}
+
+ FloatType (HirId ref, HirId ty_ref, FloatKind kind,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::FLOAT,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ float_kind (kind)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ FloatKind get_float_kind () const { return float_kind; }
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_equal (const BaseType &other) const override;
+ bool is_concrete () const override final { return true; }
+
+private:
+ FloatKind float_kind;
+};
+
+class USizeType : public BaseType
+{
+public:
+ USizeType (HirId ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::USIZE,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ USizeType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::USIZE,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+ bool is_concrete () const override final { return true; }
+};
+
+class ISizeType : public BaseType
+{
+public:
+ ISizeType (HirId ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::ISIZE,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ ISizeType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::ISIZE,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+ bool is_concrete () const override final { return true; }
+};
+
+class CharType : public BaseType
+{
+public:
+ CharType (HirId ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::CHAR,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ CharType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::CHAR,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+ bool is_concrete () const override final { return true; }
+};
+
+class StrType : public BaseType
+{
+public:
+ StrType (HirId ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::STR,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ StrType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::STR,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ std::string get_name () const override final { return as_string (); }
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+ bool is_concrete () const override final { return true; }
+};
+
+class ReferenceType : public BaseType
+{
+public:
+ ReferenceType (HirId ref, TyVar base, Mutability mut,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::REF,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ base (base), mut (mut)
+ {}
+
+ ReferenceType (HirId ref, HirId ty_ref, TyVar base, Mutability mut,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::REF,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ base (base), mut (mut)
+ {}
+
+ BaseType *get_base () const;
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ std::string as_string () const override;
+
+ std::string get_name () const override final
+ {
+ return "&" + get_base ()->get_name ();
+ }
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_concrete () const override final
+ {
+ return get_base ()->is_concrete ();
+ }
+
+ ReferenceType *handle_substitions (SubstitutionArgumentMappings mappings);
+
+ Mutability mutability () const { return mut; }
+
+ bool is_mutable () const { return mut == Mutability::Mut; }
+
+ bool is_dyn_object () const
+ {
+ return is_dyn_slice_type () || is_dyn_str_type ();
+ }
+
+ bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const
+ {
+ const TyTy::BaseType *element = get_base ()->destructure ();
+ if (element->get_kind () != TyTy::TypeKind::SLICE)
+ return false;
+ if (slice == nullptr)
+ return true;
+
+ *slice = static_cast<const TyTy::SliceType *> (element);
+ return true;
+ }
+
+ bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const
+ {
+ const TyTy::BaseType *element = get_base ()->destructure ();
+ if (element->get_kind () != TyTy::TypeKind::STR)
+ return false;
+ if (str == nullptr)
+ return true;
+
+ *str = static_cast<const TyTy::StrType *> (element);
+ return true;
+ }
+
+private:
+ TyVar base;
+ Mutability mut;
+};
+
+class PointerType : public BaseType
+{
+public:
+ PointerType (HirId ref, TyVar base, Mutability mut,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::POINTER,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ base (base), mut (mut)
+ {}
+
+ PointerType (HirId ref, HirId ty_ref, TyVar base, Mutability mut,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::POINTER,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ base (base), mut (mut)
+ {}
+
+ BaseType *get_base () const;
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ std::string as_string () const override;
+
+ std::string get_name () const override final
+ {
+ return "*" + get_base ()->get_name ();
+ }
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ bool is_concrete () const override final
+ {
+ return get_base ()->is_concrete ();
+ }
+
+ PointerType *handle_substitions (SubstitutionArgumentMappings mappings);
+
+ Mutability mutability () const { return mut; }
+
+ bool is_mutable () const { return mut == Mutability::Mut; }
+
+ bool is_const () const { return mut == Mutability::Imm; }
+
+ bool is_dyn_object () const
+ {
+ return is_dyn_slice_type () || is_dyn_str_type ();
+ }
+
+ bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const
+ {
+ const TyTy::BaseType *element = get_base ()->destructure ();
+ if (element->get_kind () != TyTy::TypeKind::SLICE)
+ return false;
+ if (slice == nullptr)
+ return true;
+
+ *slice = static_cast<const TyTy::SliceType *> (element);
+ return true;
+ }
+
+ bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const
+ {
+ const TyTy::BaseType *element = get_base ()->destructure ();
+ if (element->get_kind () != TyTy::TypeKind::STR)
+ return false;
+ if (str == nullptr)
+ return true;
+
+ *str = static_cast<const TyTy::StrType *> (element);
+ return true;
+ }
+
+private:
+ TyVar base;
+ Mutability mut;
+};
+
+// https://doc.rust-lang.org/std/primitive.never.html
+//
+// Since the `!` type is really complicated and it is even still unstable
+// in rustc, only fairly limited support for this type is introduced here.
+// Unification between `!` and ANY other type (including `<T?>`) is simply
+// not allowed. If it is needed, it should be handled manually. For example,
+// unifying `!` with other types is very necessary when resolving types of
+// `if/else` expressions.
+//
+// See related discussion at https://github.com/Rust-GCC/gccrs/pull/364
+class NeverType : public BaseType
+{
+public:
+ NeverType (HirId ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::NEVER,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ NeverType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::NEVER,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+ BaseType *monomorphized_clone () const final override;
+
+ std::string get_name () const override final { return as_string (); }
+
+ bool is_unit () const override { return true; }
+ bool is_concrete () const override final { return true; }
+};
+
+// used at the type in associated types in traits
+// see: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+class PlaceholderType : public BaseType
+{
+public:
+ PlaceholderType (std::string symbol, HirId ref,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::PLACEHOLDER,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ symbol (symbol)
+ {}
+
+ PlaceholderType (std::string symbol, HirId ref, HirId ty_ref,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::PLACEHOLDER,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ symbol (symbol)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+ BaseType *monomorphized_clone () const final override;
+
+ std::string get_name () const override final { return as_string (); }
+
+ bool is_unit () const override
+ {
+ rust_assert (can_resolve ());
+ return resolve ()->is_unit ();
+ }
+
+ std::string get_symbol () const { return symbol; }
+
+ void set_associated_type (HirId ref);
+
+ void clear_associated_type ();
+
+ bool can_resolve () const;
+
+ BaseType *resolve () const;
+
+ bool is_equal (const BaseType &other) const override;
+
+ bool is_concrete () const override final
+ {
+ if (!can_resolve ())
+ return true;
+
+ return resolve ()->is_concrete ();
+ }
+
+private:
+ std::string symbol;
+};
+
+class ProjectionType : public BaseType, public SubstitutionRef
+{
+public:
+ ProjectionType (HirId ref, BaseType *base,
+ const Resolver::TraitReference *trait, DefId item,
+ std::vector<SubstitutionParamMapping> subst_refs,
+ SubstitutionArgumentMappings generic_arguments
+ = SubstitutionArgumentMappings::error (),
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::PROJECTION,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
+ base (base), trait (trait), item (item)
+ {}
+
+ ProjectionType (HirId ref, HirId ty_ref, BaseType *base,
+ const Resolver::TraitReference *trait, DefId item,
+ std::vector<SubstitutionParamMapping> subst_refs,
+ SubstitutionArgumentMappings generic_arguments
+ = SubstitutionArgumentMappings::error (),
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::PROJECTION,
+ {Resolver::CanonicalPath::create_empty (),
+ Linemap::predeclared_location ()},
+ refs),
+ SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
+ base (base), trait (trait), item (item)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+ BaseType *monomorphized_clone () const final override;
+
+ std::string get_name () const override final { return as_string (); }
+
+ bool is_unit () const override { return false; }
+
+ bool needs_generic_substitutions () const override final
+ {
+ return needs_substitution ();
+ }
+
+ bool supports_substitutions () const override final { return true; }
+
+ bool has_subsititions_defined () const override final
+ {
+ return has_substitutions ();
+ }
+
+ const BaseType *get () const { return base; }
+ BaseType *get () { return base; }
+
+ bool is_concrete () const override final { return base->is_concrete (); }
+
+ ProjectionType *
+ handle_substitions (SubstitutionArgumentMappings mappings) override final;
+
+private:
+ BaseType *base;
+ const Resolver::TraitReference *trait;
+ DefId item;
+};
+
+class DynamicObjectType : public BaseType
+{
+public:
+ DynamicObjectType (HirId ref, RustIdent ident,
+ std::vector<TypeBoundPredicate> specified_bounds,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ref, TypeKind::DYNAMIC, ident, specified_bounds, refs)
+ {}
+
+ DynamicObjectType (HirId ref, HirId ty_ref, RustIdent ident,
+ std::vector<TypeBoundPredicate> specified_bounds,
+ std::set<HirId> refs = std::set<HirId> ())
+ : BaseType (ref, ty_ref, TypeKind::DYNAMIC, ident, specified_bounds, refs)
+ {}
+
+ void accept_vis (TyVisitor &vis) override;
+ void accept_vis (TyConstVisitor &vis) const override;
+
+ 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;
+
+ BaseType *clone () const final override;
+ BaseType *monomorphized_clone () const final override;
+
+ std::string get_name () const override final;
+
+ bool is_concrete () const override final { return true; }
+
+ // this returns a flat list of items including super trait bounds
+ const std::vector<
+ std::pair<const Resolver::TraitItemReference *, const TypeBoundPredicate *>>
+ get_object_items () const;
+};
+
+} // namespace TyTy
+} // namespace Rust
+
+#endif // RUST_TYTY
--
2.25.1
next prev parent reply other threads:[~2022-08-24 12:01 UTC|newest]
Thread overview: 59+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-24 11:59 Rust frontend patches v2 herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 01/37] Use DW_ATE_UTF for the Rust 'char' type herron.philip
2022-08-24 14:28 ` Jason Merrill
2022-08-24 11:59 ` [PATCH Rust front-end v2 02/37] gccrs: Add nessecary hooks for a Rust front-end testsuite herron.philip
2022-09-10 4:05 ` Mike Stump
2022-08-24 11:59 ` [PATCH Rust front-end v2 03/37] gccrs: Add Debug info testsuite herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 04/37] gccrs: Add link cases testsuite herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 05/37] gccrs: Add general compilation test cases herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 06/37] gccrs: Add execution " herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 07/37] gccrs: Add gcc-check-target check-rust herron.philip
2022-09-14 13:41 ` Richard Biener
2022-09-14 14:04 ` Jakub Jelinek
2022-08-24 11:59 ` [PATCH Rust front-end v2 08/37] gccrs: Add the Rust front-end AST data structures herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 09/37] gccrs: Add Lexer for Rust front-end herron.philip
2022-09-14 13:30 ` Richard Biener
2022-09-14 13:39 ` Jakub Jelinek
2022-08-24 11:59 ` [PATCH Rust front-end v2 10/37] gccrs: Add Parser " herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 11/37] gccrs: Add expansion pass for the " herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 12/37] gccrs: Add name resolution pass to " herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 13/37] gccrs: Add second intermedite representation called HIR herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 14/37] gccrs: Add AST to HIR lowering pass herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 15/37] gccrs: Add wrapper for make_unique herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 16/37] gccrs: Add port of FNV hash used during legacy symbol mangling herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 17/37] gccrs: Add Rust ABI enum helpers herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 18/37] gccrs: Add Base62 implementation herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 19/37] gccrs: Add implementation of Optional herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 20/37] gccrs: Add attributes checker herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 21/37] gccrs: Add helpers mappings canonical path and lang items herron.philip
2022-08-24 11:59 ` herron.philip [this message]
2022-08-24 11:59 ` [PATCH Rust front-end v2 23/37] gccrs: Add unsafe checks for Rust herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 24/37] gccrs: Add const checker herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 25/37] gccrs: Add privacy checks herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 26/37] gccrs: Add dead code scan on HIR herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 27/37] gccrs: Add unused variable scan herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 28/37] gccrs: Add metadata ouptput pass herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 29/37] gccrs: HIR to GCC GENERIC lowering herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 30/37] gccrs: These are wrappers ported from reusing gccgo herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 31/37] gccrs: Add GCC Rust front-end Make-lang.in herron.philip
2022-09-14 13:34 ` Richard Biener
2022-12-01 11:05 ` Thomas Schwinge
2022-08-24 11:59 ` [PATCH Rust front-end v2 32/37] gccrs: Add config-lang.in herron.philip
2022-09-14 13:40 ` Richard Biener
2023-02-20 13:33 ` Rust: Don't depend on unused 'target-libffi', 'target-libbacktrace' (was: [PATCH Rust front-end v2 32/37] gccrs: Add config-lang.in) Thomas Schwinge
2022-08-24 11:59 ` [PATCH Rust front-end v2 33/37] gccrs: add lang-spec.h herron.philip
2022-09-14 13:40 ` Richard Biener
2022-10-14 16:33 ` Iain Buclaw
2022-08-24 11:59 ` [PATCH Rust front-end v2 34/37] gccrs: add lang.opt herron.philip
2022-09-14 13:39 ` Richard Biener
2022-09-14 16:20 ` Thomas Schwinge
2022-09-15 6:23 ` Richard Biener
2022-08-24 11:59 ` [PATCH Rust front-end v2 35/37] gccrs: add compiler driver herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 36/37] gccrs: compiler proper interface kicks off the pipeline herron.philip
2022-08-24 11:59 ` [PATCH Rust front-end v2 37/37] gccrs: Add README, CONTRIBUTING and compiler logo herron.philip
2022-08-25 9:46 ` Rust frontend patches v2 Philip Herron
2022-08-25 9:52 ` Martin Liška
2022-08-25 10:18 ` Philip Herron
2022-08-25 12:50 ` Frank Ch. Eigler
2022-08-25 13:44 ` Philip Herron
2022-08-25 11:13 ` Mark Wielaard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220824115956.737931-23-philip.herron@embecosm.com \
--to=herron.philip@googlemail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=gcc-rust@gcc.gnu.org \
--cc=philip.herron@embecosm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).