summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2022-10-21 13:53:14 +0200
committerArthur Cohen <arthur.cohen@embecosm.com>2022-12-13 14:00:06 +0100
commitc6c3db21769e8455f38e0d6ce004c44521aad7bd (patch)
treefc41d0fe02aec8ad82d3ce6b62c3962e77d93972
parent9ce37e720624accb7977ead5d0f25ac2b459c2aa (diff)
gccrs: Add type resolution and trait solving pass
This serves to handle parts of the Rust type-system. Namely, the type resolution (similar to type-checking) and the trait solving algorithms (which ensure Rust's type contracts are upheld throughout the codebase). gcc/rust/ * typecheck/rust-hir-trait-resolve.cc: New. * typecheck/rust-hir-trait-resolve.h: New. * typecheck/rust-hir-type-check-base.cc: New. * typecheck/rust-hir-type-check-base.h: New. * typecheck/rust-hir-type-check-enumitem.cc: New. * typecheck/rust-hir-type-check-enumitem.h: New. * typecheck/rust-hir-type-check-expr.cc: New. * typecheck/rust-hir-type-check-expr.h: New. * typecheck/rust-hir-type-check-implitem.cc: New. * typecheck/rust-hir-type-check-implitem.h: New. * typecheck/rust-hir-type-check-item.cc: New. * typecheck/rust-hir-type-check-item.h: New. * typecheck/rust-hir-type-check-path.cc: New. * typecheck/rust-hir-type-check-pattern.cc: New. * typecheck/rust-hir-type-check-pattern.h: New. * typecheck/rust-hir-type-check-stmt.cc: New. * typecheck/rust-hir-type-check-stmt.h: New. * typecheck/rust-hir-type-check-struct-field.h: New. * typecheck/rust-hir-type-check-struct.cc: New. * typecheck/rust-hir-type-check-toplevel.cc: New. * typecheck/rust-hir-type-check-toplevel.h: New. * typecheck/rust-hir-type-check-type.cc: New. * typecheck/rust-hir-type-check-type.h: New. * typecheck/rust-hir-type-check-util.cc: New. * typecheck/rust-hir-type-check-util.h: New. * typecheck/rust-hir-type-check.cc: New. * typecheck/rust-hir-type-check.h: New. * typecheck/rust-tyty-visitor.h: New.
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.cc599
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.h87
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-base.cc439
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-base.h80
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-enumitem.cc213
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-enumitem.h50
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.cc1567
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h131
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.cc583
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h114
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.cc237
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.h58
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-path.cc467
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-pattern.cc416
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-pattern.h62
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-stmt.cc498
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-stmt.h96
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct-field.h59
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct.cc340
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-toplevel.cc364
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-toplevel.h56
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-type.cc838
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-type.h130
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-util.cc41
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-util.h50
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc295
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.h379
-rw-r--r--gcc/rust/typecheck/rust-tyty-visitor.h88
28 files changed, 8337 insertions, 0 deletions
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-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> &params_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> &params_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 &param : 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 &param : 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 &param : 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 &param : 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 &param : 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 &param)
+{
+ // nothing to do
+}
+
+void
+TypeResolveGenericParam::visit (HIR::ConstGenericParam &param)
+{
+ // TODO
+}
+
+void
+TypeResolveGenericParam::visit (HIR::TypeParam &param)
+{
+ 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 &param);
+ void visit (HIR::LifetimeParam &param);
+ void visit (HIR::ConstGenericParam &param);
+
+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 &param : 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-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