@@ -117,6 +117,7 @@ GRS_OBJS = \
rust/rust-tyty.o \
rust/rust-tyty-util.o \
rust/rust-tyty-call.o \
+ rust/rust-tyty-subst.o \
rust/rust-tyctx.o \
rust/rust-tyty-bounds.o \
rust/rust-hir-type-check-util.o \
new file mode 100644
@@ -0,0 +1,927 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-tyty-subst.h"
+#include "rust-hir-full.h"
+#include "rust-tyty.h"
+#include "rust-hir-type-check.h"
+#include "rust-substitution-mapper.h"
+#include "rust-hir-type-check-type.h"
+
+namespace Rust {
+namespace TyTy {
+
+SubstitutionParamMapping::SubstitutionParamMapping (
+ const HIR::TypeParam &generic, ParamType *param)
+ : generic (generic), param (param)
+{}
+
+SubstitutionParamMapping::SubstitutionParamMapping (
+ const SubstitutionParamMapping &other)
+ : generic (other.generic), param (other.param)
+{}
+
+std::string
+SubstitutionParamMapping::as_string () const
+{
+ if (param == nullptr)
+ return "nullptr";
+
+ return param->get_name ();
+}
+
+SubstitutionParamMapping
+SubstitutionParamMapping::clone () const
+{
+ return SubstitutionParamMapping (generic,
+ static_cast<ParamType *> (param->clone ()));
+}
+
+ParamType *
+SubstitutionParamMapping::get_param_ty ()
+{
+ return param;
+}
+
+const ParamType *
+SubstitutionParamMapping::get_param_ty () const
+{
+ return param;
+}
+
+const HIR::TypeParam &
+SubstitutionParamMapping::get_generic_param ()
+{
+ return generic;
+};
+
+bool
+SubstitutionParamMapping::needs_substitution () const
+{
+ return !(get_param_ty ()->is_concrete ());
+}
+
+Location
+SubstitutionParamMapping::get_param_locus () const
+{
+ return generic.get_locus ();
+}
+
+bool
+SubstitutionParamMapping::param_has_default_ty () const
+{
+ return generic.has_type ();
+}
+
+BaseType *
+SubstitutionParamMapping::get_default_ty () const
+{
+ TyVar var (generic.get_type_mappings ().get_hirid ());
+ return var.get_tyty ();
+}
+
+bool
+SubstitutionParamMapping::need_substitution () const
+{
+ if (!param->can_resolve ())
+ return true;
+
+ auto resolved = param->resolve ();
+ return !resolved->is_concrete ();
+}
+
+bool
+SubstitutionParamMapping::fill_param_ty (
+ SubstitutionArgumentMappings &subst_mappings, Location locus)
+{
+ SubstitutionArg arg = SubstitutionArg::error ();
+ bool ok = subst_mappings.get_argument_for_symbol (get_param_ty (), &arg);
+ if (!ok)
+ return true;
+
+ TyTy::BaseType &type = *arg.get_tyty ();
+ if (type.get_kind () == TyTy::TypeKind::INFER)
+ {
+ type.inherit_bounds (*param);
+ }
+ else
+ {
+ if (!param->bounds_compatible (type, locus, true))
+ return false;
+ }
+
+ if (type.get_kind () == TypeKind::PARAM)
+ {
+ // delete param;
+ param = static_cast<ParamType *> (type.clone ());
+ }
+ else
+ {
+ // check the substitution is compatible with bounds
+ if (!param->bounds_compatible (type, locus, true))
+ return false;
+
+ // recursively pass this down to all HRTB's
+ for (auto &bound : param->get_specified_bounds ())
+ bound.handle_substitions (subst_mappings);
+
+ param->set_ty_ref (type.get_ref ());
+ }
+
+ return true;
+}
+
+void
+SubstitutionParamMapping::override_context ()
+{
+ if (!param->can_resolve ())
+ return;
+
+ auto mappings = Analysis::Mappings::get ();
+ auto context = Resolver::TypeCheckContext::get ();
+
+ context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (),
+ UNKNOWN_NODEID,
+ param->get_ref (),
+ UNKNOWN_LOCAL_DEFID),
+ param->resolve ());
+}
+
+SubstitutionArg::SubstitutionArg (const SubstitutionParamMapping *param,
+ BaseType *argument)
+ : param (param), argument (argument)
+{}
+
+SubstitutionArg::SubstitutionArg (const SubstitutionArg &other)
+ : param (other.param), argument (other.argument)
+{}
+
+SubstitutionArg &
+SubstitutionArg::operator= (const SubstitutionArg &other)
+{
+ param = other.param;
+ argument = other.argument;
+ return *this;
+}
+
+BaseType *
+SubstitutionArg::get_tyty ()
+{
+ return argument;
+}
+
+const BaseType *
+SubstitutionArg::get_tyty () const
+{
+ return argument;
+}
+
+const SubstitutionParamMapping *
+SubstitutionArg::get_param_mapping () const
+{
+ return param;
+}
+
+SubstitutionArg
+SubstitutionArg::error ()
+{
+ return SubstitutionArg (nullptr, nullptr);
+}
+
+bool
+SubstitutionArg::is_error () const
+{
+ return param == nullptr || argument == nullptr;
+}
+
+bool
+SubstitutionArg::is_conrete () const
+{
+ if (argument != nullptr)
+ return true;
+
+ if (argument->get_kind () == TyTy::TypeKind::PARAM)
+ return false;
+
+ return argument->is_concrete ();
+}
+
+std::string
+SubstitutionArg::as_string () const
+{
+ return param->as_string ()
+ + (argument != nullptr ? ":" + argument->as_string () : "");
+}
+
+// SubstitutionArgumentMappings
+
+SubstitutionArgumentMappings::SubstitutionArgumentMappings (
+ std::vector<SubstitutionArg> mappings,
+ std::map<std::string, BaseType *> binding_args, Location locus,
+ ParamSubstCb param_subst_cb, bool trait_item_flag)
+ : mappings (mappings), binding_args (binding_args), locus (locus),
+ param_subst_cb (param_subst_cb), trait_item_flag (trait_item_flag)
+{}
+
+SubstitutionArgumentMappings::SubstitutionArgumentMappings (
+ const SubstitutionArgumentMappings &other)
+ : mappings (other.mappings), binding_args (other.binding_args),
+ locus (other.locus), param_subst_cb (other.param_subst_cb),
+ trait_item_flag (other.trait_item_flag)
+{}
+
+SubstitutionArgumentMappings &
+SubstitutionArgumentMappings::operator= (
+ const SubstitutionArgumentMappings &other)
+{
+ mappings = other.mappings;
+ binding_args = other.binding_args;
+ locus = other.locus;
+ param_subst_cb = other.param_subst_cb;
+ trait_item_flag = other.trait_item_flag;
+
+ return *this;
+}
+
+SubstitutionArgumentMappings
+SubstitutionArgumentMappings::error ()
+{
+ return SubstitutionArgumentMappings ({}, {}, Location (), nullptr, false);
+}
+
+bool
+SubstitutionArgumentMappings::is_error () const
+{
+ return mappings.size () == 0;
+}
+
+bool
+SubstitutionArgumentMappings::get_argument_for_symbol (
+ const ParamType *param_to_find, SubstitutionArg *argument)
+{
+ for (auto &mapping : mappings)
+ {
+ const SubstitutionParamMapping *param = mapping.get_param_mapping ();
+ const ParamType *p = param->get_param_ty ();
+
+ if (p->get_symbol ().compare (param_to_find->get_symbol ()) == 0)
+ {
+ *argument = mapping;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+SubstitutionArgumentMappings::get_argument_at (size_t index,
+ SubstitutionArg *argument)
+{
+ if (index > mappings.size ())
+ return false;
+
+ *argument = mappings.at (index);
+ return true;
+}
+
+bool
+SubstitutionArgumentMappings::is_concrete () const
+{
+ for (auto &mapping : mappings)
+ {
+ if (!mapping.is_conrete ())
+ return false;
+ }
+ return true;
+}
+
+Location
+SubstitutionArgumentMappings::get_locus () const
+{
+ return locus;
+}
+
+size_t
+SubstitutionArgumentMappings::size () const
+{
+ return mappings.size ();
+}
+
+bool
+SubstitutionArgumentMappings::is_empty () const
+{
+ return size () == 0;
+}
+
+std::vector<SubstitutionArg> &
+SubstitutionArgumentMappings::get_mappings ()
+{
+ return mappings;
+}
+
+const std::vector<SubstitutionArg> &
+SubstitutionArgumentMappings::get_mappings () const
+{
+ return mappings;
+}
+
+std::map<std::string, BaseType *> &
+SubstitutionArgumentMappings::get_binding_args ()
+{
+ return binding_args;
+}
+
+const std::map<std::string, BaseType *> &
+SubstitutionArgumentMappings::get_binding_args () const
+{
+ return binding_args;
+}
+
+std::string
+SubstitutionArgumentMappings::as_string () const
+{
+ std::string buffer;
+ for (auto &mapping : mappings)
+ {
+ buffer += mapping.as_string () + ", ";
+ }
+ return "<" + buffer + ">";
+}
+
+void
+SubstitutionArgumentMappings::on_param_subst (const ParamType &p,
+ const SubstitutionArg &a) const
+{
+ if (param_subst_cb == nullptr)
+ return;
+
+ param_subst_cb (p, a);
+}
+
+ParamSubstCb
+SubstitutionArgumentMappings::get_subst_cb () const
+{
+ return param_subst_cb;
+}
+
+bool
+SubstitutionArgumentMappings::trait_item_mode () const
+{
+ return trait_item_flag;
+}
+
+// SubstitutionRef
+
+SubstitutionRef::SubstitutionRef (
+ std::vector<SubstitutionParamMapping> substitutions,
+ SubstitutionArgumentMappings arguments)
+ : substitutions (substitutions), used_arguments (arguments)
+{}
+
+bool
+SubstitutionRef::has_substitutions () const
+{
+ return substitutions.size () > 0;
+}
+
+std::string
+SubstitutionRef::subst_as_string () const
+{
+ std::string buffer;
+ for (size_t i = 0; i < substitutions.size (); i++)
+ {
+ const SubstitutionParamMapping &sub = substitutions.at (i);
+ buffer += sub.as_string ();
+
+ if ((i + 1) < substitutions.size ())
+ buffer += ", ";
+ }
+
+ return buffer.empty () ? "" : "<" + buffer + ">";
+}
+
+bool
+SubstitutionRef::supports_associated_bindings () const
+{
+ return get_num_associated_bindings () > 0;
+}
+
+size_t
+SubstitutionRef::get_num_associated_bindings () const
+{
+ return 0;
+}
+
+TypeBoundPredicateItem
+SubstitutionRef::lookup_associated_type (const std::string &search)
+{
+ return TypeBoundPredicateItem::error ();
+}
+
+size_t
+SubstitutionRef::get_num_substitutions () const
+{
+ return substitutions.size ();
+}
+
+std::vector<SubstitutionParamMapping> &
+SubstitutionRef::get_substs ()
+{
+ return substitutions;
+}
+
+const std::vector<SubstitutionParamMapping> &
+SubstitutionRef::get_substs () const
+{
+ return substitutions;
+}
+
+std::vector<SubstitutionParamMapping>
+SubstitutionRef::clone_substs () const
+{
+ std::vector<SubstitutionParamMapping> clone;
+
+ for (auto &sub : substitutions)
+ clone.push_back (sub.clone ());
+
+ return clone;
+}
+
+void
+SubstitutionRef::override_context ()
+{
+ for (auto &sub : substitutions)
+ {
+ sub.override_context ();
+ }
+}
+
+bool
+SubstitutionRef::needs_substitution () const
+{
+ for (auto &sub : substitutions)
+ {
+ if (sub.need_substitution ())
+ return true;
+ }
+ return false;
+}
+
+bool
+SubstitutionRef::was_substituted () const
+{
+ return !needs_substitution ();
+}
+
+SubstitutionArgumentMappings
+SubstitutionRef::get_substitution_arguments () const
+{
+ return used_arguments;
+}
+
+size_t
+SubstitutionRef::num_required_substitutions () const
+{
+ size_t n = 0;
+ for (auto &p : substitutions)
+ {
+ if (p.needs_substitution ())
+ n++;
+ }
+ return n;
+}
+
+size_t
+SubstitutionRef::min_required_substitutions () const
+{
+ size_t n = 0;
+ for (auto &p : substitutions)
+ {
+ if (p.needs_substitution () && !p.param_has_default_ty ())
+ n++;
+ }
+ return n;
+}
+
+SubstitutionArgumentMappings
+SubstitutionRef::get_used_arguments () const
+{
+ return used_arguments;
+}
+
+SubstitutionArgumentMappings
+SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args)
+{
+ std::map<std::string, BaseType *> binding_arguments;
+ if (args.get_binding_args ().size () > 0)
+ {
+ if (supports_associated_bindings ())
+ {
+ if (args.get_binding_args ().size () > get_num_associated_bindings ())
+ {
+ RichLocation r (args.get_locus ());
+
+ rust_error_at (r,
+ "generic item takes at most %lu type binding "
+ "arguments but %lu were supplied",
+ (unsigned long) get_num_associated_bindings (),
+ (unsigned long) args.get_binding_args ().size ());
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ for (auto &binding : args.get_binding_args ())
+ {
+ BaseType *resolved
+ = Resolver::TypeCheckType::Resolve (binding.get_type ().get ());
+ if (resolved == nullptr
+ || resolved->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (binding.get_locus (),
+ "failed to resolve type arguments");
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ // resolve to relevant binding
+ auto binding_item
+ = lookup_associated_type (binding.get_identifier ());
+ if (binding_item.is_error ())
+ {
+ rust_error_at (binding.get_locus (),
+ "unknown associated type binding: %s",
+ binding.get_identifier ().c_str ());
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ binding_arguments[binding.get_identifier ()] = resolved;
+ }
+ }
+ else
+ {
+ RichLocation r (args.get_locus ());
+ for (auto &binding : args.get_binding_args ())
+ r.add_range (binding.get_locus ());
+
+ rust_error_at (r, "associated type bindings are not allowed here");
+ return SubstitutionArgumentMappings::error ();
+ }
+ }
+
+ // for inherited arguments
+ size_t offs = used_arguments.size ();
+ if (args.get_type_args ().size () + offs > substitutions.size ())
+ {
+ RichLocation r (args.get_locus ());
+ r.add_range (substitutions.front ().get_param_locus ());
+
+ rust_error_at (
+ r,
+ "generic item takes at most %lu type arguments but %lu were supplied",
+ (unsigned long) substitutions.size (),
+ (unsigned long) args.get_type_args ().size ());
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ if (args.get_type_args ().size () + offs < min_required_substitutions ())
+ {
+ RichLocation r (args.get_locus ());
+ r.add_range (substitutions.front ().get_param_locus ());
+
+ rust_error_at (
+ r,
+ "generic item takes at least %lu type arguments but %lu were supplied",
+ (unsigned long) (min_required_substitutions () - offs),
+ (unsigned long) args.get_type_args ().size ());
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ std::vector<SubstitutionArg> mappings = used_arguments.get_mappings ();
+ for (auto &arg : args.get_type_args ())
+ {
+ BaseType *resolved = Resolver::TypeCheckType::Resolve (arg.get ());
+ if (resolved == nullptr || resolved->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ rust_error_at (args.get_locus (), "failed to resolve type arguments");
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ SubstitutionArg subst_arg (&substitutions.at (offs), resolved);
+ offs++;
+ mappings.push_back (std::move (subst_arg));
+ }
+
+ // we must need to fill out defaults
+ size_t left_over
+ = num_required_substitutions () - min_required_substitutions ();
+ if (left_over > 0)
+ {
+ for (size_t offs = mappings.size (); offs < substitutions.size (); offs++)
+ {
+ SubstitutionParamMapping ¶m = substitutions.at (offs);
+ rust_assert (param.param_has_default_ty ());
+
+ BaseType *resolved = param.get_default_ty ();
+ if (resolved->get_kind () == TypeKind::ERROR)
+ return SubstitutionArgumentMappings::error ();
+
+ // this resolved default might already contain default parameters
+ if (resolved->contains_type_parameters ())
+ {
+ SubstitutionArgumentMappings intermediate (mappings,
+ binding_arguments,
+ args.get_locus ());
+ resolved = Resolver::SubstMapperInternal::Resolve (resolved,
+ intermediate);
+
+ if (resolved->get_kind () == TypeKind::ERROR)
+ return SubstitutionArgumentMappings::error ();
+ }
+
+ SubstitutionArg subst_arg (¶m, resolved);
+ mappings.push_back (std::move (subst_arg));
+ }
+ }
+
+ return SubstitutionArgumentMappings (mappings, binding_arguments,
+ args.get_locus ());
+}
+
+BaseType *
+SubstitutionRef::infer_substitions (Location locus)
+{
+ std::vector<SubstitutionArg> args;
+ std::map<std::string, BaseType *> argument_mappings;
+ for (auto &p : get_substs ())
+ {
+ if (p.needs_substitution ())
+ {
+ const std::string &symbol = p.get_param_ty ()->get_symbol ();
+ auto it = argument_mappings.find (symbol);
+ bool have_mapping = it != argument_mappings.end ();
+
+ if (have_mapping)
+ {
+ args.push_back (SubstitutionArg (&p, it->second));
+ }
+ else
+ {
+ TyVar infer_var = TyVar::get_implicit_infer_var (locus);
+ args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
+ argument_mappings[symbol] = infer_var.get_tyty ();
+ }
+ }
+ else
+ {
+ args.push_back (SubstitutionArg (&p, p.get_param_ty ()->resolve ()));
+ }
+ }
+
+ // FIXME do we need to add inference variables to all the possible bindings?
+ // it might just lead to inference variable hell not 100% sure if rustc does
+ // this i think the language might needs this to be explicitly set
+
+ SubstitutionArgumentMappings infer_arguments (std::move (args),
+ {} /* binding_arguments */,
+ locus);
+ return handle_substitions (std::move (infer_arguments));
+}
+
+SubstitutionArgumentMappings
+SubstitutionRef::adjust_mappings_for_this (
+ SubstitutionArgumentMappings &mappings)
+{
+ std::vector<SubstitutionArg> resolved_mappings;
+ for (size_t i = 0; i < substitutions.size (); i++)
+ {
+ auto &subst = substitutions.at (i);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ if (mappings.size () == substitutions.size ())
+ {
+ mappings.get_argument_at (i, &arg);
+ }
+ else
+ {
+ if (subst.needs_substitution ())
+ {
+ // get from passed in mappings
+ mappings.get_argument_for_symbol (subst.get_param_ty (), &arg);
+ }
+ else
+ {
+ // we should already have this somewhere
+ used_arguments.get_argument_for_symbol (subst.get_param_ty (),
+ &arg);
+ }
+ }
+
+ bool ok = !arg.is_error ();
+ if (ok)
+ {
+ SubstitutionArg adjusted (&subst, arg.get_tyty ());
+ resolved_mappings.push_back (std::move (adjusted));
+ }
+ }
+
+ if (resolved_mappings.empty ())
+ return SubstitutionArgumentMappings::error ();
+
+ return SubstitutionArgumentMappings (resolved_mappings,
+ mappings.get_binding_args (),
+ mappings.get_locus (),
+ mappings.get_subst_cb (),
+ mappings.trait_item_mode ());
+}
+
+bool
+SubstitutionRef::are_mappings_bound (SubstitutionArgumentMappings &mappings)
+{
+ std::vector<SubstitutionArg> resolved_mappings;
+ for (size_t i = 0; i < substitutions.size (); i++)
+ {
+ auto &subst = substitutions.at (i);
+
+ SubstitutionArg arg = SubstitutionArg::error ();
+ if (mappings.size () == substitutions.size ())
+ {
+ mappings.get_argument_at (i, &arg);
+ }
+ else
+ {
+ if (subst.needs_substitution ())
+ {
+ // get from passed in mappings
+ mappings.get_argument_for_symbol (subst.get_param_ty (), &arg);
+ }
+ else
+ {
+ // we should already have this somewhere
+ used_arguments.get_argument_for_symbol (subst.get_param_ty (),
+ &arg);
+ }
+ }
+
+ bool ok = !arg.is_error ();
+ if (ok)
+ {
+ SubstitutionArg adjusted (&subst, arg.get_tyty ());
+ resolved_mappings.push_back (std::move (adjusted));
+ }
+ }
+
+ return !resolved_mappings.empty ();
+}
+
+// this function assumes that the mappings being passed are for the same type as
+// this new substitution reference so ordering matters here
+SubstitutionArgumentMappings
+SubstitutionRef::solve_mappings_from_receiver_for_self (
+ SubstitutionArgumentMappings &mappings) const
+{
+ std::vector<SubstitutionArg> resolved_mappings;
+
+ rust_assert (mappings.size () == get_num_substitutions ());
+ for (size_t i = 0; i < get_num_substitutions (); i++)
+ {
+ const SubstitutionParamMapping ¶m_mapping = substitutions.at (i);
+ SubstitutionArg &arg = mappings.get_mappings ().at (i);
+
+ if (param_mapping.needs_substitution ())
+ {
+ SubstitutionArg adjusted (¶m_mapping, arg.get_tyty ());
+ resolved_mappings.push_back (std::move (adjusted));
+ }
+ }
+
+ return SubstitutionArgumentMappings (resolved_mappings,
+ mappings.get_binding_args (),
+ mappings.get_locus ());
+}
+
+SubstitutionArgumentMappings
+SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref,
+ SubstitutionRef &to)
+{
+ rust_assert (!ref.needs_substitution ());
+ rust_assert (needs_substitution ());
+ rust_assert (get_num_substitutions () == ref.get_num_substitutions ());
+
+ Location locus = used_arguments.get_locus ();
+ std::vector<SubstitutionArg> resolved_mappings;
+
+ std::map<HirId, std::pair<ParamType *, BaseType *>> substs;
+ for (size_t i = 0; i < get_num_substitutions (); i++)
+ {
+ SubstitutionParamMapping &a = substitutions.at (i);
+ SubstitutionParamMapping &b = ref.substitutions.at (i);
+
+ if (a.need_substitution ())
+ {
+ const BaseType *root = a.get_param_ty ()->resolve ()->get_root ();
+ rust_assert (root->get_kind () == TyTy::TypeKind::PARAM);
+ const ParamType *p = static_cast<const TyTy::ParamType *> (root);
+
+ substs[p->get_ty_ref ()] = {static_cast<ParamType *> (p->clone ()),
+ b.get_param_ty ()->resolve ()};
+ }
+ }
+
+ for (auto it = substs.begin (); it != substs.end (); it++)
+ {
+ HirId param_id = it->first;
+ BaseType *arg = it->second.second;
+
+ const SubstitutionParamMapping *associate_param = nullptr;
+ for (SubstitutionParamMapping &p : to.substitutions)
+ {
+ if (p.get_param_ty ()->get_ty_ref () == param_id)
+ {
+ associate_param = &p;
+ break;
+ }
+ }
+
+ rust_assert (associate_param != nullptr);
+ SubstitutionArg argument (associate_param, arg);
+ resolved_mappings.push_back (std::move (argument));
+ }
+
+ return SubstitutionArgumentMappings (resolved_mappings, {}, locus);
+}
+
+bool
+SubstitutionRef::monomorphize ()
+{
+ auto context = Resolver::TypeCheckContext::get ();
+ for (const auto &subst : get_substs ())
+ {
+ const TyTy::ParamType *pty = subst.get_param_ty ();
+
+ if (!pty->can_resolve ())
+ continue;
+
+ const TyTy::BaseType *binding = pty->resolve ();
+ if (binding->get_kind () == TyTy::TypeKind::PARAM)
+ continue;
+
+ for (const auto &bound : pty->get_specified_bounds ())
+ {
+ const Resolver::TraitReference *specified_bound_ref = bound.get ();
+
+ // setup any associated type mappings for the specified bonds and this
+ // type
+ auto candidates = Resolver::TypeBoundsProbe::Probe (binding);
+
+ Resolver::AssociatedImplTrait *associated_impl_trait = nullptr;
+ for (auto &probed_bound : candidates)
+ {
+ const Resolver::TraitReference *bound_trait_ref
+ = probed_bound.first;
+ const HIR::ImplBlock *associated_impl = probed_bound.second;
+
+ HirId impl_block_id
+ = associated_impl->get_mappings ().get_hirid ();
+ Resolver::AssociatedImplTrait *associated = nullptr;
+ bool found_impl_trait
+ = context->lookup_associated_trait_impl (impl_block_id,
+ &associated);
+ if (found_impl_trait)
+ {
+ bool found_trait
+ = specified_bound_ref->is_equal (*bound_trait_ref);
+ bool found_self
+ = associated->get_self ()->can_eq (binding, false);
+ if (found_trait && found_self)
+ {
+ associated_impl_trait = associated;
+ break;
+ }
+ }
+ }
+
+ if (associated_impl_trait != nullptr)
+ {
+ associated_impl_trait->setup_associated_types (binding, bound);
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace TyTy
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,316 @@
+// 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_SUBST_H
+#define RUST_TYTY_SUBST_H
+
+#include "rust-system.h"
+#include "rust-location.h"
+#include "rust-hir-full-decls.h"
+#include "rust-tyty-bounds.h"
+
+namespace Rust {
+namespace TyTy {
+
+class BaseType;
+class ParamType;
+class SubstitutionArgumentMappings;
+class SubstitutionParamMapping
+{
+public:
+ SubstitutionParamMapping (const HIR::TypeParam &generic, ParamType *param);
+
+ SubstitutionParamMapping (const SubstitutionParamMapping &other);
+
+ std::string as_string () const;
+
+ bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings,
+ Location locus);
+
+ SubstitutionParamMapping clone () const;
+
+ ParamType *get_param_ty ();
+
+ const ParamType *get_param_ty () const;
+
+ const HIR::TypeParam &get_generic_param ();
+
+ // this is used for the backend to override the HirId ref of the param to
+ // what the concrete type is for the rest of the context
+ void override_context ();
+
+ bool needs_substitution () const;
+
+ Location get_param_locus () const;
+
+ bool param_has_default_ty () const;
+
+ BaseType *get_default_ty () const;
+
+ bool need_substitution () const;
+
+private:
+ const HIR::TypeParam &generic;
+ ParamType *param;
+};
+
+class SubstitutionArg
+{
+public:
+ SubstitutionArg (const SubstitutionParamMapping *param, BaseType *argument);
+
+ // FIXME
+ // the copy constructors need removed - they are unsafe see
+ // TypeBoundPredicate
+ SubstitutionArg (const SubstitutionArg &other);
+
+ SubstitutionArg &operator= (const SubstitutionArg &other);
+
+ BaseType *get_tyty ();
+
+ const BaseType *get_tyty () const;
+
+ const SubstitutionParamMapping *get_param_mapping () const;
+
+ static SubstitutionArg error ();
+
+ bool is_error () const;
+
+ bool is_conrete () const;
+
+ std::string as_string () const;
+
+private:
+ const SubstitutionParamMapping *param;
+ BaseType *argument;
+};
+
+typedef std::function<void (const ParamType &, const SubstitutionArg &)>
+ ParamSubstCb;
+class SubstitutionArgumentMappings
+{
+public:
+ SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings,
+ std::map<std::string, BaseType *> binding_args,
+ Location locus,
+ ParamSubstCb param_subst_cb = nullptr,
+ bool trait_item_flag = false);
+
+ SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other);
+ SubstitutionArgumentMappings &
+ operator= (const SubstitutionArgumentMappings &other);
+
+ SubstitutionArgumentMappings (SubstitutionArgumentMappings &&other) = default;
+ SubstitutionArgumentMappings &operator= (SubstitutionArgumentMappings &&other)
+ = default;
+
+ static SubstitutionArgumentMappings error ();
+
+ bool is_error () const;
+
+ bool get_argument_for_symbol (const ParamType *param_to_find,
+ SubstitutionArg *argument);
+
+ bool get_argument_at (size_t index, SubstitutionArg *argument);
+
+ // is_concrete means if the used args is non error, ie: non empty this will
+ // verify if actual real types have been put in place of are they still
+ // ParamTy
+ bool is_concrete () const;
+
+ Location get_locus () const;
+
+ size_t size () const;
+
+ bool is_empty () const;
+
+ std::vector<SubstitutionArg> &get_mappings ();
+
+ const std::vector<SubstitutionArg> &get_mappings () const;
+
+ std::map<std::string, BaseType *> &get_binding_args ();
+
+ const std::map<std::string, BaseType *> &get_binding_args () const;
+
+ std::string as_string () const;
+
+ void on_param_subst (const ParamType &p, const SubstitutionArg &a) const;
+
+ ParamSubstCb get_subst_cb () const;
+
+ bool trait_item_mode () const;
+
+private:
+ std::vector<SubstitutionArg> mappings;
+ std::map<std::string, BaseType *> binding_args;
+ Location locus;
+ ParamSubstCb param_subst_cb;
+ bool trait_item_flag;
+};
+
+class SubstitutionRef
+{
+public:
+ SubstitutionRef (std::vector<SubstitutionParamMapping> substitutions,
+ SubstitutionArgumentMappings arguments);
+
+ bool has_substitutions () const;
+
+ std::string subst_as_string () const;
+
+ bool supports_associated_bindings () const;
+
+ // this is overridden in TypeBoundPredicate
+ // which support bindings we don't add them directly to the SubstitutionRef
+ // base class because this class represents the fn<X: Foo, Y: Bar>. The only
+ // construct which supports associated types
+ virtual size_t get_num_associated_bindings () const;
+
+ // this is overridden in TypeBoundPredicate
+ virtual TypeBoundPredicateItem
+ lookup_associated_type (const std::string &search);
+
+ size_t get_num_substitutions () const;
+
+ std::vector<SubstitutionParamMapping> &get_substs ();
+
+ const std::vector<SubstitutionParamMapping> &get_substs () const;
+
+ std::vector<SubstitutionParamMapping> clone_substs () const;
+
+ void override_context ();
+
+ bool needs_substitution () const;
+
+ bool was_substituted () const;
+
+ SubstitutionArgumentMappings get_substitution_arguments () const;
+
+ // this is the count of type params that are not substituted fuly
+ size_t num_required_substitutions () const;
+
+ // this is the count of type params that need substituted taking into account
+ // possible defaults
+ size_t min_required_substitutions () const;
+
+ // We are trying to subst <i32, f32> into Struct Foo<X,Y> {}
+ // in the case of Foo<i32,f32>{...}
+ //
+ // the substitions we have here define X,Y but the arguments have no bindings
+ // so its a matter of ordering
+ SubstitutionArgumentMappings
+ get_mappings_from_generic_args (HIR::GenericArgs &args);
+
+ // Recursive substitutions
+ // Foo <A,B> { a:A, b: B}; Bar <X,Y,Z>{a:X, b: Foo<Y,Z>}
+ //
+ // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo
+ // Which binds to A,B
+ SubstitutionArgumentMappings
+ adjust_mappings_for_this (SubstitutionArgumentMappings &mappings);
+
+ // Are the mappings here actually bound to this type. For example imagine the
+ // case:
+ //
+ // struct Foo<T>(T);
+ // impl<T> Foo<T> {
+ // fn test(self) { ... }
+ // }
+ //
+ // In this case we have a generic ADT of Foo and an impl block of a generic T
+ // on Foo for the Self type. When we it comes to path resolution we can have:
+ //
+ // Foo::<i32>::test()
+ //
+ // This means the first segment of Foo::<i32> returns the ADT Foo<i32> not the
+ // Self ADT bound to the T from the impl block. This means when it comes to
+ // the next segment of test which resolves to the function we need to check
+ // wether the arguments in the struct definition of foo can be bound here
+ // before substituting the previous segments type here. This functions acts as
+ // a guard for the solve_mappings_from_receiver_for_self to handle the case
+ // where arguments are not bound. This is important for this next case:
+ //
+ // struct Baz<A, B>(A, B);
+ // impl Baz<i32, f32> {
+ // fn test<X>(a: X) -> X {
+ // a
+ // }
+ // }
+ //
+ // In this case Baz has been already substituted for the impl's Self to become
+ // ADT<i32, f32> so that the function test only has 1 generic argument of X.
+ // The path for this will be:
+ //
+ // Baz::test::<_>(123)
+ //
+ // So the first segment here will be Baz<_, _> to try and infer the arguments
+ // which will be taken from the impl's Self type in this case since it is
+ // already substituted and like the previous case the check to see if we need
+ // to inherit the previous segments generic arguments takes place but the
+ // generic arguments are not bound to this type as they have already been
+ // substituted.
+ //
+ // Its important to remember from the first example the FnType actually looks
+ // like:
+ //
+ // fn <T>test(self :Foo<T>(T))
+ //
+ // As the generic parameters are "bound" to each of the items in the impl
+ // block. So this check is about wether the arguments we have here can
+ // actually be bound to this type.
+ bool are_mappings_bound (SubstitutionArgumentMappings &mappings);
+
+ // struct Foo<A, B>(A, B);
+ //
+ // impl<T> Foo<T, f32>;
+ // -> fn test<X>(self, a: X) -> X
+ //
+ // We might invoke this via:
+ //
+ // a = Foo(123, 456f32);
+ // b = a.test::<bool>(false);
+ //
+ // we need to figure out relevant generic arguemts for self to apply to the
+ // fntype
+ SubstitutionArgumentMappings solve_mappings_from_receiver_for_self (
+ SubstitutionArgumentMappings &mappings) const;
+
+ // TODO comment
+ SubstitutionArgumentMappings
+ solve_missing_mappings_from_this (SubstitutionRef &ref, SubstitutionRef &to);
+
+ // TODO comment
+ BaseType *infer_substitions (Location locus);
+
+ // TODO comment
+ bool monomorphize ();
+
+ // TODO comment
+ virtual BaseType *handle_substitions (SubstitutionArgumentMappings mappings)
+ = 0;
+
+ SubstitutionArgumentMappings get_used_arguments () const;
+
+protected:
+ std::vector<SubstitutionParamMapping> substitutions;
+ SubstitutionArgumentMappings used_arguments;
+};
+
+} // namespace TyTy
+} // namespace Rust
+#endif // RUST_TYTY_SUBST_H
@@ -514,472 +514,6 @@ StructFieldType::monomorphized_clone () const
get_field_type ()->monomorphized_clone (), locus);
}
-bool
-SubstitutionParamMapping::need_substitution () const
-{
- if (!param->can_resolve ())
- return true;
-
- auto resolved = param->resolve ();
- return !resolved->is_concrete ();
-}
-
-bool
-SubstitutionParamMapping::fill_param_ty (
- SubstitutionArgumentMappings &subst_mappings, Location locus)
-{
- SubstitutionArg arg = SubstitutionArg::error ();
- bool ok = subst_mappings.get_argument_for_symbol (get_param_ty (), &arg);
- if (!ok)
- return true;
-
- TyTy::BaseType &type = *arg.get_tyty ();
- if (type.get_kind () == TyTy::TypeKind::INFER)
- {
- type.inherit_bounds (*param);
- }
- else
- {
- if (!param->bounds_compatible (type, locus, true))
- return false;
- }
-
- if (type.get_kind () == TypeKind::PARAM)
- {
- // delete param;
- param = static_cast<ParamType *> (type.clone ());
- }
- else
- {
- // check the substitution is compatible with bounds
- if (!param->bounds_compatible (type, locus, true))
- return false;
-
- // recursively pass this down to all HRTB's
- for (auto &bound : param->get_specified_bounds ())
- bound.handle_substitions (subst_mappings);
-
- param->set_ty_ref (type.get_ref ());
- }
-
- return true;
-}
-
-void
-SubstitutionParamMapping::override_context ()
-{
- if (!param->can_resolve ())
- return;
-
- auto mappings = Analysis::Mappings::get ();
- auto context = Resolver::TypeCheckContext::get ();
-
- context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (),
- UNKNOWN_NODEID,
- param->get_ref (),
- UNKNOWN_LOCAL_DEFID),
- param->resolve ());
-}
-
-SubstitutionArgumentMappings
-SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args)
-{
- std::map<std::string, BaseType *> binding_arguments;
- if (args.get_binding_args ().size () > 0)
- {
- if (supports_associated_bindings ())
- {
- if (args.get_binding_args ().size () > get_num_associated_bindings ())
- {
- RichLocation r (args.get_locus ());
-
- rust_error_at (r,
- "generic item takes at most %lu type binding "
- "arguments but %lu were supplied",
- (unsigned long) get_num_associated_bindings (),
- (unsigned long) args.get_binding_args ().size ());
- return SubstitutionArgumentMappings::error ();
- }
-
- for (auto &binding : args.get_binding_args ())
- {
- BaseType *resolved
- = Resolver::TypeCheckType::Resolve (binding.get_type ().get ());
- if (resolved == nullptr
- || resolved->get_kind () == TyTy::TypeKind::ERROR)
- {
- rust_error_at (binding.get_locus (),
- "failed to resolve type arguments");
- return SubstitutionArgumentMappings::error ();
- }
-
- // resolve to relevant binding
- auto binding_item
- = lookup_associated_type (binding.get_identifier ());
- if (binding_item.is_error ())
- {
- rust_error_at (binding.get_locus (),
- "unknown associated type binding: %s",
- binding.get_identifier ().c_str ());
- return SubstitutionArgumentMappings::error ();
- }
-
- binding_arguments[binding.get_identifier ()] = resolved;
- }
- }
- else
- {
- RichLocation r (args.get_locus ());
- for (auto &binding : args.get_binding_args ())
- r.add_range (binding.get_locus ());
-
- rust_error_at (r, "associated type bindings are not allowed here");
- return SubstitutionArgumentMappings::error ();
- }
- }
-
- // for inherited arguments
- size_t offs = used_arguments.size ();
- if (args.get_type_args ().size () + offs > substitutions.size ())
- {
- RichLocation r (args.get_locus ());
- r.add_range (substitutions.front ().get_param_locus ());
-
- rust_error_at (
- r,
- "generic item takes at most %lu type arguments but %lu were supplied",
- (unsigned long) substitutions.size (),
- (unsigned long) args.get_type_args ().size ());
- return SubstitutionArgumentMappings::error ();
- }
-
- if (args.get_type_args ().size () + offs < min_required_substitutions ())
- {
- RichLocation r (args.get_locus ());
- r.add_range (substitutions.front ().get_param_locus ());
-
- rust_error_at (
- r,
- "generic item takes at least %lu type arguments but %lu were supplied",
- (unsigned long) (min_required_substitutions () - offs),
- (unsigned long) args.get_type_args ().size ());
- return SubstitutionArgumentMappings::error ();
- }
-
- std::vector<SubstitutionArg> mappings = used_arguments.get_mappings ();
- for (auto &arg : args.get_type_args ())
- {
- BaseType *resolved = Resolver::TypeCheckType::Resolve (arg.get ());
- if (resolved == nullptr || resolved->get_kind () == TyTy::TypeKind::ERROR)
- {
- rust_error_at (args.get_locus (), "failed to resolve type arguments");
- return SubstitutionArgumentMappings::error ();
- }
-
- SubstitutionArg subst_arg (&substitutions.at (offs), resolved);
- offs++;
- mappings.push_back (std::move (subst_arg));
- }
-
- // we must need to fill out defaults
- size_t left_over
- = num_required_substitutions () - min_required_substitutions ();
- if (left_over > 0)
- {
- for (size_t offs = mappings.size (); offs < substitutions.size (); offs++)
- {
- SubstitutionParamMapping ¶m = substitutions.at (offs);
- rust_assert (param.param_has_default_ty ());
-
- BaseType *resolved = param.get_default_ty ();
- if (resolved->get_kind () == TypeKind::ERROR)
- return SubstitutionArgumentMappings::error ();
-
- // this resolved default might already contain default parameters
- if (resolved->contains_type_parameters ())
- {
- SubstitutionArgumentMappings intermediate (mappings,
- binding_arguments,
- args.get_locus ());
- resolved = Resolver::SubstMapperInternal::Resolve (resolved,
- intermediate);
-
- if (resolved->get_kind () == TypeKind::ERROR)
- return SubstitutionArgumentMappings::error ();
- }
-
- SubstitutionArg subst_arg (¶m, resolved);
- mappings.push_back (std::move (subst_arg));
- }
- }
-
- return SubstitutionArgumentMappings (mappings, binding_arguments,
- args.get_locus ());
-}
-
-BaseType *
-SubstitutionRef::infer_substitions (Location locus)
-{
- std::vector<SubstitutionArg> args;
- std::map<std::string, BaseType *> argument_mappings;
- for (auto &p : get_substs ())
- {
- if (p.needs_substitution ())
- {
- const std::string &symbol = p.get_param_ty ()->get_symbol ();
- auto it = argument_mappings.find (symbol);
- bool have_mapping = it != argument_mappings.end ();
-
- if (have_mapping)
- {
- args.push_back (SubstitutionArg (&p, it->second));
- }
- else
- {
- TyVar infer_var = TyVar::get_implicit_infer_var (locus);
- args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
- argument_mappings[symbol] = infer_var.get_tyty ();
- }
- }
- else
- {
- args.push_back (SubstitutionArg (&p, p.get_param_ty ()->resolve ()));
- }
- }
-
- // FIXME do we need to add inference variables to all the possible bindings?
- // it might just lead to inference variable hell not 100% sure if rustc does
- // this i think the language might needs this to be explicitly set
-
- SubstitutionArgumentMappings infer_arguments (std::move (args),
- {} /* binding_arguments */,
- locus);
- return handle_substitions (std::move (infer_arguments));
-}
-
-SubstitutionArgumentMappings
-SubstitutionRef::adjust_mappings_for_this (
- SubstitutionArgumentMappings &mappings)
-{
- std::vector<SubstitutionArg> resolved_mappings;
- for (size_t i = 0; i < substitutions.size (); i++)
- {
- auto &subst = substitutions.at (i);
-
- SubstitutionArg arg = SubstitutionArg::error ();
- if (mappings.size () == substitutions.size ())
- {
- mappings.get_argument_at (i, &arg);
- }
- else
- {
- if (subst.needs_substitution ())
- {
- // get from passed in mappings
- mappings.get_argument_for_symbol (subst.get_param_ty (), &arg);
- }
- else
- {
- // we should already have this somewhere
- used_arguments.get_argument_for_symbol (subst.get_param_ty (),
- &arg);
- }
- }
-
- bool ok = !arg.is_error ();
- if (ok)
- {
- SubstitutionArg adjusted (&subst, arg.get_tyty ());
- resolved_mappings.push_back (std::move (adjusted));
- }
- }
-
- if (resolved_mappings.empty ())
- return SubstitutionArgumentMappings::error ();
-
- return SubstitutionArgumentMappings (resolved_mappings,
- mappings.get_binding_args (),
- mappings.get_locus (),
- mappings.get_subst_cb (),
- mappings.trait_item_mode ());
-}
-
-bool
-SubstitutionRef::are_mappings_bound (SubstitutionArgumentMappings &mappings)
-{
- std::vector<SubstitutionArg> resolved_mappings;
- for (size_t i = 0; i < substitutions.size (); i++)
- {
- auto &subst = substitutions.at (i);
-
- SubstitutionArg arg = SubstitutionArg::error ();
- if (mappings.size () == substitutions.size ())
- {
- mappings.get_argument_at (i, &arg);
- }
- else
- {
- if (subst.needs_substitution ())
- {
- // get from passed in mappings
- mappings.get_argument_for_symbol (subst.get_param_ty (), &arg);
- }
- else
- {
- // we should already have this somewhere
- used_arguments.get_argument_for_symbol (subst.get_param_ty (),
- &arg);
- }
- }
-
- bool ok = !arg.is_error ();
- if (ok)
- {
- SubstitutionArg adjusted (&subst, arg.get_tyty ());
- resolved_mappings.push_back (std::move (adjusted));
- }
- }
-
- return !resolved_mappings.empty ();
-}
-
-// this function assumes that the mappings being passed are for the same type as
-// this new substitution reference so ordering matters here
-SubstitutionArgumentMappings
-SubstitutionRef::solve_mappings_from_receiver_for_self (
- SubstitutionArgumentMappings &mappings) const
-{
- std::vector<SubstitutionArg> resolved_mappings;
-
- rust_assert (mappings.size () == get_num_substitutions ());
- for (size_t i = 0; i < get_num_substitutions (); i++)
- {
- const SubstitutionParamMapping ¶m_mapping = substitutions.at (i);
- SubstitutionArg &arg = mappings.get_mappings ().at (i);
-
- if (param_mapping.needs_substitution ())
- {
- SubstitutionArg adjusted (¶m_mapping, arg.get_tyty ());
- resolved_mappings.push_back (std::move (adjusted));
- }
- }
-
- return SubstitutionArgumentMappings (resolved_mappings,
- mappings.get_binding_args (),
- mappings.get_locus ());
-}
-
-SubstitutionArgumentMappings
-SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref,
- SubstitutionRef &to)
-{
- rust_assert (!ref.needs_substitution ());
- rust_assert (needs_substitution ());
- rust_assert (get_num_substitutions () == ref.get_num_substitutions ());
-
- Location locus = used_arguments.get_locus ();
- std::vector<SubstitutionArg> resolved_mappings;
-
- std::map<HirId, std::pair<ParamType *, BaseType *>> substs;
- for (size_t i = 0; i < get_num_substitutions (); i++)
- {
- SubstitutionParamMapping &a = substitutions.at (i);
- SubstitutionParamMapping &b = ref.substitutions.at (i);
-
- if (a.need_substitution ())
- {
- const BaseType *root = a.get_param_ty ()->resolve ()->get_root ();
- rust_assert (root->get_kind () == TyTy::TypeKind::PARAM);
- const ParamType *p = static_cast<const TyTy::ParamType *> (root);
-
- substs[p->get_ty_ref ()] = {static_cast<ParamType *> (p->clone ()),
- b.get_param_ty ()->resolve ()};
- }
- }
-
- for (auto it = substs.begin (); it != substs.end (); it++)
- {
- HirId param_id = it->first;
- BaseType *arg = it->second.second;
-
- const SubstitutionParamMapping *associate_param = nullptr;
- for (SubstitutionParamMapping &p : to.substitutions)
- {
- if (p.get_param_ty ()->get_ty_ref () == param_id)
- {
- associate_param = &p;
- break;
- }
- }
-
- rust_assert (associate_param != nullptr);
- SubstitutionArg argument (associate_param, arg);
- resolved_mappings.push_back (std::move (argument));
- }
-
- return SubstitutionArgumentMappings (resolved_mappings, {}, locus);
-}
-
-bool
-SubstitutionRef::monomorphize ()
-{
- auto context = Resolver::TypeCheckContext::get ();
- for (const auto &subst : get_substs ())
- {
- const TyTy::ParamType *pty = subst.get_param_ty ();
-
- if (!pty->can_resolve ())
- continue;
-
- const TyTy::BaseType *binding = pty->resolve ();
- if (binding->get_kind () == TyTy::TypeKind::PARAM)
- continue;
-
- for (const auto &bound : pty->get_specified_bounds ())
- {
- const Resolver::TraitReference *specified_bound_ref = bound.get ();
-
- // setup any associated type mappings for the specified bonds and this
- // type
- auto candidates = Resolver::TypeBoundsProbe::Probe (binding);
-
- Resolver::AssociatedImplTrait *associated_impl_trait = nullptr;
- for (auto &probed_bound : candidates)
- {
- const Resolver::TraitReference *bound_trait_ref
- = probed_bound.first;
- const HIR::ImplBlock *associated_impl = probed_bound.second;
-
- HirId impl_block_id
- = associated_impl->get_mappings ().get_hirid ();
- Resolver::AssociatedImplTrait *associated = nullptr;
- bool found_impl_trait
- = context->lookup_associated_trait_impl (impl_block_id,
- &associated);
- if (found_impl_trait)
- {
- bool found_trait
- = specified_bound_ref->is_equal (*bound_trait_ref);
- bool found_self
- = associated->get_self ()->can_eq (binding, false);
- if (found_trait && found_self)
- {
- associated_impl_trait = associated;
- break;
- }
- }
- }
-
- if (associated_impl_trait != nullptr)
- {
- associated_impl_trait->setup_associated_types (binding, bound);
- }
- }
- }
-
- return true;
-}
-
void
ADTType::accept_vis (TyVisitor &vis)
{
@@ -27,6 +27,7 @@
#include "rust-identifier.h"
#include "rust-tyty-bounds.h"
#include "rust-tyty-util.h"
+#include "rust-tyty-subst.h"
namespace Rust {
@@ -462,469 +463,6 @@ private:
std::vector<TyVar> fields;
};
-class SubstitutionParamMapping
-{
-public:
- SubstitutionParamMapping (const HIR::TypeParam &generic, ParamType *param)
- : generic (generic), param (param)
- {}
-
- SubstitutionParamMapping (const SubstitutionParamMapping &other)
- : generic (other.generic), param (other.param)
- {}
-
- std::string as_string () const
- {
- if (param == nullptr)
- return "nullptr";
-
- return param->get_name ();
- }
-
- bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings,
- Location locus);
-
- SubstitutionParamMapping clone () const
- {
- return SubstitutionParamMapping (generic, static_cast<ParamType *> (
- param->clone ()));
- }
-
- ParamType *get_param_ty () { return param; }
-
- const ParamType *get_param_ty () const { return param; }
-
- const HIR::TypeParam &get_generic_param () { return generic; };
-
- // this is used for the backend to override the HirId ref of the param to
- // what the concrete type is for the rest of the context
- void override_context ();
-
- bool needs_substitution () const
- {
- return !(get_param_ty ()->is_concrete ());
- }
-
- Location get_param_locus () const { return generic.get_locus (); }
-
- bool param_has_default_ty () const { return generic.has_type (); }
-
- BaseType *get_default_ty () const
- {
- TyVar var (generic.get_type_mappings ().get_hirid ());
- return var.get_tyty ();
- }
-
- bool need_substitution () const;
-
-private:
- const HIR::TypeParam &generic;
- ParamType *param;
-};
-
-class SubstitutionArg
-{
-public:
- SubstitutionArg (const SubstitutionParamMapping *param, BaseType *argument)
- : param (param), argument (argument)
- {}
-
- // FIXME
- // the copy constructors need removed - they are unsafe see
- // TypeBoundPredicate
- SubstitutionArg (const SubstitutionArg &other)
- : param (other.param), argument (other.argument)
- {}
-
- SubstitutionArg &operator= (const SubstitutionArg &other)
- {
- param = other.param;
- argument = other.argument;
- return *this;
- }
-
- BaseType *get_tyty () { return argument; }
-
- const BaseType *get_tyty () const { return argument; }
-
- const SubstitutionParamMapping *get_param_mapping () const { return param; }
-
- static SubstitutionArg error () { return SubstitutionArg (nullptr, nullptr); }
-
- bool is_error () const { return param == nullptr || argument == nullptr; }
-
- bool is_conrete () const
- {
- if (argument != nullptr)
- return true;
-
- if (argument->get_kind () == TyTy::TypeKind::PARAM)
- return false;
-
- return argument->is_concrete ();
- }
-
- std::string as_string () const
- {
- return param->as_string ()
- + (argument != nullptr ? ":" + argument->as_string () : "");
- }
-
-private:
- const SubstitutionParamMapping *param;
- BaseType *argument;
-};
-
-typedef std::function<void (const ParamType &, const SubstitutionArg &)>
- ParamSubstCb;
-class SubstitutionArgumentMappings
-{
-public:
- SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings,
- std::map<std::string, BaseType *> binding_args,
- Location locus,
- ParamSubstCb param_subst_cb = nullptr,
- bool trait_item_flag = false)
- : mappings (mappings), binding_args (binding_args), locus (locus),
- param_subst_cb (param_subst_cb), trait_item_flag (trait_item_flag)
- {}
-
- SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other)
- : mappings (other.mappings), binding_args (other.binding_args),
- locus (other.locus), param_subst_cb (other.param_subst_cb),
- trait_item_flag (other.trait_item_flag)
- {}
-
- SubstitutionArgumentMappings &
- operator= (const SubstitutionArgumentMappings &other)
- {
- mappings = other.mappings;
- binding_args = other.binding_args;
- locus = other.locus;
- param_subst_cb = other.param_subst_cb;
- trait_item_flag = other.trait_item_flag;
-
- return *this;
- }
-
- SubstitutionArgumentMappings (SubstitutionArgumentMappings &&other) = default;
- SubstitutionArgumentMappings &operator= (SubstitutionArgumentMappings &&other)
- = default;
-
- static SubstitutionArgumentMappings error ()
- {
- return SubstitutionArgumentMappings ({}, {}, Location (), nullptr, false);
- }
-
- bool is_error () const { return mappings.size () == 0; }
-
- bool get_argument_for_symbol (const ParamType *param_to_find,
- SubstitutionArg *argument)
- {
- for (auto &mapping : mappings)
- {
- const SubstitutionParamMapping *param = mapping.get_param_mapping ();
- const ParamType *p = param->get_param_ty ();
-
- if (p->get_symbol ().compare (param_to_find->get_symbol ()) == 0)
- {
- *argument = mapping;
- return true;
- }
- }
- return false;
- }
-
- bool get_argument_at (size_t index, SubstitutionArg *argument)
- {
- if (index > mappings.size ())
- return false;
-
- *argument = mappings.at (index);
- return true;
- }
-
- // is_concrete means if the used args is non error, ie: non empty this will
- // verify if actual real types have been put in place of are they still
- // ParamTy
- bool is_concrete () const
- {
- for (auto &mapping : mappings)
- {
- if (!mapping.is_conrete ())
- return false;
- }
- return true;
- }
-
- Location get_locus () const { return locus; }
-
- size_t size () const { return mappings.size (); }
-
- bool is_empty () const { return size () == 0; }
-
- std::vector<SubstitutionArg> &get_mappings () { return mappings; }
-
- const std::vector<SubstitutionArg> &get_mappings () const { return mappings; }
-
- std::map<std::string, BaseType *> &get_binding_args ()
- {
- return binding_args;
- }
-
- const std::map<std::string, BaseType *> &get_binding_args () const
- {
- return binding_args;
- }
-
- std::string as_string () const
- {
- std::string buffer;
- for (auto &mapping : mappings)
- {
- buffer += mapping.as_string () + ", ";
- }
- return "<" + buffer + ">";
- }
-
- void on_param_subst (const ParamType &p, const SubstitutionArg &a) const
- {
- if (param_subst_cb == nullptr)
- return;
-
- param_subst_cb (p, a);
- }
-
- ParamSubstCb get_subst_cb () const { return param_subst_cb; }
-
- bool trait_item_mode () const { return trait_item_flag; }
-
-private:
- std::vector<SubstitutionArg> mappings;
- std::map<std::string, BaseType *> binding_args;
- Location locus;
- ParamSubstCb param_subst_cb;
- bool trait_item_flag;
-};
-
-class SubstitutionRef
-{
-public:
- SubstitutionRef (std::vector<SubstitutionParamMapping> substitutions,
- SubstitutionArgumentMappings arguments)
- : substitutions (substitutions), used_arguments (arguments)
- {}
-
- bool has_substitutions () const { return substitutions.size () > 0; }
-
- std::string subst_as_string () const
- {
- std::string buffer;
- for (size_t i = 0; i < substitutions.size (); i++)
- {
- const SubstitutionParamMapping &sub = substitutions.at (i);
- buffer += sub.as_string ();
-
- if ((i + 1) < substitutions.size ())
- buffer += ", ";
- }
-
- return buffer.empty () ? "" : "<" + buffer + ">";
- }
-
- bool supports_associated_bindings () const
- {
- return get_num_associated_bindings () > 0;
- }
-
- // this is overridden in TypeBoundPredicate
- // which support bindings we don't add them directly to the SubstitutionRef
- // base class because this class represents the fn<X: Foo, Y: Bar>. The only
- // construct which supports associated types
- virtual size_t get_num_associated_bindings () const { return 0; }
-
- // this is overridden in TypeBoundPredicate
- virtual TypeBoundPredicateItem
- lookup_associated_type (const std::string &search)
- {
- return TypeBoundPredicateItem::error ();
- }
-
- size_t get_num_substitutions () const { return substitutions.size (); }
-
- std::vector<SubstitutionParamMapping> &get_substs () { return substitutions; }
-
- const std::vector<SubstitutionParamMapping> &get_substs () const
- {
- return substitutions;
- }
-
- std::vector<SubstitutionParamMapping> clone_substs () const
- {
- std::vector<SubstitutionParamMapping> clone;
-
- for (auto &sub : substitutions)
- clone.push_back (sub.clone ());
-
- return clone;
- }
-
- void override_context ()
- {
- for (auto &sub : substitutions)
- {
- sub.override_context ();
- }
- }
-
- bool needs_substitution () const
- {
- for (auto &sub : substitutions)
- {
- if (sub.need_substitution ())
- return true;
- }
- return false;
- }
-
- bool was_substituted () const { return !needs_substitution (); }
-
- SubstitutionArgumentMappings get_substitution_arguments () const
- {
- return used_arguments;
- }
-
- // this is the count of type params that are not substituted fuly
- size_t num_required_substitutions () const
- {
- size_t n = 0;
- for (auto &p : substitutions)
- {
- if (p.needs_substitution ())
- n++;
- }
- return n;
- }
-
- // this is the count of type params that need substituted taking into account
- // possible defaults
- size_t min_required_substitutions () const
- {
- size_t n = 0;
- for (auto &p : substitutions)
- {
- if (p.needs_substitution () && !p.param_has_default_ty ())
- n++;
- }
- return n;
- }
-
- // We are trying to subst <i32, f32> into Struct Foo<X,Y> {}
- // in the case of Foo<i32,f32>{...}
- //
- // the substitions we have here define X,Y but the arguments have no bindings
- // so its a matter of ordering
- SubstitutionArgumentMappings
- get_mappings_from_generic_args (HIR::GenericArgs &args);
-
- // Recursive substitutions
- // Foo <A,B> { a:A, b: B}; Bar <X,Y,Z>{a:X, b: Foo<Y,Z>}
- //
- // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo
- // Which binds to A,B
- SubstitutionArgumentMappings
- adjust_mappings_for_this (SubstitutionArgumentMappings &mappings);
-
- // Are the mappings here actually bound to this type. For example imagine the
- // case:
- //
- // struct Foo<T>(T);
- // impl<T> Foo<T> {
- // fn test(self) { ... }
- // }
- //
- // In this case we have a generic ADT of Foo and an impl block of a generic T
- // on Foo for the Self type. When we it comes to path resolution we can have:
- //
- // Foo::<i32>::test()
- //
- // This means the first segment of Foo::<i32> returns the ADT Foo<i32> not the
- // Self ADT bound to the T from the impl block. This means when it comes to
- // the next segment of test which resolves to the function we need to check
- // wether the arguments in the struct definition of foo can be bound here
- // before substituting the previous segments type here. This functions acts as
- // a guard for the solve_mappings_from_receiver_for_self to handle the case
- // where arguments are not bound. This is important for this next case:
- //
- // struct Baz<A, B>(A, B);
- // impl Baz<i32, f32> {
- // fn test<X>(a: X) -> X {
- // a
- // }
- // }
- //
- // In this case Baz has been already substituted for the impl's Self to become
- // ADT<i32, f32> so that the function test only has 1 generic argument of X.
- // The path for this will be:
- //
- // Baz::test::<_>(123)
- //
- // So the first segment here will be Baz<_, _> to try and infer the arguments
- // which will be taken from the impl's Self type in this case since it is
- // already substituted and like the previous case the check to see if we need
- // to inherit the previous segments generic arguments takes place but the
- // generic arguments are not bound to this type as they have already been
- // substituted.
- //
- // Its important to remember from the first example the FnType actually looks
- // like:
- //
- // fn <T>test(self :Foo<T>(T))
- //
- // As the generic parameters are "bound" to each of the items in the impl
- // block. So this check is about wether the arguments we have here can
- // actually be bound to this type.
- bool are_mappings_bound (SubstitutionArgumentMappings &mappings);
-
- // struct Foo<A, B>(A, B);
- //
- // impl<T> Foo<T, f32>;
- // -> fn test<X>(self, a: X) -> X
- //
- // We might invoke this via:
- //
- // a = Foo(123, 456f32);
- // b = a.test::<bool>(false);
- //
- // we need to figure out relevant generic arguemts for self to apply to the
- // fntype
- SubstitutionArgumentMappings solve_mappings_from_receiver_for_self (
- SubstitutionArgumentMappings &mappings) const;
-
- // TODO comment
- SubstitutionArgumentMappings
- solve_missing_mappings_from_this (SubstitutionRef &ref, SubstitutionRef &to);
-
- // TODO comment
- BaseType *infer_substitions (Location locus);
-
- // TODO comment
- bool monomorphize ();
-
- // TODO comment
- virtual BaseType *handle_substitions (SubstitutionArgumentMappings mappings)
- = 0;
-
- SubstitutionArgumentMappings get_used_arguments () const
- {
- return used_arguments;
- }
-
-protected:
- std::vector<SubstitutionParamMapping> substitutions;
- SubstitutionArgumentMappings used_arguments;
-};
-
class TypeBoundPredicate : public SubstitutionRef
{
public: