mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-20 17:40:46 +08:00
gccrs: Add type resolution and trait solving pass
This serves to handle parts of the Rust type-system. Namely, the type resolution (similar to type-checking) and the trait solving algorithms (which ensure Rust's type contracts are upheld throughout the codebase). gcc/rust/ * typecheck/rust-hir-trait-resolve.cc: New. * typecheck/rust-hir-trait-resolve.h: New. * typecheck/rust-hir-type-check-base.cc: New. * typecheck/rust-hir-type-check-base.h: New. * typecheck/rust-hir-type-check-enumitem.cc: New. * typecheck/rust-hir-type-check-enumitem.h: New. * typecheck/rust-hir-type-check-expr.cc: New. * typecheck/rust-hir-type-check-expr.h: New. * typecheck/rust-hir-type-check-implitem.cc: New. * typecheck/rust-hir-type-check-implitem.h: New. * typecheck/rust-hir-type-check-item.cc: New. * typecheck/rust-hir-type-check-item.h: New. * typecheck/rust-hir-type-check-path.cc: New. * typecheck/rust-hir-type-check-pattern.cc: New. * typecheck/rust-hir-type-check-pattern.h: New. * typecheck/rust-hir-type-check-stmt.cc: New. * typecheck/rust-hir-type-check-stmt.h: New. * typecheck/rust-hir-type-check-struct-field.h: New. * typecheck/rust-hir-type-check-struct.cc: New. * typecheck/rust-hir-type-check-toplevel.cc: New. * typecheck/rust-hir-type-check-toplevel.h: New. * typecheck/rust-hir-type-check-type.cc: New. * typecheck/rust-hir-type-check-type.h: New. * typecheck/rust-hir-type-check-util.cc: New. * typecheck/rust-hir-type-check-util.h: New. * typecheck/rust-hir-type-check.cc: New. * typecheck/rust-hir-type-check.h: New. * typecheck/rust-tyty-visitor.h: New.
This commit is contained in:
parent
9ce37e7206
commit
c6c3db2176
gcc/rust/typecheck
rust-hir-trait-resolve.ccrust-hir-trait-resolve.hrust-hir-type-check-base.ccrust-hir-type-check-base.hrust-hir-type-check-enumitem.ccrust-hir-type-check-enumitem.hrust-hir-type-check-expr.ccrust-hir-type-check-expr.hrust-hir-type-check-implitem.ccrust-hir-type-check-implitem.hrust-hir-type-check-item.ccrust-hir-type-check-item.hrust-hir-type-check-path.ccrust-hir-type-check-pattern.ccrust-hir-type-check-pattern.hrust-hir-type-check-stmt.ccrust-hir-type-check-stmt.hrust-hir-type-check-struct-field.hrust-hir-type-check-struct.ccrust-hir-type-check-toplevel.ccrust-hir-type-check-toplevel.hrust-hir-type-check-type.ccrust-hir-type-check-type.hrust-hir-type-check-util.ccrust-hir-type-check-util.hrust-hir-type-check.ccrust-hir-type-check.hrust-tyty-visitor.h
599
gcc/rust/typecheck/rust-hir-trait-resolve.cc
Normal file
599
gcc/rust/typecheck/rust-hir-trait-resolve.cc
Normal file
@ -0,0 +1,599 @@
|
||||
// Copyright (C) 2021-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-trait-resolve.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
void
|
||||
ResolveTraitItemToRef::visit (HIR::TraitItemType &type)
|
||||
{
|
||||
// create trait-item-ref
|
||||
Location locus = type.get_locus ();
|
||||
bool is_optional = false;
|
||||
std::string identifier = type.get_name ();
|
||||
|
||||
resolved = TraitItemReference (identifier, is_optional,
|
||||
TraitItemReference::TraitItemType::TYPE, &type,
|
||||
self, substitutions, locus);
|
||||
}
|
||||
|
||||
void
|
||||
ResolveTraitItemToRef::visit (HIR::TraitItemConst &cst)
|
||||
{
|
||||
// create trait-item-ref
|
||||
Location locus = cst.get_locus ();
|
||||
bool is_optional = cst.has_expr ();
|
||||
std::string identifier = cst.get_name ();
|
||||
|
||||
resolved = TraitItemReference (identifier, is_optional,
|
||||
TraitItemReference::TraitItemType::CONST, &cst,
|
||||
self, substitutions, locus);
|
||||
}
|
||||
|
||||
void
|
||||
ResolveTraitItemToRef::visit (HIR::TraitItemFunc &fn)
|
||||
{
|
||||
// create trait-item-ref
|
||||
Location locus = fn.get_locus ();
|
||||
bool is_optional = fn.has_block_defined ();
|
||||
std::string identifier = fn.get_decl ().get_function_name ();
|
||||
|
||||
resolved = TraitItemReference (identifier, is_optional,
|
||||
TraitItemReference::TraitItemType::FN, &fn,
|
||||
self, std::move (substitutions), locus);
|
||||
}
|
||||
|
||||
ResolveTraitItemToRef::ResolveTraitItemToRef (
|
||||
TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> &&substitutions)
|
||||
: TypeCheckBase (), resolved (TraitItemReference::error ()), self (self),
|
||||
substitutions (std::move (substitutions))
|
||||
{}
|
||||
|
||||
// TraitItemReference items
|
||||
|
||||
TraitReference *
|
||||
TraitResolver::Resolve (HIR::TypePath &path)
|
||||
{
|
||||
TraitResolver resolver;
|
||||
return resolver.resolve_path (path);
|
||||
}
|
||||
|
||||
TraitReference *
|
||||
TraitResolver::Resolve (HIR::Trait &trait)
|
||||
{
|
||||
TraitResolver resolver;
|
||||
return resolver.resolve_trait (&trait);
|
||||
}
|
||||
|
||||
TraitReference *
|
||||
TraitResolver::Lookup (HIR::TypePath &path)
|
||||
{
|
||||
TraitResolver resolver;
|
||||
return resolver.lookup_path (path);
|
||||
}
|
||||
|
||||
TraitResolver::TraitResolver ()
|
||||
: TypeCheckBase (), resolved_trait_reference (nullptr)
|
||||
{}
|
||||
|
||||
TraitReference *
|
||||
TraitResolver::resolve_path (HIR::TypePath &path)
|
||||
{
|
||||
NodeId ref;
|
||||
if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (),
|
||||
&ref))
|
||||
{
|
||||
rust_error_at (path.get_locus (), "Failed to resolve path to node-id");
|
||||
return &TraitReference::error_node ();
|
||||
}
|
||||
|
||||
HirId hir_node = UNKNOWN_HIRID;
|
||||
if (!mappings->lookup_node_to_hir (ref, &hir_node))
|
||||
{
|
||||
rust_error_at (path.get_locus (), "Failed to resolve path to hir-id");
|
||||
return &TraitReference::error_node ();
|
||||
}
|
||||
|
||||
HIR::Item *resolved_item = mappings->lookup_hir_item (hir_node);
|
||||
|
||||
rust_assert (resolved_item != nullptr);
|
||||
resolved_item->accept_vis (*this);
|
||||
rust_assert (resolved_trait_reference != nullptr);
|
||||
|
||||
return resolve_trait (resolved_trait_reference);
|
||||
}
|
||||
|
||||
TraitReference *
|
||||
TraitResolver::resolve_trait (HIR::Trait *trait_reference)
|
||||
{
|
||||
TraitReference *tref = &TraitReference::error_node ();
|
||||
if (context->lookup_trait_reference (
|
||||
trait_reference->get_mappings ().get_defid (), &tref))
|
||||
{
|
||||
return tref;
|
||||
}
|
||||
|
||||
TyTy::BaseType *self = nullptr;
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
for (auto &generic_param : trait_reference->get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (), param_type);
|
||||
|
||||
auto &typaram = static_cast<HIR::TypeParam &> (*generic_param);
|
||||
substitutions.push_back (
|
||||
TyTy::SubstitutionParamMapping (typaram, param_type));
|
||||
|
||||
if (typaram.get_type_representation ().compare ("Self") == 0)
|
||||
{
|
||||
self = param_type;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
rust_assert (self != nullptr);
|
||||
|
||||
// Check if there is a super-trait, and apply this bound to the Self
|
||||
// TypeParam
|
||||
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
|
||||
|
||||
// copy the substitition mappings
|
||||
std::vector<TyTy::SubstitutionParamMapping> self_subst_copy;
|
||||
for (auto &sub : substitutions)
|
||||
self_subst_copy.push_back (sub.clone ());
|
||||
|
||||
// They also inherit themselves as a bound this enables a trait item to
|
||||
// reference other Self::trait_items
|
||||
auto self_hrtb
|
||||
= TyTy::TypeBoundPredicate (trait_reference->get_mappings ().get_defid (),
|
||||
std::move (self_subst_copy),
|
||||
trait_reference->get_locus ());
|
||||
specified_bounds.push_back (self_hrtb);
|
||||
|
||||
// look for any
|
||||
std::vector<const TraitReference *> super_traits;
|
||||
if (trait_reference->has_type_param_bounds ())
|
||||
{
|
||||
for (auto &bound : trait_reference->get_type_param_bounds ())
|
||||
{
|
||||
if (bound->get_bound_type ()
|
||||
== HIR::TypeParamBound::BoundType::TRAITBOUND)
|
||||
{
|
||||
HIR::TraitBound *b
|
||||
= static_cast<HIR::TraitBound *> (bound.get ());
|
||||
|
||||
// FIXME this might be recursive we need a check for that
|
||||
auto predicate = get_predicate_from_bound (b->get_path ());
|
||||
specified_bounds.push_back (predicate);
|
||||
super_traits.push_back (predicate.get ());
|
||||
}
|
||||
}
|
||||
}
|
||||
self->inherit_bounds (specified_bounds);
|
||||
|
||||
std::vector<TraitItemReference> item_refs;
|
||||
for (auto &item : trait_reference->get_trait_items ())
|
||||
{
|
||||
// make a copy of the substs
|
||||
std::vector<TyTy::SubstitutionParamMapping> item_subst;
|
||||
for (auto &sub : substitutions)
|
||||
item_subst.push_back (sub.clone ());
|
||||
|
||||
TraitItemReference trait_item_ref
|
||||
= ResolveTraitItemToRef::Resolve (*item.get (), self,
|
||||
std::move (item_subst));
|
||||
item_refs.push_back (std::move (trait_item_ref));
|
||||
}
|
||||
|
||||
TraitReference trait_object (trait_reference, item_refs,
|
||||
std::move (super_traits),
|
||||
std::move (substitutions));
|
||||
context->insert_trait_reference (
|
||||
trait_reference->get_mappings ().get_defid (), std::move (trait_object));
|
||||
|
||||
tref = &TraitReference::error_node ();
|
||||
bool ok = context->lookup_trait_reference (
|
||||
trait_reference->get_mappings ().get_defid (), &tref);
|
||||
rust_assert (ok);
|
||||
|
||||
// hook to allow the trait to resolve its optional item blocks, we cant
|
||||
// resolve the blocks of functions etc because it can end up in a recursive
|
||||
// loop of trying to resolve traits as required by the types
|
||||
tref->on_resolved ();
|
||||
|
||||
return tref;
|
||||
}
|
||||
|
||||
TraitReference *
|
||||
TraitResolver::lookup_path (HIR::TypePath &path)
|
||||
{
|
||||
NodeId ref;
|
||||
if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (),
|
||||
&ref))
|
||||
{
|
||||
rust_error_at (path.get_locus (), "Failed to resolve path to node-id");
|
||||
return &TraitReference::error_node ();
|
||||
}
|
||||
|
||||
HirId hir_node = UNKNOWN_HIRID;
|
||||
if (!mappings->lookup_node_to_hir (ref, &hir_node))
|
||||
{
|
||||
rust_error_at (path.get_locus (), "Failed to resolve path to hir-id");
|
||||
return &TraitReference::error_node ();
|
||||
}
|
||||
|
||||
HIR::Item *resolved_item = mappings->lookup_hir_item (hir_node);
|
||||
|
||||
rust_assert (resolved_item != nullptr);
|
||||
resolved_item->accept_vis (*this);
|
||||
rust_assert (resolved_trait_reference != nullptr);
|
||||
|
||||
TraitReference *tref = &TraitReference::error_node ();
|
||||
if (context->lookup_trait_reference (
|
||||
resolved_trait_reference->get_mappings ().get_defid (), &tref))
|
||||
{
|
||||
return tref;
|
||||
}
|
||||
return &TraitReference::error_node ();
|
||||
}
|
||||
|
||||
void
|
||||
TraitItemReference::on_resolved ()
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CONST:
|
||||
resolve_item (static_cast<HIR::TraitItemConst &> (*hir_trait_item));
|
||||
break;
|
||||
|
||||
case TYPE:
|
||||
resolve_item (static_cast<HIR::TraitItemType &> (*hir_trait_item));
|
||||
break;
|
||||
|
||||
case FN:
|
||||
resolve_item (static_cast<HIR::TraitItemFunc &> (*hir_trait_item));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TraitItemReference::resolve_item (HIR::TraitItemType &type)
|
||||
{
|
||||
TyTy::BaseType *ty
|
||||
= new TyTy::PlaceholderType (type.get_name (),
|
||||
type.get_mappings ().get_hirid ());
|
||||
context->insert_type (type.get_mappings (), ty);
|
||||
}
|
||||
|
||||
void
|
||||
TraitItemReference::resolve_item (HIR::TraitItemConst &constant)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void
|
||||
TraitItemReference::resolve_item (HIR::TraitItemFunc &func)
|
||||
{
|
||||
if (!is_optional ())
|
||||
return;
|
||||
|
||||
TyTy::BaseType *item_tyty = get_tyty ();
|
||||
if (item_tyty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
// check the block and return types
|
||||
rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF);
|
||||
|
||||
// need to get the return type from this
|
||||
TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (item_tyty);
|
||||
auto expected_ret_tyty = resolved_fn_type->get_return_type ();
|
||||
context->push_return_type (TypeCheckContextItem (&func), expected_ret_tyty);
|
||||
|
||||
auto block_expr_ty = TypeCheckExpr::Resolve (func.get_block_expr ().get ());
|
||||
|
||||
context->pop_return_type ();
|
||||
|
||||
if (block_expr_ty->get_kind () != TyTy::NEVER)
|
||||
expected_ret_tyty->unify (block_expr_ty);
|
||||
}
|
||||
|
||||
void
|
||||
TraitItemReference::associated_type_set (TyTy::BaseType *ty) const
|
||||
{
|
||||
rust_assert (get_trait_item_type () == TraitItemType::TYPE);
|
||||
|
||||
TyTy::BaseType *item_ty = get_tyty ();
|
||||
rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER);
|
||||
TyTy::PlaceholderType *placeholder
|
||||
= static_cast<TyTy::PlaceholderType *> (item_ty);
|
||||
|
||||
placeholder->set_associated_type (ty->get_ty_ref ());
|
||||
}
|
||||
|
||||
void
|
||||
TraitItemReference::associated_type_reset () const
|
||||
{
|
||||
rust_assert (get_trait_item_type () == TraitItemType::TYPE);
|
||||
|
||||
TyTy::BaseType *item_ty = get_tyty ();
|
||||
rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER);
|
||||
TyTy::PlaceholderType *placeholder
|
||||
= static_cast<TyTy::PlaceholderType *> (item_ty);
|
||||
|
||||
placeholder->clear_associated_type ();
|
||||
}
|
||||
|
||||
void
|
||||
AssociatedImplTrait::setup_associated_types (
|
||||
const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound)
|
||||
{
|
||||
// compute the constrained impl block generic arguments based on self and the
|
||||
// higher ranked trait bound
|
||||
TyTy::BaseType *receiver = self->clone ();
|
||||
|
||||
// impl<Y> SliceIndex<[Y]> for Range<usize>
|
||||
// vs
|
||||
// I: SliceIndex<[<integer>]> and Range<<integer>>
|
||||
//
|
||||
// we need to figure out what Y is
|
||||
|
||||
TyTy::BaseType *associated_self = get_self ();
|
||||
rust_assert (associated_self->can_eq (self, false));
|
||||
|
||||
// grab the parameters
|
||||
HIR::ImplBlock &impl_block = *get_impl_block ();
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
for (auto &generic_param : impl_block.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
TyTy::BaseType *l = nullptr;
|
||||
bool ok = context->lookup_type (
|
||||
generic_param->get_mappings ().get_hirid (), &l);
|
||||
if (ok && l->get_kind () == TyTy::TypeKind::PARAM)
|
||||
{
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param),
|
||||
static_cast<TyTy::ParamType *> (l)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// generate inference variables for these bound arguments so we can compute
|
||||
// their values
|
||||
Location locus;
|
||||
std::vector<TyTy::SubstitutionArg> args;
|
||||
for (auto &p : substitutions)
|
||||
{
|
||||
if (p.needs_substitution ())
|
||||
{
|
||||
TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus);
|
||||
args.push_back (TyTy::SubstitutionArg (&p, infer_var.get_tyty ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
args.push_back (
|
||||
TyTy::SubstitutionArg (&p, p.get_param_ty ()->resolve ()));
|
||||
}
|
||||
}
|
||||
|
||||
// this callback gives us the parameters that get substituted so we can
|
||||
// compute the constrained type parameters for this impl block
|
||||
std::map<std::string, HirId> param_mappings;
|
||||
TyTy::ParamSubstCb param_subst_cb
|
||||
= [&] (const TyTy::ParamType &p, const TyTy::SubstitutionArg &a) {
|
||||
param_mappings[p.get_symbol ()] = a.get_tyty ()->get_ref ();
|
||||
};
|
||||
|
||||
TyTy::SubstitutionArgumentMappings infer_arguments (std::move (args), locus,
|
||||
param_subst_cb);
|
||||
TyTy::BaseType *impl_self_infer
|
||||
= (associated_self->needs_generic_substitutions ())
|
||||
? SubstMapperInternal::Resolve (associated_self, infer_arguments)
|
||||
: associated_self;
|
||||
|
||||
// FIXME this needs to do a lookup for the trait-reference DefId instead of
|
||||
// assuming its the first one in the list
|
||||
rust_assert (associated_self->num_specified_bounds () > 0);
|
||||
TyTy::TypeBoundPredicate &impl_predicate
|
||||
= associated_self->get_specified_bounds ().at (0);
|
||||
|
||||
// infer the arguments on the predicate
|
||||
std::vector<TyTy::BaseType *> impl_trait_predicate_args;
|
||||
for (const auto &arg : impl_predicate.get_substs ())
|
||||
{
|
||||
const TyTy::ParamType *p = arg.get_param_ty ();
|
||||
if (p->get_symbol ().compare ("Self") == 0)
|
||||
continue;
|
||||
|
||||
TyTy::BaseType *r = p->resolve ();
|
||||
r = SubstMapperInternal::Resolve (r, infer_arguments);
|
||||
impl_trait_predicate_args.push_back (r);
|
||||
}
|
||||
|
||||
// we need to unify the receiver with the impl-block Self so that we compute
|
||||
// the type correctly as our receiver may be generic and we are inferring its
|
||||
// generic arguments and this Self might be the concrete version or vice
|
||||
// versa.
|
||||
auto result = receiver->unify (impl_self_infer);
|
||||
rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
|
||||
|
||||
// unify the bounds arguments
|
||||
std::vector<TyTy::BaseType *> hrtb_bound_arguments;
|
||||
for (const auto &arg : bound.get_substs ())
|
||||
{
|
||||
const TyTy::ParamType *p = arg.get_param_ty ();
|
||||
if (p->get_symbol ().compare ("Self") == 0)
|
||||
continue;
|
||||
|
||||
TyTy::BaseType *r = p->resolve ();
|
||||
hrtb_bound_arguments.push_back (r);
|
||||
}
|
||||
|
||||
rust_assert (impl_trait_predicate_args.size ()
|
||||
== hrtb_bound_arguments.size ());
|
||||
for (size_t i = 0; i < impl_trait_predicate_args.size (); i++)
|
||||
{
|
||||
TyTy::BaseType *a = impl_trait_predicate_args.at (i);
|
||||
TyTy::BaseType *b = hrtb_bound_arguments.at (i);
|
||||
|
||||
result = a->unify (b);
|
||||
rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
|
||||
}
|
||||
|
||||
// create the argument list
|
||||
std::vector<TyTy::SubstitutionArg> associated_arguments;
|
||||
for (auto &p : substitutions)
|
||||
{
|
||||
std::string symbol = p.get_param_ty ()->get_symbol ();
|
||||
auto it = param_mappings.find (symbol);
|
||||
rust_assert (it != param_mappings.end ());
|
||||
|
||||
HirId id = it->second;
|
||||
TyTy::BaseType *argument = nullptr;
|
||||
bool ok = context->lookup_type (id, &argument);
|
||||
rust_assert (ok);
|
||||
|
||||
TyTy::SubstitutionArg arg (&p, argument);
|
||||
associated_arguments.push_back (arg);
|
||||
}
|
||||
|
||||
TyTy::SubstitutionArgumentMappings associated_type_args (
|
||||
std::move (associated_arguments), locus);
|
||||
|
||||
ImplTypeIterator iter (*impl, [&] (HIR::TypeAlias &type) {
|
||||
TraitItemReference *resolved_trait_item = nullptr;
|
||||
bool ok = trait->lookup_trait_item (type.get_new_type_name (),
|
||||
&resolved_trait_item);
|
||||
if (!ok)
|
||||
return;
|
||||
if (resolved_trait_item->get_trait_item_type ()
|
||||
!= TraitItemReference::TraitItemType::TYPE)
|
||||
return;
|
||||
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
|
||||
return;
|
||||
|
||||
// this might be generic
|
||||
TyTy::BaseType *substituted
|
||||
= SubstMapperInternal::Resolve (lookup, associated_type_args);
|
||||
resolved_trait_item->associated_type_set (substituted);
|
||||
});
|
||||
iter.go ();
|
||||
}
|
||||
|
||||
void
|
||||
AssociatedImplTrait::reset_associated_types ()
|
||||
{
|
||||
trait->clear_associated_types ();
|
||||
}
|
||||
|
||||
Analysis::NodeMapping
|
||||
TraitItemReference::get_parent_trait_mappings () const
|
||||
{
|
||||
auto mappings = Analysis::Mappings::get ();
|
||||
|
||||
HIR::Trait *trait
|
||||
= mappings->lookup_trait_item_mapping (get_mappings ().get_hirid ());
|
||||
rust_assert (trait != nullptr);
|
||||
|
||||
return trait->get_mappings ();
|
||||
}
|
||||
|
||||
bool
|
||||
TraitItemReference::is_object_safe () const
|
||||
{
|
||||
// https://doc.rust-lang.org/reference/items/traits.html#object-safety
|
||||
switch (get_trait_item_type ())
|
||||
{
|
||||
case TraitItemReference::TraitItemType::FN: {
|
||||
// lets be boring and just check that this is indeed a method will do
|
||||
// for now
|
||||
const HIR::TraitItem *item = get_hir_trait_item ();
|
||||
const HIR::TraitItemFunc *fn
|
||||
= static_cast<const HIR::TraitItemFunc *> (item);
|
||||
return fn->get_decl ().is_method ();
|
||||
}
|
||||
|
||||
// constants are not available via dyn dispatch and so is not object safe
|
||||
case TraitItemReference::TraitItemType::CONST:
|
||||
return false;
|
||||
|
||||
// types are object safe since they are not available via dyn dispatch
|
||||
case TraitItemReference::TraitItemType::TYPE:
|
||||
return true;
|
||||
|
||||
// this is just an error so lets just fail it
|
||||
case TraitItemReference::TraitItemType::ERROR:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// rust-hir-path-probe.h
|
||||
|
||||
void
|
||||
PathProbeImplTrait::process_trait_impl_items_for_candidates ()
|
||||
{
|
||||
mappings->iterate_impl_items (
|
||||
[&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
|
||||
// just need to check if this is an impl block for this trait the next
|
||||
// function checks the receiver
|
||||
if (!impl->has_trait_ref ())
|
||||
return true;
|
||||
|
||||
TraitReference *resolved
|
||||
= TraitResolver::Lookup (*(impl->get_trait_ref ().get ()));
|
||||
if (!trait_reference->is_equal (*resolved))
|
||||
return true;
|
||||
|
||||
process_impl_item_candidate (id, item, impl);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
87
gcc/rust/typecheck/rust-hir-trait-resolve.h
Normal file
87
gcc/rust/typecheck/rust-hir-trait-resolve.h
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2021-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TRAIT_RESOLVE_H
|
||||
#define RUST_HIR_TRAIT_RESOLVE_H
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-trait-ref.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class ResolveTraitItemToRef : public TypeCheckBase,
|
||||
private HIR::HIRTraitItemVisitor
|
||||
{
|
||||
public:
|
||||
static TraitItemReference
|
||||
Resolve (HIR::TraitItem &item, TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
{
|
||||
ResolveTraitItemToRef resolver (self, std::move (substitutions));
|
||||
item.accept_vis (resolver);
|
||||
return std::move (resolver.resolved);
|
||||
}
|
||||
|
||||
void visit (HIR::TraitItemType &type) override;
|
||||
|
||||
void visit (HIR::TraitItemConst &cst) override;
|
||||
|
||||
void visit (HIR::TraitItemFunc &fn) override;
|
||||
|
||||
private:
|
||||
ResolveTraitItemToRef (
|
||||
TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> &&substitutions);
|
||||
|
||||
TraitItemReference resolved;
|
||||
TyTy::BaseType *self;
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
};
|
||||
|
||||
class TraitResolver : public TypeCheckBase, private HIR::HIRFullVisitorBase
|
||||
{
|
||||
using HIR::HIRFullVisitorBase::visit;
|
||||
|
||||
public:
|
||||
static TraitReference *Resolve (HIR::TypePath &path);
|
||||
|
||||
static TraitReference *Resolve (HIR::Trait &trait);
|
||||
|
||||
static TraitReference *Lookup (HIR::TypePath &path);
|
||||
|
||||
private:
|
||||
TraitResolver ();
|
||||
|
||||
TraitReference *resolve_path (HIR::TypePath &path);
|
||||
|
||||
TraitReference *resolve_trait (HIR::Trait *trait_reference);
|
||||
|
||||
TraitReference *lookup_path (HIR::TypePath &path);
|
||||
|
||||
HIR::Trait *resolved_trait_reference;
|
||||
|
||||
public:
|
||||
void visit (HIR::Trait &trait) override { resolved_trait_reference = &trait; }
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TRAIT_RESOLVE_H
|
439
gcc/rust/typecheck/rust-hir-type-check-base.cc
Normal file
439
gcc/rust/typecheck/rust-hir-type-check-base.cc
Normal file
@ -0,0 +1,439 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-coercion.h"
|
||||
#include "rust-casts.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
bool
|
||||
TypeCheckBase::check_for_unconstrained (
|
||||
const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain,
|
||||
const TyTy::SubstitutionArgumentMappings &constraint_a,
|
||||
const TyTy::SubstitutionArgumentMappings &constraint_b,
|
||||
const TyTy::BaseType *reference)
|
||||
{
|
||||
std::set<HirId> symbols_to_constrain;
|
||||
std::map<HirId, Location> symbol_to_location;
|
||||
for (const auto &p : params_to_constrain)
|
||||
{
|
||||
HirId ref = p.get_param_ty ()->get_ref ();
|
||||
symbols_to_constrain.insert (ref);
|
||||
symbol_to_location.insert ({ref, p.get_param_locus ()});
|
||||
}
|
||||
|
||||
// set up the set of constrained symbols
|
||||
std::set<HirId> constrained_symbols;
|
||||
for (const auto &c : constraint_a.get_mappings ())
|
||||
{
|
||||
const TyTy::BaseType *arg = c.get_tyty ();
|
||||
if (arg != nullptr)
|
||||
{
|
||||
const TyTy::BaseType *p = arg->get_root ();
|
||||
constrained_symbols.insert (p->get_ty_ref ());
|
||||
}
|
||||
}
|
||||
for (const auto &c : constraint_b.get_mappings ())
|
||||
{
|
||||
const TyTy::BaseType *arg = c.get_tyty ();
|
||||
if (arg != nullptr)
|
||||
{
|
||||
const TyTy::BaseType *p = arg->get_root ();
|
||||
constrained_symbols.insert (p->get_ty_ref ());
|
||||
}
|
||||
}
|
||||
|
||||
const auto root = reference->get_root ();
|
||||
if (root->get_kind () == TyTy::TypeKind::PARAM)
|
||||
{
|
||||
const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (root);
|
||||
constrained_symbols.insert (p->get_ty_ref ());
|
||||
}
|
||||
|
||||
// check for unconstrained
|
||||
bool unconstrained = false;
|
||||
for (auto &sym : symbols_to_constrain)
|
||||
{
|
||||
bool used = constrained_symbols.find (sym) != constrained_symbols.end ();
|
||||
if (!used)
|
||||
{
|
||||
Location locus = symbol_to_location.at (sym);
|
||||
rust_error_at (locus, "unconstrained type parameter");
|
||||
unconstrained = true;
|
||||
}
|
||||
}
|
||||
return unconstrained;
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings,
|
||||
HIR::Literal &literal, Location locus)
|
||||
{
|
||||
TyTy::BaseType *infered = nullptr;
|
||||
switch (literal.get_lit_type ())
|
||||
{
|
||||
case HIR::Literal::LitType::INT: {
|
||||
bool ok = false;
|
||||
|
||||
switch (literal.get_type_hint ())
|
||||
{
|
||||
case CORETYPE_I8:
|
||||
ok = context->lookup_builtin ("i8", &infered);
|
||||
break;
|
||||
case CORETYPE_I16:
|
||||
ok = context->lookup_builtin ("i16", &infered);
|
||||
break;
|
||||
case CORETYPE_I32:
|
||||
ok = context->lookup_builtin ("i32", &infered);
|
||||
break;
|
||||
case CORETYPE_I64:
|
||||
ok = context->lookup_builtin ("i64", &infered);
|
||||
break;
|
||||
case CORETYPE_I128:
|
||||
ok = context->lookup_builtin ("i128", &infered);
|
||||
break;
|
||||
|
||||
case CORETYPE_U8:
|
||||
ok = context->lookup_builtin ("u8", &infered);
|
||||
break;
|
||||
case CORETYPE_U16:
|
||||
ok = context->lookup_builtin ("u16", &infered);
|
||||
break;
|
||||
case CORETYPE_U32:
|
||||
ok = context->lookup_builtin ("u32", &infered);
|
||||
break;
|
||||
case CORETYPE_U64:
|
||||
ok = context->lookup_builtin ("u64", &infered);
|
||||
break;
|
||||
case CORETYPE_U128:
|
||||
ok = context->lookup_builtin ("u128", &infered);
|
||||
break;
|
||||
|
||||
case CORETYPE_F32:
|
||||
literal.set_lit_type (HIR::Literal::LitType::FLOAT);
|
||||
ok = context->lookup_builtin ("f32", &infered);
|
||||
break;
|
||||
case CORETYPE_F64:
|
||||
literal.set_lit_type (HIR::Literal::LitType::FLOAT);
|
||||
ok = context->lookup_builtin ("f64", &infered);
|
||||
break;
|
||||
|
||||
case CORETYPE_ISIZE:
|
||||
ok = context->lookup_builtin ("isize", &infered);
|
||||
break;
|
||||
|
||||
case CORETYPE_USIZE:
|
||||
ok = context->lookup_builtin ("usize", &infered);
|
||||
break;
|
||||
|
||||
default:
|
||||
ok = true;
|
||||
infered
|
||||
= new TyTy::InferType (expr_mappings.get_hirid (),
|
||||
TyTy::InferType::InferTypeKind::INTEGRAL,
|
||||
locus);
|
||||
break;
|
||||
}
|
||||
rust_assert (ok);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::Literal::LitType::FLOAT: {
|
||||
bool ok = false;
|
||||
|
||||
switch (literal.get_type_hint ())
|
||||
{
|
||||
case CORETYPE_F32:
|
||||
ok = context->lookup_builtin ("f32", &infered);
|
||||
break;
|
||||
case CORETYPE_F64:
|
||||
ok = context->lookup_builtin ("f64", &infered);
|
||||
break;
|
||||
|
||||
default:
|
||||
ok = true;
|
||||
infered
|
||||
= new TyTy::InferType (expr_mappings.get_hirid (),
|
||||
TyTy::InferType::InferTypeKind::FLOAT,
|
||||
locus);
|
||||
break;
|
||||
}
|
||||
rust_assert (ok);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::Literal::LitType::BOOL: {
|
||||
auto ok = context->lookup_builtin ("bool", &infered);
|
||||
rust_assert (ok);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::Literal::LitType::CHAR: {
|
||||
auto ok = context->lookup_builtin ("char", &infered);
|
||||
rust_assert (ok);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::Literal::LitType::BYTE: {
|
||||
auto ok = context->lookup_builtin ("u8", &infered);
|
||||
rust_assert (ok);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::Literal::LitType::STRING: {
|
||||
TyTy::BaseType *base = nullptr;
|
||||
auto ok = context->lookup_builtin ("str", &base);
|
||||
rust_assert (ok);
|
||||
|
||||
infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
|
||||
TyTy::TyVar (base->get_ref ()),
|
||||
Mutability::Imm);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::Literal::LitType::BYTE_STRING: {
|
||||
/* This is an arraytype of u8 reference (&[u8;size]). It isn't in
|
||||
UTF-8, but really just a byte array. Code to construct the array
|
||||
reference copied from ArrayElemsValues and ArrayType. */
|
||||
TyTy::BaseType *u8;
|
||||
auto ok = context->lookup_builtin ("u8", &u8);
|
||||
rust_assert (ok);
|
||||
|
||||
auto crate_num = mappings->get_current_crate ();
|
||||
Analysis::NodeMapping capacity_mapping (crate_num, UNKNOWN_NODEID,
|
||||
mappings->get_next_hir_id (
|
||||
crate_num),
|
||||
UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
/* Capacity is the size of the string (number of chars).
|
||||
It is a constant, but for fold it to get a tree. */
|
||||
std::string capacity_str
|
||||
= std::to_string (literal.as_string ().size ());
|
||||
HIR::LiteralExpr *literal_capacity
|
||||
= new HIR::LiteralExpr (capacity_mapping, capacity_str,
|
||||
HIR::Literal::LitType::INT,
|
||||
PrimitiveCoreType::CORETYPE_USIZE, locus, {});
|
||||
|
||||
// mark the type for this implicit node
|
||||
TyTy::BaseType *expected_ty = nullptr;
|
||||
ok = context->lookup_builtin ("usize", &expected_ty);
|
||||
rust_assert (ok);
|
||||
context->insert_type (capacity_mapping, expected_ty);
|
||||
|
||||
Analysis::NodeMapping array_mapping (crate_num, UNKNOWN_NODEID,
|
||||
mappings->get_next_hir_id (
|
||||
crate_num),
|
||||
UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
TyTy::ArrayType *array
|
||||
= new TyTy::ArrayType (array_mapping.get_hirid (), locus,
|
||||
*literal_capacity,
|
||||
TyTy::TyVar (u8->get_ref ()));
|
||||
context->insert_type (array_mapping, array);
|
||||
|
||||
infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
|
||||
TyTy::TyVar (array->get_ref ()),
|
||||
Mutability::Imm);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
break;
|
||||
}
|
||||
|
||||
return infered;
|
||||
}
|
||||
|
||||
TyTy::ADTType::ReprOptions
|
||||
TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, Location locus)
|
||||
{
|
||||
TyTy::ADTType::ReprOptions repr;
|
||||
repr.pack = 0;
|
||||
repr.align = 0;
|
||||
|
||||
for (const auto &attr : attrs)
|
||||
{
|
||||
bool is_repr = attr.get_path ().as_string ().compare ("repr") == 0;
|
||||
if (is_repr)
|
||||
{
|
||||
const AST::AttrInput &input = attr.get_attr_input ();
|
||||
bool is_token_tree = input.get_attr_input_type ()
|
||||
== AST::AttrInput::AttrInputType::TOKEN_TREE;
|
||||
rust_assert (is_token_tree);
|
||||
const auto &option = static_cast<const AST::DelimTokenTree &> (input);
|
||||
AST::AttrInputMetaItemContainer *meta_items
|
||||
= option.parse_to_meta_item ();
|
||||
|
||||
const std::string inline_option
|
||||
= meta_items->get_items ().at (0)->as_string ();
|
||||
|
||||
// TODO: it would probably be better to make the MetaItems more aware
|
||||
// of constructs with nesting like #[repr(packed(2))] rather than
|
||||
// manually parsing the string "packed(2)" here.
|
||||
|
||||
size_t oparen = inline_option.find ('(', 0);
|
||||
bool is_pack = false, is_align = false;
|
||||
unsigned char value = 1;
|
||||
|
||||
if (oparen == std::string::npos)
|
||||
{
|
||||
is_pack = inline_option.compare ("packed") == 0;
|
||||
is_align = inline_option.compare ("align") == 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
std::string rep = inline_option.substr (0, oparen);
|
||||
is_pack = rep.compare ("packed") == 0;
|
||||
is_align = rep.compare ("align") == 0;
|
||||
|
||||
size_t cparen = inline_option.find (')', oparen);
|
||||
if (cparen == std::string::npos)
|
||||
{
|
||||
rust_error_at (locus, "malformed attribute");
|
||||
}
|
||||
|
||||
std::string value_str = inline_option.substr (oparen, cparen);
|
||||
value = strtoul (value_str.c_str () + 1, NULL, 10);
|
||||
}
|
||||
|
||||
if (is_pack)
|
||||
repr.pack = value;
|
||||
else if (is_align)
|
||||
repr.align = value;
|
||||
|
||||
// Multiple repr options must be specified with e.g. #[repr(C,
|
||||
// packed(2))].
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return repr;
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckBase::coercion_site (HirId id, TyTy::BaseType *expected,
|
||||
TyTy::BaseType *expr, Location locus)
|
||||
{
|
||||
rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
|
||||
expected->debug_str ().c_str (), expr->debug_str ().c_str ());
|
||||
|
||||
auto context = TypeCheckContext::get ();
|
||||
if (expected->get_kind () == TyTy::TypeKind::ERROR
|
||||
|| expr->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return expr;
|
||||
|
||||
// can we autoderef it?
|
||||
auto result = TypeCoercionRules::Coerce (expr, expected, locus);
|
||||
|
||||
// the result needs to be unified
|
||||
TyTy::BaseType *receiver = expr;
|
||||
if (!result.is_error ())
|
||||
{
|
||||
receiver = result.tyty;
|
||||
}
|
||||
|
||||
rust_debug ("coerce_default_unify(a={%s}, b={%s})",
|
||||
receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
|
||||
TyTy::BaseType *coerced = expected->unify (receiver);
|
||||
context->insert_autoderef_mappings (id, std::move (result.adjustments));
|
||||
return coerced;
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckBase::cast_site (HirId id, TyTy::TyWithLocation from,
|
||||
TyTy::TyWithLocation to, Location cast_locus)
|
||||
{
|
||||
rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
|
||||
from.get_ty ()->debug_str ().c_str (),
|
||||
to.get_ty ()->debug_str ().c_str ());
|
||||
|
||||
auto context = TypeCheckContext::get ();
|
||||
if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
|
||||
|| to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return to.get_ty ();
|
||||
|
||||
// do the cast
|
||||
auto result = TypeCastRules::resolve (cast_locus, from, to);
|
||||
|
||||
// we assume error has already been emitted
|
||||
if (result.is_error ())
|
||||
return to.get_ty ();
|
||||
|
||||
// the result needs to be unified
|
||||
TyTy::BaseType *casted_result = result.tyty;
|
||||
rust_debug ("cast_default_unify(a={%s}, b={%s})",
|
||||
casted_result->debug_str ().c_str (),
|
||||
to.get_ty ()->debug_str ().c_str ());
|
||||
TyTy::BaseType *casted = to.get_ty ()->unify (casted_result);
|
||||
context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
|
||||
return casted;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckBase::resolve_generic_params (
|
||||
const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
|
||||
std::vector<TyTy::SubstitutionParamMapping> &substitutions)
|
||||
{
|
||||
for (auto &generic_param : generic_params)
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
// FIXME: Skipping Lifetime completely until better
|
||||
// handling.
|
||||
break;
|
||||
case HIR::GenericParam::GenericKind::CONST: {
|
||||
auto param
|
||||
= static_cast<HIR::ConstGenericParam *> (generic_param.get ());
|
||||
auto specified_type
|
||||
= TypeCheckType::Resolve (param->get_type ().get ());
|
||||
|
||||
if (param->has_default_expression ())
|
||||
{
|
||||
auto expr_type = TypeCheckExpr::Resolve (
|
||||
param->get_default_expression ().get ());
|
||||
|
||||
specified_type->unify (expr_type);
|
||||
}
|
||||
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
specified_type);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (), param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
80
gcc/rust/typecheck/rust-hir-type-check-base.h
Normal file
80
gcc/rust/typecheck/rust-hir-type-check-base.h
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_BASE
|
||||
#define RUST_HIR_TYPE_CHECK_BASE
|
||||
|
||||
#include "rust-diagnostics.h"
|
||||
#include "rust-hir-type-check.h"
|
||||
#include "rust-name-resolver.h"
|
||||
#include "rust-hir-visitor.h"
|
||||
#include "rust-hir-map.h"
|
||||
#include "rust-backend.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TraitReference;
|
||||
class TypeCheckBase
|
||||
{
|
||||
public:
|
||||
virtual ~TypeCheckBase () {}
|
||||
|
||||
static TyTy::BaseType *coercion_site (HirId id, TyTy::BaseType *lhs,
|
||||
TyTy::BaseType *rhs,
|
||||
Location coercion_locus);
|
||||
|
||||
static TyTy::BaseType *cast_site (HirId id, TyTy::TyWithLocation from,
|
||||
TyTy::TyWithLocation to,
|
||||
Location cast_locus);
|
||||
|
||||
protected:
|
||||
TypeCheckBase ()
|
||||
: mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()),
|
||||
context (TypeCheckContext::get ())
|
||||
{}
|
||||
|
||||
TraitReference *resolve_trait_path (HIR::TypePath &);
|
||||
|
||||
TyTy::TypeBoundPredicate get_predicate_from_bound (HIR::TypePath &path);
|
||||
|
||||
bool check_for_unconstrained (
|
||||
const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain,
|
||||
const TyTy::SubstitutionArgumentMappings &constraint_a,
|
||||
const TyTy::SubstitutionArgumentMappings &constraint_b,
|
||||
const TyTy::BaseType *reference);
|
||||
|
||||
TyTy::BaseType *resolve_literal (const Analysis::NodeMapping &mappings,
|
||||
HIR::Literal &literal, Location locus);
|
||||
|
||||
TyTy::ADTType::ReprOptions parse_repr_options (const AST::AttrVec &attrs,
|
||||
Location locus);
|
||||
|
||||
void resolve_generic_params (
|
||||
const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
|
||||
std::vector<TyTy::SubstitutionParamMapping> &substitutions);
|
||||
|
||||
Analysis::Mappings *mappings;
|
||||
Resolver *resolver;
|
||||
TypeCheckContext *context;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_BASE
|
213
gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
Normal file
213
gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
Normal file
@ -0,0 +1,213 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-enumitem.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TyTy::VariantDef *
|
||||
TypeCheckEnumItem::Resolve (HIR::EnumItem *item, int64_t last_discriminant)
|
||||
{
|
||||
TypeCheckEnumItem resolver (last_discriminant);
|
||||
switch (item->get_enum_item_kind ())
|
||||
{
|
||||
case HIR::EnumItem::EnumItemKind::Named:
|
||||
resolver.visit (static_cast<HIR::EnumItem &> (*item));
|
||||
break;
|
||||
|
||||
case HIR::EnumItem::EnumItemKind::Tuple:
|
||||
resolver.visit (static_cast<HIR::EnumItemTuple &> (*item));
|
||||
break;
|
||||
|
||||
case HIR::EnumItem::EnumItemKind::Struct:
|
||||
resolver.visit (static_cast<HIR::EnumItemStruct &> (*item));
|
||||
break;
|
||||
|
||||
case HIR::EnumItem::EnumItemKind::Discriminant:
|
||||
resolver.visit (static_cast<HIR::EnumItemDiscriminant &> (*item));
|
||||
break;
|
||||
}
|
||||
return resolver.variant;
|
||||
}
|
||||
|
||||
TypeCheckEnumItem::TypeCheckEnumItem (int64_t last_discriminant)
|
||||
: TypeCheckBase (), variant (nullptr), last_discriminant (last_discriminant)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckEnumItem::visit (HIR::EnumItem &item)
|
||||
{
|
||||
if (last_discriminant == INT64_MAX)
|
||||
rust_error_at (item.get_locus (), "discriminant too big");
|
||||
|
||||
Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (),
|
||||
item.get_mappings ().get_nodeid (),
|
||||
mappings->get_next_hir_id (
|
||||
item.get_mappings ().get_crate_num ()),
|
||||
item.get_mappings ().get_local_defid ());
|
||||
HIR::LiteralExpr *discim_expr
|
||||
= new HIR::LiteralExpr (mapping, std::to_string (last_discriminant),
|
||||
HIR::Literal::LitType::INT,
|
||||
PrimitiveCoreType::CORETYPE_I64, item.get_locus (),
|
||||
{});
|
||||
|
||||
TyTy::BaseType *isize = nullptr;
|
||||
bool ok = context->lookup_builtin ("isize", &isize);
|
||||
rust_assert (ok);
|
||||
context->insert_type (mapping, isize);
|
||||
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, item.get_locus ()};
|
||||
variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
|
||||
item.get_identifier (), ident, discim_expr);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckEnumItem::visit (HIR::EnumItemDiscriminant &item)
|
||||
{
|
||||
if (last_discriminant == INT64_MAX)
|
||||
rust_error_at (item.get_locus (), "discriminant too big");
|
||||
|
||||
auto &discriminant = item.get_discriminant_expression ();
|
||||
auto capacity_type = TypeCheckExpr::Resolve (discriminant.get ());
|
||||
if (capacity_type->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
TyTy::ISizeType *expected_ty
|
||||
= new TyTy::ISizeType (discriminant->get_mappings ().get_hirid ());
|
||||
context->insert_type (discriminant->get_mappings (), expected_ty);
|
||||
|
||||
auto unified = expected_ty->unify (capacity_type);
|
||||
if (unified->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, item.get_locus ()};
|
||||
variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
|
||||
item.get_identifier (), ident,
|
||||
item.get_discriminant_expression ().get ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckEnumItem::visit (HIR::EnumItemTuple &item)
|
||||
{
|
||||
if (last_discriminant == INT64_MAX)
|
||||
rust_error_at (item.get_locus (), "discriminant too big");
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
size_t idx = 0;
|
||||
for (auto &field : item.get_tuple_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
std::to_string (idx), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
|
||||
idx++;
|
||||
}
|
||||
|
||||
Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (),
|
||||
item.get_mappings ().get_nodeid (),
|
||||
mappings->get_next_hir_id (
|
||||
item.get_mappings ().get_crate_num ()),
|
||||
item.get_mappings ().get_local_defid ());
|
||||
HIR::LiteralExpr *discim_expr
|
||||
= new HIR::LiteralExpr (mapping, std::to_string (last_discriminant),
|
||||
HIR::Literal::LitType::INT,
|
||||
PrimitiveCoreType::CORETYPE_I64, item.get_locus (),
|
||||
{});
|
||||
|
||||
TyTy::BaseType *isize = nullptr;
|
||||
bool ok = context->lookup_builtin ("isize", &isize);
|
||||
rust_assert (ok);
|
||||
context->insert_type (mapping, isize);
|
||||
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, item.get_locus ()};
|
||||
variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
|
||||
item.get_identifier (), ident,
|
||||
TyTy::VariantDef::VariantType::TUPLE,
|
||||
discim_expr, fields);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckEnumItem::visit (HIR::EnumItemStruct &item)
|
||||
{
|
||||
if (last_discriminant == INT64_MAX)
|
||||
rust_error_at (item.get_locus (), "discriminant too big");
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &field : item.get_struct_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
field.get_field_name (), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
|
||||
}
|
||||
|
||||
Analysis::NodeMapping mapping (item.get_mappings ().get_crate_num (),
|
||||
item.get_mappings ().get_nodeid (),
|
||||
mappings->get_next_hir_id (
|
||||
item.get_mappings ().get_crate_num ()),
|
||||
item.get_mappings ().get_local_defid ());
|
||||
HIR::LiteralExpr *discrim_expr
|
||||
= new HIR::LiteralExpr (mapping, std::to_string (last_discriminant),
|
||||
HIR::Literal::LitType::INT,
|
||||
PrimitiveCoreType::CORETYPE_I64, item.get_locus (),
|
||||
{});
|
||||
|
||||
TyTy::BaseType *isize = nullptr;
|
||||
bool ok = context->lookup_builtin ("isize", &isize);
|
||||
rust_assert (ok);
|
||||
context->insert_type (mapping, isize);
|
||||
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
ok = mappings->lookup_canonical_path (item.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, item.get_locus ()};
|
||||
variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
|
||||
item.get_identifier (), ident,
|
||||
TyTy::VariantDef::VariantType::STRUCT,
|
||||
discrim_expr, fields);
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
50
gcc/rust/typecheck/rust-hir-type-check-enumitem.h
Normal file
50
gcc/rust/typecheck/rust-hir-type-check-enumitem.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_ENUMITEM
|
||||
#define RUST_HIR_TYPE_CHECK_ENUMITEM
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckEnumItem : public TypeCheckBase
|
||||
{
|
||||
public:
|
||||
static TyTy::VariantDef *Resolve (HIR::EnumItem *item,
|
||||
int64_t last_discriminant);
|
||||
|
||||
protected:
|
||||
void visit (HIR::EnumItem &item);
|
||||
void visit (HIR::EnumItemDiscriminant &item);
|
||||
void visit (HIR::EnumItemTuple &item);
|
||||
void visit (HIR::EnumItemStruct &item);
|
||||
|
||||
private:
|
||||
TypeCheckEnumItem (int64_t last_discriminant);
|
||||
|
||||
TyTy::VariantDef *variant;
|
||||
int64_t last_discriminant;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_ENUMITEM
|
1567
gcc/rust/typecheck/rust-hir-type-check-expr.cc
Normal file
1567
gcc/rust/typecheck/rust-hir-type-check-expr.cc
Normal file
File diff suppressed because it is too large
Load Diff
131
gcc/rust/typecheck/rust-hir-type-check-expr.h
Normal file
131
gcc/rust/typecheck/rust-hir-type-check-expr.h
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_EXPR
|
||||
#define RUST_HIR_TYPE_CHECK_EXPR
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-tyty.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckExpr : public TypeCheckBase, private HIR::HIRExpressionVisitor
|
||||
{
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (HIR::Expr *expr);
|
||||
|
||||
void visit (HIR::TupleIndexExpr &expr) override;
|
||||
void visit (HIR::TupleExpr &expr) override;
|
||||
void visit (HIR::ReturnExpr &expr) override;
|
||||
void visit (HIR::CallExpr &expr) override;
|
||||
void visit (HIR::MethodCallExpr &expr) override;
|
||||
void visit (HIR::AssignmentExpr &expr) override;
|
||||
void visit (HIR::CompoundAssignmentExpr &expr) override;
|
||||
void visit (HIR::LiteralExpr &expr) override;
|
||||
void visit (HIR::ArithmeticOrLogicalExpr &expr) override;
|
||||
void visit (HIR::ComparisonExpr &expr) override;
|
||||
void visit (HIR::LazyBooleanExpr &expr) override;
|
||||
void visit (HIR::NegationExpr &expr) override;
|
||||
void visit (HIR::IfExpr &expr) override;
|
||||
void visit (HIR::IfExprConseqElse &expr) override;
|
||||
void visit (HIR::IfExprConseqIf &expr) override;
|
||||
void visit (HIR::IfLetExpr &expr) override;
|
||||
void visit (HIR::BlockExpr &expr) override;
|
||||
void visit (HIR::UnsafeBlockExpr &expr) override;
|
||||
void visit (HIR::ArrayIndexExpr &expr) override;
|
||||
void visit (HIR::ArrayExpr &expr) override;
|
||||
void visit (HIR::StructExprStruct &struct_expr) override;
|
||||
void visit (HIR::StructExprStructFields &struct_expr) override;
|
||||
void visit (HIR::GroupedExpr &expr) override;
|
||||
void visit (HIR::FieldAccessExpr &expr) override;
|
||||
void visit (HIR::QualifiedPathInExpression &expr) override;
|
||||
void visit (HIR::PathInExpression &expr) override;
|
||||
void visit (HIR::LoopExpr &expr) override;
|
||||
void visit (HIR::BreakExpr &expr) override;
|
||||
void visit (HIR::ContinueExpr &expr) override;
|
||||
void visit (HIR::BorrowExpr &expr) override;
|
||||
void visit (HIR::DereferenceExpr &expr) override;
|
||||
void visit (HIR::TypeCastExpr &expr) override;
|
||||
void visit (HIR::MatchExpr &expr) override;
|
||||
void visit (HIR::RangeFromToExpr &expr) override;
|
||||
void visit (HIR::RangeFromExpr &expr) override;
|
||||
void visit (HIR::RangeToExpr &expr) override;
|
||||
void visit (HIR::RangeFullExpr &expr) override;
|
||||
void visit (HIR::RangeFromToInclExpr &expr) override;
|
||||
void visit (HIR::WhileLoopExpr &expr) override;
|
||||
|
||||
// TODO
|
||||
void visit (HIR::ClosureExprInnerTyped &) override {}
|
||||
void visit (HIR::ClosureExprInner &expr) override {}
|
||||
void visit (HIR::ErrorPropagationExpr &expr) override {}
|
||||
void visit (HIR::RangeToInclExpr &expr) override {}
|
||||
void visit (HIR::WhileLetLoopExpr &expr) override {}
|
||||
void visit (HIR::ForLoopExpr &expr) override {}
|
||||
void visit (HIR::IfExprConseqIfLet &expr) override {}
|
||||
void visit (HIR::IfLetExprConseqElse &expr) override {}
|
||||
void visit (HIR::IfLetExprConseqIf &expr) override {}
|
||||
void visit (HIR::IfLetExprConseqIfLet &expr) override {}
|
||||
void visit (HIR::AwaitExpr &expr) override {}
|
||||
void visit (HIR::AsyncBlockExpr &expr) override {}
|
||||
|
||||
// don't need to implement these see rust-hir-type-check-struct-field.h
|
||||
void visit (HIR::StructExprFieldIdentifier &field) override
|
||||
{
|
||||
gcc_unreachable ();
|
||||
}
|
||||
void visit (HIR::StructExprFieldIdentifierValue &field) override
|
||||
{
|
||||
gcc_unreachable ();
|
||||
}
|
||||
void visit (HIR::StructExprFieldIndexValue &field) override
|
||||
{
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_type,
|
||||
HIR::OperatorExprMeta expr, TyTy::BaseType *lhs,
|
||||
TyTy::BaseType *rhs);
|
||||
|
||||
private:
|
||||
TypeCheckExpr ();
|
||||
|
||||
TyTy::BaseType *resolve_root_path (HIR::PathInExpression &expr,
|
||||
size_t *offset,
|
||||
NodeId *root_resolved_node_id);
|
||||
|
||||
void resolve_segments (NodeId root_resolved_node_id,
|
||||
std::vector<HIR::PathExprSegment> &segments,
|
||||
size_t offset, TyTy::BaseType *tyseg,
|
||||
const Analysis::NodeMapping &expr_mappings,
|
||||
Location expr_locus);
|
||||
|
||||
bool
|
||||
validate_arithmetic_type (const TyTy::BaseType *tyty,
|
||||
HIR::ArithmeticOrLogicalExpr::ExprType expr_type);
|
||||
|
||||
/* The return value of TypeCheckExpr::Resolve */
|
||||
TyTy::BaseType *infered;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_EXPR
|
583
gcc/rust/typecheck/rust-hir-type-check-implitem.cc
Normal file
583
gcc/rust/typecheck/rust-hir-type-check-implitem.cc
Normal file
@ -0,0 +1,583 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-implitem.h"
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-pattern.h"
|
||||
#include "rust-tyty.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCheckTopLevelExternItem::TypeCheckTopLevelExternItem (
|
||||
const HIR::ExternBlock &parent)
|
||||
: TypeCheckBase (), parent (parent)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelExternItem::Resolve (HIR::ExternalItem *item,
|
||||
const HIR::ExternBlock &parent)
|
||||
{
|
||||
TypeCheckTopLevelExternItem resolver (parent);
|
||||
item->accept_vis (resolver);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelExternItem::visit (HIR::ExternalStaticItem &item)
|
||||
{
|
||||
TyTy::BaseType *actual_type
|
||||
= TypeCheckType::Resolve (item.get_item_type ().get ());
|
||||
|
||||
context->insert_type (item.get_mappings (), actual_type);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (function.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : function.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_return_type ())
|
||||
ret_type
|
||||
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved == nullptr)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"failed to resolve return type");
|
||||
return;
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ());
|
||||
|
||||
// these are implicit mappings and not used
|
||||
auto crate_num = mappings->get_current_crate ();
|
||||
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
|
||||
mappings->get_next_hir_id (crate_num),
|
||||
UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
HIR::IdentifierPattern *param_pattern
|
||||
= new HIR::IdentifierPattern (mapping, param.get_param_name (),
|
||||
Location (), false, Mutability::Imm,
|
||||
std::unique_ptr<HIR::Pattern> (nullptr));
|
||||
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern,
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
|
||||
// FIXME do we need error checking for patterns here?
|
||||
// see https://github.com/Rust-GCC/gccrs/issues/995
|
||||
}
|
||||
|
||||
uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG;
|
||||
if (function.is_variadic ())
|
||||
flags |= TyTy::FnType::FNTYPE_IS_VARADIC_FLAG;
|
||||
|
||||
RustIdent ident{
|
||||
CanonicalPath::new_seg (function.get_mappings ().get_nodeid (),
|
||||
function.get_item_name ()),
|
||||
function.get_locus ()};
|
||||
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_item_name (), ident, flags,
|
||||
parent.get_abi (), std::move (params),
|
||||
ret_type, std::move (substitutions));
|
||||
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
}
|
||||
|
||||
TypeCheckTopLevelImplItem::TypeCheckTopLevelImplItem (
|
||||
TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
: TypeCheckBase (), self (self), substitutions (substitutions)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelImplItem::Resolve (
|
||||
HIR::ImplItem *item, TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
{
|
||||
TypeCheckTopLevelImplItem resolver (self, substitutions);
|
||||
item->accept_vis (resolver);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelImplItem::visit (HIR::TypeAlias &alias)
|
||||
{
|
||||
TyTy::BaseType *actual_type
|
||||
= TypeCheckType::Resolve (alias.get_type_aliased ().get ());
|
||||
|
||||
context->insert_type (alias.get_mappings (), actual_type);
|
||||
|
||||
for (auto &where_clause_item : alias.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelImplItem::visit (HIR::ConstantItem &constant)
|
||||
{
|
||||
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
|
||||
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
|
||||
|
||||
context->insert_type (constant.get_mappings (), type->unify (expr_type));
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevelImplItem::visit (HIR::Function &function)
|
||||
{
|
||||
if (function.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : function.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &where_clause_item : function.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_function_return_type ())
|
||||
ret_type
|
||||
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved == nullptr)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"failed to resolve return type");
|
||||
return;
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
|
||||
if (function.is_method ())
|
||||
{
|
||||
// these are implicit mappings and not used
|
||||
auto crate_num = mappings->get_current_crate ();
|
||||
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
|
||||
mappings->get_next_hir_id (crate_num),
|
||||
UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
// add the synthetic self param at the front, this is a placeholder for
|
||||
// compilation to know parameter names. The types are ignored but we
|
||||
// reuse the HIR identifier pattern which requires it
|
||||
HIR::SelfParam &self_param = function.get_self_param ();
|
||||
HIR::IdentifierPattern *self_pattern
|
||||
= new HIR::IdentifierPattern (mapping, "self", self_param.get_locus (),
|
||||
self_param.is_ref (),
|
||||
self_param.get_mut (),
|
||||
std::unique_ptr<HIR::Pattern> (nullptr));
|
||||
|
||||
// might have a specified type
|
||||
TyTy::BaseType *self_type = nullptr;
|
||||
if (self_param.has_type ())
|
||||
{
|
||||
std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
|
||||
self_type = TypeCheckType::Resolve (specified_type.get ());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (self_param.get_self_kind ())
|
||||
{
|
||||
case HIR::SelfParam::IMM:
|
||||
case HIR::SelfParam::MUT:
|
||||
self_type = self->clone ();
|
||||
break;
|
||||
|
||||
case HIR::SelfParam::IMM_REF:
|
||||
self_type = new TyTy::ReferenceType (
|
||||
self_param.get_mappings ().get_hirid (),
|
||||
TyTy::TyVar (self->get_ref ()), Mutability::Imm);
|
||||
break;
|
||||
|
||||
case HIR::SelfParam::MUT_REF:
|
||||
self_type = new TyTy::ReferenceType (
|
||||
self_param.get_mappings ().get_hirid (),
|
||||
TyTy::TyVar (self->get_ref ()), Mutability::Mut);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
context->insert_type (self_param.get_mappings (), self_type);
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type));
|
||||
}
|
||||
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
|
||||
}
|
||||
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, function.get_locus ()};
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_function_name (), ident,
|
||||
function.is_method ()
|
||||
? TyTy::FnType::FNTYPE_IS_METHOD_FLAG
|
||||
: TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
|
||||
ABI::RUST, std::move (params), ret_type,
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
}
|
||||
|
||||
TypeCheckImplItem::TypeCheckImplItem (HIR::ImplBlock *parent,
|
||||
TyTy::BaseType *self)
|
||||
: TypeCheckBase (), parent (parent), self (self)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckImplItem::Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
|
||||
TyTy::BaseType *self)
|
||||
{
|
||||
TypeCheckImplItem resolver (parent, self);
|
||||
item->accept_vis (resolver);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItem::visit (HIR::Function &function)
|
||||
{
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
|
||||
{
|
||||
rust_error_at (function.get_locus (), "failed to lookup function type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"found invalid type for function [%s]",
|
||||
lookup->as_string ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// need to get the return type from this
|
||||
TyTy::FnType *resolve_fn_type = static_cast<TyTy::FnType *> (lookup);
|
||||
auto expected_ret_tyty = resolve_fn_type->get_return_type ();
|
||||
context->push_return_type (TypeCheckContextItem (parent, &function),
|
||||
expected_ret_tyty);
|
||||
|
||||
auto block_expr_ty
|
||||
= TypeCheckExpr::Resolve (function.get_definition ().get ());
|
||||
|
||||
context->pop_return_type ();
|
||||
expected_ret_tyty->unify (block_expr_ty);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItem::visit (HIR::ConstantItem &const_item)
|
||||
{}
|
||||
|
||||
void
|
||||
TypeCheckImplItem::visit (HIR::TypeAlias &type_alias)
|
||||
{}
|
||||
|
||||
TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait (
|
||||
HIR::ImplBlock *parent, TyTy::BaseType *self,
|
||||
TyTy::TypeBoundPredicate &trait_reference,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
: TypeCheckImplItem (parent, self), trait_reference (trait_reference),
|
||||
resolved_trait_item (TyTy::TypeBoundPredicateItem::error ()),
|
||||
substitutions (substitutions)
|
||||
{
|
||||
rust_assert (is_trait_impl_block ());
|
||||
}
|
||||
|
||||
TyTy::TypeBoundPredicateItem
|
||||
TypeCheckImplItemWithTrait::Resolve (
|
||||
HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
|
||||
TyTy::TypeBoundPredicate &trait_reference,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions)
|
||||
{
|
||||
TypeCheckImplItemWithTrait resolver (parent, self, trait_reference,
|
||||
substitutions);
|
||||
item->accept_vis (resolver);
|
||||
return resolver.resolved_trait_item;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant)
|
||||
{
|
||||
// normal resolution of the item
|
||||
TypeCheckImplItem::visit (constant);
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup))
|
||||
return;
|
||||
|
||||
// map the impl item to the associated trait item
|
||||
const auto tref = trait_reference.get ();
|
||||
const TraitItemReference *raw_trait_item = nullptr;
|
||||
bool found
|
||||
= tref->lookup_trait_item_by_type (constant.get_identifier (),
|
||||
TraitItemReference::TraitItemType::CONST,
|
||||
&raw_trait_item);
|
||||
|
||||
// unknown trait item
|
||||
if (!found || raw_trait_item->is_error ())
|
||||
{
|
||||
RichLocation r (constant.get_locus ());
|
||||
r.add_range (trait_reference.get_locus ());
|
||||
rust_error_at (r, "constant %<%s%> is not a member of trait %<%s%>",
|
||||
constant.get_identifier ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the item from the predicate
|
||||
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
|
||||
rust_assert (!resolved_trait_item.is_error ());
|
||||
|
||||
// merge the attributes
|
||||
const HIR::TraitItem *hir_trait_item
|
||||
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
|
||||
merge_attributes (constant.get_outer_attrs (), *hir_trait_item);
|
||||
|
||||
// check the types are compatible
|
||||
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
|
||||
if (!trait_item_type->can_eq (lookup, true))
|
||||
{
|
||||
RichLocation r (constant.get_locus ());
|
||||
r.add_range (resolved_trait_item.get_locus ());
|
||||
|
||||
rust_error_at (
|
||||
r, "constant %<%s%> has an incompatible type for trait %<%s%>",
|
||||
constant.get_identifier ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
|
||||
{
|
||||
// normal resolution of the item
|
||||
TypeCheckImplItem::visit (type);
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
|
||||
return;
|
||||
|
||||
// map the impl item to the associated trait item
|
||||
const auto tref = trait_reference.get ();
|
||||
const TraitItemReference *raw_trait_item = nullptr;
|
||||
bool found
|
||||
= tref->lookup_trait_item_by_type (type.get_new_type_name (),
|
||||
TraitItemReference::TraitItemType::TYPE,
|
||||
&raw_trait_item);
|
||||
|
||||
// unknown trait item
|
||||
if (!found || raw_trait_item->is_error ())
|
||||
{
|
||||
RichLocation r (type.get_locus ());
|
||||
r.add_range (trait_reference.get_locus ());
|
||||
rust_error_at (r, "type alias %<%s%> is not a member of trait %<%s%>",
|
||||
type.get_new_type_name ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the item from the predicate
|
||||
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
|
||||
rust_assert (!resolved_trait_item.is_error ());
|
||||
|
||||
// merge the attributes
|
||||
const HIR::TraitItem *hir_trait_item
|
||||
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
|
||||
merge_attributes (type.get_outer_attrs (), *hir_trait_item);
|
||||
|
||||
// check the types are compatible
|
||||
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
|
||||
if (!trait_item_type->can_eq (lookup, true))
|
||||
{
|
||||
RichLocation r (type.get_locus ());
|
||||
r.add_range (resolved_trait_item.get_locus ());
|
||||
|
||||
rust_error_at (
|
||||
r, "type alias %<%s%> has an incompatible type for trait %<%s%>",
|
||||
type.get_new_type_name ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
}
|
||||
|
||||
// its actually a projection, since we need a way to actually bind the
|
||||
// generic substitutions to the type itself
|
||||
TyTy::ProjectionType *projection
|
||||
= new TyTy::ProjectionType (type.get_mappings ().get_hirid (), lookup, tref,
|
||||
raw_trait_item->get_mappings ().get_defid (),
|
||||
substitutions);
|
||||
|
||||
context->insert_type (type.get_mappings (), projection);
|
||||
raw_trait_item->associated_type_set (projection);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItemWithTrait::visit (HIR::Function &function)
|
||||
{
|
||||
// we get the error checking from the base method here
|
||||
TypeCheckImplItem::visit (function);
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
|
||||
return;
|
||||
|
||||
// map the impl item to the associated trait item
|
||||
const auto tref = trait_reference.get ();
|
||||
const TraitItemReference *raw_trait_item = nullptr;
|
||||
bool found
|
||||
= tref->lookup_trait_item_by_type (function.get_function_name (),
|
||||
TraitItemReference::TraitItemType::FN,
|
||||
&raw_trait_item);
|
||||
|
||||
// unknown trait item
|
||||
if (!found || raw_trait_item->is_error ())
|
||||
{
|
||||
RichLocation r (function.get_locus ());
|
||||
r.add_range (trait_reference.get_locus ());
|
||||
rust_error_at (r, "method %<%s%> is not a member of trait %<%s%>",
|
||||
function.get_function_name ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the item from the predicate
|
||||
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
|
||||
rust_assert (!resolved_trait_item.is_error ());
|
||||
|
||||
// merge the attributes
|
||||
const HIR::TraitItem *hir_trait_item
|
||||
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
|
||||
merge_attributes (function.get_outer_attrs (), *hir_trait_item);
|
||||
|
||||
// check the types are compatible
|
||||
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
|
||||
if (!trait_item_type->can_eq (lookup, true))
|
||||
{
|
||||
RichLocation r (function.get_locus ());
|
||||
r.add_range (resolved_trait_item.get_locus ());
|
||||
|
||||
rust_error_at (r,
|
||||
"method %<%s%> has an incompatible type for trait %<%s%>",
|
||||
function.get_function_name ().c_str (),
|
||||
trait_reference.get_name ().c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckImplItemWithTrait::merge_attributes (AST::AttrVec &impl_item_attrs,
|
||||
const HIR::TraitItem &trait_item)
|
||||
{
|
||||
for (const auto &attr : trait_item.get_outer_attrs ())
|
||||
{
|
||||
impl_item_attrs.push_back (attr);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TypeCheckImplItemWithTrait::is_trait_impl_block () const
|
||||
{
|
||||
return !trait_reference.is_error ();
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
114
gcc/rust/typecheck/rust-hir-type-check-implitem.h
Normal file
114
gcc/rust/typecheck/rust-hir-type-check-implitem.h
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_IMPLITEM_H
|
||||
#define RUST_HIR_TYPE_CHECK_IMPLITEM_H
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckTopLevelExternItem : public TypeCheckBase,
|
||||
public HIR::HIRExternalItemVisitor
|
||||
{
|
||||
public:
|
||||
static void Resolve (HIR::ExternalItem *item, const HIR::ExternBlock &parent);
|
||||
|
||||
void visit (HIR::ExternalStaticItem &item) override;
|
||||
void visit (HIR::ExternalFunctionItem &function) override;
|
||||
|
||||
private:
|
||||
TypeCheckTopLevelExternItem (const HIR::ExternBlock &parent);
|
||||
|
||||
const HIR::ExternBlock &parent;
|
||||
};
|
||||
|
||||
class TypeCheckTopLevelImplItem : public TypeCheckBase,
|
||||
public HIR::HIRImplVisitor
|
||||
{
|
||||
public:
|
||||
static void
|
||||
Resolve (HIR::ImplItem *item, TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions);
|
||||
|
||||
void visit (HIR::TypeAlias &alias) override;
|
||||
void visit (HIR::ConstantItem &constant) override;
|
||||
void visit (HIR::Function &function) override;
|
||||
|
||||
private:
|
||||
TypeCheckTopLevelImplItem (
|
||||
TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions);
|
||||
|
||||
TyTy::BaseType *self;
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
};
|
||||
|
||||
class TypeCheckImplItem : public TypeCheckBase, public HIR::HIRImplVisitor
|
||||
{
|
||||
public:
|
||||
static void Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
|
||||
TyTy::BaseType *self);
|
||||
|
||||
void visit (HIR::Function &function) override;
|
||||
void visit (HIR::ConstantItem &const_item) override;
|
||||
void visit (HIR::TypeAlias &type_alias) override;
|
||||
|
||||
protected:
|
||||
TypeCheckImplItem (HIR::ImplBlock *parent, TyTy::BaseType *self);
|
||||
|
||||
HIR::ImplBlock *parent;
|
||||
TyTy::BaseType *self;
|
||||
};
|
||||
|
||||
class TypeCheckImplItemWithTrait : public TypeCheckImplItem
|
||||
{
|
||||
public:
|
||||
static TyTy::TypeBoundPredicateItem
|
||||
Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
|
||||
TyTy::TypeBoundPredicate &trait_reference,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions);
|
||||
|
||||
void visit (HIR::ConstantItem &constant) override;
|
||||
void visit (HIR::TypeAlias &type) override;
|
||||
void visit (HIR::Function &function) override;
|
||||
|
||||
protected:
|
||||
// this allows us to inherit the must_use specified on a trait definition onto
|
||||
// its implementation
|
||||
void merge_attributes (AST::AttrVec &impl_item_attrs,
|
||||
const HIR::TraitItem &trait_item);
|
||||
|
||||
private:
|
||||
TypeCheckImplItemWithTrait (
|
||||
HIR::ImplBlock *parent, TyTy::BaseType *self,
|
||||
TyTy::TypeBoundPredicate &trait_reference,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions);
|
||||
|
||||
bool is_trait_impl_block () const;
|
||||
|
||||
TyTy::TypeBoundPredicate &trait_reference;
|
||||
TyTy::TypeBoundPredicateItem resolved_trait_item;
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_IMPLITEM_H
|
237
gcc/rust/typecheck/rust-hir-type-check-item.cc
Normal file
237
gcc/rust/typecheck/rust-hir-type-check-item.cc
Normal file
@ -0,0 +1,237 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-item.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-implitem.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-stmt.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-trait-resolve.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCheckItem::TypeCheckItem () : TypeCheckBase () {}
|
||||
|
||||
void
|
||||
TypeCheckItem::Resolve (HIR::Item &item)
|
||||
{
|
||||
rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM);
|
||||
HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item);
|
||||
|
||||
TypeCheckItem resolver;
|
||||
vis_item.accept_vis (resolver);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckItem::visit (HIR::ImplBlock &impl_block)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (impl_block.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : impl_block.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
TyTy::BaseType *l = nullptr;
|
||||
bool ok = context->lookup_type (
|
||||
generic_param->get_mappings ().get_hirid (), &l);
|
||||
if (ok && l->get_kind () == TyTy::TypeKind::PARAM)
|
||||
{
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param),
|
||||
static_cast<TyTy::ParamType *> (l)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto specified_bound = TyTy::TypeBoundPredicate::error ();
|
||||
TraitReference *trait_reference = &TraitReference::error_node ();
|
||||
if (impl_block.has_trait_ref ())
|
||||
{
|
||||
std::unique_ptr<HIR::TypePath> &ref = impl_block.get_trait_ref ();
|
||||
trait_reference = TraitResolver::Resolve (*ref.get ());
|
||||
rust_assert (!trait_reference->is_error ());
|
||||
|
||||
// we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
|
||||
// for example
|
||||
specified_bound = get_predicate_from_bound (*ref.get ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *self = nullptr;
|
||||
if (!context->lookup_type (
|
||||
impl_block.get_type ()->get_mappings ().get_hirid (), &self))
|
||||
{
|
||||
rust_error_at (impl_block.get_locus (),
|
||||
"failed to resolve Self for ImplBlock");
|
||||
return;
|
||||
}
|
||||
|
||||
// inherit the bounds
|
||||
if (!specified_bound.is_error ())
|
||||
self->inherit_bounds ({specified_bound});
|
||||
|
||||
// check for any unconstrained type-params
|
||||
const TyTy::SubstitutionArgumentMappings trait_constraints
|
||||
= specified_bound.get_substitution_arguments ();
|
||||
const TyTy::SubstitutionArgumentMappings impl_constraints
|
||||
= GetUsedSubstArgs::From (self);
|
||||
|
||||
bool impl_block_has_unconstrained_typarams
|
||||
= check_for_unconstrained (substitutions, trait_constraints,
|
||||
impl_constraints, self);
|
||||
if (impl_block_has_unconstrained_typarams)
|
||||
return;
|
||||
|
||||
// validate the impl items
|
||||
bool is_trait_impl_block = !trait_reference->is_error ();
|
||||
std::vector<const TraitItemReference *> trait_item_refs;
|
||||
for (auto &impl_item : impl_block.get_impl_items ())
|
||||
{
|
||||
if (!is_trait_impl_block)
|
||||
TypeCheckImplItem::Resolve (&impl_block, impl_item.get (), self);
|
||||
else
|
||||
{
|
||||
auto trait_item_ref
|
||||
= TypeCheckImplItemWithTrait::Resolve (&impl_block,
|
||||
impl_item.get (), self,
|
||||
specified_bound,
|
||||
substitutions);
|
||||
trait_item_refs.push_back (trait_item_ref.get_raw_item ());
|
||||
}
|
||||
}
|
||||
|
||||
bool impl_block_missing_trait_items
|
||||
= is_trait_impl_block
|
||||
&& trait_reference->size () != trait_item_refs.size ();
|
||||
if (impl_block_missing_trait_items)
|
||||
{
|
||||
// filter the missing impl_items
|
||||
std::vector<std::reference_wrapper<const TraitItemReference>>
|
||||
missing_trait_items;
|
||||
for (const auto &trait_item_ref : trait_reference->get_trait_items ())
|
||||
{
|
||||
bool found = false;
|
||||
for (auto implemented_trait_item : trait_item_refs)
|
||||
{
|
||||
std::string trait_item_name = trait_item_ref.get_identifier ();
|
||||
std::string impl_item_name
|
||||
= implemented_trait_item->get_identifier ();
|
||||
found = trait_item_name.compare (impl_item_name) == 0;
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
|
||||
bool is_required_trait_item = !trait_item_ref.is_optional ();
|
||||
if (!found && is_required_trait_item)
|
||||
missing_trait_items.push_back (trait_item_ref);
|
||||
}
|
||||
|
||||
if (missing_trait_items.size () > 0)
|
||||
{
|
||||
std::string missing_items_buf;
|
||||
RichLocation r (impl_block.get_locus ());
|
||||
for (size_t i = 0; i < missing_trait_items.size (); i++)
|
||||
{
|
||||
bool has_more = (i + 1) < missing_trait_items.size ();
|
||||
const TraitItemReference &missing_trait_item
|
||||
= missing_trait_items.at (i);
|
||||
missing_items_buf += missing_trait_item.get_identifier ()
|
||||
+ (has_more ? ", " : "");
|
||||
r.add_range (missing_trait_item.get_locus ());
|
||||
}
|
||||
|
||||
rust_error_at (r, "missing %s in implementation of trait %<%s%>",
|
||||
missing_items_buf.c_str (),
|
||||
trait_reference->get_name ().c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
if (is_trait_impl_block)
|
||||
{
|
||||
trait_reference->clear_associated_types ();
|
||||
|
||||
AssociatedImplTrait associated (trait_reference, &impl_block, self,
|
||||
context);
|
||||
context->insert_associated_trait_impl (
|
||||
impl_block.get_mappings ().get_hirid (), std::move (associated));
|
||||
context->insert_associated_impl_mapping (
|
||||
trait_reference->get_mappings ().get_hirid (), self,
|
||||
impl_block.get_mappings ().get_hirid ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckItem::visit (HIR::Function &function)
|
||||
{
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
|
||||
{
|
||||
rust_error_at (function.get_locus (), "failed to lookup function type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"found invalid type for function [%s]",
|
||||
lookup->as_string ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// need to get the return type from this
|
||||
TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (lookup);
|
||||
auto expected_ret_tyty = resolved_fn_type->get_return_type ();
|
||||
context->push_return_type (TypeCheckContextItem (&function),
|
||||
expected_ret_tyty);
|
||||
|
||||
auto block_expr_ty
|
||||
= TypeCheckExpr::Resolve (function.get_definition ().get ());
|
||||
|
||||
context->pop_return_type ();
|
||||
|
||||
if (block_expr_ty->get_kind () != TyTy::NEVER)
|
||||
expected_ret_tyty->unify (block_expr_ty);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckItem::visit (HIR::Module &module)
|
||||
{
|
||||
for (auto &item : module.get_items ())
|
||||
TypeCheckItem::Resolve (*item.get ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckItem::visit (HIR::Trait &trait)
|
||||
{
|
||||
TraitResolver::Resolve (trait);
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
58
gcc/rust/typecheck/rust-hir-type-check-item.h
Normal file
58
gcc/rust/typecheck/rust-hir-type-check-item.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_ITEM
|
||||
#define RUST_HIR_TYPE_CHECK_ITEM
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckItem : private TypeCheckBase, private HIR::HIRVisItemVisitor
|
||||
{
|
||||
public:
|
||||
static void Resolve (HIR::Item &item);
|
||||
|
||||
void visit (HIR::ImplBlock &impl_block) override;
|
||||
void visit (HIR::Function &function) override;
|
||||
void visit (HIR::Module &module) override;
|
||||
void visit (HIR::Trait &trait) override;
|
||||
|
||||
// FIXME - get rid of toplevel pass
|
||||
void visit (HIR::TypeAlias &alias) override{};
|
||||
void visit (HIR::TupleStruct &struct_decl) override{};
|
||||
void visit (HIR::StructStruct &struct_decl) override{};
|
||||
void visit (HIR::Enum &enum_decl) override{};
|
||||
void visit (HIR::Union &union_decl) override{};
|
||||
void visit (HIR::StaticItem &var) override{};
|
||||
void visit (HIR::ConstantItem &constant) override{};
|
||||
void visit (HIR::ExternBlock &extern_block) override{};
|
||||
|
||||
// nothing to do
|
||||
void visit (HIR::ExternCrate &crate) override {}
|
||||
void visit (HIR::UseDeclaration &use_decl) override {}
|
||||
|
||||
private:
|
||||
TypeCheckItem ();
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_ITEM
|
467
gcc/rust/typecheck/rust-hir-type-check-path.cc
Normal file
467
gcc/rust/typecheck/rust-hir-type-check-path.cc
Normal file
@ -0,0 +1,467 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-trait-resolve.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
void
|
||||
TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
|
||||
{
|
||||
HIR::QualifiedPathType qual_path_type = expr.get_path_type ();
|
||||
TyTy::BaseType *root
|
||||
= TypeCheckType::Resolve (qual_path_type.get_type ().get ());
|
||||
if (root->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
if (!qual_path_type.has_as_clause ())
|
||||
{
|
||||
NodeId root_resolved_node_id = UNKNOWN_NODEID;
|
||||
resolve_segments (root_resolved_node_id, expr.get_segments (), 0, root,
|
||||
expr.get_mappings (), expr.get_locus ());
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve the trait now
|
||||
std::unique_ptr<HIR::TypePath> &trait_path_ref = qual_path_type.get_trait ();
|
||||
TraitReference *trait_ref = TraitResolver::Resolve (*trait_path_ref.get ());
|
||||
if (trait_ref->is_error ())
|
||||
return;
|
||||
|
||||
// does this type actually implement this type-bound?
|
||||
if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
|
||||
return;
|
||||
|
||||
// then we need to look at the next segment to create perform the correct
|
||||
// projection type
|
||||
if (expr.get_segments ().empty ())
|
||||
return;
|
||||
|
||||
// get the predicate for the bound
|
||||
auto specified_bound = get_predicate_from_bound (*trait_path_ref.get ());
|
||||
if (specified_bound.is_error ())
|
||||
return;
|
||||
|
||||
// inherit the bound
|
||||
root->inherit_bounds ({specified_bound});
|
||||
|
||||
// setup the associated types
|
||||
const TraitReference *specified_bound_ref = specified_bound.get ();
|
||||
auto candidates = TypeBoundsProbe::Probe (root);
|
||||
AssociatedImplTrait *associated_impl_trait = nullptr;
|
||||
for (auto &probed_bound : candidates)
|
||||
{
|
||||
const TraitReference *bound_trait_ref = probed_bound.first;
|
||||
const HIR::ImplBlock *associated_impl = probed_bound.second;
|
||||
|
||||
HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
|
||||
AssociatedImplTrait *associated = nullptr;
|
||||
bool found_impl_trait
|
||||
= context->lookup_associated_trait_impl (impl_block_id, &associated);
|
||||
if (found_impl_trait)
|
||||
{
|
||||
bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref);
|
||||
bool found_self = associated->get_self ()->can_eq (root, false);
|
||||
if (found_trait && found_self)
|
||||
{
|
||||
associated_impl_trait = associated;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (associated_impl_trait != nullptr)
|
||||
{
|
||||
associated_impl_trait->setup_associated_types (root, specified_bound);
|
||||
}
|
||||
|
||||
// lookup the associated item from the specified bound
|
||||
HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
|
||||
HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment ();
|
||||
TyTy::TypeBoundPredicateItem item
|
||||
= specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
|
||||
if (item.is_error ())
|
||||
{
|
||||
rust_error_at (item_seg.get_locus (), "unknown associated item");
|
||||
return;
|
||||
}
|
||||
|
||||
// infer the root type
|
||||
infered = item.get_tyty_for_receiver (root);
|
||||
|
||||
// turbo-fish segment path::<ty>
|
||||
if (item_seg.has_generic_args ())
|
||||
{
|
||||
if (!infered->can_substitute ())
|
||||
{
|
||||
rust_error_at (item_seg.get_locus (),
|
||||
"substitutions not supported for %s",
|
||||
infered->as_string ().c_str ());
|
||||
infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
|
||||
return;
|
||||
}
|
||||
infered = SubstMapper::Resolve (infered, expr.get_locus (),
|
||||
&item_seg.get_generic_args ());
|
||||
}
|
||||
|
||||
// continue on as a path-in-expression
|
||||
const TraitItemReference *trait_item_ref = item.get_raw_item ();
|
||||
NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
|
||||
bool fully_resolved = expr.get_segments ().size () <= 1;
|
||||
|
||||
if (fully_resolved)
|
||||
{
|
||||
resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
|
||||
root_resolved_node_id);
|
||||
context->insert_receiver (expr.get_mappings ().get_hirid (), root);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered,
|
||||
expr.get_mappings (), expr.get_locus ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckExpr::visit (HIR::PathInExpression &expr)
|
||||
{
|
||||
NodeId resolved_node_id = UNKNOWN_NODEID;
|
||||
size_t offset = -1;
|
||||
TyTy::BaseType *tyseg = resolve_root_path (expr, &offset, &resolved_node_id);
|
||||
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
if (tyseg->needs_generic_substitutions ())
|
||||
{
|
||||
tyseg = SubstMapper::InferSubst (tyseg, expr.get_locus ());
|
||||
}
|
||||
|
||||
bool fully_resolved = offset == expr.get_segments ().size ();
|
||||
if (fully_resolved)
|
||||
{
|
||||
infered = tyseg;
|
||||
return;
|
||||
}
|
||||
|
||||
resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg,
|
||||
expr.get_mappings (), expr.get_locus ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
|
||||
NodeId *root_resolved_node_id)
|
||||
{
|
||||
TyTy::BaseType *root_tyty = nullptr;
|
||||
*offset = 0;
|
||||
for (size_t i = 0; i < expr.get_num_segments (); i++)
|
||||
{
|
||||
HIR::PathExprSegment &seg = expr.get_segments ().at (i);
|
||||
|
||||
bool have_more_segments = (expr.get_num_segments () - 1 != i);
|
||||
bool is_root = *offset == 0;
|
||||
NodeId ast_node_id = seg.get_mappings ().get_nodeid ();
|
||||
|
||||
// then lookup the reference_node_id
|
||||
NodeId ref_node_id = UNKNOWN_NODEID;
|
||||
if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
|
||||
{
|
||||
resolver->lookup_resolved_type (ast_node_id, &ref_node_id);
|
||||
}
|
||||
|
||||
// ref_node_id is the NodeId that the segments refers to.
|
||||
if (ref_node_id == UNKNOWN_NODEID)
|
||||
{
|
||||
if (root_tyty != nullptr && *offset > 0)
|
||||
{
|
||||
// then we can let the impl path probe take over now
|
||||
return root_tyty;
|
||||
}
|
||||
|
||||
rust_error_at (seg.get_locus (),
|
||||
"failed to type resolve root segment");
|
||||
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
// node back to HIR
|
||||
HirId ref;
|
||||
if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
|
||||
{
|
||||
rust_error_at (seg.get_locus (), "456 reverse lookup failure");
|
||||
rust_debug_loc (seg.get_locus (),
|
||||
"failure with [%s] mappings [%s] ref_node_id [%u]",
|
||||
seg.as_string ().c_str (),
|
||||
seg.get_mappings ().as_string ().c_str (),
|
||||
ref_node_id);
|
||||
|
||||
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
auto seg_is_module = (nullptr != mappings->lookup_module (ref));
|
||||
auto seg_is_crate = mappings->is_local_hirid_crate (ref);
|
||||
if (seg_is_module || seg_is_crate)
|
||||
{
|
||||
// A::B::C::this_is_a_module::D::E::F
|
||||
// ^^^^^^^^^^^^^^^^
|
||||
// Currently handling this.
|
||||
if (have_more_segments)
|
||||
{
|
||||
(*offset)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// In the case of :
|
||||
// A::B::C::this_is_a_module
|
||||
// ^^^^^^^^^^^^^^^^
|
||||
// This is an error, we are not expecting a module.
|
||||
rust_error_at (seg.get_locus (), "expected value");
|
||||
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *lookup = nullptr;
|
||||
if (!context->lookup_type (ref, &lookup))
|
||||
{
|
||||
if (is_root)
|
||||
{
|
||||
rust_error_at (seg.get_locus (),
|
||||
"failed to resolve root segment");
|
||||
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
|
||||
}
|
||||
return root_tyty;
|
||||
}
|
||||
|
||||
// if we have a previous segment type
|
||||
if (root_tyty != nullptr)
|
||||
{
|
||||
// if this next segment needs substitution we must apply the
|
||||
// previous type arguments
|
||||
//
|
||||
// such as: GenericStruct::<_>::new(123, 456)
|
||||
if (lookup->needs_generic_substitutions ())
|
||||
{
|
||||
if (!root_tyty->needs_generic_substitutions ())
|
||||
{
|
||||
auto used_args_in_prev_segment
|
||||
= GetUsedSubstArgs::From (root_tyty);
|
||||
lookup
|
||||
= SubstMapperInternal::Resolve (lookup,
|
||||
used_args_in_prev_segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// turbo-fish segment path::<ty>
|
||||
if (seg.has_generic_args ())
|
||||
{
|
||||
if (!lookup->can_substitute ())
|
||||
{
|
||||
rust_error_at (expr.get_locus (),
|
||||
"substitutions not supported for %s",
|
||||
root_tyty->as_string ().c_str ());
|
||||
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
lookup = SubstMapper::Resolve (lookup, expr.get_locus (),
|
||||
&seg.get_generic_args ());
|
||||
if (lookup->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
*root_resolved_node_id = ref_node_id;
|
||||
*offset = *offset + 1;
|
||||
root_tyty = lookup;
|
||||
}
|
||||
|
||||
return root_tyty;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
|
||||
std::vector<HIR::PathExprSegment> &segments,
|
||||
size_t offset, TyTy::BaseType *tyseg,
|
||||
const Analysis::NodeMapping &expr_mappings,
|
||||
Location expr_locus)
|
||||
{
|
||||
NodeId resolved_node_id = root_resolved_node_id;
|
||||
TyTy::BaseType *prev_segment = tyseg;
|
||||
bool reciever_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
|
||||
|
||||
for (size_t i = offset; i < segments.size (); i++)
|
||||
{
|
||||
HIR::PathExprSegment &seg = segments.at (i);
|
||||
|
||||
bool probe_bounds = true;
|
||||
bool probe_impls = !reciever_is_generic;
|
||||
bool ignore_mandatory_trait_items = !reciever_is_generic;
|
||||
|
||||
// probe the path is done in two parts one where we search impls if no
|
||||
// candidate is found then we search extensions from traits
|
||||
auto candidates
|
||||
= PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls,
|
||||
false, ignore_mandatory_trait_items);
|
||||
if (candidates.size () == 0)
|
||||
{
|
||||
candidates
|
||||
= PathProbeType::Probe (prev_segment, seg.get_segment (), false,
|
||||
probe_bounds, ignore_mandatory_trait_items);
|
||||
|
||||
if (candidates.size () == 0)
|
||||
{
|
||||
rust_error_at (
|
||||
seg.get_locus (),
|
||||
"failed to resolve path segment using an impl Probe");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.size () > 1)
|
||||
{
|
||||
ReportMultipleCandidateError::Report (candidates, seg.get_segment (),
|
||||
seg.get_locus ());
|
||||
return;
|
||||
}
|
||||
|
||||
auto &candidate = candidates.at (0);
|
||||
prev_segment = tyseg;
|
||||
tyseg = candidate.ty;
|
||||
|
||||
HIR::ImplBlock *associated_impl_block = nullptr;
|
||||
if (candidate.is_enum_candidate ())
|
||||
{
|
||||
const TyTy::VariantDef *variant = candidate.item.enum_field.variant;
|
||||
|
||||
HirId variant_id = variant->get_id ();
|
||||
HIR::Item *enum_item = mappings->lookup_hir_item (variant_id);
|
||||
rust_assert (enum_item != nullptr);
|
||||
|
||||
resolved_node_id = enum_item->get_mappings ().get_nodeid ();
|
||||
|
||||
// insert the id of the variant we are resolved to
|
||||
context->insert_variant_definition (expr_mappings.get_hirid (),
|
||||
variant_id);
|
||||
}
|
||||
else if (candidate.is_impl_candidate ())
|
||||
{
|
||||
resolved_node_id
|
||||
= candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
|
||||
|
||||
associated_impl_block = candidate.item.impl.parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
resolved_node_id
|
||||
= candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
|
||||
|
||||
// lookup the associated-impl-trait
|
||||
HIR::ImplBlock *impl = candidate.item.trait.impl;
|
||||
if (impl != nullptr)
|
||||
{
|
||||
// get the associated impl block
|
||||
associated_impl_block = impl;
|
||||
}
|
||||
}
|
||||
|
||||
if (associated_impl_block != nullptr)
|
||||
{
|
||||
// get the type of the parent Self
|
||||
HirId impl_ty_id
|
||||
= associated_impl_block->get_type ()->get_mappings ().get_hirid ();
|
||||
TyTy::BaseType *impl_block_ty = nullptr;
|
||||
bool ok = context->lookup_type (impl_ty_id, &impl_block_ty);
|
||||
rust_assert (ok);
|
||||
|
||||
if (impl_block_ty->needs_generic_substitutions ())
|
||||
impl_block_ty
|
||||
= SubstMapper::InferSubst (impl_block_ty, seg.get_locus ());
|
||||
|
||||
prev_segment = prev_segment->unify (impl_block_ty);
|
||||
}
|
||||
|
||||
if (tyseg->needs_generic_substitutions ())
|
||||
{
|
||||
if (!prev_segment->needs_generic_substitutions ())
|
||||
{
|
||||
auto used_args_in_prev_segment
|
||||
= GetUsedSubstArgs::From (prev_segment);
|
||||
|
||||
if (!used_args_in_prev_segment.is_error ())
|
||||
{
|
||||
if (SubstMapperInternal::mappings_are_bound (
|
||||
tyseg, used_args_in_prev_segment))
|
||||
{
|
||||
tyseg = SubstMapperInternal::Resolve (
|
||||
tyseg, used_args_in_prev_segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (seg.has_generic_args ())
|
||||
{
|
||||
if (!tyseg->can_substitute ())
|
||||
{
|
||||
rust_error_at (expr_locus, "substitutions not supported for %s",
|
||||
tyseg->as_string ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
tyseg = SubstMapper::Resolve (tyseg, expr_locus,
|
||||
&seg.get_generic_args ());
|
||||
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
}
|
||||
else if (tyseg->needs_generic_substitutions () && !reciever_is_generic)
|
||||
{
|
||||
Location locus = seg.get_locus ();
|
||||
tyseg = SubstMapper::InferSubst (tyseg, locus);
|
||||
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rust_assert (resolved_node_id != UNKNOWN_NODEID);
|
||||
if (tyseg->needs_generic_substitutions () && !reciever_is_generic)
|
||||
{
|
||||
Location locus = segments.back ().get_locus ();
|
||||
tyseg = SubstMapper::InferSubst (tyseg, locus);
|
||||
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
}
|
||||
|
||||
context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
|
||||
|
||||
// name scope first
|
||||
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
|
||||
{
|
||||
resolver->insert_resolved_name (expr_mappings.get_nodeid (),
|
||||
resolved_node_id);
|
||||
}
|
||||
// check the type scope
|
||||
else if (resolver->get_type_scope ().decl_was_declared_here (
|
||||
resolved_node_id))
|
||||
{
|
||||
resolver->insert_resolved_type (expr_mappings.get_nodeid (),
|
||||
resolved_node_id);
|
||||
}
|
||||
|
||||
infered = tyseg;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
416
gcc/rust/typecheck/rust-hir-type-check-pattern.cc
Normal file
416
gcc/rust/typecheck/rust-hir-type-check-pattern.cc
Normal file
@ -0,0 +1,416 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-pattern.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCheckPattern::TypeCheckPattern (TyTy::BaseType *parent)
|
||||
: TypeCheckBase (), parent (parent), infered (nullptr)
|
||||
{}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckPattern::Resolve (HIR::Pattern *pattern, TyTy::BaseType *parent)
|
||||
{
|
||||
TypeCheckPattern resolver (parent);
|
||||
pattern->accept_vis (resolver);
|
||||
|
||||
if (resolver.infered == nullptr)
|
||||
return new TyTy::ErrorType (pattern->get_pattern_mappings ().get_hirid ());
|
||||
|
||||
resolver.context->insert_type (pattern->get_pattern_mappings (),
|
||||
resolver.infered);
|
||||
return resolver.infered;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::PathInExpression &pattern)
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (&pattern);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (&pattern.get_path ());
|
||||
if (infered->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
|
||||
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
|
||||
rust_assert (adt->number_of_variants () > 0);
|
||||
|
||||
TyTy::VariantDef *variant = adt->get_variants ().at (0);
|
||||
if (adt->is_enum ())
|
||||
{
|
||||
HirId variant_id = UNKNOWN_HIRID;
|
||||
bool ok = context->lookup_variant_definition (
|
||||
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
|
||||
rust_assert (ok);
|
||||
|
||||
ok = adt->lookup_variant_by_id (variant_id, &variant);
|
||||
rust_assert (ok);
|
||||
}
|
||||
|
||||
// error[E0532]: expected tuple struct or tuple variant, found struct variant
|
||||
// `Foo::D`
|
||||
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
|
||||
{
|
||||
std::string variant_type
|
||||
= TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
|
||||
|
||||
rust_error_at (
|
||||
pattern.get_locus (),
|
||||
"expected tuple struct or tuple variant, found %s variant %<%s::%s%>",
|
||||
variant_type.c_str (), adt->get_name ().c_str (),
|
||||
variant->get_identifier ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// check the elements
|
||||
// error[E0023]: this pattern has 2 fields, but the corresponding tuple
|
||||
// variant has 1 field
|
||||
// error[E0023]: this pattern has 0 fields, but the corresponding tuple
|
||||
// variant has 1 field
|
||||
|
||||
std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items ();
|
||||
switch (items->get_item_type ())
|
||||
{
|
||||
case HIR::TupleStructItems::RANGE: {
|
||||
// TODO
|
||||
gcc_unreachable ();
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::TupleStructItems::NO_RANGE: {
|
||||
HIR::TupleStructItemsNoRange &items_no_range
|
||||
= static_cast<HIR::TupleStructItemsNoRange &> (*items.get ());
|
||||
|
||||
if (items_no_range.get_patterns ().size () != variant->num_fields ())
|
||||
{
|
||||
rust_error_at (
|
||||
pattern.get_locus (),
|
||||
"this pattern has %lu fields but the corresponding "
|
||||
"tuple variant has %lu field",
|
||||
(unsigned long) items_no_range.get_patterns ().size (),
|
||||
(unsigned long) variant->num_fields ());
|
||||
// we continue on to try and setup the types as best we can for
|
||||
// type checking
|
||||
}
|
||||
|
||||
// iterate the fields and set them up, I wish we had ZIP
|
||||
size_t i = 0;
|
||||
for (auto &pattern : items_no_range.get_patterns ())
|
||||
{
|
||||
if (i >= variant->num_fields ())
|
||||
break;
|
||||
|
||||
TyTy::StructFieldType *field = variant->get_field_at_index (i++);
|
||||
TyTy::BaseType *fty = field->get_field_type ();
|
||||
|
||||
// setup the type on this pattern type
|
||||
context->insert_type (pattern->get_pattern_mappings (), fty);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::StructPattern &pattern)
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (&pattern.get_path ());
|
||||
if (infered->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
|
||||
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
|
||||
rust_assert (adt->number_of_variants () > 0);
|
||||
|
||||
TyTy::VariantDef *variant = adt->get_variants ().at (0);
|
||||
if (adt->is_enum ())
|
||||
{
|
||||
HirId variant_id = UNKNOWN_HIRID;
|
||||
bool ok = context->lookup_variant_definition (
|
||||
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
|
||||
rust_assert (ok);
|
||||
|
||||
ok = adt->lookup_variant_by_id (variant_id, &variant);
|
||||
rust_assert (ok);
|
||||
}
|
||||
|
||||
// error[E0532]: expected tuple struct or tuple variant, found struct variant
|
||||
// `Foo::D`
|
||||
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT)
|
||||
{
|
||||
std::string variant_type
|
||||
= TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
|
||||
rust_error_at (pattern.get_locus (),
|
||||
"expected struct variant, found %s variant %s",
|
||||
variant_type.c_str (),
|
||||
variant->get_identifier ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// check the elements
|
||||
// error[E0027]: pattern does not mention fields `x`, `y`
|
||||
// error[E0026]: variant `Foo::D` does not have a field named `b`
|
||||
|
||||
std::vector<std::string> named_fields;
|
||||
auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
|
||||
for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
|
||||
{
|
||||
switch (field->get_item_type ())
|
||||
{
|
||||
case HIR::StructPatternField::ItemType::TUPLE_PAT: {
|
||||
// TODO
|
||||
gcc_unreachable ();
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::StructPatternField::ItemType::IDENT_PAT: {
|
||||
// TODO
|
||||
gcc_unreachable ();
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::StructPatternField::ItemType::IDENT: {
|
||||
HIR::StructPatternFieldIdent &ident
|
||||
= static_cast<HIR::StructPatternFieldIdent &> (*field.get ());
|
||||
|
||||
TyTy::StructFieldType *field = nullptr;
|
||||
if (!variant->lookup_field (ident.get_identifier (), &field,
|
||||
nullptr))
|
||||
{
|
||||
rust_error_at (ident.get_locus (),
|
||||
"variant %s does not have a field named %s",
|
||||
variant->get_identifier ().c_str (),
|
||||
ident.get_identifier ().c_str ());
|
||||
break;
|
||||
}
|
||||
named_fields.push_back (ident.get_identifier ());
|
||||
|
||||
// setup the type on this pattern
|
||||
TyTy::BaseType *fty = field->get_field_type ();
|
||||
context->insert_type (ident.get_mappings (), fty);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (named_fields.size () != variant->num_fields ())
|
||||
{
|
||||
std::map<std::string, bool> missing_names;
|
||||
|
||||
// populate with all fields
|
||||
for (auto &field : variant->get_fields ())
|
||||
missing_names[field->get_name ()] = true;
|
||||
|
||||
// then eliminate with named_fields
|
||||
for (auto &named : named_fields)
|
||||
missing_names.erase (named);
|
||||
|
||||
// then get the list of missing names
|
||||
size_t i = 0;
|
||||
std::string missing_fields_str;
|
||||
for (auto it = missing_names.begin (); it != missing_names.end (); it++)
|
||||
{
|
||||
bool has_next = (i + 1) < missing_names.size ();
|
||||
missing_fields_str += it->first + (has_next ? ", " : "");
|
||||
i++;
|
||||
}
|
||||
|
||||
rust_error_at (pattern.get_locus (), "pattern does not mention fields %s",
|
||||
missing_fields_str.c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::WildcardPattern &pattern)
|
||||
{
|
||||
// wildcard patterns within the MatchArm's are simply just the same type as
|
||||
// the parent
|
||||
infered = parent->clone ();
|
||||
infered->set_ref (pattern.get_pattern_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::TuplePattern &pattern)
|
||||
{
|
||||
std::unique_ptr<HIR::TuplePatternItems> items;
|
||||
switch (pattern.get_items ()->get_pattern_type ())
|
||||
{
|
||||
case HIR::TuplePatternItems::TuplePatternItemType::MULTIPLE: {
|
||||
HIR::TuplePatternItemsMultiple &ref
|
||||
= *static_cast<HIR::TuplePatternItemsMultiple *> (
|
||||
pattern.get_items ().get ());
|
||||
|
||||
std::vector<TyTy::TyVar> pattern_elems;
|
||||
for (size_t i = 0; i < ref.get_patterns ().size (); i++)
|
||||
{
|
||||
auto &p = ref.get_patterns ()[i];
|
||||
TyTy::BaseType *par_type = parent;
|
||||
if (parent->get_kind () == TyTy::TUPLE)
|
||||
{
|
||||
TyTy::TupleType &par = *static_cast<TyTy::TupleType *> (parent);
|
||||
par_type = par.get_field (i);
|
||||
}
|
||||
|
||||
TyTy::BaseType *elem
|
||||
= TypeCheckPattern::Resolve (p.get (), par_type);
|
||||
pattern_elems.push_back (TyTy::TyVar (elem->get_ref ()));
|
||||
}
|
||||
infered
|
||||
= new TyTy::TupleType (pattern.get_pattern_mappings ().get_hirid (),
|
||||
pattern.get_locus (), pattern_elems);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::TuplePatternItems::TuplePatternItemType::RANGED: {
|
||||
// HIR::TuplePatternItemsRanged &ref
|
||||
// = *static_cast<HIR::TuplePatternItemsRanged *> (
|
||||
// pattern.get_items ().get ());
|
||||
// TODO
|
||||
gcc_unreachable ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::LiteralPattern &pattern)
|
||||
{
|
||||
infered = resolve_literal (pattern.get_pattern_mappings (),
|
||||
pattern.get_literal (), pattern.get_locus ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::RangePattern &pattern)
|
||||
{
|
||||
// Resolve the upper and lower bounds, and ensure they are compatible types
|
||||
TyTy::BaseType *upper = nullptr, *lower = nullptr;
|
||||
|
||||
// TODO: It would be nice to factor this out into a helper since the logic for
|
||||
// both bounds is exactly the same...
|
||||
switch (pattern.get_upper_bound ()->get_bound_type ())
|
||||
{
|
||||
case HIR::RangePatternBound::RangePatternBoundType::LITERAL: {
|
||||
HIR::RangePatternBoundLiteral &ref
|
||||
= *static_cast<HIR::RangePatternBoundLiteral *> (
|
||||
pattern.get_upper_bound ().get ());
|
||||
|
||||
HIR::Literal lit = ref.get_literal ();
|
||||
|
||||
upper = resolve_literal (pattern.get_pattern_mappings (), lit,
|
||||
pattern.get_locus ());
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::RangePatternBound::RangePatternBoundType::PATH: {
|
||||
HIR::RangePatternBoundPath &ref
|
||||
= *static_cast<HIR::RangePatternBoundPath *> (
|
||||
pattern.get_upper_bound ().get ());
|
||||
|
||||
upper = TypeCheckExpr::Resolve (&ref.get_path ());
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: {
|
||||
HIR::RangePatternBoundQualPath &ref
|
||||
= *static_cast<HIR::RangePatternBoundQualPath *> (
|
||||
pattern.get_upper_bound ().get ());
|
||||
|
||||
upper = TypeCheckExpr::Resolve (&ref.get_qualified_path ());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pattern.get_lower_bound ()->get_bound_type ())
|
||||
{
|
||||
case HIR::RangePatternBound::RangePatternBoundType::LITERAL: {
|
||||
HIR::RangePatternBoundLiteral &ref
|
||||
= *static_cast<HIR::RangePatternBoundLiteral *> (
|
||||
pattern.get_lower_bound ().get ());
|
||||
|
||||
HIR::Literal lit = ref.get_literal ();
|
||||
|
||||
lower = resolve_literal (pattern.get_pattern_mappings (), lit,
|
||||
pattern.get_locus ());
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::RangePatternBound::RangePatternBoundType::PATH: {
|
||||
HIR::RangePatternBoundPath &ref
|
||||
= *static_cast<HIR::RangePatternBoundPath *> (
|
||||
pattern.get_lower_bound ().get ());
|
||||
|
||||
lower = TypeCheckExpr::Resolve (&ref.get_path ());
|
||||
}
|
||||
break;
|
||||
|
||||
case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: {
|
||||
HIR::RangePatternBoundQualPath &ref
|
||||
= *static_cast<HIR::RangePatternBoundQualPath *> (
|
||||
pattern.get_lower_bound ().get ());
|
||||
|
||||
lower = TypeCheckExpr::Resolve (&ref.get_qualified_path ());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
infered = upper->unify (lower);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::IdentifierPattern &pattern)
|
||||
{
|
||||
infered = parent;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::GroupedPattern &pattern)
|
||||
{
|
||||
// TODO
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::QualifiedPathInExpression &pattern)
|
||||
{
|
||||
// TODO
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::ReferencePattern &pattern)
|
||||
{
|
||||
// TODO
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckPattern::visit (HIR::SlicePattern &pattern)
|
||||
{
|
||||
// TODO
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
62
gcc/rust/typecheck/rust-hir-type-check-pattern.h
Normal file
62
gcc/rust/typecheck/rust-hir-type-check-pattern.h
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_PATTERN
|
||||
#define RUST_HIR_TYPE_CHECK_PATTERN
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckPattern : public TypeCheckBase, public HIR::HIRPatternVisitor
|
||||
{
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (HIR::Pattern *pattern,
|
||||
TyTy::BaseType *parent);
|
||||
|
||||
void visit (HIR::PathInExpression &pattern) override;
|
||||
void visit (HIR::StructPattern &pattern) override;
|
||||
void visit (HIR::TupleStructPattern &pattern) override;
|
||||
void visit (HIR::WildcardPattern &pattern) override;
|
||||
void visit (HIR::TuplePattern &pattern) override;
|
||||
void visit (HIR::LiteralPattern &pattern) override;
|
||||
void visit (HIR::RangePattern &pattern) override;
|
||||
void visit (HIR::IdentifierPattern &pattern) override;
|
||||
void visit (HIR::GroupedPattern &pattern) override;
|
||||
void visit (HIR::QualifiedPathInExpression &pattern) override;
|
||||
void visit (HIR::ReferencePattern &pattern) override;
|
||||
void visit (HIR::SlicePattern &pattern) override;
|
||||
|
||||
private:
|
||||
TypeCheckPattern (TyTy::BaseType *parent);
|
||||
|
||||
static TyTy::BaseType *
|
||||
typecheck_range_pattern_bound (HIR::RangePatternBound *bound,
|
||||
Analysis::NodeMapping mappings,
|
||||
Location locus);
|
||||
|
||||
TyTy::BaseType *parent;
|
||||
TyTy::BaseType *infered;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_PATTERN
|
498
gcc/rust/typecheck/rust-hir-type-check-stmt.cc
Normal file
498
gcc/rust/typecheck/rust-hir-type-check-stmt.cc
Normal file
@ -0,0 +1,498 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-stmt.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-enumitem.h"
|
||||
#include "rust-hir-type-check-implitem.h"
|
||||
#include "rust-hir-type-check-pattern.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckStmt::Resolve (HIR::Stmt *stmt)
|
||||
{
|
||||
TypeCheckStmt resolver;
|
||||
stmt->accept_vis (resolver);
|
||||
return resolver.infered;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::ExprStmtWithBlock &stmt)
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (stmt.get_expr ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::ExprStmtWithoutBlock &stmt)
|
||||
{
|
||||
infered = TypeCheckExpr::Resolve (stmt.get_expr ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::EmptyStmt &stmt)
|
||||
{
|
||||
infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::ExternBlock &extern_block)
|
||||
{
|
||||
for (auto &item : extern_block.get_extern_items ())
|
||||
{
|
||||
TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::ConstantItem &constant)
|
||||
{
|
||||
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
|
||||
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
|
||||
|
||||
infered = type->unify (expr_type);
|
||||
context->insert_type (constant.get_mappings (), infered);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::LetStmt &stmt)
|
||||
{
|
||||
infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
|
||||
|
||||
const HIR::Pattern &stmt_pattern = *stmt.get_pattern ();
|
||||
TyTy::BaseType *init_expr_ty = nullptr;
|
||||
if (stmt.has_init_expr ())
|
||||
{
|
||||
init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ());
|
||||
if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
init_expr_ty->append_reference (
|
||||
stmt_pattern.get_pattern_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *specified_ty = nullptr;
|
||||
if (stmt.has_type ())
|
||||
specified_ty = TypeCheckType::Resolve (stmt.get_type ());
|
||||
|
||||
// let x:i32 = 123;
|
||||
if (specified_ty != nullptr && init_expr_ty != nullptr)
|
||||
{
|
||||
// FIXME use this result and look at the regressions
|
||||
coercion_site (stmt.get_mappings ().get_hirid (), specified_ty,
|
||||
init_expr_ty, stmt.get_locus ());
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (), specified_ty);
|
||||
}
|
||||
else
|
||||
{
|
||||
// let x:i32;
|
||||
if (specified_ty != nullptr)
|
||||
{
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (),
|
||||
specified_ty);
|
||||
}
|
||||
// let x = 123;
|
||||
else if (init_expr_ty != nullptr)
|
||||
{
|
||||
context->insert_type (stmt_pattern.get_pattern_mappings (),
|
||||
init_expr_ty);
|
||||
}
|
||||
// let x;
|
||||
else
|
||||
{
|
||||
context->insert_type (
|
||||
stmt_pattern.get_pattern_mappings (),
|
||||
new TyTy::InferType (
|
||||
stmt_pattern.get_pattern_mappings ().get_hirid (),
|
||||
TyTy::InferType::InferTypeKind::GENERAL, stmt.get_locus ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::TupleStruct &struct_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (struct_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : struct_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
size_t idx = 0;
|
||||
for (auto &field : struct_decl.get_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
std::to_string (idx), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
|
||||
idx++;
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
|
||||
|
||||
// Process #[repr(...)] attribute, if any
|
||||
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
|
||||
TyTy::ADTType::ReprOptions repr
|
||||
= parse_repr_options (attrs, struct_decl.get_locus ());
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::TUPLE_STRUCT,
|
||||
std::move (variants), std::move (substitutions), repr);
|
||||
|
||||
context->insert_type (struct_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::Enum &enum_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (enum_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : enum_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
int64_t discriminant_value = 0;
|
||||
for (auto &variant : enum_decl.get_variants ())
|
||||
{
|
||||
TyTy::VariantDef *field_type
|
||||
= TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
|
||||
|
||||
discriminant_value++;
|
||||
variants.push_back (field_type);
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, enum_decl.get_locus ()};
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
enum_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::ENUM, std::move (variants),
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (enum_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::StructStruct &struct_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (struct_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : struct_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &field : struct_decl.get_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
field.get_field_name (), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
|
||||
|
||||
// Process #[repr(...)] attribute, if any
|
||||
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
|
||||
TyTy::ADTType::ReprOptions repr
|
||||
= parse_repr_options (attrs, struct_decl.get_locus ());
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::STRUCT_STRUCT,
|
||||
std::move (variants), std::move (substitutions), repr);
|
||||
|
||||
context->insert_type (struct_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::Union &union_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (union_decl.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : union_decl.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &variant : union_decl.get_variants ())
|
||||
{
|
||||
TyTy::BaseType *variant_type
|
||||
= TypeCheckType::Resolve (variant.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_variant
|
||||
= new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
|
||||
variant.get_field_name (), variant_type);
|
||||
fields.push_back (ty_variant);
|
||||
context->insert_type (variant.get_mappings (),
|
||||
ty_variant->get_field_type ());
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, union_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
union_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::UNION, std::move (variants),
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (union_decl.get_mappings (), type);
|
||||
infered = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStmt::visit (HIR::Function &function)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (function.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : function.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_function_return_type ())
|
||||
ret_type
|
||||
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved == nullptr)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"failed to resolve return type");
|
||||
return;
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, function.get_locus ()};
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_function_name (), ident,
|
||||
TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
|
||||
std::move (params), ret_type,
|
||||
std::move (substitutions));
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
|
||||
TyTy::FnType *resolved_fn_type = fnType;
|
||||
auto expected_ret_tyty = resolved_fn_type->get_return_type ();
|
||||
context->push_return_type (TypeCheckContextItem (&function),
|
||||
expected_ret_tyty);
|
||||
|
||||
auto block_expr_ty
|
||||
= TypeCheckExpr::Resolve (function.get_definition ().get ());
|
||||
|
||||
context->pop_return_type ();
|
||||
|
||||
if (block_expr_ty->get_kind () != TyTy::NEVER)
|
||||
expected_ret_tyty->unify (block_expr_ty);
|
||||
|
||||
infered = fnType;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
96
gcc/rust/typecheck/rust-hir-type-check-stmt.h
Normal file
96
gcc/rust/typecheck/rust-hir-type-check-stmt.h
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_STMT
|
||||
#define RUST_HIR_TYPE_CHECK_STMT
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckStmt : private TypeCheckBase, private HIR::HIRStmtVisitor
|
||||
{
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (HIR::Stmt *stmt);
|
||||
|
||||
void visit (HIR::ExprStmtWithBlock &stmt) override;
|
||||
void visit (HIR::ExprStmtWithoutBlock &stmt) override;
|
||||
void visit (HIR::EmptyStmt &stmt) override;
|
||||
void visit (HIR::ExternBlock &extern_block) override;
|
||||
void visit (HIR::ConstantItem &constant) override;
|
||||
void visit (HIR::LetStmt &stmt) override;
|
||||
void visit (HIR::TupleStruct &struct_decl) override;
|
||||
void visit (HIR::Enum &enum_decl) override;
|
||||
void visit (HIR::StructStruct &struct_decl) override;
|
||||
void visit (HIR::Union &union_decl) override;
|
||||
void visit (HIR::Function &function) override;
|
||||
|
||||
void visit (HIR::EnumItemTuple &) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::EnumItemStruct &) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::EnumItem &item) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::EnumItemDiscriminant &) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::TypePathSegmentFunction &segment) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::TypePath &path) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::QualifiedPathInType &path) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::Module &module) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::ExternCrate &crate) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::UseDeclaration &use_decl) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::TypeAlias &type_alias) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::StaticItem &static_item) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::Trait &trait) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
void visit (HIR::ImplBlock &impl) override
|
||||
{ /* TODO? */
|
||||
}
|
||||
|
||||
private:
|
||||
TypeCheckStmt () : TypeCheckBase (), infered (nullptr) {}
|
||||
|
||||
TyTy::BaseType *infered;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_STMT
|
59
gcc/rust/typecheck/rust-hir-type-check-struct-field.h
Normal file
59
gcc/rust/typecheck/rust-hir-type-check-struct-field.h
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_STRUCT_FIELD
|
||||
#define RUST_HIR_TYPE_CHECK_STRUCT_FIELD
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-tyty.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckStructExpr : public TypeCheckBase
|
||||
{
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (HIR::StructExprStructFields *expr);
|
||||
|
||||
protected:
|
||||
void resolve (HIR::StructExprStructFields &struct_expr);
|
||||
|
||||
void visit (HIR::StructExprFieldIdentifierValue &field);
|
||||
void visit (HIR::StructExprFieldIndexValue &field);
|
||||
void visit (HIR::StructExprFieldIdentifier &field);
|
||||
|
||||
private:
|
||||
TypeCheckStructExpr (HIR::Expr *e);
|
||||
|
||||
// result
|
||||
TyTy::BaseType *resolved;
|
||||
|
||||
// internal state:
|
||||
TyTy::ADTType *struct_path_resolved;
|
||||
TyTy::VariantDef *variant;
|
||||
TyTy::BaseType *resolved_field_value_expr;
|
||||
std::set<std::string> fields_assigned;
|
||||
std::map<size_t, HIR::StructExprField *> adtFieldIndexToField;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_STRUCT_FIELD
|
340
gcc/rust/typecheck/rust-hir-type-check-struct.cc
Normal file
340
gcc/rust/typecheck/rust-hir-type-check-struct.cc
Normal file
@ -0,0 +1,340 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-struct-field.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr *e)
|
||||
: TypeCheckBase (),
|
||||
resolved (new TyTy::ErrorType (e->get_mappings ().get_hirid ())),
|
||||
struct_path_resolved (nullptr),
|
||||
variant (&TyTy::VariantDef::get_error_node ())
|
||||
{}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckStructExpr::Resolve (HIR::StructExprStructFields *expr)
|
||||
{
|
||||
TypeCheckStructExpr resolver (expr);
|
||||
resolver.resolve (*expr);
|
||||
return resolver.resolved;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
|
||||
{
|
||||
TyTy::BaseType *struct_path_ty
|
||||
= TypeCheckExpr::Resolve (&struct_expr.get_struct_name ());
|
||||
if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
|
||||
{
|
||||
rust_error_at (struct_expr.get_struct_name ().get_locus (),
|
||||
"expected an ADT type for constructor");
|
||||
return;
|
||||
}
|
||||
|
||||
struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty);
|
||||
TyTy::ADTType *struct_def = struct_path_resolved;
|
||||
if (struct_expr.has_struct_base ())
|
||||
{
|
||||
TyTy::BaseType *base_resolved
|
||||
= TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ());
|
||||
struct_def = static_cast<TyTy::ADTType *> (
|
||||
struct_path_resolved->unify (base_resolved));
|
||||
if (struct_def == nullptr)
|
||||
{
|
||||
rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (),
|
||||
"incompatible types for base struct reference");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// figure out the variant
|
||||
if (struct_path_resolved->is_enum ())
|
||||
{
|
||||
// lookup variant id
|
||||
HirId variant_id;
|
||||
bool ok = context->lookup_variant_definition (
|
||||
struct_expr.get_struct_name ().get_mappings ().get_hirid (),
|
||||
&variant_id);
|
||||
rust_assert (ok);
|
||||
|
||||
ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant);
|
||||
rust_assert (ok);
|
||||
}
|
||||
else
|
||||
{
|
||||
rust_assert (struct_path_resolved->number_of_variants () == 1);
|
||||
variant = struct_path_resolved->get_variants ().at (0);
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> infered_fields;
|
||||
bool ok = true;
|
||||
|
||||
for (auto &field : struct_expr.get_fields ())
|
||||
{
|
||||
resolved_field_value_expr = nullptr;
|
||||
|
||||
switch (field->get_kind ())
|
||||
{
|
||||
case HIR::StructExprField::StructExprFieldKind::IDENTIFIER:
|
||||
visit (static_cast<HIR::StructExprFieldIdentifier &> (*field.get ()));
|
||||
break;
|
||||
|
||||
case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE:
|
||||
visit (
|
||||
static_cast<HIR::StructExprFieldIdentifierValue &> (*field.get ()));
|
||||
break;
|
||||
|
||||
case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE:
|
||||
visit (static_cast<HIR::StructExprFieldIndexValue &> (*field.get ()));
|
||||
break;
|
||||
}
|
||||
|
||||
if (resolved_field_value_expr == nullptr)
|
||||
{
|
||||
rust_fatal_error (field->get_locus (),
|
||||
"failed to resolve type for field");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
context->insert_type (field->get_mappings (), resolved_field_value_expr);
|
||||
}
|
||||
|
||||
// something failed setting up the fields
|
||||
if (!ok)
|
||||
{
|
||||
rust_error_at (struct_expr.get_locus (),
|
||||
"constructor type resolution failure");
|
||||
return;
|
||||
}
|
||||
|
||||
// check the arguments are all assigned and fix up the ordering
|
||||
if (fields_assigned.size () != variant->num_fields ())
|
||||
{
|
||||
if (struct_def->is_union ())
|
||||
{
|
||||
if (fields_assigned.size () != 1 || struct_expr.has_struct_base ())
|
||||
{
|
||||
rust_error_at (
|
||||
struct_expr.get_locus (),
|
||||
"union must have exactly one field variant assigned");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!struct_expr.has_struct_base ())
|
||||
{
|
||||
rust_error_at (struct_expr.get_locus (),
|
||||
"constructor is missing fields");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have a struct base to assign the missing fields from.
|
||||
// the missing fields can be implicit FieldAccessExprs for the value
|
||||
std::set<std::string> missing_fields;
|
||||
for (auto &field : variant->get_fields ())
|
||||
{
|
||||
auto it = fields_assigned.find (field->get_name ());
|
||||
if (it == fields_assigned.end ())
|
||||
missing_fields.insert (field->get_name ());
|
||||
}
|
||||
|
||||
// we can generate FieldAccessExpr or TupleAccessExpr for the
|
||||
// values of the missing fields.
|
||||
for (auto &missing : missing_fields)
|
||||
{
|
||||
HIR::Expr *receiver
|
||||
= struct_expr.struct_base->base_struct->clone_expr_impl ();
|
||||
|
||||
HIR::StructExprField *implicit_field = nullptr;
|
||||
|
||||
AST::AttrVec outer_attribs;
|
||||
auto crate_num = mappings->get_current_crate ();
|
||||
Analysis::NodeMapping mapping (
|
||||
crate_num,
|
||||
struct_expr.struct_base->base_struct->get_mappings ()
|
||||
.get_nodeid (),
|
||||
mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
HIR::Expr *field_value = new HIR::FieldAccessExpr (
|
||||
mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
|
||||
std::move (outer_attribs),
|
||||
struct_expr.struct_base->base_struct->get_locus ());
|
||||
|
||||
implicit_field = new HIR::StructExprFieldIdentifierValue (
|
||||
mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
|
||||
struct_expr.struct_base->base_struct->get_locus ());
|
||||
|
||||
size_t field_index;
|
||||
bool ok = variant->lookup_field (missing, nullptr, &field_index);
|
||||
rust_assert (ok);
|
||||
|
||||
adtFieldIndexToField[field_index] = implicit_field;
|
||||
struct_expr.get_fields ().push_back (
|
||||
std::unique_ptr<HIR::StructExprField> (implicit_field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (struct_def->is_union ())
|
||||
{
|
||||
// There is exactly one field in this constructor, we need to
|
||||
// figure out the field index to make sure we initialize the
|
||||
// right union field.
|
||||
for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
|
||||
{
|
||||
if (adtFieldIndexToField[i])
|
||||
{
|
||||
struct_expr.union_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rust_assert (struct_expr.union_index != -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// everything is ok, now we need to ensure all field values are ordered
|
||||
// correctly. The GIMPLE backend uses a simple algorithm that assumes each
|
||||
// assigned field in the constructor is in the same order as the field in
|
||||
// the type
|
||||
for (auto &field : struct_expr.get_fields ())
|
||||
field.release ();
|
||||
|
||||
std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
|
||||
for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
|
||||
{
|
||||
ordered_fields.push_back (
|
||||
std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
|
||||
}
|
||||
struct_expr.set_fields_as_owner (std::move (ordered_fields));
|
||||
}
|
||||
|
||||
resolved = struct_def;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
|
||||
{
|
||||
auto it = fields_assigned.find (field.field_name);
|
||||
if (it != fields_assigned.end ())
|
||||
{
|
||||
rust_fatal_error (field.get_locus (), "used more than once");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t field_index;
|
||||
TyTy::StructFieldType *field_type;
|
||||
bool ok = variant->lookup_field (field.field_name, &field_type, &field_index);
|
||||
if (!ok)
|
||||
{
|
||||
rust_error_at (field.get_locus (), "unknown field");
|
||||
return;
|
||||
}
|
||||
|
||||
TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
|
||||
resolved_field_value_expr
|
||||
= coercion_site (field.get_mappings ().get_hirid (),
|
||||
field_type->get_field_type (), value, field.get_locus ());
|
||||
if (resolved_field_value_expr != nullptr)
|
||||
{
|
||||
fields_assigned.insert (field.field_name);
|
||||
adtFieldIndexToField[field_index] = &field;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
|
||||
{
|
||||
std::string field_name (std::to_string (field.get_tuple_index ()));
|
||||
auto it = fields_assigned.find (field_name);
|
||||
if (it != fields_assigned.end ())
|
||||
{
|
||||
rust_fatal_error (field.get_locus (), "used more than once");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t field_index;
|
||||
TyTy::StructFieldType *field_type;
|
||||
bool ok = variant->lookup_field (field_name, &field_type, &field_index);
|
||||
if (!ok)
|
||||
{
|
||||
rust_error_at (field.get_locus (), "unknown field");
|
||||
return;
|
||||
}
|
||||
|
||||
TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
|
||||
resolved_field_value_expr
|
||||
= coercion_site (field.get_mappings ().get_hirid (),
|
||||
field_type->get_field_type (), value, field.get_locus ());
|
||||
if (resolved_field_value_expr != nullptr)
|
||||
{
|
||||
fields_assigned.insert (field_name);
|
||||
adtFieldIndexToField[field_index] = &field;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
|
||||
{
|
||||
auto it = fields_assigned.find (field.get_field_name ());
|
||||
if (it != fields_assigned.end ())
|
||||
{
|
||||
rust_fatal_error (field.get_locus (), "used more than once");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t field_index;
|
||||
TyTy::StructFieldType *field_type;
|
||||
bool ok = variant->lookup_field (field.get_field_name (), &field_type,
|
||||
&field_index);
|
||||
if (!ok)
|
||||
{
|
||||
rust_error_at (field.get_locus (), "unknown field");
|
||||
return;
|
||||
}
|
||||
|
||||
// we can make the field look like a path expr to take advantage of existing
|
||||
// code
|
||||
Analysis::NodeMapping mappings_copy1 = field.get_mappings ();
|
||||
Analysis::NodeMapping mappings_copy2 = field.get_mappings ();
|
||||
|
||||
HIR::PathIdentSegment ident_seg (field.get_field_name ());
|
||||
HIR::PathExprSegment seg (mappings_copy1, ident_seg, field.get_locus (),
|
||||
HIR::GenericArgs::create_empty ());
|
||||
HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false,
|
||||
{});
|
||||
TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr);
|
||||
|
||||
resolved_field_value_expr
|
||||
= coercion_site (field.get_mappings ().get_hirid (),
|
||||
field_type->get_field_type (), value, field.get_locus ());
|
||||
if (resolved_field_value_expr != nullptr)
|
||||
|
||||
{
|
||||
fields_assigned.insert (field.get_field_name ());
|
||||
adtFieldIndexToField[field_index] = &field;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
364
gcc/rust/typecheck/rust-hir-type-check-toplevel.cc
Normal file
364
gcc/rust/typecheck/rust-hir-type-check-toplevel.cc
Normal file
@ -0,0 +1,364 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-toplevel.h"
|
||||
#include "rust-hir-type-check-enumitem.h"
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-pattern.h"
|
||||
#include "rust-hir-type-check-implitem.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCheckTopLevel::TypeCheckTopLevel () : TypeCheckBase () {}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::Resolve (HIR::Item &item)
|
||||
{
|
||||
rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM);
|
||||
HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item);
|
||||
|
||||
TypeCheckTopLevel resolver;
|
||||
vis_item.accept_vis (resolver);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::TypeAlias &alias)
|
||||
{
|
||||
TyTy::BaseType *actual_type
|
||||
= TypeCheckType::Resolve (alias.get_type_aliased ().get ());
|
||||
|
||||
context->insert_type (alias.get_mappings (), actual_type);
|
||||
|
||||
for (auto &where_clause_item : alias.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::TupleStruct &struct_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (struct_decl.has_generics ())
|
||||
resolve_generic_params (struct_decl.get_generic_params (), substitutions);
|
||||
|
||||
for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
size_t idx = 0;
|
||||
for (auto &field : struct_decl.get_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
std::to_string (idx), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
|
||||
idx++;
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
|
||||
|
||||
// its a single variant ADT
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
|
||||
|
||||
// Process #[repr(X)] attribute, if any
|
||||
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
|
||||
TyTy::ADTType::ReprOptions repr
|
||||
= parse_repr_options (attrs, struct_decl.get_locus ());
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::TUPLE_STRUCT,
|
||||
std::move (variants), std::move (substitutions), repr);
|
||||
|
||||
context->insert_type (struct_decl.get_mappings (), type);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::Module &module)
|
||||
{
|
||||
for (auto &item : module.get_items ())
|
||||
TypeCheckTopLevel::Resolve (*item.get ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::StructStruct &struct_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (struct_decl.has_generics ())
|
||||
resolve_generic_params (struct_decl.get_generic_params (), substitutions);
|
||||
|
||||
for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &field : struct_decl.get_fields ())
|
||||
{
|
||||
TyTy::BaseType *field_type
|
||||
= TypeCheckType::Resolve (field.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_field
|
||||
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
|
||||
field.get_field_name (), field_type);
|
||||
fields.push_back (ty_field);
|
||||
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (
|
||||
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
|
||||
|
||||
// its a single variant ADT
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
|
||||
|
||||
// Process #[repr(X)] attribute, if any
|
||||
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
|
||||
TyTy::ADTType::ReprOptions repr
|
||||
= parse_repr_options (attrs, struct_decl.get_locus ());
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
struct_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::STRUCT_STRUCT,
|
||||
std::move (variants), std::move (substitutions), repr);
|
||||
|
||||
context->insert_type (struct_decl.get_mappings (), type);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::Enum &enum_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (enum_decl.has_generics ())
|
||||
resolve_generic_params (enum_decl.get_generic_params (), substitutions);
|
||||
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
int64_t discriminant_value = 0;
|
||||
for (auto &variant : enum_decl.get_variants ())
|
||||
{
|
||||
TyTy::VariantDef *field_type
|
||||
= TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
|
||||
|
||||
discriminant_value++;
|
||||
variants.push_back (field_type);
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, enum_decl.get_locus ()};
|
||||
|
||||
// multi variant ADT
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
enum_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::ENUM, std::move (variants),
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (enum_decl.get_mappings (), type);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::Union &union_decl)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (union_decl.has_generics ())
|
||||
resolve_generic_params (union_decl.get_generic_params (), substitutions);
|
||||
|
||||
for (auto &where_clause_item : union_decl.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
|
||||
std::vector<TyTy::StructFieldType *> fields;
|
||||
for (auto &variant : union_decl.get_variants ())
|
||||
{
|
||||
TyTy::BaseType *variant_type
|
||||
= TypeCheckType::Resolve (variant.get_field_type ().get ());
|
||||
TyTy::StructFieldType *ty_variant
|
||||
= new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
|
||||
variant.get_field_name (), variant_type);
|
||||
fields.push_back (ty_variant);
|
||||
context->insert_type (variant.get_mappings (),
|
||||
ty_variant->get_field_type ());
|
||||
}
|
||||
|
||||
// get the path
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
RustIdent ident{*canonical_path, union_decl.get_locus ()};
|
||||
|
||||
// there is only a single variant
|
||||
std::vector<TyTy::VariantDef *> variants;
|
||||
variants.push_back (new TyTy::VariantDef (
|
||||
union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
|
||||
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
|
||||
|
||||
TyTy::BaseType *type
|
||||
= new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
|
||||
mappings->get_next_hir_id (),
|
||||
union_decl.get_identifier (), ident,
|
||||
TyTy::ADTType::ADTKind::UNION, std::move (variants),
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (union_decl.get_mappings (), type);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::StaticItem &var)
|
||||
{
|
||||
TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ());
|
||||
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (var.get_expr ());
|
||||
|
||||
context->insert_type (var.get_mappings (), type->unify (expr_type));
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::ConstantItem &constant)
|
||||
{
|
||||
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
|
||||
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
|
||||
|
||||
context->insert_type (constant.get_mappings (), type->unify (expr_type));
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::Function &function)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (function.has_generics ())
|
||||
resolve_generic_params (function.get_generic_params (), substitutions);
|
||||
|
||||
for (auto &where_clause_item : function.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_function_return_type ())
|
||||
ret_type
|
||||
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (function.get_locus (),
|
||||
"failed to resolve return type");
|
||||
return;
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *>> params;
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
|
||||
}
|
||||
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok
|
||||
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, function.get_locus ()};
|
||||
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
|
||||
function.get_mappings ().get_defid (),
|
||||
function.get_function_name (), ident,
|
||||
TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
|
||||
std::move (params), ret_type,
|
||||
std::move (substitutions));
|
||||
|
||||
context->insert_type (function.get_mappings (), fnType);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::ImplBlock &impl_block)
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions;
|
||||
if (impl_block.has_generics ())
|
||||
resolve_generic_params (impl_block.get_generic_params (), substitutions);
|
||||
|
||||
for (auto &where_clause_item : impl_block.get_where_clause ().get_items ())
|
||||
{
|
||||
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
|
||||
}
|
||||
|
||||
auto self = TypeCheckType::Resolve (impl_block.get_type ().get ());
|
||||
if (self->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
for (auto &impl_item : impl_block.get_impl_items ())
|
||||
TypeCheckTopLevelImplItem::Resolve (impl_item.get (), self, substitutions);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckTopLevel::visit (HIR::ExternBlock &extern_block)
|
||||
{
|
||||
for (auto &item : extern_block.get_extern_items ())
|
||||
{
|
||||
TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
56
gcc/rust/typecheck/rust-hir-type-check-toplevel.h
Normal file
56
gcc/rust/typecheck/rust-hir-type-check-toplevel.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_TOPLEVEL
|
||||
#define RUST_HIR_TYPE_CHECK_TOPLEVEL
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckTopLevel : private TypeCheckBase, public HIR::HIRVisItemVisitor
|
||||
{
|
||||
public:
|
||||
static void Resolve (HIR::Item &item);
|
||||
|
||||
void visit (HIR::Module &module) override;
|
||||
void visit (HIR::Function &function) override;
|
||||
void visit (HIR::TypeAlias &alias) override;
|
||||
void visit (HIR::TupleStruct &struct_decl) override;
|
||||
void visit (HIR::StructStruct &struct_decl) override;
|
||||
void visit (HIR::Enum &enum_decl) override;
|
||||
void visit (HIR::Union &union_decl) override;
|
||||
void visit (HIR::StaticItem &var) override;
|
||||
void visit (HIR::ConstantItem &constant) override;
|
||||
void visit (HIR::ImplBlock &impl_block) override;
|
||||
void visit (HIR::ExternBlock &extern_block) override;
|
||||
|
||||
// nothing to do
|
||||
void visit (HIR::Trait &trait_block) override {}
|
||||
void visit (HIR::ExternCrate &crate) override {}
|
||||
void visit (HIR::UseDeclaration &use_decl) override {}
|
||||
|
||||
private:
|
||||
TypeCheckTopLevel ();
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_TOPLEVEL
|
838
gcc/rust/typecheck/rust-hir-type-check-type.cc
Normal file
838
gcc/rust/typecheck/rust-hir-type-check-type.cc
Normal file
@ -0,0 +1,838 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-type.h"
|
||||
#include "rust-hir-trait-resolve.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
HIR::GenericArgs
|
||||
TypeCheckResolveGenericArguments::resolve (HIR::TypePathSegment *segment)
|
||||
{
|
||||
TypeCheckResolveGenericArguments resolver (segment->get_locus ());
|
||||
switch (segment->get_type ())
|
||||
{
|
||||
case HIR::TypePathSegment::SegmentType::GENERIC:
|
||||
resolver.visit (static_cast<HIR::TypePathSegmentGeneric &> (*segment));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return resolver.args;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckResolveGenericArguments::visit (HIR::TypePathSegmentGeneric &generic)
|
||||
{
|
||||
args = generic.get_generic_args ();
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckType::Resolve (HIR::Type *type)
|
||||
{
|
||||
TypeCheckType resolver (type->get_mappings ().get_hirid ());
|
||||
type->accept_vis (resolver);
|
||||
rust_assert (resolver.translated != nullptr);
|
||||
resolver.context->insert_type (type->get_mappings (), resolver.translated);
|
||||
return resolver.translated;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::BareFunctionType &fntype)
|
||||
{
|
||||
TyTy::BaseType *return_type
|
||||
= fntype.has_return_type ()
|
||||
? TypeCheckType::Resolve (fntype.get_return_type ().get ())
|
||||
: TyTy::TupleType::get_unit_type (fntype.get_mappings ().get_hirid ());
|
||||
|
||||
std::vector<TyTy::TyVar> params;
|
||||
for (auto ¶m : fntype.get_function_params ())
|
||||
{
|
||||
TyTy::BaseType *ptype = TypeCheckType::Resolve (param.get_type ().get ());
|
||||
params.push_back (TyTy::TyVar (ptype->get_ref ()));
|
||||
}
|
||||
|
||||
translated = new TyTy::FnPtr (fntype.get_mappings ().get_hirid (),
|
||||
fntype.get_locus (), std::move (params),
|
||||
TyTy::TyVar (return_type->get_ref ()));
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::TupleType &tuple)
|
||||
{
|
||||
if (tuple.is_unit_type ())
|
||||
{
|
||||
auto unit_node_id = resolver->get_unit_type_node_id ();
|
||||
if (!context->lookup_builtin (unit_node_id, &translated))
|
||||
{
|
||||
rust_error_at (tuple.get_locus (),
|
||||
"failed to lookup builtin unit type");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<TyTy::TyVar> fields;
|
||||
for (auto &elem : tuple.get_elems ())
|
||||
{
|
||||
auto field_ty = TypeCheckType::Resolve (elem.get ());
|
||||
fields.push_back (TyTy::TyVar (field_ty->get_ref ()));
|
||||
}
|
||||
|
||||
translated = new TyTy::TupleType (tuple.get_mappings ().get_hirid (),
|
||||
tuple.get_locus (), fields);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::TypePath &path)
|
||||
{
|
||||
// lookup the Node this resolves to
|
||||
NodeId ref;
|
||||
auto nid = path.get_mappings ().get_nodeid ();
|
||||
bool is_fully_resolved = resolver->lookup_resolved_type (nid, &ref);
|
||||
|
||||
TyTy::BaseType *lookup = nullptr;
|
||||
if (!is_fully_resolved)
|
||||
{
|
||||
// this can happen so we need to look up the root then resolve the
|
||||
// remaining segments if possible
|
||||
size_t offset = 0;
|
||||
NodeId resolved_node_id = UNKNOWN_NODEID;
|
||||
TyTy::BaseType *root
|
||||
= resolve_root_path (path, &offset, &resolved_node_id);
|
||||
|
||||
rust_assert (root != nullptr);
|
||||
if (root->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
translated
|
||||
= resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (),
|
||||
path.get_segments (), offset, root,
|
||||
path.get_mappings (), path.get_locus ());
|
||||
return;
|
||||
}
|
||||
|
||||
HirId hir_lookup;
|
||||
if (!context->lookup_type_by_node_id (ref, &hir_lookup))
|
||||
{
|
||||
rust_error_at (path.get_locus (), "failed to lookup HIR %d for node '%s'",
|
||||
ref, path.as_string ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context->lookup_type (hir_lookup, &lookup))
|
||||
{
|
||||
rust_error_at (path.get_locus (), "failed to lookup HIR TyTy");
|
||||
return;
|
||||
}
|
||||
|
||||
TyTy::BaseType *path_type = lookup->clone ();
|
||||
path_type->set_ref (path.get_mappings ().get_hirid ());
|
||||
|
||||
HIR::TypePathSegment *final_seg = path.get_final_segment ().get ();
|
||||
HIR::GenericArgs args = TypeCheckResolveGenericArguments::resolve (final_seg);
|
||||
|
||||
bool is_big_self = final_seg->is_ident_only ()
|
||||
&& (final_seg->as_string ().compare ("Self") == 0);
|
||||
|
||||
if (path_type->needs_generic_substitutions ())
|
||||
{
|
||||
if (is_big_self)
|
||||
{
|
||||
translated = path_type;
|
||||
return;
|
||||
}
|
||||
|
||||
translated = SubstMapper::Resolve (path_type, path.get_locus (), &args);
|
||||
}
|
||||
else if (!args.is_empty ())
|
||||
{
|
||||
rust_error_at (path.get_locus (),
|
||||
"TypePath %s declares generic arguments but "
|
||||
"the type %s does not have any",
|
||||
path.as_string ().c_str (),
|
||||
path_type->as_string ().c_str ());
|
||||
}
|
||||
else
|
||||
{
|
||||
translated = path_type;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::QualifiedPathInType &path)
|
||||
{
|
||||
HIR::QualifiedPathType qual_path_type = path.get_path_type ();
|
||||
TyTy::BaseType *root
|
||||
= TypeCheckType::Resolve (qual_path_type.get_type ().get ());
|
||||
if (root->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_debug_loc (path.get_locus (), "failed to resolve the root");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qual_path_type.has_as_clause ())
|
||||
{
|
||||
// then this is just a normal path-in-expression
|
||||
NodeId root_resolved_node_id = UNKNOWN_NODEID;
|
||||
bool ok = resolver->lookup_resolved_type (
|
||||
qual_path_type.get_type ()->get_mappings ().get_nodeid (),
|
||||
&root_resolved_node_id);
|
||||
rust_assert (ok);
|
||||
|
||||
translated = resolve_segments (root_resolved_node_id,
|
||||
path.get_mappings ().get_hirid (),
|
||||
path.get_segments (), 0, translated,
|
||||
path.get_mappings (), path.get_locus ());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve the trait now
|
||||
TraitReference *trait_ref
|
||||
= TraitResolver::Resolve (*qual_path_type.get_trait ().get ());
|
||||
if (trait_ref->is_error ())
|
||||
return;
|
||||
|
||||
// does this type actually implement this type-bound?
|
||||
if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
|
||||
{
|
||||
rust_error_at (qual_path_type.get_locus (),
|
||||
"root does not satisfy specified trait-bound");
|
||||
return;
|
||||
}
|
||||
|
||||
// get the predicate for the bound
|
||||
auto specified_bound
|
||||
= get_predicate_from_bound (*qual_path_type.get_trait ().get ());
|
||||
if (specified_bound.is_error ())
|
||||
return;
|
||||
|
||||
// inherit the bound
|
||||
root->inherit_bounds ({specified_bound});
|
||||
|
||||
// setup the associated types
|
||||
const TraitReference *specified_bound_ref = specified_bound.get ();
|
||||
auto candidates = TypeBoundsProbe::Probe (root);
|
||||
AssociatedImplTrait *associated_impl_trait = nullptr;
|
||||
for (auto &probed_bound : candidates)
|
||||
{
|
||||
const TraitReference *bound_trait_ref = probed_bound.first;
|
||||
const HIR::ImplBlock *associated_impl = probed_bound.second;
|
||||
|
||||
HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
|
||||
AssociatedImplTrait *associated = nullptr;
|
||||
bool found_impl_trait
|
||||
= context->lookup_associated_trait_impl (impl_block_id, &associated);
|
||||
if (found_impl_trait)
|
||||
{
|
||||
bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref);
|
||||
bool found_self = associated->get_self ()->can_eq (root, false);
|
||||
if (found_trait && found_self)
|
||||
{
|
||||
associated_impl_trait = associated;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (associated_impl_trait != nullptr)
|
||||
{
|
||||
associated_impl_trait->setup_associated_types (root, specified_bound);
|
||||
}
|
||||
|
||||
// lookup the associated item from the specified bound
|
||||
std::unique_ptr<HIR::TypePathSegment> &item_seg
|
||||
= path.get_associated_segment ();
|
||||
HIR::PathIdentSegment item_seg_identifier = item_seg->get_ident_segment ();
|
||||
TyTy::TypeBoundPredicateItem item
|
||||
= specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
|
||||
if (item.is_error ())
|
||||
{
|
||||
rust_error_at (item_seg->get_locus (), "unknown associated item");
|
||||
return;
|
||||
}
|
||||
|
||||
// infer the root type
|
||||
translated = item.get_tyty_for_receiver (root);
|
||||
|
||||
// turbo-fish segment path::<ty>
|
||||
if (item_seg->get_type () == HIR::TypePathSegment::SegmentType::GENERIC)
|
||||
{
|
||||
HIR::TypePathSegmentGeneric &generic_seg
|
||||
= static_cast<HIR::TypePathSegmentGeneric &> (*item_seg.get ());
|
||||
|
||||
// turbo-fish segment path::<ty>
|
||||
if (generic_seg.has_generic_args ())
|
||||
{
|
||||
if (!translated->can_substitute ())
|
||||
{
|
||||
rust_error_at (item_seg->get_locus (),
|
||||
"substitutions not supported for %s",
|
||||
translated->as_string ().c_str ());
|
||||
translated
|
||||
= new TyTy::ErrorType (path.get_mappings ().get_hirid ());
|
||||
return;
|
||||
}
|
||||
translated = SubstMapper::Resolve (translated, path.get_locus (),
|
||||
&generic_seg.get_generic_args ());
|
||||
}
|
||||
}
|
||||
|
||||
// continue on as a path-in-expression
|
||||
const TraitItemReference *trait_item_ref = item.get_raw_item ();
|
||||
NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
|
||||
bool fully_resolved = path.get_segments ().empty ();
|
||||
if (fully_resolved)
|
||||
{
|
||||
resolver->insert_resolved_type (path.get_mappings ().get_nodeid (),
|
||||
root_resolved_node_id);
|
||||
context->insert_receiver (path.get_mappings ().get_hirid (), root);
|
||||
return;
|
||||
}
|
||||
|
||||
translated
|
||||
= resolve_segments (root_resolved_node_id,
|
||||
path.get_mappings ().get_hirid (), path.get_segments (),
|
||||
0, translated, path.get_mappings (), path.get_locus ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
|
||||
NodeId *root_resolved_node_id)
|
||||
{
|
||||
TyTy::BaseType *root_tyty = nullptr;
|
||||
*offset = 0;
|
||||
for (size_t i = 0; i < path.get_num_segments (); i++)
|
||||
{
|
||||
std::unique_ptr<HIR::TypePathSegment> &seg = path.get_segments ().at (i);
|
||||
|
||||
bool have_more_segments = (path.get_num_segments () - 1 != i);
|
||||
bool is_root = *offset == 0;
|
||||
NodeId ast_node_id = seg->get_mappings ().get_nodeid ();
|
||||
|
||||
// then lookup the reference_node_id
|
||||
NodeId ref_node_id = UNKNOWN_NODEID;
|
||||
if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
|
||||
{
|
||||
resolver->lookup_resolved_type (ast_node_id, &ref_node_id);
|
||||
}
|
||||
|
||||
// ref_node_id is the NodeId that the segments refers to.
|
||||
if (ref_node_id == UNKNOWN_NODEID)
|
||||
{
|
||||
if (is_root)
|
||||
{
|
||||
rust_error_at (seg->get_locus (),
|
||||
"unknown reference for resolved name: %<%s%>",
|
||||
seg->get_ident_segment ().as_string ().c_str ());
|
||||
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
|
||||
}
|
||||
return root_tyty;
|
||||
}
|
||||
|
||||
// node back to HIR
|
||||
HirId ref = UNKNOWN_HIRID;
|
||||
if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
|
||||
{
|
||||
if (is_root)
|
||||
{
|
||||
rust_error_at (seg->get_locus (), "789 reverse lookup failure");
|
||||
rust_debug_loc (
|
||||
seg->get_locus (),
|
||||
"failure with [%s] mappings [%s] ref_node_id [%u]",
|
||||
seg->as_string ().c_str (),
|
||||
seg->get_mappings ().as_string ().c_str (), ref_node_id);
|
||||
|
||||
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
return root_tyty;
|
||||
}
|
||||
|
||||
auto seg_is_module = (nullptr != mappings->lookup_module (ref));
|
||||
auto seg_is_crate = mappings->is_local_hirid_crate (ref);
|
||||
if (seg_is_module || seg_is_crate)
|
||||
{
|
||||
// A::B::C::this_is_a_module::D::E::F
|
||||
// ^^^^^^^^^^^^^^^^
|
||||
// Currently handling this.
|
||||
if (have_more_segments)
|
||||
{
|
||||
(*offset)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// In the case of :
|
||||
// A::B::C::this_is_a_module
|
||||
// ^^^^^^^^^^^^^^^^
|
||||
// This is an error, we are not expecting a module.
|
||||
rust_error_at (seg->get_locus (), "expected value");
|
||||
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *lookup = nullptr;
|
||||
if (!context->lookup_type (ref, &lookup))
|
||||
{
|
||||
if (is_root)
|
||||
{
|
||||
rust_error_at (seg->get_locus (),
|
||||
"failed to resolve root segment");
|
||||
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
|
||||
}
|
||||
return root_tyty;
|
||||
}
|
||||
|
||||
// if we have a previous segment type
|
||||
if (root_tyty != nullptr)
|
||||
{
|
||||
// if this next segment needs substitution we must apply the
|
||||
// previous type arguments
|
||||
//
|
||||
// such as: GenericStruct::<_>::new(123, 456)
|
||||
if (lookup->needs_generic_substitutions ())
|
||||
{
|
||||
if (!root_tyty->needs_generic_substitutions ())
|
||||
{
|
||||
auto used_args_in_prev_segment
|
||||
= GetUsedSubstArgs::From (root_tyty);
|
||||
lookup
|
||||
= SubstMapperInternal::Resolve (lookup,
|
||||
used_args_in_prev_segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// turbo-fish segment path::<ty>
|
||||
if (seg->is_generic_segment ())
|
||||
{
|
||||
HIR::TypePathSegmentGeneric *generic_segment
|
||||
= static_cast<HIR::TypePathSegmentGeneric *> (seg.get ());
|
||||
|
||||
if (!lookup->can_substitute ())
|
||||
{
|
||||
rust_error_at (seg->get_locus (),
|
||||
"substitutions not supported for %s",
|
||||
lookup->as_string ().c_str ());
|
||||
return new TyTy::ErrorType (lookup->get_ref ());
|
||||
}
|
||||
lookup = SubstMapper::Resolve (lookup, path.get_locus (),
|
||||
&generic_segment->get_generic_args ());
|
||||
}
|
||||
|
||||
*root_resolved_node_id = ref_node_id;
|
||||
*offset = *offset + 1;
|
||||
root_tyty = lookup;
|
||||
}
|
||||
|
||||
return root_tyty;
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckType::resolve_segments (
|
||||
NodeId root_resolved_node_id, HirId expr_id,
|
||||
std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset,
|
||||
TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
|
||||
Location expr_locus)
|
||||
{
|
||||
NodeId resolved_node_id = root_resolved_node_id;
|
||||
TyTy::BaseType *prev_segment = tyseg;
|
||||
for (size_t i = offset; i < segments.size (); i++)
|
||||
{
|
||||
std::unique_ptr<HIR::TypePathSegment> &seg = segments.at (i);
|
||||
|
||||
bool reciever_is_generic
|
||||
= prev_segment->get_kind () == TyTy::TypeKind::PARAM;
|
||||
bool probe_bounds = true;
|
||||
bool probe_impls = !reciever_is_generic;
|
||||
bool ignore_mandatory_trait_items = !reciever_is_generic;
|
||||
|
||||
// probe the path is done in two parts one where we search impls if no
|
||||
// candidate is found then we search extensions from traits
|
||||
auto candidates
|
||||
= PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
|
||||
probe_impls, false,
|
||||
ignore_mandatory_trait_items);
|
||||
if (candidates.size () == 0)
|
||||
{
|
||||
candidates
|
||||
= PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
|
||||
false, probe_bounds,
|
||||
ignore_mandatory_trait_items);
|
||||
|
||||
if (candidates.size () == 0)
|
||||
{
|
||||
rust_error_at (
|
||||
seg->get_locus (),
|
||||
"failed to resolve path segment using an impl Probe");
|
||||
return new TyTy::ErrorType (expr_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.size () > 1)
|
||||
{
|
||||
ReportMultipleCandidateError::Report (candidates,
|
||||
seg->get_ident_segment (),
|
||||
seg->get_locus ());
|
||||
return new TyTy::ErrorType (expr_id);
|
||||
}
|
||||
|
||||
auto &candidate = candidates.at (0);
|
||||
prev_segment = tyseg;
|
||||
tyseg = candidate.ty;
|
||||
|
||||
if (candidate.is_impl_candidate ())
|
||||
{
|
||||
resolved_node_id
|
||||
= candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
|
||||
}
|
||||
else
|
||||
{
|
||||
resolved_node_id
|
||||
= candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
|
||||
}
|
||||
|
||||
if (seg->is_generic_segment ())
|
||||
{
|
||||
HIR::TypePathSegmentGeneric *generic_segment
|
||||
= static_cast<HIR::TypePathSegmentGeneric *> (seg.get ());
|
||||
|
||||
if (!tyseg->can_substitute ())
|
||||
{
|
||||
rust_error_at (expr_locus, "substitutions not supported for %s",
|
||||
tyseg->as_string ().c_str ());
|
||||
return new TyTy::ErrorType (expr_id);
|
||||
}
|
||||
|
||||
tyseg = SubstMapper::Resolve (tyseg, expr_locus,
|
||||
&generic_segment->get_generic_args ());
|
||||
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return new TyTy::ErrorType (expr_id);
|
||||
}
|
||||
}
|
||||
|
||||
context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
|
||||
if (tyseg->needs_generic_substitutions ())
|
||||
{
|
||||
Location locus = segments.back ()->get_locus ();
|
||||
if (!prev_segment->needs_generic_substitutions ())
|
||||
{
|
||||
auto used_args_in_prev_segment
|
||||
= GetUsedSubstArgs::From (prev_segment);
|
||||
if (!used_args_in_prev_segment.is_error ())
|
||||
tyseg
|
||||
= SubstMapperInternal::Resolve (tyseg, used_args_in_prev_segment);
|
||||
}
|
||||
else
|
||||
{
|
||||
tyseg = SubstMapper::InferSubst (tyseg, locus);
|
||||
}
|
||||
|
||||
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return new TyTy::ErrorType (expr_id);
|
||||
}
|
||||
|
||||
rust_assert (resolved_node_id != UNKNOWN_NODEID);
|
||||
|
||||
// lookup if the name resolver was able to canonically resolve this or not
|
||||
NodeId path_resolved_id = UNKNOWN_NODEID;
|
||||
if (resolver->lookup_resolved_name (expr_mappings.get_nodeid (),
|
||||
&path_resolved_id))
|
||||
{
|
||||
rust_assert (path_resolved_id == resolved_node_id);
|
||||
}
|
||||
// check the type scope
|
||||
else if (resolver->lookup_resolved_type (expr_mappings.get_nodeid (),
|
||||
&path_resolved_id))
|
||||
{
|
||||
rust_assert (path_resolved_id == resolved_node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// name scope first
|
||||
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
|
||||
{
|
||||
resolver->insert_resolved_name (expr_mappings.get_nodeid (),
|
||||
resolved_node_id);
|
||||
}
|
||||
// check the type scope
|
||||
else if (resolver->get_type_scope ().decl_was_declared_here (
|
||||
resolved_node_id))
|
||||
{
|
||||
resolver->insert_resolved_type (expr_mappings.get_nodeid (),
|
||||
resolved_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
return tyseg;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::TraitObjectType &type)
|
||||
{
|
||||
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
|
||||
for (auto &bound : type.get_type_param_bounds ())
|
||||
{
|
||||
if (bound->get_bound_type ()
|
||||
!= HIR::TypeParamBound::BoundType::TRAITBOUND)
|
||||
continue;
|
||||
|
||||
HIR::TypeParamBound &b = *bound.get ();
|
||||
HIR::TraitBound &trait_bound = static_cast<HIR::TraitBound &> (b);
|
||||
|
||||
TyTy::TypeBoundPredicate predicate
|
||||
= get_predicate_from_bound (trait_bound.get_path ());
|
||||
|
||||
if (!predicate.is_error ()
|
||||
&& predicate.is_object_safe (true, type.get_locus ()))
|
||||
specified_bounds.push_back (std::move (predicate));
|
||||
}
|
||||
|
||||
RustIdent ident{CanonicalPath::create_empty (), type.get_locus ()};
|
||||
translated
|
||||
= new TyTy::DynamicObjectType (type.get_mappings ().get_hirid (), ident,
|
||||
std::move (specified_bounds));
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::ArrayType &type)
|
||||
{
|
||||
auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ());
|
||||
if (capacity_type->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
TyTy::BaseType *expected_ty = nullptr;
|
||||
bool ok = context->lookup_builtin ("usize", &expected_ty);
|
||||
rust_assert (ok);
|
||||
context->insert_type (type.get_size_expr ()->get_mappings (), expected_ty);
|
||||
|
||||
auto unified = expected_ty->unify (capacity_type);
|
||||
if (unified->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return;
|
||||
|
||||
TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ());
|
||||
translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (),
|
||||
type.get_locus (), *type.get_size_expr (),
|
||||
TyTy::TyVar (base->get_ref ()));
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::SliceType &type)
|
||||
{
|
||||
TyTy::BaseType *base
|
||||
= TypeCheckType::Resolve (type.get_element_type ().get ());
|
||||
translated
|
||||
= new TyTy::SliceType (type.get_mappings ().get_hirid (), type.get_locus (),
|
||||
TyTy::TyVar (base->get_ref ()));
|
||||
}
|
||||
void
|
||||
TypeCheckType::visit (HIR::ReferenceType &type)
|
||||
{
|
||||
TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ());
|
||||
translated
|
||||
= new TyTy::ReferenceType (type.get_mappings ().get_hirid (),
|
||||
TyTy::TyVar (base->get_ref ()), type.get_mut ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::RawPointerType &type)
|
||||
{
|
||||
TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ());
|
||||
translated
|
||||
= new TyTy::PointerType (type.get_mappings ().get_hirid (),
|
||||
TyTy::TyVar (base->get_ref ()), type.get_mut ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::InferredType &type)
|
||||
{
|
||||
translated = new TyTy::InferType (type.get_mappings ().get_hirid (),
|
||||
TyTy::InferType::InferTypeKind::GENERAL,
|
||||
type.get_locus ());
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckType::visit (HIR::NeverType &type)
|
||||
{
|
||||
TyTy::BaseType *lookup = nullptr;
|
||||
bool ok = context->lookup_builtin ("!", &lookup);
|
||||
rust_assert (ok);
|
||||
|
||||
translated = lookup->clone ();
|
||||
}
|
||||
|
||||
TyTy::ParamType *
|
||||
TypeResolveGenericParam::Resolve (HIR::GenericParam *param)
|
||||
{
|
||||
TypeResolveGenericParam resolver;
|
||||
switch (param->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::TYPE:
|
||||
resolver.visit (static_cast<HIR::TypeParam &> (*param));
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
resolver.visit (static_cast<HIR::ConstGenericParam &> (*param));
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
resolver.visit (static_cast<HIR::LifetimeParam &> (*param));
|
||||
break;
|
||||
}
|
||||
return resolver.resolved;
|
||||
}
|
||||
|
||||
void
|
||||
TypeResolveGenericParam::visit (HIR::LifetimeParam ¶m)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void
|
||||
TypeResolveGenericParam::visit (HIR::ConstGenericParam ¶m)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void
|
||||
TypeResolveGenericParam::visit (HIR::TypeParam ¶m)
|
||||
{
|
||||
if (param.has_type ())
|
||||
TypeCheckType::Resolve (param.get_type ().get ());
|
||||
|
||||
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
|
||||
if (param.has_type_param_bounds ())
|
||||
{
|
||||
for (auto &bound : param.get_type_param_bounds ())
|
||||
{
|
||||
switch (bound->get_bound_type ())
|
||||
{
|
||||
case HIR::TypeParamBound::BoundType::TRAITBOUND: {
|
||||
HIR::TraitBound *b
|
||||
= static_cast<HIR::TraitBound *> (bound.get ());
|
||||
|
||||
TyTy::TypeBoundPredicate predicate
|
||||
= get_predicate_from_bound (b->get_path ());
|
||||
if (!predicate.is_error ())
|
||||
specified_bounds.push_back (std::move (predicate));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolved
|
||||
= new TyTy::ParamType (param.get_type_representation (), param.get_locus (),
|
||||
param.get_mappings ().get_hirid (), param,
|
||||
specified_bounds);
|
||||
}
|
||||
|
||||
void
|
||||
ResolveWhereClauseItem::Resolve (HIR::WhereClauseItem &item)
|
||||
{
|
||||
ResolveWhereClauseItem resolver;
|
||||
switch (item.get_item_type ())
|
||||
{
|
||||
case HIR::WhereClauseItem::LIFETIME:
|
||||
resolver.visit (static_cast<HIR::LifetimeWhereClauseItem &> (item));
|
||||
break;
|
||||
|
||||
case HIR::WhereClauseItem::TYPE_BOUND:
|
||||
resolver.visit (static_cast<HIR::TypeBoundWhereClauseItem &> (item));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &item)
|
||||
{}
|
||||
|
||||
void
|
||||
ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item)
|
||||
{
|
||||
auto &binding_type_path = item.get_bound_type ();
|
||||
TyTy::BaseType *binding = TypeCheckType::Resolve (binding_type_path.get ());
|
||||
|
||||
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
|
||||
for (auto &bound : item.get_type_param_bounds ())
|
||||
{
|
||||
switch (bound->get_bound_type ())
|
||||
{
|
||||
case HIR::TypeParamBound::BoundType::TRAITBOUND: {
|
||||
HIR::TraitBound *b = static_cast<HIR::TraitBound *> (bound.get ());
|
||||
|
||||
TyTy::TypeBoundPredicate predicate
|
||||
= get_predicate_from_bound (b->get_path ());
|
||||
if (!predicate.is_error ())
|
||||
specified_bounds.push_back (std::move (predicate));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
binding->inherit_bounds (specified_bounds);
|
||||
|
||||
// When we apply these bounds we must lookup which type this binding
|
||||
// resolves to, as this is the type which will be used during resolution
|
||||
// of the block.
|
||||
NodeId ast_node_id = binding_type_path->get_mappings ().get_nodeid ();
|
||||
|
||||
// then lookup the reference_node_id
|
||||
NodeId ref_node_id = UNKNOWN_NODEID;
|
||||
if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id))
|
||||
{
|
||||
// FIXME
|
||||
rust_error_at (Location (),
|
||||
"Failed to lookup type reference for node: %s",
|
||||
binding_type_path->as_string ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// node back to HIR
|
||||
HirId ref;
|
||||
if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
|
||||
{
|
||||
// FIXME
|
||||
rust_error_at (Location (), "where-clause reverse lookup failure");
|
||||
return;
|
||||
}
|
||||
|
||||
// the base reference for this name _must_ have a type set
|
||||
TyTy::BaseType *lookup;
|
||||
if (!context->lookup_type (ref, &lookup))
|
||||
{
|
||||
rust_error_at (mappings->lookup_location (ref),
|
||||
"Failed to resolve where-clause binding type: %s",
|
||||
binding_type_path->as_string ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// rust_assert (binding->is_equal (*lookup));
|
||||
lookup->inherit_bounds (specified_bounds);
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
130
gcc/rust/typecheck/rust-hir-type-check-type.h
Normal file
130
gcc/rust/typecheck/rust-hir-type-check-type.h
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_TYPE
|
||||
#define RUST_HIR_TYPE_CHECK_TYPE
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-substitution-mapper.h"
|
||||
#include "rust-hir-path-probe.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
// FIXME
|
||||
// This simply fetches the HIR:::GenericArgs from the base class. Check to see
|
||||
// if we can get rid of this class
|
||||
class TypeCheckResolveGenericArguments : public TypeCheckBase
|
||||
{
|
||||
public:
|
||||
static HIR::GenericArgs resolve (HIR::TypePathSegment *segment);
|
||||
|
||||
void visit (HIR::TypePathSegmentGeneric &generic);
|
||||
|
||||
private:
|
||||
TypeCheckResolveGenericArguments (Location locus)
|
||||
: TypeCheckBase (), args (HIR::GenericArgs::create_empty (locus))
|
||||
{}
|
||||
|
||||
HIR::GenericArgs args;
|
||||
};
|
||||
|
||||
class TypeCheckType : public TypeCheckBase, public HIR::HIRTypeVisitor
|
||||
{
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (HIR::Type *type);
|
||||
|
||||
void visit (HIR::BareFunctionType &fntype) override;
|
||||
void visit (HIR::TupleType &tuple) override;
|
||||
void visit (HIR::TypePath &path) override;
|
||||
void visit (HIR::QualifiedPathInType &path) override;
|
||||
void visit (HIR::ArrayType &type) override;
|
||||
void visit (HIR::SliceType &type) override;
|
||||
void visit (HIR::ReferenceType &type) override;
|
||||
void visit (HIR::RawPointerType &type) override;
|
||||
void visit (HIR::InferredType &type) override;
|
||||
void visit (HIR::NeverType &type) override;
|
||||
void visit (HIR::TraitObjectType &type) override;
|
||||
|
||||
void visit (HIR::TypePathSegmentFunction &segment) override
|
||||
{ /* TODO */
|
||||
}
|
||||
void visit (HIR::TraitBound &bound) override
|
||||
{ /* TODO */
|
||||
}
|
||||
void visit (HIR::ImplTraitType &type) override
|
||||
{ /* TODO */
|
||||
}
|
||||
void visit (HIR::ParenthesisedType &type) override
|
||||
{ /* TODO */
|
||||
}
|
||||
void visit (HIR::ImplTraitTypeOneBound &type) override
|
||||
{ /* TODO */
|
||||
}
|
||||
|
||||
private:
|
||||
TypeCheckType (HirId id)
|
||||
: TypeCheckBase (), translated (new TyTy::ErrorType (id))
|
||||
{}
|
||||
|
||||
TyTy::BaseType *resolve_root_path (HIR::TypePath &path, size_t *offset,
|
||||
NodeId *root_resolved_node_id);
|
||||
|
||||
TyTy::BaseType *resolve_segments (
|
||||
NodeId root_resolved_node_id, HirId expr_id,
|
||||
std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset,
|
||||
TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
|
||||
Location expr_locus);
|
||||
|
||||
TyTy::BaseType *translated;
|
||||
};
|
||||
|
||||
class TypeResolveGenericParam : public TypeCheckBase
|
||||
{
|
||||
public:
|
||||
static TyTy::ParamType *Resolve (HIR::GenericParam *param);
|
||||
|
||||
protected:
|
||||
void visit (HIR::TypeParam ¶m);
|
||||
void visit (HIR::LifetimeParam ¶m);
|
||||
void visit (HIR::ConstGenericParam ¶m);
|
||||
|
||||
private:
|
||||
TypeResolveGenericParam () : TypeCheckBase (), resolved (nullptr) {}
|
||||
|
||||
TyTy::ParamType *resolved;
|
||||
};
|
||||
|
||||
class ResolveWhereClauseItem : public TypeCheckBase
|
||||
{
|
||||
public:
|
||||
static void Resolve (HIR::WhereClauseItem &item);
|
||||
|
||||
protected:
|
||||
void visit (HIR::LifetimeWhereClauseItem &item);
|
||||
void visit (HIR::TypeBoundWhereClauseItem &item);
|
||||
|
||||
private:
|
||||
ResolveWhereClauseItem () : TypeCheckBase () {}
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_TYPE
|
41
gcc/rust/typecheck/rust-hir-type-check-util.cc
Normal file
41
gcc/rust/typecheck/rust-hir-type-check-util.cc
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2021-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check-util.h"
|
||||
#include "rust-hir-full.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
void
|
||||
ImplTypeIterator::go ()
|
||||
{
|
||||
for (auto &item : impl.get_impl_items ())
|
||||
{
|
||||
item->accept_vis (*this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImplTypeIterator::visit (HIR::TypeAlias &alias)
|
||||
{
|
||||
cb (alias);
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
50
gcc/rust/typecheck/rust-hir-type-check-util.h
Normal file
50
gcc/rust/typecheck/rust-hir-type-check-util.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2021-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK_UTIL_H
|
||||
#define RUST_HIR_TYPE_CHECK_UTIL_H
|
||||
|
||||
#include "rust-system.h"
|
||||
#include "rust-hir-visitor.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class ImplTypeIterator : public HIR::HIRFullVisitorBase
|
||||
{
|
||||
using HIR::HIRFullVisitorBase::visit;
|
||||
|
||||
public:
|
||||
ImplTypeIterator (HIR::ImplBlock &impl,
|
||||
std::function<void (HIR::TypeAlias &alias)> cb)
|
||||
: impl (impl), cb (cb)
|
||||
{}
|
||||
|
||||
void go ();
|
||||
|
||||
void visit (HIR::TypeAlias &alias) override;
|
||||
|
||||
private:
|
||||
HIR::ImplBlock &impl;
|
||||
std::function<void (HIR::TypeAlias &alias)> cb;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK_UTIL_H
|
295
gcc/rust/typecheck/rust-hir-type-check.cc
Normal file
295
gcc/rust/typecheck/rust-hir-type-check.cc
Normal file
@ -0,0 +1,295 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-hir-type-check.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-hir-type-check-toplevel.h"
|
||||
#include "rust-hir-type-check-item.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
#include "rust-hir-type-check-pattern.h"
|
||||
#include "rust-hir-type-check-struct-field.h"
|
||||
#include "rust-hir-inherent-impl-overlap.h"
|
||||
|
||||
extern bool
|
||||
saw_errors (void);
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
void
|
||||
TypeResolution::Resolve (HIR::Crate &crate)
|
||||
{
|
||||
for (auto it = crate.items.begin (); it != crate.items.end (); it++)
|
||||
TypeCheckTopLevel::Resolve (*it->get ());
|
||||
|
||||
if (saw_errors ())
|
||||
return;
|
||||
|
||||
OverlappingImplItemPass::go ();
|
||||
if (saw_errors ())
|
||||
return;
|
||||
|
||||
for (auto it = crate.items.begin (); it != crate.items.end (); it++)
|
||||
TypeCheckItem::Resolve (*it->get ());
|
||||
|
||||
if (saw_errors ())
|
||||
return;
|
||||
|
||||
auto mappings = Analysis::Mappings::get ();
|
||||
auto context = TypeCheckContext::get ();
|
||||
|
||||
// default inference variables if possible
|
||||
context->iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool {
|
||||
// nothing to do
|
||||
if (ty->get_kind () != TyTy::TypeKind::INFER)
|
||||
return true;
|
||||
|
||||
TyTy::InferType *infer_var = static_cast<TyTy::InferType *> (ty);
|
||||
TyTy::BaseType *default_type;
|
||||
bool ok = infer_var->default_type (&default_type);
|
||||
if (!ok)
|
||||
{
|
||||
rust_error_at (mappings->lookup_location (id),
|
||||
"type annotations needed");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto result = ty->unify (default_type);
|
||||
result->set_ref (id);
|
||||
context->insert_type (
|
||||
Analysis::NodeMapping (mappings->get_current_crate (), 0, id,
|
||||
UNKNOWN_LOCAL_DEFID),
|
||||
result);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// rust-hir-trait-ref.h
|
||||
|
||||
TraitItemReference::TraitItemReference (
|
||||
std::string identifier, bool optional, TraitItemType type,
|
||||
HIR::TraitItem *hir_trait_item, TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions, Location locus)
|
||||
: identifier (identifier), optional_flag (optional), type (type),
|
||||
hir_trait_item (hir_trait_item),
|
||||
inherited_substitutions (std::move (substitutions)), locus (locus),
|
||||
self (self), context (TypeCheckContext::get ())
|
||||
{}
|
||||
|
||||
TraitItemReference::TraitItemReference (TraitItemReference const &other)
|
||||
: identifier (other.identifier), optional_flag (other.optional_flag),
|
||||
type (other.type), hir_trait_item (other.hir_trait_item),
|
||||
locus (other.locus), self (other.self), context (TypeCheckContext::get ())
|
||||
{
|
||||
inherited_substitutions.clear ();
|
||||
inherited_substitutions.reserve (other.inherited_substitutions.size ());
|
||||
for (size_t i = 0; i < other.inherited_substitutions.size (); i++)
|
||||
inherited_substitutions.push_back (
|
||||
other.inherited_substitutions.at (i).clone ());
|
||||
}
|
||||
|
||||
TraitItemReference &
|
||||
TraitItemReference::operator= (TraitItemReference const &other)
|
||||
{
|
||||
identifier = other.identifier;
|
||||
optional_flag = other.optional_flag;
|
||||
type = other.type;
|
||||
hir_trait_item = other.hir_trait_item;
|
||||
self = other.self;
|
||||
locus = other.locus;
|
||||
context = other.context;
|
||||
|
||||
inherited_substitutions.clear ();
|
||||
inherited_substitutions.reserve (other.inherited_substitutions.size ());
|
||||
for (size_t i = 0; i < other.inherited_substitutions.size (); i++)
|
||||
inherited_substitutions.push_back (
|
||||
other.inherited_substitutions.at (i).clone ());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TraitItemReference::get_type_from_typealias (/*const*/
|
||||
HIR::TraitItemType &type) const
|
||||
{
|
||||
TyTy::TyVar var (get_mappings ().get_hirid ());
|
||||
return var.get_tyty ();
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TraitItemReference::get_type_from_constant (
|
||||
/*const*/ HIR::TraitItemConst &constant) const
|
||||
{
|
||||
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ());
|
||||
if (constant.has_expr ())
|
||||
{
|
||||
TyTy::BaseType *expr
|
||||
= TypeCheckExpr::Resolve (constant.get_expr ().get ());
|
||||
|
||||
return type->unify (expr);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const
|
||||
{
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions
|
||||
= inherited_substitutions;
|
||||
|
||||
HIR::TraitFunctionDecl &function = fn.get_decl ();
|
||||
if (function.has_generics ())
|
||||
{
|
||||
for (auto &generic_param : function.get_generic_params ())
|
||||
{
|
||||
switch (generic_param.get ()->get_kind ())
|
||||
{
|
||||
case HIR::GenericParam::GenericKind::LIFETIME:
|
||||
case HIR::GenericParam::GenericKind::CONST:
|
||||
// FIXME: Skipping Lifetime and Const completely until better
|
||||
// handling.
|
||||
break;
|
||||
|
||||
case HIR::GenericParam::GenericKind::TYPE: {
|
||||
auto param_type
|
||||
= TypeResolveGenericParam::Resolve (generic_param.get ());
|
||||
context->insert_type (generic_param->get_mappings (),
|
||||
param_type);
|
||||
|
||||
substitutions.push_back (TyTy::SubstitutionParamMapping (
|
||||
static_cast<HIR::TypeParam &> (*generic_param), param_type));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TyTy::BaseType *ret_type = nullptr;
|
||||
if (!function.has_return_type ())
|
||||
ret_type = TyTy::TupleType::get_unit_type (fn.get_mappings ().get_hirid ());
|
||||
else
|
||||
{
|
||||
auto resolved
|
||||
= TypeCheckType::Resolve (function.get_return_type ().get ());
|
||||
if (resolved->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (fn.get_locus (), "failed to resolve return type");
|
||||
return get_error ();
|
||||
}
|
||||
|
||||
ret_type = resolved->clone ();
|
||||
ret_type->set_ref (
|
||||
function.get_return_type ()->get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
|
||||
if (function.is_method ())
|
||||
{
|
||||
// these are implicit mappings and not used
|
||||
auto mappings = Analysis::Mappings::get ();
|
||||
auto crate_num = mappings->get_current_crate ();
|
||||
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
|
||||
mappings->get_next_hir_id (crate_num),
|
||||
UNKNOWN_LOCAL_DEFID);
|
||||
|
||||
// add the synthetic self param at the front, this is a placeholder
|
||||
// for compilation to know parameter names. The types are ignored
|
||||
// but we reuse the HIR identifier pattern which requires it
|
||||
HIR::SelfParam &self_param = function.get_self ();
|
||||
HIR::IdentifierPattern *self_pattern
|
||||
= new HIR::IdentifierPattern (mapping, "self", self_param.get_locus (),
|
||||
self_param.is_ref (),
|
||||
self_param.is_mut () ? Mutability::Mut
|
||||
: Mutability::Imm,
|
||||
std::unique_ptr<HIR::Pattern> (nullptr));
|
||||
// might have a specified type
|
||||
TyTy::BaseType *self_type = nullptr;
|
||||
if (self_param.has_type ())
|
||||
{
|
||||
std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
|
||||
self_type = TypeCheckType::Resolve (specified_type.get ());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (self_param.get_self_kind ())
|
||||
{
|
||||
case HIR::SelfParam::IMM:
|
||||
case HIR::SelfParam::MUT:
|
||||
self_type = self->clone ();
|
||||
break;
|
||||
|
||||
case HIR::SelfParam::IMM_REF:
|
||||
self_type = new TyTy::ReferenceType (
|
||||
self_param.get_mappings ().get_hirid (),
|
||||
TyTy::TyVar (self->get_ref ()), Mutability::Imm);
|
||||
break;
|
||||
|
||||
case HIR::SelfParam::MUT_REF:
|
||||
self_type = new TyTy::ReferenceType (
|
||||
self_param.get_mappings ().get_hirid (),
|
||||
TyTy::TyVar (self->get_ref ()), Mutability::Mut);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
context->insert_type (self_param.get_mappings (), self_type);
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type));
|
||||
}
|
||||
|
||||
for (auto ¶m : function.get_function_params ())
|
||||
{
|
||||
// get the name as well required for later on
|
||||
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
|
||||
params.push_back (
|
||||
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
|
||||
param_tyty));
|
||||
|
||||
context->insert_type (param.get_mappings (), param_tyty);
|
||||
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
|
||||
}
|
||||
|
||||
auto mappings = Analysis::Mappings::get ();
|
||||
const CanonicalPath *canonical_path = nullptr;
|
||||
bool ok = mappings->lookup_canonical_path (fn.get_mappings ().get_nodeid (),
|
||||
&canonical_path);
|
||||
rust_assert (ok);
|
||||
|
||||
RustIdent ident{*canonical_path, fn.get_locus ()};
|
||||
auto resolved
|
||||
= new TyTy::FnType (fn.get_mappings ().get_hirid (),
|
||||
fn.get_mappings ().get_defid (),
|
||||
function.get_function_name (), ident,
|
||||
function.is_method ()
|
||||
? TyTy::FnType::FNTYPE_IS_METHOD_FLAG
|
||||
: TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
|
||||
ABI::RUST, std::move (params), ret_type, substitutions);
|
||||
|
||||
context->insert_type (fn.get_mappings (), resolved);
|
||||
return resolved;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
379
gcc/rust/typecheck/rust-hir-type-check.h
Normal file
379
gcc/rust/typecheck/rust-hir-type-check.h
Normal file
@ -0,0 +1,379 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_HIR_TYPE_CHECK
|
||||
#define RUST_HIR_TYPE_CHECK
|
||||
|
||||
#include "rust-hir-full-decls.h"
|
||||
#include "rust-hir-map.h"
|
||||
#include "rust-tyty.h"
|
||||
#include "rust-hir-trait-ref.h"
|
||||
#include "rust-autoderef.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCheckContextItem
|
||||
{
|
||||
public:
|
||||
enum ItemType
|
||||
{
|
||||
ITEM,
|
||||
IMPL_ITEM,
|
||||
TRAIT_ITEM,
|
||||
};
|
||||
|
||||
TypeCheckContextItem (HIR::Function *item)
|
||||
: type (ItemType::ITEM), item (item)
|
||||
{}
|
||||
|
||||
TypeCheckContextItem (HIR::ImplBlock *impl_block, HIR::Function *item)
|
||||
: type (ItemType::IMPL_ITEM), item (impl_block, item)
|
||||
{}
|
||||
|
||||
TypeCheckContextItem (HIR::TraitItemFunc *trait_item)
|
||||
: type (ItemType::TRAIT_ITEM), item (trait_item)
|
||||
{}
|
||||
|
||||
ItemType get_type () const { return type; }
|
||||
|
||||
HIR::Function *get_item ()
|
||||
{
|
||||
rust_assert (get_type () == ItemType::ITEM);
|
||||
return item.item;
|
||||
}
|
||||
|
||||
std::pair<HIR::ImplBlock *, HIR::Function *> &get_impl_item ()
|
||||
{
|
||||
rust_assert (get_type () == ItemType::IMPL_ITEM);
|
||||
return item.impl_item;
|
||||
};
|
||||
|
||||
HIR::TraitItemFunc *get_trait_item ()
|
||||
{
|
||||
rust_assert (get_type () == ItemType::TRAIT_ITEM);
|
||||
return item.trait_item;
|
||||
}
|
||||
|
||||
private:
|
||||
union Item
|
||||
{
|
||||
HIR::Function *item;
|
||||
std::pair<HIR::ImplBlock *, HIR::Function *> impl_item;
|
||||
HIR::TraitItemFunc *trait_item;
|
||||
|
||||
Item (HIR::Function *item) : item (item) {}
|
||||
|
||||
Item (HIR::ImplBlock *impl_block, HIR::Function *item)
|
||||
: impl_item ({impl_block, item})
|
||||
{}
|
||||
|
||||
Item (HIR::TraitItemFunc *trait_item) : trait_item (trait_item) {}
|
||||
};
|
||||
|
||||
ItemType type;
|
||||
Item item;
|
||||
};
|
||||
|
||||
class TypeCheckContext
|
||||
{
|
||||
public:
|
||||
static TypeCheckContext *get ();
|
||||
|
||||
~TypeCheckContext ();
|
||||
|
||||
bool lookup_builtin (NodeId id, TyTy::BaseType **type);
|
||||
bool lookup_builtin (std::string name, TyTy::BaseType **type);
|
||||
void insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type);
|
||||
|
||||
void insert_type (const Analysis::NodeMapping &mappings,
|
||||
TyTy::BaseType *type);
|
||||
void insert_implicit_type (TyTy::BaseType *type);
|
||||
bool lookup_type (HirId id, TyTy::BaseType **type) const;
|
||||
|
||||
void insert_implicit_type (HirId id, TyTy::BaseType *type);
|
||||
|
||||
void insert_type_by_node_id (NodeId ref, HirId id);
|
||||
bool lookup_type_by_node_id (NodeId ref, HirId *id);
|
||||
|
||||
TyTy::BaseType *peek_return_type ();
|
||||
TypeCheckContextItem &peek_context ();
|
||||
void push_return_type (TypeCheckContextItem item,
|
||||
TyTy::BaseType *return_type);
|
||||
void pop_return_type ();
|
||||
|
||||
void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb)
|
||||
{
|
||||
for (auto it = resolved.begin (); it != resolved.end (); it++)
|
||||
{
|
||||
if (!cb (it->first, it->second))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool have_loop_context () const { return !loop_type_stack.empty (); }
|
||||
|
||||
void push_new_loop_context (HirId id, Location locus)
|
||||
{
|
||||
TyTy::BaseType *infer_var
|
||||
= new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL,
|
||||
locus);
|
||||
loop_type_stack.push_back (infer_var);
|
||||
}
|
||||
|
||||
void push_new_while_loop_context (HirId id)
|
||||
{
|
||||
TyTy::BaseType *infer_var = new TyTy::ErrorType (id);
|
||||
loop_type_stack.push_back (infer_var);
|
||||
}
|
||||
|
||||
TyTy::BaseType *peek_loop_context () { return loop_type_stack.back (); }
|
||||
|
||||
TyTy::BaseType *pop_loop_context ()
|
||||
{
|
||||
auto back = peek_loop_context ();
|
||||
loop_type_stack.pop_back ();
|
||||
return back;
|
||||
}
|
||||
|
||||
void swap_head_loop_context (TyTy::BaseType *val)
|
||||
{
|
||||
loop_type_stack.pop_back ();
|
||||
loop_type_stack.push_back (val);
|
||||
}
|
||||
|
||||
void insert_trait_reference (DefId id, TraitReference &&ref)
|
||||
{
|
||||
rust_assert (trait_context.find (id) == trait_context.end ());
|
||||
trait_context.emplace (id, std::move (ref));
|
||||
}
|
||||
|
||||
bool lookup_trait_reference (DefId id, TraitReference **ref)
|
||||
{
|
||||
auto it = trait_context.find (id);
|
||||
if (it == trait_context.end ())
|
||||
return false;
|
||||
|
||||
*ref = &it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert_receiver (HirId id, TyTy::BaseType *t)
|
||||
{
|
||||
receiver_context[id] = t;
|
||||
}
|
||||
|
||||
bool lookup_receiver (HirId id, TyTy::BaseType **ref)
|
||||
{
|
||||
auto it = receiver_context.find (id);
|
||||
if (it == receiver_context.end ())
|
||||
return false;
|
||||
|
||||
*ref = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert_associated_trait_impl (HirId id, AssociatedImplTrait &&associated)
|
||||
{
|
||||
rust_assert (associated_impl_traits.find (id)
|
||||
== associated_impl_traits.end ());
|
||||
associated_impl_traits.emplace (id, std::move (associated));
|
||||
}
|
||||
|
||||
bool lookup_associated_trait_impl (HirId id, AssociatedImplTrait **associated)
|
||||
{
|
||||
auto it = associated_impl_traits.find (id);
|
||||
if (it == associated_impl_traits.end ())
|
||||
return false;
|
||||
|
||||
*associated = &it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert_associated_type_mapping (HirId id, HirId mapping)
|
||||
{
|
||||
associated_type_mappings[id] = mapping;
|
||||
}
|
||||
|
||||
void clear_associated_type_mapping (HirId id)
|
||||
{
|
||||
auto it = associated_type_mappings.find (id);
|
||||
if (it != associated_type_mappings.end ())
|
||||
associated_type_mappings.erase (it);
|
||||
}
|
||||
|
||||
// lookup any associated type mappings, the out parameter of mapping is
|
||||
// allowed to be nullptr which allows this interface to do a simple does exist
|
||||
// check
|
||||
bool lookup_associated_type_mapping (HirId id, HirId *mapping)
|
||||
{
|
||||
auto it = associated_type_mappings.find (id);
|
||||
if (it == associated_type_mappings.end ())
|
||||
return false;
|
||||
|
||||
if (mapping != nullptr)
|
||||
*mapping = it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert_associated_impl_mapping (HirId trait_id,
|
||||
const TyTy::BaseType *impl_type,
|
||||
HirId impl_id)
|
||||
{
|
||||
auto it = associated_traits_to_impls.find (trait_id);
|
||||
if (it == associated_traits_to_impls.end ())
|
||||
{
|
||||
associated_traits_to_impls[trait_id] = {};
|
||||
}
|
||||
|
||||
associated_traits_to_impls[trait_id].push_back ({impl_type, impl_id});
|
||||
}
|
||||
|
||||
bool lookup_associated_impl_mapping_for_self (HirId trait_id,
|
||||
const TyTy::BaseType *self,
|
||||
HirId *mapping)
|
||||
{
|
||||
auto it = associated_traits_to_impls.find (trait_id);
|
||||
if (it == associated_traits_to_impls.end ())
|
||||
return false;
|
||||
|
||||
for (auto &item : it->second)
|
||||
{
|
||||
if (item.first->can_eq (self, false))
|
||||
{
|
||||
*mapping = item.second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void insert_autoderef_mappings (HirId id,
|
||||
std::vector<Adjustment> &&adjustments)
|
||||
{
|
||||
rust_assert (autoderef_mappings.find (id) == autoderef_mappings.end ());
|
||||
autoderef_mappings.emplace (id, std::move (adjustments));
|
||||
}
|
||||
|
||||
bool lookup_autoderef_mappings (HirId id,
|
||||
std::vector<Adjustment> **adjustments)
|
||||
{
|
||||
auto it = autoderef_mappings.find (id);
|
||||
if (it == autoderef_mappings.end ())
|
||||
return false;
|
||||
|
||||
*adjustments = &it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert_cast_autoderef_mappings (HirId id,
|
||||
std::vector<Adjustment> &&adjustments)
|
||||
{
|
||||
rust_assert (cast_autoderef_mappings.find (id)
|
||||
== cast_autoderef_mappings.end ());
|
||||
cast_autoderef_mappings.emplace (id, std::move (adjustments));
|
||||
}
|
||||
|
||||
bool lookup_cast_autoderef_mappings (HirId id,
|
||||
std::vector<Adjustment> **adjustments)
|
||||
{
|
||||
auto it = cast_autoderef_mappings.find (id);
|
||||
if (it == cast_autoderef_mappings.end ())
|
||||
return false;
|
||||
|
||||
*adjustments = &it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert_variant_definition (HirId id, HirId variant)
|
||||
{
|
||||
auto it = variants.find (id);
|
||||
rust_assert (it == variants.end ());
|
||||
|
||||
variants[id] = variant;
|
||||
}
|
||||
|
||||
bool lookup_variant_definition (HirId id, HirId *variant)
|
||||
{
|
||||
auto it = variants.find (id);
|
||||
if (it == variants.end ())
|
||||
return false;
|
||||
|
||||
*variant = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert_operator_overload (HirId id, TyTy::FnType *call_site)
|
||||
{
|
||||
auto it = operator_overloads.find (id);
|
||||
rust_assert (it == operator_overloads.end ());
|
||||
|
||||
operator_overloads[id] = call_site;
|
||||
}
|
||||
|
||||
bool lookup_operator_overload (HirId id, TyTy::FnType **call)
|
||||
{
|
||||
auto it = operator_overloads.find (id);
|
||||
if (it == operator_overloads.end ())
|
||||
return false;
|
||||
|
||||
*call = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
TypeCheckContext ();
|
||||
|
||||
std::map<NodeId, HirId> node_id_refs;
|
||||
std::map<HirId, TyTy::BaseType *> resolved;
|
||||
std::vector<std::unique_ptr<TyTy::BaseType>> builtins;
|
||||
std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>>
|
||||
return_type_stack;
|
||||
std::vector<TyTy::BaseType *> loop_type_stack;
|
||||
std::map<DefId, TraitReference> trait_context;
|
||||
std::map<HirId, TyTy::BaseType *> receiver_context;
|
||||
std::map<HirId, AssociatedImplTrait> associated_impl_traits;
|
||||
|
||||
// trait-id -> list of < self-tyty:impl-id>
|
||||
std::map<HirId, std::vector<std::pair<const TyTy::BaseType *, HirId>>>
|
||||
associated_traits_to_impls;
|
||||
|
||||
std::map<HirId, HirId> associated_type_mappings;
|
||||
|
||||
// adjustment mappings
|
||||
std::map<HirId, std::vector<Adjustment>> autoderef_mappings;
|
||||
std::map<HirId, std::vector<Adjustment>> cast_autoderef_mappings;
|
||||
|
||||
// operator overloads
|
||||
std::map<HirId, TyTy::FnType *> operator_overloads;
|
||||
|
||||
// variants
|
||||
std::map<HirId, HirId> variants;
|
||||
};
|
||||
|
||||
class TypeResolution
|
||||
{
|
||||
public:
|
||||
static void Resolve (HIR::Crate &crate);
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_CHECK
|
88
gcc/rust/typecheck/rust-tyty-visitor.h
Normal file
88
gcc/rust/typecheck/rust-tyty-visitor.h
Normal file
@ -0,0 +1,88 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_TYTY_VISITOR
|
||||
#define RUST_TYTY_VISITOR
|
||||
|
||||
#include "rust-tyty.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace TyTy {
|
||||
|
||||
class TyVisitor
|
||||
{
|
||||
public:
|
||||
virtual void visit (InferType &type) = 0;
|
||||
virtual void visit (ADTType &type) = 0;
|
||||
virtual void visit (TupleType &type) = 0;
|
||||
virtual void visit (FnType &type) = 0;
|
||||
virtual void visit (FnPtr &type) = 0;
|
||||
virtual void visit (ArrayType &type) = 0;
|
||||
virtual void visit (SliceType &type) = 0;
|
||||
virtual void visit (BoolType &type) = 0;
|
||||
virtual void visit (IntType &type) = 0;
|
||||
virtual void visit (UintType &type) = 0;
|
||||
virtual void visit (FloatType &type) = 0;
|
||||
virtual void visit (USizeType &type) = 0;
|
||||
virtual void visit (ISizeType &type) = 0;
|
||||
virtual void visit (ErrorType &type) = 0;
|
||||
virtual void visit (CharType &type) = 0;
|
||||
virtual void visit (ReferenceType &type) = 0;
|
||||
virtual void visit (PointerType &type) = 0;
|
||||
virtual void visit (ParamType &type) = 0;
|
||||
virtual void visit (StrType &type) = 0;
|
||||
virtual void visit (NeverType &type) = 0;
|
||||
virtual void visit (PlaceholderType &type) = 0;
|
||||
virtual void visit (ProjectionType &type) = 0;
|
||||
virtual void visit (DynamicObjectType &type) = 0;
|
||||
virtual void visit (ClosureType &type) = 0;
|
||||
};
|
||||
|
||||
class TyConstVisitor
|
||||
{
|
||||
public:
|
||||
virtual void visit (const InferType &type) = 0;
|
||||
virtual void visit (const ADTType &type) = 0;
|
||||
virtual void visit (const TupleType &type) = 0;
|
||||
virtual void visit (const FnType &type) = 0;
|
||||
virtual void visit (const FnPtr &type) = 0;
|
||||
virtual void visit (const ArrayType &type) = 0;
|
||||
virtual void visit (const SliceType &type) = 0;
|
||||
virtual void visit (const BoolType &type) = 0;
|
||||
virtual void visit (const IntType &type) = 0;
|
||||
virtual void visit (const UintType &type) = 0;
|
||||
virtual void visit (const FloatType &type) = 0;
|
||||
virtual void visit (const USizeType &type) = 0;
|
||||
virtual void visit (const ISizeType &type) = 0;
|
||||
virtual void visit (const ErrorType &type) = 0;
|
||||
virtual void visit (const CharType &type) = 0;
|
||||
virtual void visit (const ReferenceType &type) = 0;
|
||||
virtual void visit (const PointerType &type) = 0;
|
||||
virtual void visit (const ParamType &type) = 0;
|
||||
virtual void visit (const StrType &type) = 0;
|
||||
virtual void visit (const NeverType &type) = 0;
|
||||
virtual void visit (const PlaceholderType &type) = 0;
|
||||
virtual void visit (const ProjectionType &type) = 0;
|
||||
virtual void visit (const DynamicObjectType &type) = 0;
|
||||
virtual void visit (const ClosureType &type) = 0;
|
||||
};
|
||||
|
||||
} // namespace TyTy
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_TYTY_VISITOR
|
Loading…
x
Reference in New Issue
Block a user