mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 20:01:22 -05:00
gccrs: Refactor SubstitutionRef base class into its own CC file
Signed-off-by: Philip Herron <herron.philip@googlemail.com> gcc/rust/ChangeLog: * Make-lang.in: update the makefile * typecheck/rust-tyty.cc (SubstitutionParamMapping::need_substitution): likewise (SubstitutionParamMapping::override_context): likewise (SubstitutionRef::get_mappings_from_generic_args): likewise (SubstitutionRef::infer_substitions): likewise (SubstitutionRef::are_mappings_bound): likewise (SubstitutionRef::solve_missing_mappings_from_this): likewise (SubstitutionRef::monomorphize): likewise * typecheck/rust-tyty.h (class SubstitutionParamMapping): likewise (class SubstitutionArg): likewise (std::function<void): likewise (class SubstitutionArgumentMappings): likewise (class SubstitutionRef): likewise * typecheck/rust-tyty-subst.cc: New file. * typecheck/rust-tyty-subst.h: New file.
This commit is contained in:
committed by
Arthur Cohen
parent
688fccb522
commit
e42118c327
@@ -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 \
|
||||
|
||||
927
gcc/rust/typecheck/rust-tyty-subst.cc
Normal file
927
gcc/rust/typecheck/rust-tyty-subst.cc
Normal file
@@ -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
|
||||
316
gcc/rust/typecheck/rust-tyty-subst.h
Normal file
316
gcc/rust/typecheck/rust-tyty-subst.h
Normal file
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user