2
0
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:
Philip Herron 2022-10-21 13:53:14 +02:00 committed by Arthur Cohen
parent 9ce37e7206
commit c6c3db2176
28 changed files with 8337 additions and 0 deletions

@ -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

@ -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

@ -0,0 +1,439 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check-base.h"
#include "rust-hir-type-check-type.h"
#include "rust-hir-type-check-expr.h"
#include "rust-coercion.h"
#include "rust-casts.h"
namespace Rust {
namespace Resolver {
bool
TypeCheckBase::check_for_unconstrained (
const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
const TyTy::SubstitutionArgumentMappings &constraint_a,
const TyTy::SubstitutionArgumentMappings &constraint_b,
const TyTy::BaseType *reference)
{
std::set<HirId> symbols_to_constrain;
std::map<HirId, Location> symbol_to_location;
for (const auto &p : params_to_constrain)
{
HirId ref = p.get_param_ty ()->get_ref ();
symbols_to_constrain.insert (ref);
symbol_to_location.insert ({ref, p.get_param_locus ()});
}
// set up the set of constrained symbols
std::set<HirId> constrained_symbols;
for (const auto &c : constraint_a.get_mappings ())
{
const TyTy::BaseType *arg = c.get_tyty ();
if (arg != nullptr)
{
const TyTy::BaseType *p = arg->get_root ();
constrained_symbols.insert (p->get_ty_ref ());
}
}
for (const auto &c : constraint_b.get_mappings ())
{
const TyTy::BaseType *arg = c.get_tyty ();
if (arg != nullptr)
{
const TyTy::BaseType *p = arg->get_root ();
constrained_symbols.insert (p->get_ty_ref ());
}
}
const auto root = reference->get_root ();
if (root->get_kind () == TyTy::TypeKind::PARAM)
{
const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (root);
constrained_symbols.insert (p->get_ty_ref ());
}
// check for unconstrained
bool unconstrained = false;
for (auto &sym : symbols_to_constrain)
{
bool used = constrained_symbols.find (sym) != constrained_symbols.end ();
if (!used)
{
Location locus = symbol_to_location.at (sym);
rust_error_at (locus, "unconstrained type parameter");
unconstrained = true;
}
}
return unconstrained;
}
TyTy::BaseType *
TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings,
HIR::Literal &literal, Location locus)
{
TyTy::BaseType *infered = nullptr;
switch (literal.get_lit_type ())
{
case HIR::Literal::LitType::INT: {
bool ok = false;
switch (literal.get_type_hint ())
{
case CORETYPE_I8:
ok = context->lookup_builtin ("i8", &infered);
break;
case CORETYPE_I16:
ok = context->lookup_builtin ("i16", &infered);
break;
case CORETYPE_I32:
ok = context->lookup_builtin ("i32", &infered);
break;
case CORETYPE_I64:
ok = context->lookup_builtin ("i64", &infered);
break;
case CORETYPE_I128:
ok = context->lookup_builtin ("i128", &infered);
break;
case CORETYPE_U8:
ok = context->lookup_builtin ("u8", &infered);
break;
case CORETYPE_U16:
ok = context->lookup_builtin ("u16", &infered);
break;
case CORETYPE_U32:
ok = context->lookup_builtin ("u32", &infered);
break;
case CORETYPE_U64:
ok = context->lookup_builtin ("u64", &infered);
break;
case CORETYPE_U128:
ok = context->lookup_builtin ("u128", &infered);
break;
case CORETYPE_F32:
literal.set_lit_type (HIR::Literal::LitType::FLOAT);
ok = context->lookup_builtin ("f32", &infered);
break;
case CORETYPE_F64:
literal.set_lit_type (HIR::Literal::LitType::FLOAT);
ok = context->lookup_builtin ("f64", &infered);
break;
case CORETYPE_ISIZE:
ok = context->lookup_builtin ("isize", &infered);
break;
case CORETYPE_USIZE:
ok = context->lookup_builtin ("usize", &infered);
break;
default:
ok = true;
infered
= new TyTy::InferType (expr_mappings.get_hirid (),
TyTy::InferType::InferTypeKind::INTEGRAL,
locus);
break;
}
rust_assert (ok);
}
break;
case HIR::Literal::LitType::FLOAT: {
bool ok = false;
switch (literal.get_type_hint ())
{
case CORETYPE_F32:
ok = context->lookup_builtin ("f32", &infered);
break;
case CORETYPE_F64:
ok = context->lookup_builtin ("f64", &infered);
break;
default:
ok = true;
infered
= new TyTy::InferType (expr_mappings.get_hirid (),
TyTy::InferType::InferTypeKind::FLOAT,
locus);
break;
}
rust_assert (ok);
}
break;
case HIR::Literal::LitType::BOOL: {
auto ok = context->lookup_builtin ("bool", &infered);
rust_assert (ok);
}
break;
case HIR::Literal::LitType::CHAR: {
auto ok = context->lookup_builtin ("char", &infered);
rust_assert (ok);
}
break;
case HIR::Literal::LitType::BYTE: {
auto ok = context->lookup_builtin ("u8", &infered);
rust_assert (ok);
}
break;
case HIR::Literal::LitType::STRING: {
TyTy::BaseType *base = nullptr;
auto ok = context->lookup_builtin ("str", &base);
rust_assert (ok);
infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
TyTy::TyVar (base->get_ref ()),
Mutability::Imm);
}
break;
case HIR::Literal::LitType::BYTE_STRING: {
/* This is an arraytype of u8 reference (&[u8;size]). It isn't in
UTF-8, but really just a byte array. Code to construct the array
reference copied from ArrayElemsValues and ArrayType. */
TyTy::BaseType *u8;
auto ok = context->lookup_builtin ("u8", &u8);
rust_assert (ok);
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping capacity_mapping (crate_num, UNKNOWN_NODEID,
mappings->get_next_hir_id (
crate_num),
UNKNOWN_LOCAL_DEFID);
/* Capacity is the size of the string (number of chars).
It is a constant, but for fold it to get a tree. */
std::string capacity_str
= std::to_string (literal.as_string ().size ());
HIR::LiteralExpr *literal_capacity
= new HIR::LiteralExpr (capacity_mapping, capacity_str,
HIR::Literal::LitType::INT,
PrimitiveCoreType::CORETYPE_USIZE, locus, {});
// mark the type for this implicit node
TyTy::BaseType *expected_ty = nullptr;
ok = context->lookup_builtin ("usize", &expected_ty);
rust_assert (ok);
context->insert_type (capacity_mapping, expected_ty);
Analysis::NodeMapping array_mapping (crate_num, UNKNOWN_NODEID,
mappings->get_next_hir_id (
crate_num),
UNKNOWN_LOCAL_DEFID);
TyTy::ArrayType *array
= new TyTy::ArrayType (array_mapping.get_hirid (), locus,
*literal_capacity,
TyTy::TyVar (u8->get_ref ()));
context->insert_type (array_mapping, array);
infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
TyTy::TyVar (array->get_ref ()),
Mutability::Imm);
}
break;
default:
gcc_unreachable ();
break;
}
return infered;
}
TyTy::ADTType::ReprOptions
TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, Location locus)
{
TyTy::ADTType::ReprOptions repr;
repr.pack = 0;
repr.align = 0;
for (const auto &attr : attrs)
{
bool is_repr = attr.get_path ().as_string ().compare ("repr") == 0;
if (is_repr)
{
const AST::AttrInput &input = attr.get_attr_input ();
bool is_token_tree = input.get_attr_input_type ()
== AST::AttrInput::AttrInputType::TOKEN_TREE;
rust_assert (is_token_tree);
const auto &option = static_cast<const AST::DelimTokenTree &> (input);
AST::AttrInputMetaItemContainer *meta_items
= option.parse_to_meta_item ();
const std::string inline_option
= meta_items->get_items ().at (0)->as_string ();
// TODO: it would probably be better to make the MetaItems more aware
// of constructs with nesting like #[repr(packed(2))] rather than
// manually parsing the string "packed(2)" here.
size_t oparen = inline_option.find ('(', 0);
bool is_pack = false, is_align = false;
unsigned char value = 1;
if (oparen == std::string::npos)
{
is_pack = inline_option.compare ("packed") == 0;
is_align = inline_option.compare ("align") == 0;
}
else
{
std::string rep = inline_option.substr (0, oparen);
is_pack = rep.compare ("packed") == 0;
is_align = rep.compare ("align") == 0;
size_t cparen = inline_option.find (')', oparen);
if (cparen == std::string::npos)
{
rust_error_at (locus, "malformed attribute");
}
std::string value_str = inline_option.substr (oparen, cparen);
value = strtoul (value_str.c_str () + 1, NULL, 10);
}
if (is_pack)
repr.pack = value;
else if (is_align)
repr.align = value;
// Multiple repr options must be specified with e.g. #[repr(C,
// packed(2))].
break;
}
}
return repr;
}
TyTy::BaseType *
TypeCheckBase::coercion_site (HirId id, TyTy::BaseType *expected,
TyTy::BaseType *expr, Location locus)
{
rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
expected->debug_str ().c_str (), expr->debug_str ().c_str ());
auto context = TypeCheckContext::get ();
if (expected->get_kind () == TyTy::TypeKind::ERROR
|| expr->get_kind () == TyTy::TypeKind::ERROR)
return expr;
// can we autoderef it?
auto result = TypeCoercionRules::Coerce (expr, expected, locus);
// the result needs to be unified
TyTy::BaseType *receiver = expr;
if (!result.is_error ())
{
receiver = result.tyty;
}
rust_debug ("coerce_default_unify(a={%s}, b={%s})",
receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
TyTy::BaseType *coerced = expected->unify (receiver);
context->insert_autoderef_mappings (id, std::move (result.adjustments));
return coerced;
}
TyTy::BaseType *
TypeCheckBase::cast_site (HirId id, TyTy::TyWithLocation from,
TyTy::TyWithLocation to, Location cast_locus)
{
rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
from.get_ty ()->debug_str ().c_str (),
to.get_ty ()->debug_str ().c_str ());
auto context = TypeCheckContext::get ();
if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
|| to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
return to.get_ty ();
// do the cast
auto result = TypeCastRules::resolve (cast_locus, from, to);
// we assume error has already been emitted
if (result.is_error ())
return to.get_ty ();
// the result needs to be unified
TyTy::BaseType *casted_result = result.tyty;
rust_debug ("cast_default_unify(a={%s}, b={%s})",
casted_result->debug_str ().c_str (),
to.get_ty ()->debug_str ().c_str ());
TyTy::BaseType *casted = to.get_ty ()->unify (casted_result);
context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
return casted;
}
void
TypeCheckBase::resolve_generic_params (
const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
std::vector<TyTy::SubstitutionParamMapping> &substitutions)
{
for (auto &generic_param : generic_params)
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
// FIXME: Skipping Lifetime completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::CONST: {
auto param
= static_cast<HIR::ConstGenericParam *> (generic_param.get ());
auto specified_type
= TypeCheckType::Resolve (param->get_type ().get ());
if (param->has_default_expression ())
{
auto expr_type = TypeCheckExpr::Resolve (
param->get_default_expression ().get ());
specified_type->unify (expr_type);
}
context->insert_type (generic_param->get_mappings (),
specified_type);
}
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (), param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
} // namespace Resolver
} // namespace Rust

@ -0,0 +1,80 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#ifndef RUST_HIR_TYPE_CHECK_BASE
#define RUST_HIR_TYPE_CHECK_BASE
#include "rust-diagnostics.h"
#include "rust-hir-type-check.h"
#include "rust-name-resolver.h"
#include "rust-hir-visitor.h"
#include "rust-hir-map.h"
#include "rust-backend.h"
namespace Rust {
namespace Resolver {
class TraitReference;
class TypeCheckBase
{
public:
virtual ~TypeCheckBase () {}
static TyTy::BaseType *coercion_site (HirId id, TyTy::BaseType *lhs,
TyTy::BaseType *rhs,
Location coercion_locus);
static TyTy::BaseType *cast_site (HirId id, TyTy::TyWithLocation from,
TyTy::TyWithLocation to,
Location cast_locus);
protected:
TypeCheckBase ()
: mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()),
context (TypeCheckContext::get ())
{}
TraitReference *resolve_trait_path (HIR::TypePath &);
TyTy::TypeBoundPredicate get_predicate_from_bound (HIR::TypePath &path);
bool check_for_unconstrained (
const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
const TyTy::SubstitutionArgumentMappings &constraint_a,
const TyTy::SubstitutionArgumentMappings &constraint_b,
const TyTy::BaseType *reference);
TyTy::BaseType *resolve_literal (const Analysis::NodeMapping &mappings,
HIR::Literal &literal, Location locus);
TyTy::ADTType::ReprOptions parse_repr_options (const AST::AttrVec &attrs,
Location locus);
void resolve_generic_params (
const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
std::vector<TyTy::SubstitutionParamMapping> &substitutions);
Analysis::Mappings *mappings;
Resolver *resolver;
TypeCheckContext *context;
};
} // namespace Resolver
} // namespace Rust
#endif // RUST_HIR_TYPE_CHECK_BASE

@ -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

@ -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

File diff suppressed because it is too large Load Diff

@ -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

@ -0,0 +1,583 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check-implitem.h"
#include "rust-hir-type-check-base.h"
#include "rust-hir-full.h"
#include "rust-hir-type-check-type.h"
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check-pattern.h"
#include "rust-tyty.h"
namespace Rust {
namespace Resolver {
TypeCheckTopLevelExternItem::TypeCheckTopLevelExternItem (
const HIR::ExternBlock &parent)
: TypeCheckBase (), parent (parent)
{}
void
TypeCheckTopLevelExternItem::Resolve (HIR::ExternalItem *item,
const HIR::ExternBlock &parent)
{
TypeCheckTopLevelExternItem resolver (parent);
item->accept_vis (resolver);
}
void
TypeCheckTopLevelExternItem::visit (HIR::ExternalStaticItem &item)
{
TyTy::BaseType *actual_type
= TypeCheckType::Resolve (item.get_item_type ().get ());
context->insert_type (item.get_mappings (), actual_type);
}
void
TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (function.has_generics ())
{
for (auto &generic_param : function.get_generic_params ())
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
case HIR::GenericParam::GenericKind::CONST:
// FIXME: Skipping Lifetime and Const completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (),
param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
TyTy::BaseType *ret_type = nullptr;
if (!function.has_return_type ())
ret_type
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
else
{
auto resolved
= TypeCheckType::Resolve (function.get_return_type ().get ());
if (resolved == nullptr)
{
rust_error_at (function.get_locus (),
"failed to resolve return type");
return;
}
ret_type = resolved->clone ();
ret_type->set_ref (
function.get_return_type ()->get_mappings ().get_hirid ());
}
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
for (auto &param : function.get_function_params ())
{
// get the name as well required for later on
auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ());
// these are implicit mappings and not used
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
mappings->get_next_hir_id (crate_num),
UNKNOWN_LOCAL_DEFID);
HIR::IdentifierPattern *param_pattern
= new HIR::IdentifierPattern (mapping, param.get_param_name (),
Location (), false, Mutability::Imm,
std::unique_ptr<HIR::Pattern> (nullptr));
params.push_back (
std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern,
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
// FIXME do we need error checking for patterns here?
// see https://github.com/Rust-GCC/gccrs/issues/995
}
uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG;
if (function.is_variadic ())
flags |= TyTy::FnType::FNTYPE_IS_VARADIC_FLAG;
RustIdent ident{
CanonicalPath::new_seg (function.get_mappings ().get_nodeid (),
function.get_item_name ()),
function.get_locus ()};
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
function.get_mappings ().get_defid (),
function.get_item_name (), ident, flags,
parent.get_abi (), std::move (params),
ret_type, std::move (substitutions));
context->insert_type (function.get_mappings (), fnType);
}
TypeCheckTopLevelImplItem::TypeCheckTopLevelImplItem (
TyTy::BaseType *self,
std::vector<TyTy::SubstitutionParamMapping> substitutions)
: TypeCheckBase (), self (self), substitutions (substitutions)
{}
void
TypeCheckTopLevelImplItem::Resolve (
HIR::ImplItem *item, TyTy::BaseType *self,
std::vector<TyTy::SubstitutionParamMapping> substitutions)
{
TypeCheckTopLevelImplItem resolver (self, substitutions);
item->accept_vis (resolver);
}
void
TypeCheckTopLevelImplItem::visit (HIR::TypeAlias &alias)
{
TyTy::BaseType *actual_type
= TypeCheckType::Resolve (alias.get_type_aliased ().get ());
context->insert_type (alias.get_mappings (), actual_type);
for (auto &where_clause_item : alias.get_where_clause ().get_items ())
{
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
}
void
TypeCheckTopLevelImplItem::visit (HIR::ConstantItem &constant)
{
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
context->insert_type (constant.get_mappings (), type->unify (expr_type));
}
void
TypeCheckTopLevelImplItem::visit (HIR::Function &function)
{
if (function.has_generics ())
{
for (auto &generic_param : function.get_generic_params ())
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
case HIR::GenericParam::GenericKind::CONST:
// FIXME: Skipping Lifetime and Const completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (),
param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
for (auto &where_clause_item : function.get_where_clause ().get_items ())
{
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
TyTy::BaseType *ret_type = nullptr;
if (!function.has_function_return_type ())
ret_type
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
else
{
auto resolved
= TypeCheckType::Resolve (function.get_return_type ().get ());
if (resolved == nullptr)
{
rust_error_at (function.get_locus (),
"failed to resolve return type");
return;
}
ret_type = resolved->clone ();
ret_type->set_ref (
function.get_return_type ()->get_mappings ().get_hirid ());
}
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
if (function.is_method ())
{
// these are implicit mappings and not used
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
mappings->get_next_hir_id (crate_num),
UNKNOWN_LOCAL_DEFID);
// add the synthetic self param at the front, this is a placeholder for
// compilation to know parameter names. The types are ignored but we
// reuse the HIR identifier pattern which requires it
HIR::SelfParam &self_param = function.get_self_param ();
HIR::IdentifierPattern *self_pattern
= new HIR::IdentifierPattern (mapping, "self", self_param.get_locus (),
self_param.is_ref (),
self_param.get_mut (),
std::unique_ptr<HIR::Pattern> (nullptr));
// might have a specified type
TyTy::BaseType *self_type = nullptr;
if (self_param.has_type ())
{
std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
self_type = TypeCheckType::Resolve (specified_type.get ());
}
else
{
switch (self_param.get_self_kind ())
{
case HIR::SelfParam::IMM:
case HIR::SelfParam::MUT:
self_type = self->clone ();
break;
case HIR::SelfParam::IMM_REF:
self_type = new TyTy::ReferenceType (
self_param.get_mappings ().get_hirid (),
TyTy::TyVar (self->get_ref ()), Mutability::Imm);
break;
case HIR::SelfParam::MUT_REF:
self_type = new TyTy::ReferenceType (
self_param.get_mappings ().get_hirid (),
TyTy::TyVar (self->get_ref ()), Mutability::Mut);
break;
default:
gcc_unreachable ();
return;
}
}
context->insert_type (self_param.get_mappings (), self_type);
params.push_back (
std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type));
}
for (auto &param : function.get_function_params ())
{
// get the name as well required for later on
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
params.push_back (
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
}
const CanonicalPath *canonical_path = nullptr;
bool ok
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
&canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, function.get_locus ()};
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
function.get_mappings ().get_defid (),
function.get_function_name (), ident,
function.is_method ()
? TyTy::FnType::FNTYPE_IS_METHOD_FLAG
: TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
ABI::RUST, std::move (params), ret_type,
std::move (substitutions));
context->insert_type (function.get_mappings (), fnType);
}
TypeCheckImplItem::TypeCheckImplItem (HIR::ImplBlock *parent,
TyTy::BaseType *self)
: TypeCheckBase (), parent (parent), self (self)
{}
void
TypeCheckImplItem::Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item,
TyTy::BaseType *self)
{
TypeCheckImplItem resolver (parent, self);
item->accept_vis (resolver);
}
void
TypeCheckImplItem::visit (HIR::Function &function)
{
TyTy::BaseType *lookup;
if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
{
rust_error_at (function.get_locus (), "failed to lookup function type");
return;
}
if (lookup->get_kind () != TyTy::TypeKind::FNDEF)
{
rust_error_at (function.get_locus (),
"found invalid type for function [%s]",
lookup->as_string ().c_str ());
return;
}
// need to get the return type from this
TyTy::FnType *resolve_fn_type = static_cast<TyTy::FnType *> (lookup);
auto expected_ret_tyty = resolve_fn_type->get_return_type ();
context->push_return_type (TypeCheckContextItem (parent, &function),
expected_ret_tyty);
auto block_expr_ty
= TypeCheckExpr::Resolve (function.get_definition ().get ());
context->pop_return_type ();
expected_ret_tyty->unify (block_expr_ty);
}
void
TypeCheckImplItem::visit (HIR::ConstantItem &const_item)
{}
void
TypeCheckImplItem::visit (HIR::TypeAlias &type_alias)
{}
TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait (
HIR::ImplBlock *parent, TyTy::BaseType *self,
TyTy::TypeBoundPredicate &trait_reference,
std::vector<TyTy::SubstitutionParamMapping> substitutions)
: TypeCheckImplItem (parent, self), trait_reference (trait_reference),
resolved_trait_item (TyTy::TypeBoundPredicateItem::error ()),
substitutions (substitutions)
{
rust_assert (is_trait_impl_block ());
}
TyTy::TypeBoundPredicateItem
TypeCheckImplItemWithTrait::Resolve (
HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self,
TyTy::TypeBoundPredicate &trait_reference,
std::vector<TyTy::SubstitutionParamMapping> substitutions)
{
TypeCheckImplItemWithTrait resolver (parent, self, trait_reference,
substitutions);
item->accept_vis (resolver);
return resolver.resolved_trait_item;
}
void
TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant)
{
// normal resolution of the item
TypeCheckImplItem::visit (constant);
TyTy::BaseType *lookup;
if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup))
return;
// map the impl item to the associated trait item
const auto tref = trait_reference.get ();
const TraitItemReference *raw_trait_item = nullptr;
bool found
= tref->lookup_trait_item_by_type (constant.get_identifier (),
TraitItemReference::TraitItemType::CONST,
&raw_trait_item);
// unknown trait item
if (!found || raw_trait_item->is_error ())
{
RichLocation r (constant.get_locus ());
r.add_range (trait_reference.get_locus ());
rust_error_at (r, "constant %<%s%> is not a member of trait %<%s%>",
constant.get_identifier ().c_str (),
trait_reference.get_name ().c_str ());
return;
}
// get the item from the predicate
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
rust_assert (!resolved_trait_item.is_error ());
// merge the attributes
const HIR::TraitItem *hir_trait_item
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
merge_attributes (constant.get_outer_attrs (), *hir_trait_item);
// check the types are compatible
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
if (!trait_item_type->can_eq (lookup, true))
{
RichLocation r (constant.get_locus ());
r.add_range (resolved_trait_item.get_locus ());
rust_error_at (
r, "constant %<%s%> has an incompatible type for trait %<%s%>",
constant.get_identifier ().c_str (),
trait_reference.get_name ().c_str ());
}
}
void
TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
{
// normal resolution of the item
TypeCheckImplItem::visit (type);
TyTy::BaseType *lookup;
if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
return;
// map the impl item to the associated trait item
const auto tref = trait_reference.get ();
const TraitItemReference *raw_trait_item = nullptr;
bool found
= tref->lookup_trait_item_by_type (type.get_new_type_name (),
TraitItemReference::TraitItemType::TYPE,
&raw_trait_item);
// unknown trait item
if (!found || raw_trait_item->is_error ())
{
RichLocation r (type.get_locus ());
r.add_range (trait_reference.get_locus ());
rust_error_at (r, "type alias %<%s%> is not a member of trait %<%s%>",
type.get_new_type_name ().c_str (),
trait_reference.get_name ().c_str ());
return;
}
// get the item from the predicate
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
rust_assert (!resolved_trait_item.is_error ());
// merge the attributes
const HIR::TraitItem *hir_trait_item
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
merge_attributes (type.get_outer_attrs (), *hir_trait_item);
// check the types are compatible
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
if (!trait_item_type->can_eq (lookup, true))
{
RichLocation r (type.get_locus ());
r.add_range (resolved_trait_item.get_locus ());
rust_error_at (
r, "type alias %<%s%> has an incompatible type for trait %<%s%>",
type.get_new_type_name ().c_str (),
trait_reference.get_name ().c_str ());
}
// its actually a projection, since we need a way to actually bind the
// generic substitutions to the type itself
TyTy::ProjectionType *projection
= new TyTy::ProjectionType (type.get_mappings ().get_hirid (), lookup, tref,
raw_trait_item->get_mappings ().get_defid (),
substitutions);
context->insert_type (type.get_mappings (), projection);
raw_trait_item->associated_type_set (projection);
}
void
TypeCheckImplItemWithTrait::visit (HIR::Function &function)
{
// we get the error checking from the base method here
TypeCheckImplItem::visit (function);
TyTy::BaseType *lookup;
if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup))
return;
// map the impl item to the associated trait item
const auto tref = trait_reference.get ();
const TraitItemReference *raw_trait_item = nullptr;
bool found
= tref->lookup_trait_item_by_type (function.get_function_name (),
TraitItemReference::TraitItemType::FN,
&raw_trait_item);
// unknown trait item
if (!found || raw_trait_item->is_error ())
{
RichLocation r (function.get_locus ());
r.add_range (trait_reference.get_locus ());
rust_error_at (r, "method %<%s%> is not a member of trait %<%s%>",
function.get_function_name ().c_str (),
trait_reference.get_name ().c_str ());
return;
}
// get the item from the predicate
resolved_trait_item = trait_reference.lookup_associated_item (raw_trait_item);
rust_assert (!resolved_trait_item.is_error ());
// merge the attributes
const HIR::TraitItem *hir_trait_item
= resolved_trait_item.get_raw_item ()->get_hir_trait_item ();
merge_attributes (function.get_outer_attrs (), *hir_trait_item);
// check the types are compatible
auto trait_item_type = resolved_trait_item.get_tyty_for_receiver (self);
if (!trait_item_type->can_eq (lookup, true))
{
RichLocation r (function.get_locus ());
r.add_range (resolved_trait_item.get_locus ());
rust_error_at (r,
"method %<%s%> has an incompatible type for trait %<%s%>",
function.get_function_name ().c_str (),
trait_reference.get_name ().c_str ());
}
}
void
TypeCheckImplItemWithTrait::merge_attributes (AST::AttrVec &impl_item_attrs,
const HIR::TraitItem &trait_item)
{
for (const auto &attr : trait_item.get_outer_attrs ())
{
impl_item_attrs.push_back (attr);
}
}
bool
TypeCheckImplItemWithTrait::is_trait_impl_block () const
{
return !trait_reference.is_error ();
}
} // namespace Resolver
} // namespace Rust

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -0,0 +1,498 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check-stmt.h"
#include "rust-hir-full.h"
#include "rust-hir-type-check-type.h"
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check-enumitem.h"
#include "rust-hir-type-check-implitem.h"
#include "rust-hir-type-check-pattern.h"
namespace Rust {
namespace Resolver {
TyTy::BaseType *
TypeCheckStmt::Resolve (HIR::Stmt *stmt)
{
TypeCheckStmt resolver;
stmt->accept_vis (resolver);
return resolver.infered;
}
void
TypeCheckStmt::visit (HIR::ExprStmtWithBlock &stmt)
{
infered = TypeCheckExpr::Resolve (stmt.get_expr ());
}
void
TypeCheckStmt::visit (HIR::ExprStmtWithoutBlock &stmt)
{
infered = TypeCheckExpr::Resolve (stmt.get_expr ());
}
void
TypeCheckStmt::visit (HIR::EmptyStmt &stmt)
{
infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
}
void
TypeCheckStmt::visit (HIR::ExternBlock &extern_block)
{
for (auto &item : extern_block.get_extern_items ())
{
TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
}
}
void
TypeCheckStmt::visit (HIR::ConstantItem &constant)
{
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
infered = type->unify (expr_type);
context->insert_type (constant.get_mappings (), infered);
}
void
TypeCheckStmt::visit (HIR::LetStmt &stmt)
{
infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ());
const HIR::Pattern &stmt_pattern = *stmt.get_pattern ();
TyTy::BaseType *init_expr_ty = nullptr;
if (stmt.has_init_expr ())
{
init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ());
if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
return;
init_expr_ty->append_reference (
stmt_pattern.get_pattern_mappings ().get_hirid ());
}
TyTy::BaseType *specified_ty = nullptr;
if (stmt.has_type ())
specified_ty = TypeCheckType::Resolve (stmt.get_type ());
// let x:i32 = 123;
if (specified_ty != nullptr && init_expr_ty != nullptr)
{
// FIXME use this result and look at the regressions
coercion_site (stmt.get_mappings ().get_hirid (), specified_ty,
init_expr_ty, stmt.get_locus ());
context->insert_type (stmt_pattern.get_pattern_mappings (), specified_ty);
}
else
{
// let x:i32;
if (specified_ty != nullptr)
{
context->insert_type (stmt_pattern.get_pattern_mappings (),
specified_ty);
}
// let x = 123;
else if (init_expr_ty != nullptr)
{
context->insert_type (stmt_pattern.get_pattern_mappings (),
init_expr_ty);
}
// let x;
else
{
context->insert_type (
stmt_pattern.get_pattern_mappings (),
new TyTy::InferType (
stmt_pattern.get_pattern_mappings ().get_hirid (),
TyTy::InferType::InferTypeKind::GENERAL, stmt.get_locus ()));
}
}
}
void
TypeCheckStmt::visit (HIR::TupleStruct &struct_decl)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (struct_decl.has_generics ())
{
for (auto &generic_param : struct_decl.get_generic_params ())
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
case HIR::GenericParam::GenericKind::CONST:
// FIXME: Skipping Lifetime and Const completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (),
param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
std::vector<TyTy::StructFieldType *> fields;
size_t idx = 0;
for (auto &field : struct_decl.get_fields ())
{
TyTy::BaseType *field_type
= TypeCheckType::Resolve (field.get_field_type ().get ());
TyTy::StructFieldType *ty_field
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
std::to_string (idx), field_type);
fields.push_back (ty_field);
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
idx++;
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok = mappings->lookup_canonical_path (
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
// there is only a single variant
std::vector<TyTy::VariantDef *> variants;
variants.push_back (new TyTy::VariantDef (
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
// Process #[repr(...)] attribute, if any
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
TyTy::ADTType::ReprOptions repr
= parse_repr_options (attrs, struct_decl.get_locus ());
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
struct_decl.get_identifier (), ident,
TyTy::ADTType::ADTKind::TUPLE_STRUCT,
std::move (variants), std::move (substitutions), repr);
context->insert_type (struct_decl.get_mappings (), type);
infered = type;
}
void
TypeCheckStmt::visit (HIR::Enum &enum_decl)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (enum_decl.has_generics ())
{
for (auto &generic_param : enum_decl.get_generic_params ())
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
case HIR::GenericParam::GenericKind::CONST:
// FIXME: Skipping Lifetime and Const completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (),
param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
std::vector<TyTy::VariantDef *> variants;
int64_t discriminant_value = 0;
for (auto &variant : enum_decl.get_variants ())
{
TyTy::VariantDef *field_type
= TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
discriminant_value++;
variants.push_back (field_type);
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok
= mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
&canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, enum_decl.get_locus ()};
TyTy::BaseType *type
= new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
enum_decl.get_identifier (), ident,
TyTy::ADTType::ADTKind::ENUM, std::move (variants),
std::move (substitutions));
context->insert_type (enum_decl.get_mappings (), type);
infered = type;
}
void
TypeCheckStmt::visit (HIR::StructStruct &struct_decl)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (struct_decl.has_generics ())
{
for (auto &generic_param : struct_decl.get_generic_params ())
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
case HIR::GenericParam::GenericKind::CONST:
// FIXME: Skipping Lifetime and Const completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (),
param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
std::vector<TyTy::StructFieldType *> fields;
for (auto &field : struct_decl.get_fields ())
{
TyTy::BaseType *field_type
= TypeCheckType::Resolve (field.get_field_type ().get ());
TyTy::StructFieldType *ty_field
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
field.get_field_name (), field_type);
fields.push_back (ty_field);
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok = mappings->lookup_canonical_path (
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
// there is only a single variant
std::vector<TyTy::VariantDef *> variants;
variants.push_back (new TyTy::VariantDef (
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
// Process #[repr(...)] attribute, if any
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
TyTy::ADTType::ReprOptions repr
= parse_repr_options (attrs, struct_decl.get_locus ());
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
struct_decl.get_identifier (), ident,
TyTy::ADTType::ADTKind::STRUCT_STRUCT,
std::move (variants), std::move (substitutions), repr);
context->insert_type (struct_decl.get_mappings (), type);
infered = type;
}
void
TypeCheckStmt::visit (HIR::Union &union_decl)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (union_decl.has_generics ())
{
for (auto &generic_param : union_decl.get_generic_params ())
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
case HIR::GenericParam::GenericKind::CONST:
// FIXME: Skipping Lifetime and Const completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (),
param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
std::vector<TyTy::StructFieldType *> fields;
for (auto &variant : union_decl.get_variants ())
{
TyTy::BaseType *variant_type
= TypeCheckType::Resolve (variant.get_field_type ().get ());
TyTy::StructFieldType *ty_variant
= new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
variant.get_field_name (), variant_type);
fields.push_back (ty_variant);
context->insert_type (variant.get_mappings (),
ty_variant->get_field_type ());
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok
= mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
&canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, union_decl.get_locus ()};
// there is only a single variant
std::vector<TyTy::VariantDef *> variants;
variants.push_back (new TyTy::VariantDef (
union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
TyTy::BaseType *type
= new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
union_decl.get_identifier (), ident,
TyTy::ADTType::ADTKind::UNION, std::move (variants),
std::move (substitutions));
context->insert_type (union_decl.get_mappings (), type);
infered = type;
}
void
TypeCheckStmt::visit (HIR::Function &function)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (function.has_generics ())
{
for (auto &generic_param : function.get_generic_params ())
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
case HIR::GenericParam::GenericKind::CONST:
// FIXME: Skipping Lifetime and Const completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (),
param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
TyTy::BaseType *ret_type = nullptr;
if (!function.has_function_return_type ())
ret_type
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
else
{
auto resolved
= TypeCheckType::Resolve (function.get_return_type ().get ());
if (resolved == nullptr)
{
rust_error_at (function.get_locus (),
"failed to resolve return type");
return;
}
ret_type = resolved->clone ();
ret_type->set_ref (
function.get_return_type ()->get_mappings ().get_hirid ());
}
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
for (auto &param : function.get_function_params ())
{
// get the name as well required for later on
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
params.push_back (
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
&canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, function.get_locus ()};
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
function.get_mappings ().get_defid (),
function.get_function_name (), ident,
TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
std::move (params), ret_type,
std::move (substitutions));
context->insert_type (function.get_mappings (), fnType);
TyTy::FnType *resolved_fn_type = fnType;
auto expected_ret_tyty = resolved_fn_type->get_return_type ();
context->push_return_type (TypeCheckContextItem (&function),
expected_ret_tyty);
auto block_expr_ty
= TypeCheckExpr::Resolve (function.get_definition ().get ());
context->pop_return_type ();
if (block_expr_ty->get_kind () != TyTy::NEVER)
expected_ret_tyty->unify (block_expr_ty);
infered = fnType;
}
} // namespace Resolver
} // namespace Rust

@ -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

@ -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

@ -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

@ -0,0 +1,364 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check-toplevel.h"
#include "rust-hir-type-check-enumitem.h"
#include "rust-hir-type-check-type.h"
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check-pattern.h"
#include "rust-hir-type-check-implitem.h"
namespace Rust {
namespace Resolver {
TypeCheckTopLevel::TypeCheckTopLevel () : TypeCheckBase () {}
void
TypeCheckTopLevel::Resolve (HIR::Item &item)
{
rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM);
HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item);
TypeCheckTopLevel resolver;
vis_item.accept_vis (resolver);
}
void
TypeCheckTopLevel::visit (HIR::TypeAlias &alias)
{
TyTy::BaseType *actual_type
= TypeCheckType::Resolve (alias.get_type_aliased ().get ());
context->insert_type (alias.get_mappings (), actual_type);
for (auto &where_clause_item : alias.get_where_clause ().get_items ())
{
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
}
void
TypeCheckTopLevel::visit (HIR::TupleStruct &struct_decl)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (struct_decl.has_generics ())
resolve_generic_params (struct_decl.get_generic_params (), substitutions);
for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
{
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
std::vector<TyTy::StructFieldType *> fields;
size_t idx = 0;
for (auto &field : struct_decl.get_fields ())
{
TyTy::BaseType *field_type
= TypeCheckType::Resolve (field.get_field_type ().get ());
TyTy::StructFieldType *ty_field
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
std::to_string (idx), field_type);
fields.push_back (ty_field);
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
idx++;
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok = mappings->lookup_canonical_path (
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
// its a single variant ADT
std::vector<TyTy::VariantDef *> variants;
variants.push_back (new TyTy::VariantDef (
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
ident, TyTy::VariantDef::VariantType::TUPLE, nullptr, std::move (fields)));
// Process #[repr(X)] attribute, if any
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
TyTy::ADTType::ReprOptions repr
= parse_repr_options (attrs, struct_decl.get_locus ());
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
struct_decl.get_identifier (), ident,
TyTy::ADTType::ADTKind::TUPLE_STRUCT,
std::move (variants), std::move (substitutions), repr);
context->insert_type (struct_decl.get_mappings (), type);
}
void
TypeCheckTopLevel::visit (HIR::Module &module)
{
for (auto &item : module.get_items ())
TypeCheckTopLevel::Resolve (*item.get ());
}
void
TypeCheckTopLevel::visit (HIR::StructStruct &struct_decl)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (struct_decl.has_generics ())
resolve_generic_params (struct_decl.get_generic_params (), substitutions);
for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
{
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
std::vector<TyTy::StructFieldType *> fields;
for (auto &field : struct_decl.get_fields ())
{
TyTy::BaseType *field_type
= TypeCheckType::Resolve (field.get_field_type ().get ());
TyTy::StructFieldType *ty_field
= new TyTy::StructFieldType (field.get_mappings ().get_hirid (),
field.get_field_name (), field_type);
fields.push_back (ty_field);
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok = mappings->lookup_canonical_path (
struct_decl.get_mappings ().get_nodeid (), &canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, struct_decl.get_locus ()};
// its a single variant ADT
std::vector<TyTy::VariantDef *> variants;
variants.push_back (new TyTy::VariantDef (
struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier (),
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
// Process #[repr(X)] attribute, if any
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
TyTy::ADTType::ReprOptions repr
= parse_repr_options (attrs, struct_decl.get_locus ());
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
struct_decl.get_identifier (), ident,
TyTy::ADTType::ADTKind::STRUCT_STRUCT,
std::move (variants), std::move (substitutions), repr);
context->insert_type (struct_decl.get_mappings (), type);
}
void
TypeCheckTopLevel::visit (HIR::Enum &enum_decl)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (enum_decl.has_generics ())
resolve_generic_params (enum_decl.get_generic_params (), substitutions);
std::vector<TyTy::VariantDef *> variants;
int64_t discriminant_value = 0;
for (auto &variant : enum_decl.get_variants ())
{
TyTy::VariantDef *field_type
= TypeCheckEnumItem::Resolve (variant.get (), discriminant_value);
discriminant_value++;
variants.push_back (field_type);
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok
= mappings->lookup_canonical_path (enum_decl.get_mappings ().get_nodeid (),
&canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, enum_decl.get_locus ()};
// multi variant ADT
TyTy::BaseType *type
= new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
enum_decl.get_identifier (), ident,
TyTy::ADTType::ADTKind::ENUM, std::move (variants),
std::move (substitutions));
context->insert_type (enum_decl.get_mappings (), type);
}
void
TypeCheckTopLevel::visit (HIR::Union &union_decl)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (union_decl.has_generics ())
resolve_generic_params (union_decl.get_generic_params (), substitutions);
for (auto &where_clause_item : union_decl.get_where_clause ().get_items ())
{
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
std::vector<TyTy::StructFieldType *> fields;
for (auto &variant : union_decl.get_variants ())
{
TyTy::BaseType *variant_type
= TypeCheckType::Resolve (variant.get_field_type ().get ());
TyTy::StructFieldType *ty_variant
= new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
variant.get_field_name (), variant_type);
fields.push_back (ty_variant);
context->insert_type (variant.get_mappings (),
ty_variant->get_field_type ());
}
// get the path
const CanonicalPath *canonical_path = nullptr;
bool ok
= mappings->lookup_canonical_path (union_decl.get_mappings ().get_nodeid (),
&canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, union_decl.get_locus ()};
// there is only a single variant
std::vector<TyTy::VariantDef *> variants;
variants.push_back (new TyTy::VariantDef (
union_decl.get_mappings ().get_hirid (), union_decl.get_identifier (),
ident, TyTy::VariantDef::VariantType::STRUCT, nullptr, std::move (fields)));
TyTy::BaseType *type
= new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
union_decl.get_identifier (), ident,
TyTy::ADTType::ADTKind::UNION, std::move (variants),
std::move (substitutions));
context->insert_type (union_decl.get_mappings (), type);
}
void
TypeCheckTopLevel::visit (HIR::StaticItem &var)
{
TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ());
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (var.get_expr ());
context->insert_type (var.get_mappings (), type->unify (expr_type));
}
void
TypeCheckTopLevel::visit (HIR::ConstantItem &constant)
{
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
context->insert_type (constant.get_mappings (), type->unify (expr_type));
}
void
TypeCheckTopLevel::visit (HIR::Function &function)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (function.has_generics ())
resolve_generic_params (function.get_generic_params (), substitutions);
for (auto &where_clause_item : function.get_where_clause ().get_items ())
{
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
TyTy::BaseType *ret_type = nullptr;
if (!function.has_function_return_type ())
ret_type
= TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ());
else
{
auto resolved
= TypeCheckType::Resolve (function.get_return_type ().get ());
if (resolved->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (function.get_locus (),
"failed to resolve return type");
return;
}
ret_type = resolved->clone ();
ret_type->set_ref (
function.get_return_type ()->get_mappings ().get_hirid ());
}
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *>> params;
for (auto &param : function.get_function_params ())
{
// get the name as well required for later on
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
params.push_back (
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
}
const CanonicalPath *canonical_path = nullptr;
bool ok
= mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (),
&canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, function.get_locus ()};
auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (),
function.get_mappings ().get_defid (),
function.get_function_name (), ident,
TyTy::FnType::FNTYPE_DEFAULT_FLAGS, ABI::RUST,
std::move (params), ret_type,
std::move (substitutions));
context->insert_type (function.get_mappings (), fnType);
}
void
TypeCheckTopLevel::visit (HIR::ImplBlock &impl_block)
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
if (impl_block.has_generics ())
resolve_generic_params (impl_block.get_generic_params (), substitutions);
for (auto &where_clause_item : impl_block.get_where_clause ().get_items ())
{
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
}
auto self = TypeCheckType::Resolve (impl_block.get_type ().get ());
if (self->get_kind () == TyTy::TypeKind::ERROR)
return;
for (auto &impl_item : impl_block.get_impl_items ())
TypeCheckTopLevelImplItem::Resolve (impl_item.get (), self, substitutions);
}
void
TypeCheckTopLevel::visit (HIR::ExternBlock &extern_block)
{
for (auto &item : extern_block.get_extern_items ())
{
TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block);
}
}
} // namespace Resolver
} // namespace Rust

@ -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

@ -0,0 +1,838 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check-type.h"
#include "rust-hir-trait-resolve.h"
#include "rust-hir-type-check-expr.h"
namespace Rust {
namespace Resolver {
HIR::GenericArgs
TypeCheckResolveGenericArguments::resolve (HIR::TypePathSegment *segment)
{
TypeCheckResolveGenericArguments resolver (segment->get_locus ());
switch (segment->get_type ())
{
case HIR::TypePathSegment::SegmentType::GENERIC:
resolver.visit (static_cast<HIR::TypePathSegmentGeneric &> (*segment));
break;
default:
break;
}
return resolver.args;
}
void
TypeCheckResolveGenericArguments::visit (HIR::TypePathSegmentGeneric &generic)
{
args = generic.get_generic_args ();
}
TyTy::BaseType *
TypeCheckType::Resolve (HIR::Type *type)
{
TypeCheckType resolver (type->get_mappings ().get_hirid ());
type->accept_vis (resolver);
rust_assert (resolver.translated != nullptr);
resolver.context->insert_type (type->get_mappings (), resolver.translated);
return resolver.translated;
}
void
TypeCheckType::visit (HIR::BareFunctionType &fntype)
{
TyTy::BaseType *return_type
= fntype.has_return_type ()
? TypeCheckType::Resolve (fntype.get_return_type ().get ())
: TyTy::TupleType::get_unit_type (fntype.get_mappings ().get_hirid ());
std::vector<TyTy::TyVar> params;
for (auto &param : fntype.get_function_params ())
{
TyTy::BaseType *ptype = TypeCheckType::Resolve (param.get_type ().get ());
params.push_back (TyTy::TyVar (ptype->get_ref ()));
}
translated = new TyTy::FnPtr (fntype.get_mappings ().get_hirid (),
fntype.get_locus (), std::move (params),
TyTy::TyVar (return_type->get_ref ()));
}
void
TypeCheckType::visit (HIR::TupleType &tuple)
{
if (tuple.is_unit_type ())
{
auto unit_node_id = resolver->get_unit_type_node_id ();
if (!context->lookup_builtin (unit_node_id, &translated))
{
rust_error_at (tuple.get_locus (),
"failed to lookup builtin unit type");
}
return;
}
std::vector<TyTy::TyVar> fields;
for (auto &elem : tuple.get_elems ())
{
auto field_ty = TypeCheckType::Resolve (elem.get ());
fields.push_back (TyTy::TyVar (field_ty->get_ref ()));
}
translated = new TyTy::TupleType (tuple.get_mappings ().get_hirid (),
tuple.get_locus (), fields);
}
void
TypeCheckType::visit (HIR::TypePath &path)
{
// lookup the Node this resolves to
NodeId ref;
auto nid = path.get_mappings ().get_nodeid ();
bool is_fully_resolved = resolver->lookup_resolved_type (nid, &ref);
TyTy::BaseType *lookup = nullptr;
if (!is_fully_resolved)
{
// this can happen so we need to look up the root then resolve the
// remaining segments if possible
size_t offset = 0;
NodeId resolved_node_id = UNKNOWN_NODEID;
TyTy::BaseType *root
= resolve_root_path (path, &offset, &resolved_node_id);
rust_assert (root != nullptr);
if (root->get_kind () == TyTy::TypeKind::ERROR)
return;
translated
= resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (),
path.get_segments (), offset, root,
path.get_mappings (), path.get_locus ());
return;
}
HirId hir_lookup;
if (!context->lookup_type_by_node_id (ref, &hir_lookup))
{
rust_error_at (path.get_locus (), "failed to lookup HIR %d for node '%s'",
ref, path.as_string ().c_str ());
return;
}
if (!context->lookup_type (hir_lookup, &lookup))
{
rust_error_at (path.get_locus (), "failed to lookup HIR TyTy");
return;
}
TyTy::BaseType *path_type = lookup->clone ();
path_type->set_ref (path.get_mappings ().get_hirid ());
HIR::TypePathSegment *final_seg = path.get_final_segment ().get ();
HIR::GenericArgs args = TypeCheckResolveGenericArguments::resolve (final_seg);
bool is_big_self = final_seg->is_ident_only ()
&& (final_seg->as_string ().compare ("Self") == 0);
if (path_type->needs_generic_substitutions ())
{
if (is_big_self)
{
translated = path_type;
return;
}
translated = SubstMapper::Resolve (path_type, path.get_locus (), &args);
}
else if (!args.is_empty ())
{
rust_error_at (path.get_locus (),
"TypePath %s declares generic arguments but "
"the type %s does not have any",
path.as_string ().c_str (),
path_type->as_string ().c_str ());
}
else
{
translated = path_type;
}
}
void
TypeCheckType::visit (HIR::QualifiedPathInType &path)
{
HIR::QualifiedPathType qual_path_type = path.get_path_type ();
TyTy::BaseType *root
= TypeCheckType::Resolve (qual_path_type.get_type ().get ());
if (root->get_kind () == TyTy::TypeKind::ERROR)
{
rust_debug_loc (path.get_locus (), "failed to resolve the root");
return;
}
if (!qual_path_type.has_as_clause ())
{
// then this is just a normal path-in-expression
NodeId root_resolved_node_id = UNKNOWN_NODEID;
bool ok = resolver->lookup_resolved_type (
qual_path_type.get_type ()->get_mappings ().get_nodeid (),
&root_resolved_node_id);
rust_assert (ok);
translated = resolve_segments (root_resolved_node_id,
path.get_mappings ().get_hirid (),
path.get_segments (), 0, translated,
path.get_mappings (), path.get_locus ());
return;
}
// Resolve the trait now
TraitReference *trait_ref
= TraitResolver::Resolve (*qual_path_type.get_trait ().get ());
if (trait_ref->is_error ())
return;
// does this type actually implement this type-bound?
if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
{
rust_error_at (qual_path_type.get_locus (),
"root does not satisfy specified trait-bound");
return;
}
// get the predicate for the bound
auto specified_bound
= get_predicate_from_bound (*qual_path_type.get_trait ().get ());
if (specified_bound.is_error ())
return;
// inherit the bound
root->inherit_bounds ({specified_bound});
// setup the associated types
const TraitReference *specified_bound_ref = specified_bound.get ();
auto candidates = TypeBoundsProbe::Probe (root);
AssociatedImplTrait *associated_impl_trait = nullptr;
for (auto &probed_bound : candidates)
{
const TraitReference *bound_trait_ref = probed_bound.first;
const HIR::ImplBlock *associated_impl = probed_bound.second;
HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
AssociatedImplTrait *associated = nullptr;
bool found_impl_trait
= context->lookup_associated_trait_impl (impl_block_id, &associated);
if (found_impl_trait)
{
bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref);
bool found_self = associated->get_self ()->can_eq (root, false);
if (found_trait && found_self)
{
associated_impl_trait = associated;
break;
}
}
}
if (associated_impl_trait != nullptr)
{
associated_impl_trait->setup_associated_types (root, specified_bound);
}
// lookup the associated item from the specified bound
std::unique_ptr<HIR::TypePathSegment> &item_seg
= path.get_associated_segment ();
HIR::PathIdentSegment item_seg_identifier = item_seg->get_ident_segment ();
TyTy::TypeBoundPredicateItem item
= specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
if (item.is_error ())
{
rust_error_at (item_seg->get_locus (), "unknown associated item");
return;
}
// infer the root type
translated = item.get_tyty_for_receiver (root);
// turbo-fish segment path::<ty>
if (item_seg->get_type () == HIR::TypePathSegment::SegmentType::GENERIC)
{
HIR::TypePathSegmentGeneric &generic_seg
= static_cast<HIR::TypePathSegmentGeneric &> (*item_seg.get ());
// turbo-fish segment path::<ty>
if (generic_seg.has_generic_args ())
{
if (!translated->can_substitute ())
{
rust_error_at (item_seg->get_locus (),
"substitutions not supported for %s",
translated->as_string ().c_str ());
translated
= new TyTy::ErrorType (path.get_mappings ().get_hirid ());
return;
}
translated = SubstMapper::Resolve (translated, path.get_locus (),
&generic_seg.get_generic_args ());
}
}
// continue on as a path-in-expression
const TraitItemReference *trait_item_ref = item.get_raw_item ();
NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
bool fully_resolved = path.get_segments ().empty ();
if (fully_resolved)
{
resolver->insert_resolved_type (path.get_mappings ().get_nodeid (),
root_resolved_node_id);
context->insert_receiver (path.get_mappings ().get_hirid (), root);
return;
}
translated
= resolve_segments (root_resolved_node_id,
path.get_mappings ().get_hirid (), path.get_segments (),
0, translated, path.get_mappings (), path.get_locus ());
}
TyTy::BaseType *
TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
NodeId *root_resolved_node_id)
{
TyTy::BaseType *root_tyty = nullptr;
*offset = 0;
for (size_t i = 0; i < path.get_num_segments (); i++)
{
std::unique_ptr<HIR::TypePathSegment> &seg = path.get_segments ().at (i);
bool have_more_segments = (path.get_num_segments () - 1 != i);
bool is_root = *offset == 0;
NodeId ast_node_id = seg->get_mappings ().get_nodeid ();
// then lookup the reference_node_id
NodeId ref_node_id = UNKNOWN_NODEID;
if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
{
resolver->lookup_resolved_type (ast_node_id, &ref_node_id);
}
// ref_node_id is the NodeId that the segments refers to.
if (ref_node_id == UNKNOWN_NODEID)
{
if (is_root)
{
rust_error_at (seg->get_locus (),
"unknown reference for resolved name: %<%s%>",
seg->get_ident_segment ().as_string ().c_str ());
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
}
return root_tyty;
}
// node back to HIR
HirId ref = UNKNOWN_HIRID;
if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
{
if (is_root)
{
rust_error_at (seg->get_locus (), "789 reverse lookup failure");
rust_debug_loc (
seg->get_locus (),
"failure with [%s] mappings [%s] ref_node_id [%u]",
seg->as_string ().c_str (),
seg->get_mappings ().as_string ().c_str (), ref_node_id);
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
}
return root_tyty;
}
auto seg_is_module = (nullptr != mappings->lookup_module (ref));
auto seg_is_crate = mappings->is_local_hirid_crate (ref);
if (seg_is_module || seg_is_crate)
{
// A::B::C::this_is_a_module::D::E::F
// ^^^^^^^^^^^^^^^^
// Currently handling this.
if (have_more_segments)
{
(*offset)++;
continue;
}
// In the case of :
// A::B::C::this_is_a_module
// ^^^^^^^^^^^^^^^^
// This is an error, we are not expecting a module.
rust_error_at (seg->get_locus (), "expected value");
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
}
TyTy::BaseType *lookup = nullptr;
if (!context->lookup_type (ref, &lookup))
{
if (is_root)
{
rust_error_at (seg->get_locus (),
"failed to resolve root segment");
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
}
return root_tyty;
}
// if we have a previous segment type
if (root_tyty != nullptr)
{
// if this next segment needs substitution we must apply the
// previous type arguments
//
// such as: GenericStruct::<_>::new(123, 456)
if (lookup->needs_generic_substitutions ())
{
if (!root_tyty->needs_generic_substitutions ())
{
auto used_args_in_prev_segment
= GetUsedSubstArgs::From (root_tyty);
lookup
= SubstMapperInternal::Resolve (lookup,
used_args_in_prev_segment);
}
}
}
// turbo-fish segment path::<ty>
if (seg->is_generic_segment ())
{
HIR::TypePathSegmentGeneric *generic_segment
= static_cast<HIR::TypePathSegmentGeneric *> (seg.get ());
if (!lookup->can_substitute ())
{
rust_error_at (seg->get_locus (),
"substitutions not supported for %s",
lookup->as_string ().c_str ());
return new TyTy::ErrorType (lookup->get_ref ());
}
lookup = SubstMapper::Resolve (lookup, path.get_locus (),
&generic_segment->get_generic_args ());
}
*root_resolved_node_id = ref_node_id;
*offset = *offset + 1;
root_tyty = lookup;
}
return root_tyty;
}
TyTy::BaseType *
TypeCheckType::resolve_segments (
NodeId root_resolved_node_id, HirId expr_id,
std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset,
TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
Location expr_locus)
{
NodeId resolved_node_id = root_resolved_node_id;
TyTy::BaseType *prev_segment = tyseg;
for (size_t i = offset; i < segments.size (); i++)
{
std::unique_ptr<HIR::TypePathSegment> &seg = segments.at (i);
bool reciever_is_generic
= prev_segment->get_kind () == TyTy::TypeKind::PARAM;
bool probe_bounds = true;
bool probe_impls = !reciever_is_generic;
bool ignore_mandatory_trait_items = !reciever_is_generic;
// probe the path is done in two parts one where we search impls if no
// candidate is found then we search extensions from traits
auto candidates
= PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
probe_impls, false,
ignore_mandatory_trait_items);
if (candidates.size () == 0)
{
candidates
= PathProbeType::Probe (prev_segment, seg->get_ident_segment (),
false, probe_bounds,
ignore_mandatory_trait_items);
if (candidates.size () == 0)
{
rust_error_at (
seg->get_locus (),
"failed to resolve path segment using an impl Probe");
return new TyTy::ErrorType (expr_id);
}
}
if (candidates.size () > 1)
{
ReportMultipleCandidateError::Report (candidates,
seg->get_ident_segment (),
seg->get_locus ());
return new TyTy::ErrorType (expr_id);
}
auto &candidate = candidates.at (0);
prev_segment = tyseg;
tyseg = candidate.ty;
if (candidate.is_impl_candidate ())
{
resolved_node_id
= candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
}
else
{
resolved_node_id
= candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
}
if (seg->is_generic_segment ())
{
HIR::TypePathSegmentGeneric *generic_segment
= static_cast<HIR::TypePathSegmentGeneric *> (seg.get ());
if (!tyseg->can_substitute ())
{
rust_error_at (expr_locus, "substitutions not supported for %s",
tyseg->as_string ().c_str ());
return new TyTy::ErrorType (expr_id);
}
tyseg = SubstMapper::Resolve (tyseg, expr_locus,
&generic_segment->get_generic_args ());
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
return new TyTy::ErrorType (expr_id);
}
}
context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
if (tyseg->needs_generic_substitutions ())
{
Location locus = segments.back ()->get_locus ();
if (!prev_segment->needs_generic_substitutions ())
{
auto used_args_in_prev_segment
= GetUsedSubstArgs::From (prev_segment);
if (!used_args_in_prev_segment.is_error ())
tyseg
= SubstMapperInternal::Resolve (tyseg, used_args_in_prev_segment);
}
else
{
tyseg = SubstMapper::InferSubst (tyseg, locus);
}
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
return new TyTy::ErrorType (expr_id);
}
rust_assert (resolved_node_id != UNKNOWN_NODEID);
// lookup if the name resolver was able to canonically resolve this or not
NodeId path_resolved_id = UNKNOWN_NODEID;
if (resolver->lookup_resolved_name (expr_mappings.get_nodeid (),
&path_resolved_id))
{
rust_assert (path_resolved_id == resolved_node_id);
}
// check the type scope
else if (resolver->lookup_resolved_type (expr_mappings.get_nodeid (),
&path_resolved_id))
{
rust_assert (path_resolved_id == resolved_node_id);
}
else
{
// name scope first
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
{
resolver->insert_resolved_name (expr_mappings.get_nodeid (),
resolved_node_id);
}
// check the type scope
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node_id))
{
resolver->insert_resolved_type (expr_mappings.get_nodeid (),
resolved_node_id);
}
}
return tyseg;
}
void
TypeCheckType::visit (HIR::TraitObjectType &type)
{
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
for (auto &bound : type.get_type_param_bounds ())
{
if (bound->get_bound_type ()
!= HIR::TypeParamBound::BoundType::TRAITBOUND)
continue;
HIR::TypeParamBound &b = *bound.get ();
HIR::TraitBound &trait_bound = static_cast<HIR::TraitBound &> (b);
TyTy::TypeBoundPredicate predicate
= get_predicate_from_bound (trait_bound.get_path ());
if (!predicate.is_error ()
&& predicate.is_object_safe (true, type.get_locus ()))
specified_bounds.push_back (std::move (predicate));
}
RustIdent ident{CanonicalPath::create_empty (), type.get_locus ()};
translated
= new TyTy::DynamicObjectType (type.get_mappings ().get_hirid (), ident,
std::move (specified_bounds));
}
void
TypeCheckType::visit (HIR::ArrayType &type)
{
auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ());
if (capacity_type->get_kind () == TyTy::TypeKind::ERROR)
return;
TyTy::BaseType *expected_ty = nullptr;
bool ok = context->lookup_builtin ("usize", &expected_ty);
rust_assert (ok);
context->insert_type (type.get_size_expr ()->get_mappings (), expected_ty);
auto unified = expected_ty->unify (capacity_type);
if (unified->get_kind () == TyTy::TypeKind::ERROR)
return;
TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ());
translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (),
type.get_locus (), *type.get_size_expr (),
TyTy::TyVar (base->get_ref ()));
}
void
TypeCheckType::visit (HIR::SliceType &type)
{
TyTy::BaseType *base
= TypeCheckType::Resolve (type.get_element_type ().get ());
translated
= new TyTy::SliceType (type.get_mappings ().get_hirid (), type.get_locus (),
TyTy::TyVar (base->get_ref ()));
}
void
TypeCheckType::visit (HIR::ReferenceType &type)
{
TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ());
translated
= new TyTy::ReferenceType (type.get_mappings ().get_hirid (),
TyTy::TyVar (base->get_ref ()), type.get_mut ());
}
void
TypeCheckType::visit (HIR::RawPointerType &type)
{
TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ());
translated
= new TyTy::PointerType (type.get_mappings ().get_hirid (),
TyTy::TyVar (base->get_ref ()), type.get_mut ());
}
void
TypeCheckType::visit (HIR::InferredType &type)
{
translated = new TyTy::InferType (type.get_mappings ().get_hirid (),
TyTy::InferType::InferTypeKind::GENERAL,
type.get_locus ());
}
void
TypeCheckType::visit (HIR::NeverType &type)
{
TyTy::BaseType *lookup = nullptr;
bool ok = context->lookup_builtin ("!", &lookup);
rust_assert (ok);
translated = lookup->clone ();
}
TyTy::ParamType *
TypeResolveGenericParam::Resolve (HIR::GenericParam *param)
{
TypeResolveGenericParam resolver;
switch (param->get_kind ())
{
case HIR::GenericParam::GenericKind::TYPE:
resolver.visit (static_cast<HIR::TypeParam &> (*param));
break;
case HIR::GenericParam::GenericKind::CONST:
resolver.visit (static_cast<HIR::ConstGenericParam &> (*param));
break;
case HIR::GenericParam::GenericKind::LIFETIME:
resolver.visit (static_cast<HIR::LifetimeParam &> (*param));
break;
}
return resolver.resolved;
}
void
TypeResolveGenericParam::visit (HIR::LifetimeParam &param)
{
// nothing to do
}
void
TypeResolveGenericParam::visit (HIR::ConstGenericParam &param)
{
// TODO
}
void
TypeResolveGenericParam::visit (HIR::TypeParam &param)
{
if (param.has_type ())
TypeCheckType::Resolve (param.get_type ().get ());
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
if (param.has_type_param_bounds ())
{
for (auto &bound : param.get_type_param_bounds ())
{
switch (bound->get_bound_type ())
{
case HIR::TypeParamBound::BoundType::TRAITBOUND: {
HIR::TraitBound *b
= static_cast<HIR::TraitBound *> (bound.get ());
TyTy::TypeBoundPredicate predicate
= get_predicate_from_bound (b->get_path ());
if (!predicate.is_error ())
specified_bounds.push_back (std::move (predicate));
}
break;
default:
break;
}
}
}
resolved
= new TyTy::ParamType (param.get_type_representation (), param.get_locus (),
param.get_mappings ().get_hirid (), param,
specified_bounds);
}
void
ResolveWhereClauseItem::Resolve (HIR::WhereClauseItem &item)
{
ResolveWhereClauseItem resolver;
switch (item.get_item_type ())
{
case HIR::WhereClauseItem::LIFETIME:
resolver.visit (static_cast<HIR::LifetimeWhereClauseItem &> (item));
break;
case HIR::WhereClauseItem::TYPE_BOUND:
resolver.visit (static_cast<HIR::TypeBoundWhereClauseItem &> (item));
break;
}
}
void
ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &item)
{}
void
ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item)
{
auto &binding_type_path = item.get_bound_type ();
TyTy::BaseType *binding = TypeCheckType::Resolve (binding_type_path.get ());
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
for (auto &bound : item.get_type_param_bounds ())
{
switch (bound->get_bound_type ())
{
case HIR::TypeParamBound::BoundType::TRAITBOUND: {
HIR::TraitBound *b = static_cast<HIR::TraitBound *> (bound.get ());
TyTy::TypeBoundPredicate predicate
= get_predicate_from_bound (b->get_path ());
if (!predicate.is_error ())
specified_bounds.push_back (std::move (predicate));
}
break;
default:
break;
}
}
binding->inherit_bounds (specified_bounds);
// When we apply these bounds we must lookup which type this binding
// resolves to, as this is the type which will be used during resolution
// of the block.
NodeId ast_node_id = binding_type_path->get_mappings ().get_nodeid ();
// then lookup the reference_node_id
NodeId ref_node_id = UNKNOWN_NODEID;
if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id))
{
// FIXME
rust_error_at (Location (),
"Failed to lookup type reference for node: %s",
binding_type_path->as_string ().c_str ());
return;
}
// node back to HIR
HirId ref;
if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
{
// FIXME
rust_error_at (Location (), "where-clause reverse lookup failure");
return;
}
// the base reference for this name _must_ have a type set
TyTy::BaseType *lookup;
if (!context->lookup_type (ref, &lookup))
{
rust_error_at (mappings->lookup_location (ref),
"Failed to resolve where-clause binding type: %s",
binding_type_path->as_string ().c_str ());
return;
}
// FIXME
// rust_assert (binding->is_equal (*lookup));
lookup->inherit_bounds (specified_bounds);
}
} // namespace Resolver
} // namespace Rust

@ -0,0 +1,130 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#ifndef RUST_HIR_TYPE_CHECK_TYPE
#define RUST_HIR_TYPE_CHECK_TYPE
#include "rust-hir-type-check-base.h"
#include "rust-hir-full.h"
#include "rust-substitution-mapper.h"
#include "rust-hir-path-probe.h"
namespace Rust {
namespace Resolver {
// FIXME
// This simply fetches the HIR:::GenericArgs from the base class. Check to see
// if we can get rid of this class
class TypeCheckResolveGenericArguments : public TypeCheckBase
{
public:
static HIR::GenericArgs resolve (HIR::TypePathSegment *segment);
void visit (HIR::TypePathSegmentGeneric &generic);
private:
TypeCheckResolveGenericArguments (Location locus)
: TypeCheckBase (), args (HIR::GenericArgs::create_empty (locus))
{}
HIR::GenericArgs args;
};
class TypeCheckType : public TypeCheckBase, public HIR::HIRTypeVisitor
{
public:
static TyTy::BaseType *Resolve (HIR::Type *type);
void visit (HIR::BareFunctionType &fntype) override;
void visit (HIR::TupleType &tuple) override;
void visit (HIR::TypePath &path) override;
void visit (HIR::QualifiedPathInType &path) override;
void visit (HIR::ArrayType &type) override;
void visit (HIR::SliceType &type) override;
void visit (HIR::ReferenceType &type) override;
void visit (HIR::RawPointerType &type) override;
void visit (HIR::InferredType &type) override;
void visit (HIR::NeverType &type) override;
void visit (HIR::TraitObjectType &type) override;
void visit (HIR::TypePathSegmentFunction &segment) override
{ /* TODO */
}
void visit (HIR::TraitBound &bound) override
{ /* TODO */
}
void visit (HIR::ImplTraitType &type) override
{ /* TODO */
}
void visit (HIR::ParenthesisedType &type) override
{ /* TODO */
}
void visit (HIR::ImplTraitTypeOneBound &type) override
{ /* TODO */
}
private:
TypeCheckType (HirId id)
: TypeCheckBase (), translated (new TyTy::ErrorType (id))
{}
TyTy::BaseType *resolve_root_path (HIR::TypePath &path, size_t *offset,
NodeId *root_resolved_node_id);
TyTy::BaseType *resolve_segments (
NodeId root_resolved_node_id, HirId expr_id,
std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset,
TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
Location expr_locus);
TyTy::BaseType *translated;
};
class TypeResolveGenericParam : public TypeCheckBase
{
public:
static TyTy::ParamType *Resolve (HIR::GenericParam *param);
protected:
void visit (HIR::TypeParam &param);
void visit (HIR::LifetimeParam &param);
void visit (HIR::ConstGenericParam &param);
private:
TypeResolveGenericParam () : TypeCheckBase (), resolved (nullptr) {}
TyTy::ParamType *resolved;
};
class ResolveWhereClauseItem : public TypeCheckBase
{
public:
static void Resolve (HIR::WhereClauseItem &item);
protected:
void visit (HIR::LifetimeWhereClauseItem &item);
void visit (HIR::TypeBoundWhereClauseItem &item);
private:
ResolveWhereClauseItem () : TypeCheckBase () {}
};
} // namespace Resolver
} // namespace Rust
#endif // RUST_HIR_TYPE_CHECK_TYPE

@ -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

@ -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

@ -0,0 +1,295 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check.h"
#include "rust-hir-full.h"
#include "rust-hir-type-check-toplevel.h"
#include "rust-hir-type-check-item.h"
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check-pattern.h"
#include "rust-hir-type-check-struct-field.h"
#include "rust-hir-inherent-impl-overlap.h"
extern bool
saw_errors (void);
namespace Rust {
namespace Resolver {
void
TypeResolution::Resolve (HIR::Crate &crate)
{
for (auto it = crate.items.begin (); it != crate.items.end (); it++)
TypeCheckTopLevel::Resolve (*it->get ());
if (saw_errors ())
return;
OverlappingImplItemPass::go ();
if (saw_errors ())
return;
for (auto it = crate.items.begin (); it != crate.items.end (); it++)
TypeCheckItem::Resolve (*it->get ());
if (saw_errors ())
return;
auto mappings = Analysis::Mappings::get ();
auto context = TypeCheckContext::get ();
// default inference variables if possible
context->iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool {
// nothing to do
if (ty->get_kind () != TyTy::TypeKind::INFER)
return true;
TyTy::InferType *infer_var = static_cast<TyTy::InferType *> (ty);
TyTy::BaseType *default_type;
bool ok = infer_var->default_type (&default_type);
if (!ok)
{
rust_error_at (mappings->lookup_location (id),
"type annotations needed");
return true;
}
else
{
auto result = ty->unify (default_type);
result->set_ref (id);
context->insert_type (
Analysis::NodeMapping (mappings->get_current_crate (), 0, id,
UNKNOWN_LOCAL_DEFID),
result);
}
return true;
});
}
// rust-hir-trait-ref.h
TraitItemReference::TraitItemReference (
std::string identifier, bool optional, TraitItemType type,
HIR::TraitItem *hir_trait_item, TyTy::BaseType *self,
std::vector<TyTy::SubstitutionParamMapping> substitutions, Location locus)
: identifier (identifier), optional_flag (optional), type (type),
hir_trait_item (hir_trait_item),
inherited_substitutions (std::move (substitutions)), locus (locus),
self (self), context (TypeCheckContext::get ())
{}
TraitItemReference::TraitItemReference (TraitItemReference const &other)
: identifier (other.identifier), optional_flag (other.optional_flag),
type (other.type), hir_trait_item (other.hir_trait_item),
locus (other.locus), self (other.self), context (TypeCheckContext::get ())
{
inherited_substitutions.clear ();
inherited_substitutions.reserve (other.inherited_substitutions.size ());
for (size_t i = 0; i < other.inherited_substitutions.size (); i++)
inherited_substitutions.push_back (
other.inherited_substitutions.at (i).clone ());
}
TraitItemReference &
TraitItemReference::operator= (TraitItemReference const &other)
{
identifier = other.identifier;
optional_flag = other.optional_flag;
type = other.type;
hir_trait_item = other.hir_trait_item;
self = other.self;
locus = other.locus;
context = other.context;
inherited_substitutions.clear ();
inherited_substitutions.reserve (other.inherited_substitutions.size ());
for (size_t i = 0; i < other.inherited_substitutions.size (); i++)
inherited_substitutions.push_back (
other.inherited_substitutions.at (i).clone ());
return *this;
}
TyTy::BaseType *
TraitItemReference::get_type_from_typealias (/*const*/
HIR::TraitItemType &type) const
{
TyTy::TyVar var (get_mappings ().get_hirid ());
return var.get_tyty ();
}
TyTy::BaseType *
TraitItemReference::get_type_from_constant (
/*const*/ HIR::TraitItemConst &constant) const
{
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ());
if (constant.has_expr ())
{
TyTy::BaseType *expr
= TypeCheckExpr::Resolve (constant.get_expr ().get ());
return type->unify (expr);
}
return type;
}
TyTy::BaseType *
TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const
{
std::vector<TyTy::SubstitutionParamMapping> substitutions
= inherited_substitutions;
HIR::TraitFunctionDecl &function = fn.get_decl ();
if (function.has_generics ())
{
for (auto &generic_param : function.get_generic_params ())
{
switch (generic_param.get ()->get_kind ())
{
case HIR::GenericParam::GenericKind::LIFETIME:
case HIR::GenericParam::GenericKind::CONST:
// FIXME: Skipping Lifetime and Const completely until better
// handling.
break;
case HIR::GenericParam::GenericKind::TYPE: {
auto param_type
= TypeResolveGenericParam::Resolve (generic_param.get ());
context->insert_type (generic_param->get_mappings (),
param_type);
substitutions.push_back (TyTy::SubstitutionParamMapping (
static_cast<HIR::TypeParam &> (*generic_param), param_type));
}
break;
}
}
}
TyTy::BaseType *ret_type = nullptr;
if (!function.has_return_type ())
ret_type = TyTy::TupleType::get_unit_type (fn.get_mappings ().get_hirid ());
else
{
auto resolved
= TypeCheckType::Resolve (function.get_return_type ().get ());
if (resolved->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (fn.get_locus (), "failed to resolve return type");
return get_error ();
}
ret_type = resolved->clone ();
ret_type->set_ref (
function.get_return_type ()->get_mappings ().get_hirid ());
}
std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params;
if (function.is_method ())
{
// these are implicit mappings and not used
auto mappings = Analysis::Mappings::get ();
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id (),
mappings->get_next_hir_id (crate_num),
UNKNOWN_LOCAL_DEFID);
// add the synthetic self param at the front, this is a placeholder
// for compilation to know parameter names. The types are ignored
// but we reuse the HIR identifier pattern which requires it
HIR::SelfParam &self_param = function.get_self ();
HIR::IdentifierPattern *self_pattern
= new HIR::IdentifierPattern (mapping, "self", self_param.get_locus (),
self_param.is_ref (),
self_param.is_mut () ? Mutability::Mut
: Mutability::Imm,
std::unique_ptr<HIR::Pattern> (nullptr));
// might have a specified type
TyTy::BaseType *self_type = nullptr;
if (self_param.has_type ())
{
std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
self_type = TypeCheckType::Resolve (specified_type.get ());
}
else
{
switch (self_param.get_self_kind ())
{
case HIR::SelfParam::IMM:
case HIR::SelfParam::MUT:
self_type = self->clone ();
break;
case HIR::SelfParam::IMM_REF:
self_type = new TyTy::ReferenceType (
self_param.get_mappings ().get_hirid (),
TyTy::TyVar (self->get_ref ()), Mutability::Imm);
break;
case HIR::SelfParam::MUT_REF:
self_type = new TyTy::ReferenceType (
self_param.get_mappings ().get_hirid (),
TyTy::TyVar (self->get_ref ()), Mutability::Mut);
break;
default:
gcc_unreachable ();
return nullptr;
}
}
context->insert_type (self_param.get_mappings (), self_type);
params.push_back (
std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type));
}
for (auto &param : function.get_function_params ())
{
// get the name as well required for later on
auto param_tyty = TypeCheckType::Resolve (param.get_type ());
params.push_back (
std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (),
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
}
auto mappings = Analysis::Mappings::get ();
const CanonicalPath *canonical_path = nullptr;
bool ok = mappings->lookup_canonical_path (fn.get_mappings ().get_nodeid (),
&canonical_path);
rust_assert (ok);
RustIdent ident{*canonical_path, fn.get_locus ()};
auto resolved
= new TyTy::FnType (fn.get_mappings ().get_hirid (),
fn.get_mappings ().get_defid (),
function.get_function_name (), ident,
function.is_method ()
? TyTy::FnType::FNTYPE_IS_METHOD_FLAG
: TyTy::FnType::FNTYPE_DEFAULT_FLAGS,
ABI::RUST, std::move (params), ret_type, substitutions);
context->insert_type (fn.get_mappings (), resolved);
return resolved;
}
} // namespace Resolver
} // namespace Rust

@ -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

@ -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