mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-20 08:10:28 +08:00
gccrs: Add remaining type system transformations
This patch implements multiple transformation performed on the HIR during type-resolution such as type coercion, casts, auto-dereferencement. gcc/rust/ * typecheck/rust-autoderef.cc: New. * typecheck/rust-autoderef.h: New. * typecheck/rust-casts.cc: New. * typecheck/rust-casts.h: New. * typecheck/rust-coercion.cc: New. * typecheck/rust-coercion.h: New. * typecheck/rust-hir-dot-operator.cc: New. * typecheck/rust-hir-dot-operator.h: New. * typecheck/rust-hir-inherent-impl-overlap.h: New. * typecheck/rust-hir-path-probe.h: New. * typecheck/rust-hir-trait-ref.h: New. * typecheck/rust-hir-type-bounds.h: New. * typecheck/rust-substitution-mapper.cc: New. * typecheck/rust-substitution-mapper.h: New. * typecheck/rust-tycheck-dump.h: New. * typecheck/rust-tyctx.cc: New. * typecheck/rust-tyty-bounds.cc: New. * typecheck/rust-tyty-call.cc: New. * typecheck/rust-tyty-call.h: New. * typecheck/rust-tyty-cmp.h: New. * typecheck/rust-tyty-rules.h: New.
This commit is contained in:
parent
24393cb68f
commit
06688fe40a
398
gcc/rust/typecheck/rust-autoderef.cc
Normal file
398
gcc/rust/typecheck/rust-autoderef.cc
Normal file
@ -0,0 +1,398 @@
|
||||
// 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-autoderef.h"
|
||||
#include "rust-hir-path-probe.h"
|
||||
#include "rust-hir-dot-operator.h"
|
||||
#include "rust-hir-trait-resolve.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
static bool
|
||||
resolve_operator_overload_fn (
|
||||
Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty,
|
||||
TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
|
||||
Adjustment::AdjustmentType *requires_ref_adjustment);
|
||||
|
||||
TyTy::BaseType *
|
||||
Adjuster::adjust_type (const std::vector<Adjustment> &adjustments)
|
||||
{
|
||||
if (adjustments.size () == 0)
|
||||
return base->clone ();
|
||||
|
||||
return adjustments.back ().get_expected ()->clone ();
|
||||
}
|
||||
|
||||
Adjustment
|
||||
Adjuster::try_deref_type (const TyTy::BaseType *ty,
|
||||
Analysis::RustLangItem::ItemType deref_lang_item)
|
||||
{
|
||||
HIR::ImplItem *impl_item = nullptr;
|
||||
TyTy::FnType *fn = nullptr;
|
||||
Adjustment::AdjustmentType requires_ref_adjustment
|
||||
= Adjustment::AdjustmentType::ERROR;
|
||||
bool operator_overloaded
|
||||
= resolve_operator_overload_fn (deref_lang_item, ty, &fn, &impl_item,
|
||||
&requires_ref_adjustment);
|
||||
if (!operator_overloaded)
|
||||
{
|
||||
return Adjustment::get_error ();
|
||||
}
|
||||
|
||||
auto resolved_base = fn->get_return_type ()->clone ();
|
||||
bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF;
|
||||
if (!is_valid_type)
|
||||
return Adjustment::get_error ();
|
||||
|
||||
TyTy::ReferenceType *ref_base
|
||||
= static_cast<TyTy::ReferenceType *> (resolved_base);
|
||||
|
||||
Adjustment::AdjustmentType adjustment_type
|
||||
= Adjustment::AdjustmentType::ERROR;
|
||||
switch (deref_lang_item)
|
||||
{
|
||||
case Analysis::RustLangItem::ItemType::DEREF:
|
||||
adjustment_type = Adjustment::AdjustmentType::DEREF;
|
||||
break;
|
||||
|
||||
case Analysis::RustLangItem::ItemType::DEREF_MUT:
|
||||
adjustment_type = Adjustment::AdjustmentType::DEREF_MUT;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Adjustment::get_op_overload_deref_adjustment (adjustment_type, ty,
|
||||
ref_base, fn, impl_item,
|
||||
requires_ref_adjustment);
|
||||
}
|
||||
|
||||
Adjustment
|
||||
Adjuster::try_raw_deref_type (const TyTy::BaseType *ty)
|
||||
{
|
||||
bool is_valid_type = ty->get_kind () == TyTy::TypeKind::REF;
|
||||
if (!is_valid_type)
|
||||
return Adjustment::get_error ();
|
||||
|
||||
const TyTy::ReferenceType *ref_base
|
||||
= static_cast<const TyTy::ReferenceType *> (ty);
|
||||
auto infered = ref_base->get_base ()->clone ();
|
||||
|
||||
return Adjustment (Adjustment::AdjustmentType::INDIRECTION, ty, infered);
|
||||
}
|
||||
|
||||
Adjustment
|
||||
Adjuster::try_unsize_type (const TyTy::BaseType *ty)
|
||||
{
|
||||
bool is_valid_type = ty->get_kind () == TyTy::TypeKind::ARRAY;
|
||||
if (!is_valid_type)
|
||||
return Adjustment::get_error ();
|
||||
|
||||
auto mappings = Analysis::Mappings::get ();
|
||||
auto context = TypeCheckContext::get ();
|
||||
|
||||
const auto ref_base = static_cast<const TyTy::ArrayType *> (ty);
|
||||
auto slice_elem = ref_base->get_element_type ();
|
||||
|
||||
auto slice
|
||||
= new TyTy::SliceType (mappings->get_next_hir_id (), ty->get_ident ().locus,
|
||||
TyTy::TyVar (slice_elem->get_ref ()));
|
||||
context->insert_implicit_type (slice);
|
||||
|
||||
return Adjustment (Adjustment::AdjustmentType::UNSIZE, ty, slice);
|
||||
}
|
||||
|
||||
static bool
|
||||
resolve_operator_overload_fn (
|
||||
Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty,
|
||||
TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
|
||||
Adjustment::AdjustmentType *requires_ref_adjustment)
|
||||
{
|
||||
auto context = TypeCheckContext::get ();
|
||||
auto mappings = Analysis::Mappings::get ();
|
||||
|
||||
// look up lang item for arithmetic type
|
||||
std::string associated_item_name
|
||||
= Analysis::RustLangItem::ToString (lang_item_type);
|
||||
DefId respective_lang_item_id = UNKNOWN_DEFID;
|
||||
bool lang_item_defined
|
||||
= mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
|
||||
|
||||
if (!lang_item_defined)
|
||||
return false;
|
||||
|
||||
auto segment = HIR::PathIdentSegment (associated_item_name);
|
||||
auto candidate
|
||||
= MethodResolver::Probe (ty, HIR::PathIdentSegment (associated_item_name),
|
||||
true);
|
||||
|
||||
bool have_implementation_for_lang_item = !candidate.is_error ();
|
||||
if (!have_implementation_for_lang_item)
|
||||
return false;
|
||||
|
||||
// Get the adjusted self
|
||||
Adjuster adj (ty);
|
||||
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
|
||||
|
||||
// is this the case we are recursive
|
||||
// handle the case where we are within the impl block for this
|
||||
// lang_item otherwise we end up with a recursive operator overload
|
||||
// such as the i32 operator overload trait
|
||||
TypeCheckContextItem &fn_context = context->peek_context ();
|
||||
if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
|
||||
{
|
||||
auto &impl_item = fn_context.get_impl_item ();
|
||||
HIR::ImplBlock *parent = impl_item.first;
|
||||
HIR::Function *fn = impl_item.second;
|
||||
|
||||
if (parent->has_trait_ref ()
|
||||
&& fn->get_function_name ().compare (associated_item_name) == 0)
|
||||
{
|
||||
TraitReference *trait_reference
|
||||
= TraitResolver::Lookup (*parent->get_trait_ref ().get ());
|
||||
if (!trait_reference->is_error ())
|
||||
{
|
||||
TyTy::BaseType *lookup = nullptr;
|
||||
bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
|
||||
&lookup);
|
||||
rust_assert (ok);
|
||||
rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
|
||||
|
||||
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
|
||||
rust_assert (fntype->is_method ());
|
||||
|
||||
bool is_lang_item_impl
|
||||
= trait_reference->get_mappings ().get_defid ()
|
||||
== respective_lang_item_id;
|
||||
bool self_is_lang_item_self
|
||||
= fntype->get_self_type ()->is_equal (*adjusted_self);
|
||||
bool recursive_operator_overload
|
||||
= is_lang_item_impl && self_is_lang_item_self;
|
||||
|
||||
if (recursive_operator_overload)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
|
||||
|
||||
// rust only support impl item deref operator overloading ie you must have an
|
||||
// impl block for it
|
||||
rust_assert (candidate.candidate.type
|
||||
== PathProbeCandidate::CandidateType::IMPL_FUNC);
|
||||
*impl_item = candidate.candidate.item.impl.impl_item;
|
||||
|
||||
rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
|
||||
TyTy::BaseType *lookup = lookup_tyty;
|
||||
TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
|
||||
rust_assert (fn->is_method ());
|
||||
|
||||
if (fn->needs_substitution ())
|
||||
{
|
||||
if (ty->get_kind () == TyTy::TypeKind::ADT)
|
||||
{
|
||||
const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (ty);
|
||||
|
||||
auto s = fn->get_self_type ()->get_root ();
|
||||
rust_assert (s->can_eq (adt, false));
|
||||
rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
|
||||
const TyTy::ADTType *self_adt
|
||||
= static_cast<const TyTy::ADTType *> (s);
|
||||
|
||||
// we need to grab the Self substitutions as the inherit type
|
||||
// parameters for this
|
||||
if (self_adt->needs_substitution ())
|
||||
{
|
||||
rust_assert (adt->was_substituted ());
|
||||
|
||||
TyTy::SubstitutionArgumentMappings used_args_in_prev_segment
|
||||
= GetUsedSubstArgs::From (adt);
|
||||
|
||||
TyTy::SubstitutionArgumentMappings inherit_type_args
|
||||
= self_adt->solve_mappings_from_receiver_for_self (
|
||||
used_args_in_prev_segment);
|
||||
|
||||
// there may or may not be inherited type arguments
|
||||
if (!inherit_type_args.is_error ())
|
||||
{
|
||||
// need to apply the inherited type arguments to the
|
||||
// function
|
||||
lookup = fn->handle_substitions (inherit_type_args);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rust_assert (candidate.adjustments.size () < 2);
|
||||
|
||||
// lets infer the params for this we could probably fix this up by
|
||||
// actually just performing a substitution of a single param but this
|
||||
// seems more generic i think.
|
||||
//
|
||||
// this is the case where we had say Foo<&Bar>> and we have derefed to
|
||||
// the &Bar and we are trying to match a method self of Bar which
|
||||
// requires another deref which is matched to the deref trait impl of
|
||||
// &&T so this requires another reference and deref call
|
||||
|
||||
lookup = fn->infer_substitions (Location ());
|
||||
rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
|
||||
fn = static_cast<TyTy::FnType *> (lookup);
|
||||
fn->get_self_type ()->unify (adjusted_self);
|
||||
lookup = fn;
|
||||
}
|
||||
}
|
||||
|
||||
if (candidate.adjustments.size () > 0)
|
||||
*requires_ref_adjustment = candidate.adjustments.at (0).get_type ();
|
||||
|
||||
*resolved_fn = static_cast<TyTy::FnType *> (lookup);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AutoderefCycle::AutoderefCycle (bool autoderef_flag)
|
||||
: autoderef_flag (autoderef_flag)
|
||||
{}
|
||||
|
||||
AutoderefCycle::~AutoderefCycle () {}
|
||||
|
||||
void
|
||||
AutoderefCycle::try_hook (const TyTy::BaseType &)
|
||||
{}
|
||||
|
||||
bool
|
||||
AutoderefCycle::cycle (const TyTy::BaseType *receiver)
|
||||
{
|
||||
const TyTy::BaseType *r = receiver;
|
||||
while (true)
|
||||
{
|
||||
if (try_autoderefed (r))
|
||||
return true;
|
||||
|
||||
// 4. deref to to 1, if cannot deref then quit
|
||||
if (autoderef_flag)
|
||||
return false;
|
||||
|
||||
// try unsize
|
||||
Adjustment unsize = Adjuster::try_unsize_type (r);
|
||||
if (!unsize.is_error ())
|
||||
{
|
||||
adjustments.push_back (unsize);
|
||||
auto unsize_r = unsize.get_expected ();
|
||||
|
||||
if (try_autoderefed (unsize_r))
|
||||
return true;
|
||||
|
||||
adjustments.pop_back ();
|
||||
}
|
||||
|
||||
Adjustment deref
|
||||
= Adjuster::try_deref_type (r, Analysis::RustLangItem::ItemType::DEREF);
|
||||
if (!deref.is_error ())
|
||||
{
|
||||
auto deref_r = deref.get_expected ();
|
||||
adjustments.push_back (deref);
|
||||
|
||||
if (try_autoderefed (deref_r))
|
||||
return true;
|
||||
|
||||
adjustments.pop_back ();
|
||||
}
|
||||
|
||||
Adjustment deref_mut = Adjuster::try_deref_type (
|
||||
r, Analysis::RustLangItem::ItemType::DEREF_MUT);
|
||||
if (!deref_mut.is_error ())
|
||||
{
|
||||
auto deref_r = deref_mut.get_expected ();
|
||||
adjustments.push_back (deref_mut);
|
||||
|
||||
if (try_autoderefed (deref_r))
|
||||
return true;
|
||||
|
||||
adjustments.pop_back ();
|
||||
}
|
||||
|
||||
if (!deref_mut.is_error ())
|
||||
{
|
||||
auto deref_r = deref_mut.get_expected ();
|
||||
adjustments.push_back (deref_mut);
|
||||
Adjustment raw_deref = Adjuster::try_raw_deref_type (deref_r);
|
||||
adjustments.push_back (raw_deref);
|
||||
deref_r = raw_deref.get_expected ();
|
||||
|
||||
if (try_autoderefed (deref_r))
|
||||
return true;
|
||||
|
||||
adjustments.pop_back ();
|
||||
adjustments.pop_back ();
|
||||
}
|
||||
|
||||
if (!deref.is_error ())
|
||||
{
|
||||
r = deref.get_expected ();
|
||||
adjustments.push_back (deref);
|
||||
}
|
||||
Adjustment raw_deref = Adjuster::try_raw_deref_type (r);
|
||||
if (raw_deref.is_error ())
|
||||
return false;
|
||||
|
||||
r = raw_deref.get_expected ();
|
||||
adjustments.push_back (raw_deref);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AutoderefCycle::try_autoderefed (const TyTy::BaseType *r)
|
||||
{
|
||||
try_hook (*r);
|
||||
|
||||
// 1. try raw
|
||||
if (select (*r))
|
||||
return true;
|
||||
|
||||
// 2. try ref
|
||||
TyTy::ReferenceType *r1
|
||||
= new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
|
||||
Mutability::Imm);
|
||||
adjustments.push_back (
|
||||
Adjustment (Adjustment::AdjustmentType::IMM_REF, r, r1));
|
||||
if (select (*r1))
|
||||
return true;
|
||||
|
||||
adjustments.pop_back ();
|
||||
|
||||
// 3. try mut ref
|
||||
TyTy::ReferenceType *r2
|
||||
= new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
|
||||
Mutability::Mut);
|
||||
adjustments.push_back (
|
||||
Adjustment (Adjustment::AdjustmentType::MUT_REF, r, r2));
|
||||
if (select (*r2))
|
||||
return true;
|
||||
|
||||
adjustments.pop_back ();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
178
gcc/rust/typecheck/rust-autoderef.h
Normal file
178
gcc/rust/typecheck/rust-autoderef.h
Normal file
@ -0,0 +1,178 @@
|
||||
// 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_AUTODEREF
|
||||
#define RUST_AUTODEREF
|
||||
|
||||
#include "rust-tyty.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class Adjustment
|
||||
{
|
||||
public:
|
||||
enum AdjustmentType
|
||||
{
|
||||
ERROR,
|
||||
|
||||
IMM_REF,
|
||||
MUT_REF,
|
||||
DEREF,
|
||||
DEREF_MUT,
|
||||
INDIRECTION,
|
||||
UNSIZE,
|
||||
};
|
||||
|
||||
// ctor for all adjustments except derefs
|
||||
Adjustment (AdjustmentType type, const TyTy::BaseType *actual,
|
||||
const TyTy::BaseType *expected)
|
||||
: Adjustment (type, actual, expected, nullptr, nullptr,
|
||||
AdjustmentType::ERROR)
|
||||
{}
|
||||
|
||||
static Adjustment get_op_overload_deref_adjustment (
|
||||
AdjustmentType type, const TyTy::BaseType *actual,
|
||||
const TyTy::BaseType *expected, TyTy::FnType *fn, HIR::ImplItem *deref_item,
|
||||
Adjustment::AdjustmentType requires_ref_adjustment)
|
||||
{
|
||||
rust_assert (type == DEREF || type == DEREF_MUT);
|
||||
return Adjustment (type, actual, expected, fn, deref_item,
|
||||
requires_ref_adjustment);
|
||||
}
|
||||
|
||||
AdjustmentType get_type () const { return type; }
|
||||
|
||||
const TyTy::BaseType *get_actual () const { return actual; }
|
||||
const TyTy::BaseType *get_expected () const { return expected; }
|
||||
|
||||
std::string as_string () const
|
||||
{
|
||||
return Adjustment::type_string (get_type ()) + "->"
|
||||
+ get_expected ()->debug_str ();
|
||||
}
|
||||
|
||||
static std::string type_string (AdjustmentType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AdjustmentType::ERROR:
|
||||
return "ERROR";
|
||||
case AdjustmentType::IMM_REF:
|
||||
return "IMM_REF";
|
||||
case AdjustmentType::MUT_REF:
|
||||
return "MUT_REF";
|
||||
case AdjustmentType::DEREF:
|
||||
return "DEREF";
|
||||
case AdjustmentType::DEREF_MUT:
|
||||
return "DEREF_MUT";
|
||||
case AdjustmentType::INDIRECTION:
|
||||
return "INDIRECTION";
|
||||
case AdjustmentType::UNSIZE:
|
||||
return "UNSIZE";
|
||||
}
|
||||
gcc_unreachable ();
|
||||
return "";
|
||||
}
|
||||
|
||||
static Adjustment get_error () { return Adjustment{ERROR, nullptr, nullptr}; }
|
||||
|
||||
bool is_error () const { return type == ERROR; }
|
||||
|
||||
bool is_deref_adjustment () const { return type == DEREF; }
|
||||
|
||||
bool is_deref_mut_adjustment () const { return type == DEREF_MUT; }
|
||||
|
||||
bool has_operator_overload () const { return deref_operator_fn != nullptr; }
|
||||
|
||||
TyTy::FnType *get_deref_operator_fn () const { return deref_operator_fn; }
|
||||
|
||||
AdjustmentType get_deref_adjustment_type () const
|
||||
{
|
||||
return requires_ref_adjustment;
|
||||
}
|
||||
|
||||
HIR::ImplItem *get_deref_hir_item () const { return deref_item; }
|
||||
|
||||
private:
|
||||
Adjustment (AdjustmentType type, const TyTy::BaseType *actual,
|
||||
const TyTy::BaseType *expected, TyTy::FnType *deref_operator_fn,
|
||||
HIR::ImplItem *deref_item,
|
||||
Adjustment::AdjustmentType requires_ref_adjustment)
|
||||
: type (type), actual (actual), expected (expected),
|
||||
deref_operator_fn (deref_operator_fn), deref_item (deref_item),
|
||||
requires_ref_adjustment (requires_ref_adjustment)
|
||||
{}
|
||||
|
||||
AdjustmentType type;
|
||||
const TyTy::BaseType *actual;
|
||||
const TyTy::BaseType *expected;
|
||||
|
||||
// - only used for deref operator_overloads
|
||||
//
|
||||
// the fn that we are calling
|
||||
TyTy::FnType *deref_operator_fn;
|
||||
HIR::ImplItem *deref_item;
|
||||
// operator overloads can requre a reference
|
||||
Adjustment::AdjustmentType requires_ref_adjustment;
|
||||
};
|
||||
|
||||
class Adjuster
|
||||
{
|
||||
public:
|
||||
Adjuster (const TyTy::BaseType *ty) : base (ty) {}
|
||||
|
||||
TyTy::BaseType *adjust_type (const std::vector<Adjustment> &adjustments);
|
||||
|
||||
static Adjustment
|
||||
try_deref_type (const TyTy::BaseType *ty,
|
||||
Analysis::RustLangItem::ItemType deref_lang_item);
|
||||
|
||||
static Adjustment try_raw_deref_type (const TyTy::BaseType *ty);
|
||||
|
||||
static Adjustment try_unsize_type (const TyTy::BaseType *ty);
|
||||
|
||||
private:
|
||||
const TyTy::BaseType *base;
|
||||
};
|
||||
|
||||
class AutoderefCycle
|
||||
{
|
||||
protected:
|
||||
AutoderefCycle (bool autoderef_flag);
|
||||
|
||||
virtual ~AutoderefCycle ();
|
||||
|
||||
virtual bool select (const TyTy::BaseType &autoderefed) = 0;
|
||||
|
||||
// optional: this is a chance to hook in to grab predicate items on the raw
|
||||
// type
|
||||
virtual void try_hook (const TyTy::BaseType &);
|
||||
|
||||
virtual bool cycle (const TyTy::BaseType *receiver);
|
||||
|
||||
bool try_autoderefed (const TyTy::BaseType *r);
|
||||
|
||||
bool autoderef_flag;
|
||||
std::vector<Adjustment> adjustments;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_AUTODEREF
|
292
gcc/rust/typecheck/rust-casts.cc
Normal file
292
gcc/rust/typecheck/rust-casts.cc
Normal file
@ -0,0 +1,292 @@
|
||||
// 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-casts.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCastRules::TypeCastRules (Location locus, TyTy::TyWithLocation from,
|
||||
TyTy::TyWithLocation to)
|
||||
: locus (locus), from (from), to (to)
|
||||
{}
|
||||
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCastRules::resolve (Location locus, TyTy::TyWithLocation from,
|
||||
TyTy::TyWithLocation to)
|
||||
{
|
||||
TypeCastRules cast_rules (locus, from, to);
|
||||
return cast_rules.check ();
|
||||
}
|
||||
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCastRules::check ()
|
||||
{
|
||||
// https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
|
||||
auto possible_coercion
|
||||
= TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus);
|
||||
if (!possible_coercion.is_error ())
|
||||
return possible_coercion;
|
||||
|
||||
// try the simple cast rules
|
||||
auto simple_cast = cast_rules ();
|
||||
if (!simple_cast.is_error ())
|
||||
return simple_cast;
|
||||
|
||||
// failed to cast
|
||||
emit_cast_error ();
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCastRules::cast_rules ()
|
||||
{
|
||||
// https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L596
|
||||
// https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L654
|
||||
|
||||
rust_debug ("cast_rules from={%s} to={%s}",
|
||||
from.get_ty ()->debug_str ().c_str (),
|
||||
to.get_ty ()->debug_str ().c_str ());
|
||||
|
||||
switch (from.get_ty ()->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::INFER: {
|
||||
TyTy::InferType *from_infer
|
||||
= static_cast<TyTy::InferType *> (from.get_ty ());
|
||||
switch (from_infer->get_infer_kind ())
|
||||
{
|
||||
case TyTy::InferType::InferTypeKind::GENERAL:
|
||||
return TypeCoercionRules::CoercionResult{{},
|
||||
to.get_ty ()->clone ()};
|
||||
|
||||
case TyTy::InferType::InferTypeKind::INTEGRAL:
|
||||
switch (to.get_ty ()->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::CHAR:
|
||||
case TyTy::TypeKind::BOOL:
|
||||
case TyTy::TypeKind::USIZE:
|
||||
case TyTy::TypeKind::ISIZE:
|
||||
case TyTy::TypeKind::UINT:
|
||||
case TyTy::TypeKind::INT:
|
||||
case TyTy::TypeKind::POINTER:
|
||||
return TypeCoercionRules::CoercionResult{
|
||||
{}, to.get_ty ()->clone ()};
|
||||
|
||||
case TyTy::TypeKind::INFER: {
|
||||
TyTy::InferType *to_infer
|
||||
= static_cast<TyTy::InferType *> (to.get_ty ());
|
||||
|
||||
switch (to_infer->get_infer_kind ())
|
||||
{
|
||||
case TyTy::InferType::InferTypeKind::GENERAL:
|
||||
case TyTy::InferType::InferTypeKind::INTEGRAL:
|
||||
return TypeCoercionRules::CoercionResult{
|
||||
{}, to.get_ty ()->clone ()};
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TyTy::InferType::InferTypeKind::FLOAT:
|
||||
switch (to.get_ty ()->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::USIZE:
|
||||
case TyTy::TypeKind::ISIZE:
|
||||
case TyTy::TypeKind::UINT:
|
||||
case TyTy::TypeKind::INT:
|
||||
return TypeCoercionRules::CoercionResult{
|
||||
{}, to.get_ty ()->clone ()};
|
||||
|
||||
case TyTy::TypeKind::INFER: {
|
||||
TyTy::InferType *to_infer
|
||||
= static_cast<TyTy::InferType *> (to.get_ty ());
|
||||
|
||||
switch (to_infer->get_infer_kind ())
|
||||
{
|
||||
case TyTy::InferType::InferTypeKind::GENERAL:
|
||||
case TyTy::InferType::InferTypeKind::FLOAT:
|
||||
return TypeCoercionRules::CoercionResult{
|
||||
{}, to.get_ty ()->clone ()};
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TyTy::TypeKind::BOOL:
|
||||
switch (to.get_ty ()->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::INFER:
|
||||
case TyTy::TypeKind::USIZE:
|
||||
case TyTy::TypeKind::ISIZE:
|
||||
case TyTy::TypeKind::UINT:
|
||||
case TyTy::TypeKind::INT:
|
||||
return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TyTy::TypeKind::CHAR:
|
||||
case TyTy::TypeKind::USIZE:
|
||||
case TyTy::TypeKind::ISIZE:
|
||||
case TyTy::TypeKind::UINT:
|
||||
case TyTy::TypeKind::INT:
|
||||
switch (to.get_ty ()->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::CHAR: {
|
||||
// only u8 and char
|
||||
bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT;
|
||||
bool was_u8 = was_uint
|
||||
&& (static_cast<TyTy::UintType *> (from.get_ty ())
|
||||
->get_uint_kind ()
|
||||
== TyTy::UintType::UintKind::U8);
|
||||
if (was_u8)
|
||||
return TypeCoercionRules::CoercionResult{{},
|
||||
to.get_ty ()->clone ()};
|
||||
}
|
||||
break;
|
||||
|
||||
case TyTy::TypeKind::INFER:
|
||||
case TyTy::TypeKind::USIZE:
|
||||
case TyTy::TypeKind::ISIZE:
|
||||
case TyTy::TypeKind::UINT:
|
||||
case TyTy::TypeKind::INT:
|
||||
return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TyTy::TypeKind::FLOAT:
|
||||
switch (to.get_ty ()->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::FLOAT:
|
||||
return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
|
||||
|
||||
case TyTy::TypeKind::INFER: {
|
||||
TyTy::InferType *to_infer
|
||||
= static_cast<TyTy::InferType *> (to.get_ty ());
|
||||
|
||||
switch (to_infer->get_infer_kind ())
|
||||
{
|
||||
case TyTy::InferType::InferTypeKind::GENERAL:
|
||||
case TyTy::InferType::InferTypeKind::FLOAT:
|
||||
return TypeCoercionRules::CoercionResult{
|
||||
{}, to.get_ty ()->clone ()};
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TyTy::TypeKind::REF:
|
||||
case TyTy::TypeKind::POINTER:
|
||||
switch (to.get_ty ()->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::REF:
|
||||
case TyTy::TypeKind::POINTER:
|
||||
return check_ptr_ptr_cast ();
|
||||
|
||||
// FIXME can you cast a pointer to a integral type?
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCastRules::check_ptr_ptr_cast ()
|
||||
{
|
||||
rust_debug ("check_ptr_ptr_cast from={%s} to={%s}",
|
||||
from.get_ty ()->debug_str ().c_str (),
|
||||
to.get_ty ()->debug_str ().c_str ());
|
||||
|
||||
bool from_is_ref = from.get_ty ()->get_kind () == TyTy::TypeKind::REF;
|
||||
bool to_is_ref = to.get_ty ()->get_kind () == TyTy::TypeKind::REF;
|
||||
bool from_is_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
|
||||
bool to_is_ptr = to.get_ty ()->get_kind () == TyTy::TypeKind::POINTER;
|
||||
|
||||
if (from_is_ptr && to_is_ptr)
|
||||
{
|
||||
// mutability is ignored here as all pointer usage requires unsafe
|
||||
return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
|
||||
}
|
||||
else if (from_is_ref && to_is_ref)
|
||||
{
|
||||
// mutability must be coercedable
|
||||
TyTy::ReferenceType &f
|
||||
= static_cast<TyTy::ReferenceType &> (*from.get_ty ());
|
||||
TyTy::ReferenceType &t
|
||||
= static_cast<TyTy::ReferenceType &> (*to.get_ty ());
|
||||
|
||||
if (TypeCoercionRules::coerceable_mutability (f.mutability (),
|
||||
t.mutability ()))
|
||||
{
|
||||
return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()};
|
||||
}
|
||||
}
|
||||
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
void
|
||||
TypeCastRules::emit_cast_error () const
|
||||
{
|
||||
// error[E0604]
|
||||
RichLocation r (locus);
|
||||
r.add_range (from.get_locus ());
|
||||
r.add_range (to.get_locus ());
|
||||
rust_error_at (r, "invalid cast %<%s%> to %<%s%>",
|
||||
from.get_ty ()->get_name ().c_str (),
|
||||
to.get_ty ()->get_name ().c_str ());
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
53
gcc/rust/typecheck/rust-casts.h
Normal file
53
gcc/rust/typecheck/rust-casts.h
Normal file
@ -0,0 +1,53 @@
|
||||
// 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_CASTS
|
||||
#define RUST_CASTS
|
||||
|
||||
#include "rust-tyty.h"
|
||||
#include "rust-coercion.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCastRules
|
||||
{
|
||||
public:
|
||||
static TypeCoercionRules::CoercionResult
|
||||
resolve (Location locus, TyTy::TyWithLocation from, TyTy::TyWithLocation to);
|
||||
|
||||
protected:
|
||||
TypeCoercionRules::CoercionResult check ();
|
||||
TypeCoercionRules::CoercionResult cast_rules ();
|
||||
TypeCoercionRules::CoercionResult check_ptr_ptr_cast ();
|
||||
|
||||
void emit_cast_error () const;
|
||||
|
||||
protected:
|
||||
TypeCastRules (Location locus, TyTy::TyWithLocation from,
|
||||
TyTy::TyWithLocation to);
|
||||
|
||||
Location locus;
|
||||
TyTy::TyWithLocation from;
|
||||
TyTy::TyWithLocation to;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_CASTS
|
357
gcc/rust/typecheck/rust-coercion.cc
Normal file
357
gcc/rust/typecheck/rust-coercion.cc
Normal file
@ -0,0 +1,357 @@
|
||||
// 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-coercion.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCoercionRules::Coerce (TyTy::BaseType *receiver, TyTy::BaseType *expected,
|
||||
Location locus)
|
||||
{
|
||||
TypeCoercionRules resolver (expected, locus, true);
|
||||
bool ok = resolver.do_coercion (receiver);
|
||||
return ok ? resolver.try_result : CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCoercionRules::TryCoerce (TyTy::BaseType *receiver,
|
||||
TyTy::BaseType *expected, Location locus)
|
||||
{
|
||||
TypeCoercionRules resolver (expected, locus, false);
|
||||
bool ok = resolver.do_coercion (receiver);
|
||||
return ok ? resolver.try_result : CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
TypeCoercionRules::TypeCoercionRules (TyTy::BaseType *expected, Location locus,
|
||||
bool emit_errors)
|
||||
: AutoderefCycle (false), mappings (Analysis::Mappings::get ()),
|
||||
context (TypeCheckContext::get ()), expected (expected), locus (locus),
|
||||
try_result (CoercionResult::get_error ()), emit_errors (emit_errors)
|
||||
{}
|
||||
|
||||
bool
|
||||
TypeCoercionRules::do_coercion (TyTy::BaseType *receiver)
|
||||
{
|
||||
// FIXME this is not finished and might be super simplified
|
||||
// see:
|
||||
// https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs
|
||||
|
||||
// unsize
|
||||
bool unsafe_error = false;
|
||||
CoercionResult unsize_coercion
|
||||
= coerce_unsized (receiver, expected, unsafe_error);
|
||||
bool valid_unsize_coercion = !unsize_coercion.is_error ();
|
||||
if (valid_unsize_coercion)
|
||||
{
|
||||
try_result = unsize_coercion;
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_error)
|
||||
{
|
||||
// Location lhs = mappings->lookup_location (receiver->get_ref ());
|
||||
// Location rhs = mappings->lookup_location (expected->get_ref ());
|
||||
// object_unsafe_error (locus, lhs, rhs);
|
||||
return false;
|
||||
}
|
||||
|
||||
// pointers
|
||||
switch (expected->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::POINTER: {
|
||||
TyTy::PointerType *ptr = static_cast<TyTy::PointerType *> (expected);
|
||||
try_result = coerce_unsafe_ptr (receiver, ptr, ptr->mutability ());
|
||||
return !try_result.is_error ();
|
||||
}
|
||||
|
||||
case TyTy::TypeKind::REF: {
|
||||
TyTy::ReferenceType *ptr
|
||||
= static_cast<TyTy::ReferenceType *> (expected);
|
||||
try_result
|
||||
= coerce_borrowed_pointer (receiver, ptr, ptr->mutability ());
|
||||
return !try_result.is_error ();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return !try_result.is_error ();
|
||||
}
|
||||
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver,
|
||||
TyTy::PointerType *expected,
|
||||
Mutability to_mutbl)
|
||||
{
|
||||
rust_debug ("coerce_unsafe_ptr(a={%s}, b={%s})",
|
||||
receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
|
||||
|
||||
Mutability from_mutbl = Mutability::Imm;
|
||||
TyTy::BaseType *element = nullptr;
|
||||
switch (receiver->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::REF: {
|
||||
TyTy::ReferenceType *ref
|
||||
= static_cast<TyTy::ReferenceType *> (receiver);
|
||||
from_mutbl = ref->mutability ();
|
||||
element = ref->get_base ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TyTy::TypeKind::POINTER: {
|
||||
TyTy::PointerType *ref = static_cast<TyTy::PointerType *> (receiver);
|
||||
from_mutbl = ref->mutability ();
|
||||
element = ref->get_base ();
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
if (receiver->can_eq (expected, false))
|
||||
return CoercionResult{{}, expected->clone ()};
|
||||
|
||||
return CoercionResult::get_error ();
|
||||
}
|
||||
}
|
||||
|
||||
if (!coerceable_mutability (from_mutbl, to_mutbl))
|
||||
{
|
||||
Location lhs = mappings->lookup_location (receiver->get_ref ());
|
||||
Location rhs = mappings->lookup_location (expected->get_ref ());
|
||||
mismatched_mutability_error (locus, lhs, rhs);
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
TyTy::PointerType *result
|
||||
= new TyTy::PointerType (receiver->get_ref (),
|
||||
TyTy::TyVar (element->get_ref ()), to_mutbl);
|
||||
if (!result->can_eq (expected, false))
|
||||
return CoercionResult::get_error ();
|
||||
|
||||
return CoercionResult{{}, result};
|
||||
}
|
||||
|
||||
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
|
||||
/// To match `A` with `B`, autoderef will be performed,
|
||||
/// calling `deref`/`deref_mut` where necessary.
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver,
|
||||
TyTy::ReferenceType *expected,
|
||||
Mutability to_mutbl)
|
||||
{
|
||||
rust_debug ("coerce_borrowed_pointer(a={%s}, b={%s})",
|
||||
receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
|
||||
|
||||
Mutability from_mutbl = Mutability::Imm;
|
||||
switch (receiver->get_kind ())
|
||||
{
|
||||
case TyTy::TypeKind::REF: {
|
||||
TyTy::ReferenceType *ref
|
||||
= static_cast<TyTy::ReferenceType *> (receiver);
|
||||
from_mutbl = ref->mutability ();
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
TyTy::BaseType *result = receiver->unify (expected);
|
||||
return CoercionResult{{}, result};
|
||||
}
|
||||
}
|
||||
|
||||
if (!coerceable_mutability (from_mutbl, to_mutbl))
|
||||
{
|
||||
Location lhs = mappings->lookup_location (receiver->get_ref ());
|
||||
Location rhs = mappings->lookup_location (expected->get_ref ());
|
||||
mismatched_mutability_error (locus, lhs, rhs);
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
AutoderefCycle::cycle (receiver);
|
||||
return try_result;
|
||||
}
|
||||
|
||||
// &[T; n] or &mut [T; n] -> &[T]
|
||||
// or &mut [T; n] -> &mut [T]
|
||||
// or &Concrete -> &Trait, etc.
|
||||
TypeCoercionRules::CoercionResult
|
||||
TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
|
||||
TyTy::BaseType *target, bool &unsafe_error)
|
||||
{
|
||||
rust_debug ("coerce_unsized(source={%s}, target={%s})",
|
||||
source->debug_str ().c_str (), target->debug_str ().c_str ());
|
||||
|
||||
bool source_is_ref = source->get_kind () == TyTy::TypeKind::REF;
|
||||
bool target_is_ref = target->get_kind () == TyTy::TypeKind::REF;
|
||||
bool target_is_ptr = target->get_kind () == TyTy::TypeKind::POINTER;
|
||||
|
||||
bool needs_reborrow = false;
|
||||
TyTy::BaseType *ty_a = source;
|
||||
TyTy::BaseType *ty_b = target;
|
||||
Mutability expected_mutability = Mutability::Imm;
|
||||
if (source_is_ref && target_is_ref)
|
||||
{
|
||||
TyTy::ReferenceType *source_ref
|
||||
= static_cast<TyTy::ReferenceType *> (source);
|
||||
TyTy::ReferenceType *target_ref
|
||||
= static_cast<TyTy::ReferenceType *> (target);
|
||||
|
||||
Mutability from_mutbl = source_ref->mutability ();
|
||||
Mutability to_mutbl = target_ref->mutability ();
|
||||
if (!coerceable_mutability (from_mutbl, to_mutbl))
|
||||
{
|
||||
unsafe_error = true;
|
||||
Location lhs = mappings->lookup_location (source->get_ref ());
|
||||
Location rhs = mappings->lookup_location (target->get_ref ());
|
||||
mismatched_mutability_error (locus, lhs, rhs);
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
ty_a = source_ref->get_base ();
|
||||
ty_b = target_ref->get_base ();
|
||||
needs_reborrow = true;
|
||||
expected_mutability = to_mutbl;
|
||||
|
||||
adjustments.push_back (
|
||||
Adjustment (Adjustment::AdjustmentType::INDIRECTION, source_ref, ty_a));
|
||||
}
|
||||
else if (source_is_ref && target_is_ptr)
|
||||
{
|
||||
TyTy::ReferenceType *source_ref
|
||||
= static_cast<TyTy::ReferenceType *> (source);
|
||||
TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> (target);
|
||||
|
||||
Mutability from_mutbl = source_ref->mutability ();
|
||||
Mutability to_mutbl = target_ref->mutability ();
|
||||
if (!coerceable_mutability (from_mutbl, to_mutbl))
|
||||
{
|
||||
unsafe_error = true;
|
||||
Location lhs = mappings->lookup_location (source->get_ref ());
|
||||
Location rhs = mappings->lookup_location (target->get_ref ());
|
||||
mismatched_mutability_error (locus, lhs, rhs);
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
ty_a = source_ref->get_base ();
|
||||
ty_b = target_ref->get_base ();
|
||||
needs_reborrow = true;
|
||||
expected_mutability = to_mutbl;
|
||||
|
||||
adjustments.push_back (
|
||||
Adjustment (Adjustment::AdjustmentType::INDIRECTION, source_ref, ty_a));
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// there is a bunch of code to ensure something is coerce able to a dyn trait
|
||||
// we need to support but we need to support a few more lang items for that
|
||||
// see:
|
||||
// https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L582
|
||||
|
||||
const auto a = ty_a;
|
||||
const auto b = ty_b;
|
||||
|
||||
bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC;
|
||||
bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC;
|
||||
|
||||
if (expect_dyn && need_unsize)
|
||||
{
|
||||
bool bounds_compatible = b->bounds_compatible (*a, locus, true);
|
||||
if (!bounds_compatible)
|
||||
{
|
||||
unsafe_error = true;
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
// return the unsize coercion
|
||||
TyTy::BaseType *result = b->clone ();
|
||||
// result->set_ref (a->get_ref ());
|
||||
|
||||
// append a dyn coercion adjustment
|
||||
adjustments.push_back (Adjustment (Adjustment::UNSIZE, a, result));
|
||||
|
||||
// reborrow if needed
|
||||
if (needs_reborrow)
|
||||
{
|
||||
TyTy::ReferenceType *reborrow
|
||||
= new TyTy::ReferenceType (source->get_ref (),
|
||||
TyTy::TyVar (result->get_ref ()),
|
||||
expected_mutability);
|
||||
|
||||
Adjustment::AdjustmentType borrow_type
|
||||
= expected_mutability == Mutability::Imm ? Adjustment::IMM_REF
|
||||
: Adjustment::MUT_REF;
|
||||
adjustments.push_back (Adjustment (borrow_type, result, reborrow));
|
||||
result = reborrow;
|
||||
}
|
||||
|
||||
return CoercionResult{adjustments, result};
|
||||
}
|
||||
|
||||
adjustments.clear ();
|
||||
return TypeCoercionRules::CoercionResult::get_error ();
|
||||
}
|
||||
|
||||
bool
|
||||
TypeCoercionRules::select (const TyTy::BaseType &autoderefed)
|
||||
{
|
||||
if (autoderefed.can_eq (expected, false))
|
||||
{
|
||||
try_result = CoercionResult{adjustments, autoderefed.clone ()};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Coercing a mutable reference to an immutable works, while
|
||||
/// coercing `&T` to `&mut T` should be forbidden.
|
||||
bool
|
||||
TypeCoercionRules::coerceable_mutability (Mutability from_mutbl,
|
||||
Mutability to_mutbl)
|
||||
{
|
||||
return to_mutbl == Mutability::Imm || (from_mutbl == to_mutbl);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCoercionRules::mismatched_mutability_error (Location expr_locus,
|
||||
Location lhs, Location rhs)
|
||||
{
|
||||
if (!emit_errors)
|
||||
return;
|
||||
|
||||
RichLocation r (expr_locus);
|
||||
r.add_range (lhs);
|
||||
r.add_range (rhs);
|
||||
rust_error_at (r, "mismatched mutability");
|
||||
}
|
||||
|
||||
void
|
||||
TypeCoercionRules::object_unsafe_error (Location expr_locus, Location lhs,
|
||||
Location rhs)
|
||||
{
|
||||
if (!emit_errors)
|
||||
return;
|
||||
|
||||
RichLocation r (expr_locus);
|
||||
r.add_range (lhs);
|
||||
r.add_range (rhs);
|
||||
rust_error_at (r, "unsafe unsize coercion");
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
93
gcc/rust/typecheck/rust-coercion.h
Normal file
93
gcc/rust/typecheck/rust-coercion.h
Normal file
@ -0,0 +1,93 @@
|
||||
// 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_COERCION
|
||||
#define RUST_COERCION
|
||||
|
||||
#include "rust-autoderef.h"
|
||||
#include "rust-hir-type-check.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeCoercionRules : protected AutoderefCycle
|
||||
{
|
||||
public:
|
||||
struct CoercionResult
|
||||
{
|
||||
std::vector<Adjustment> adjustments;
|
||||
TyTy::BaseType *tyty;
|
||||
|
||||
bool is_error ()
|
||||
{
|
||||
return tyty == nullptr || tyty->get_kind () == TyTy::TypeKind::ERROR;
|
||||
}
|
||||
|
||||
static CoercionResult get_error () { return CoercionResult{{}, nullptr}; }
|
||||
};
|
||||
|
||||
static CoercionResult Coerce (TyTy::BaseType *receiver,
|
||||
TyTy::BaseType *expected, Location locus);
|
||||
|
||||
static CoercionResult TryCoerce (TyTy::BaseType *receiver,
|
||||
TyTy::BaseType *expected, Location locus);
|
||||
|
||||
CoercionResult coerce_unsafe_ptr (TyTy::BaseType *receiver,
|
||||
TyTy::PointerType *expected,
|
||||
Mutability mutability);
|
||||
|
||||
CoercionResult coerce_borrowed_pointer (TyTy::BaseType *receiver,
|
||||
TyTy::ReferenceType *expected,
|
||||
Mutability mutability);
|
||||
|
||||
CoercionResult coerce_unsized (TyTy::BaseType *receiver,
|
||||
TyTy::BaseType *expected, bool &unsafe_error);
|
||||
|
||||
static bool coerceable_mutability (Mutability from_mutbl,
|
||||
Mutability to_mutbl);
|
||||
|
||||
void mismatched_mutability_error (Location expr_locus, Location lhs,
|
||||
Location rhs);
|
||||
void object_unsafe_error (Location expr_locus, Location lhs, Location rhs);
|
||||
|
||||
protected:
|
||||
TypeCoercionRules (TyTy::BaseType *expected, Location locus,
|
||||
bool emit_errors);
|
||||
|
||||
bool select (const TyTy::BaseType &autoderefed) override;
|
||||
|
||||
bool do_coercion (TyTy::BaseType *receiver);
|
||||
|
||||
private:
|
||||
// context info
|
||||
Analysis::Mappings *mappings;
|
||||
TypeCheckContext *context;
|
||||
|
||||
// search
|
||||
TyTy::BaseType *expected;
|
||||
Location locus;
|
||||
|
||||
// mutable fields
|
||||
CoercionResult try_result;
|
||||
bool emit_errors;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_COERCION
|
263
gcc/rust/typecheck/rust-hir-dot-operator.cc
Normal file
263
gcc/rust/typecheck/rust-hir-dot-operator.cc
Normal file
@ -0,0 +1,263 @@
|
||||
// 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-dot-operator.h"
|
||||
#include "rust-hir-path-probe.h"
|
||||
#include "rust-hir-trait-resolve.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
MethodResolver::MethodResolver (bool autoderef_flag,
|
||||
const HIR::PathIdentSegment &segment_name)
|
||||
: AutoderefCycle (autoderef_flag), mappings (Analysis::Mappings::get ()),
|
||||
context (TypeCheckContext::get ()), segment_name (segment_name),
|
||||
try_result (MethodCandidate::get_error ())
|
||||
{}
|
||||
|
||||
MethodCandidate
|
||||
MethodResolver::Probe (const TyTy::BaseType *receiver,
|
||||
const HIR::PathIdentSegment &segment_name,
|
||||
bool autoderef_flag)
|
||||
{
|
||||
MethodResolver resolver (autoderef_flag, segment_name);
|
||||
bool ok = resolver.cycle (receiver);
|
||||
return ok ? resolver.try_result : MethodCandidate::get_error ();
|
||||
}
|
||||
|
||||
void
|
||||
MethodResolver::try_hook (const TyTy::BaseType &r)
|
||||
{
|
||||
const auto &specified_bounds = r.get_specified_bounds ();
|
||||
predicate_items = get_predicate_items (segment_name, r, specified_bounds);
|
||||
}
|
||||
|
||||
bool
|
||||
MethodResolver::select (const TyTy::BaseType &receiver)
|
||||
{
|
||||
struct impl_item_candidate
|
||||
{
|
||||
HIR::Function *item;
|
||||
HIR::ImplBlock *impl_block;
|
||||
TyTy::FnType *ty;
|
||||
};
|
||||
|
||||
// assemble inherent impl items
|
||||
std::vector<impl_item_candidate> inherent_impl_fns;
|
||||
mappings->iterate_impl_items (
|
||||
[&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
|
||||
bool is_trait_impl = impl->has_trait_ref ();
|
||||
if (is_trait_impl)
|
||||
return true;
|
||||
|
||||
bool is_fn
|
||||
= item->get_impl_item_type () == HIR::ImplItem::ImplItemType::FUNCTION;
|
||||
if (!is_fn)
|
||||
return true;
|
||||
|
||||
HIR::Function *func = static_cast<HIR::Function *> (item);
|
||||
if (!func->is_method ())
|
||||
return true;
|
||||
|
||||
bool name_matches
|
||||
= func->get_function_name ().compare (segment_name.as_string ()) == 0;
|
||||
if (!name_matches)
|
||||
return true;
|
||||
|
||||
TyTy::BaseType *ty = nullptr;
|
||||
if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
|
||||
return true;
|
||||
if (ty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
return true;
|
||||
|
||||
rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
|
||||
TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
|
||||
|
||||
inherent_impl_fns.push_back ({func, impl, fnty});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
struct trait_item_candidate
|
||||
{
|
||||
const HIR::TraitItemFunc *item;
|
||||
const HIR::Trait *trait;
|
||||
TyTy::FnType *ty;
|
||||
const TraitReference *reference;
|
||||
const TraitItemReference *item_ref;
|
||||
};
|
||||
|
||||
std::vector<trait_item_candidate> trait_fns;
|
||||
mappings->iterate_impl_blocks ([&] (HirId id,
|
||||
HIR::ImplBlock *impl) mutable -> bool {
|
||||
bool is_trait_impl = impl->has_trait_ref ();
|
||||
if (!is_trait_impl)
|
||||
return true;
|
||||
|
||||
// look for impl implementation else lookup the associated trait item
|
||||
for (auto &impl_item : impl->get_impl_items ())
|
||||
{
|
||||
bool is_fn = impl_item->get_impl_item_type ()
|
||||
== HIR::ImplItem::ImplItemType::FUNCTION;
|
||||
if (!is_fn)
|
||||
continue;
|
||||
|
||||
HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ());
|
||||
if (!func->is_method ())
|
||||
continue;
|
||||
|
||||
bool name_matches
|
||||
= func->get_function_name ().compare (segment_name.as_string ()) == 0;
|
||||
if (!name_matches)
|
||||
continue;
|
||||
|
||||
TyTy::BaseType *ty = nullptr;
|
||||
if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
|
||||
continue;
|
||||
if (ty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
continue;
|
||||
|
||||
rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
|
||||
TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
|
||||
|
||||
inherent_impl_fns.push_back ({func, impl, fnty});
|
||||
return true;
|
||||
}
|
||||
|
||||
TraitReference *trait_ref
|
||||
= TraitResolver::Resolve (*impl->get_trait_ref ().get ());
|
||||
rust_assert (!trait_ref->is_error ());
|
||||
|
||||
auto item_ref
|
||||
= trait_ref->lookup_trait_item (segment_name.as_string (),
|
||||
TraitItemReference::TraitItemType::FN);
|
||||
if (item_ref->is_error ())
|
||||
return true;
|
||||
|
||||
const HIR::Trait *trait = trait_ref->get_hir_trait_ref ();
|
||||
HIR::TraitItem *item = item_ref->get_hir_trait_item ();
|
||||
rust_assert (item->get_item_kind () == HIR::TraitItem::TraitItemKind::FUNC);
|
||||
HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item);
|
||||
|
||||
TyTy::BaseType *ty = item_ref->get_tyty ();
|
||||
rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
|
||||
TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
|
||||
|
||||
trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref};
|
||||
trait_fns.push_back (candidate);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// lookup specified bounds for an associated item
|
||||
struct precdicate_candidate
|
||||
{
|
||||
TyTy::TypeBoundPredicateItem lookup;
|
||||
TyTy::FnType *fntype;
|
||||
};
|
||||
|
||||
for (auto impl_item : inherent_impl_fns)
|
||||
{
|
||||
TyTy::FnType *fn = impl_item.ty;
|
||||
rust_assert (fn->is_method ());
|
||||
|
||||
TyTy::BaseType *fn_self = fn->get_self_type ();
|
||||
if (fn_self->can_eq (&receiver, false))
|
||||
{
|
||||
PathProbeCandidate::ImplItemCandidate c{impl_item.item,
|
||||
impl_item.impl_block};
|
||||
try_result = MethodCandidate{
|
||||
PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC,
|
||||
fn, impl_item.item->get_locus (), c),
|
||||
adjustments};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto trait_item : trait_fns)
|
||||
{
|
||||
TyTy::FnType *fn = trait_item.ty;
|
||||
rust_assert (fn->is_method ());
|
||||
|
||||
TyTy::BaseType *fn_self = fn->get_self_type ();
|
||||
if (fn_self->can_eq (&receiver, false))
|
||||
{
|
||||
PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
|
||||
trait_item.item_ref,
|
||||
nullptr};
|
||||
try_result = MethodCandidate{
|
||||
PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
|
||||
fn, trait_item.item->get_locus (), c),
|
||||
adjustments};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &predicate : predicate_items)
|
||||
{
|
||||
const TyTy::FnType *fn = predicate.fntype;
|
||||
rust_assert (fn->is_method ());
|
||||
|
||||
TyTy::BaseType *fn_self = fn->get_self_type ();
|
||||
if (fn_self->can_eq (&receiver, false))
|
||||
{
|
||||
const TraitReference *trait_ref
|
||||
= predicate.lookup.get_parent ()->get ();
|
||||
const TraitItemReference *trait_item
|
||||
= predicate.lookup.get_raw_item ();
|
||||
|
||||
PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
|
||||
nullptr};
|
||||
try_result = MethodCandidate{
|
||||
PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
|
||||
fn->clone (), trait_item->get_locus (), c),
|
||||
adjustments};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<MethodResolver::predicate_candidate>
|
||||
MethodResolver::get_predicate_items (
|
||||
const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
|
||||
const std::vector<TyTy::TypeBoundPredicate> &specified_bounds)
|
||||
{
|
||||
std::vector<predicate_candidate> predicate_items;
|
||||
for (auto &bound : specified_bounds)
|
||||
{
|
||||
TyTy::TypeBoundPredicateItem lookup
|
||||
= bound.lookup_associated_item (segment_name.as_string ());
|
||||
if (lookup.is_error ())
|
||||
continue;
|
||||
|
||||
TyTy::BaseType *ty = lookup.get_tyty_for_receiver (&receiver);
|
||||
if (ty->get_kind () == TyTy::TypeKind::FNDEF)
|
||||
{
|
||||
TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
|
||||
predicate_candidate candidate{lookup, fnty};
|
||||
predicate_items.push_back (candidate);
|
||||
}
|
||||
}
|
||||
|
||||
return predicate_items;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
81
gcc/rust/typecheck/rust-hir-dot-operator.h
Normal file
81
gcc/rust/typecheck/rust-hir-dot-operator.h
Normal file
@ -0,0 +1,81 @@
|
||||
// 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_DOT_OPERATOR
|
||||
#define RUST_HIR_DOT_OPERATOR
|
||||
|
||||
#include "rust-hir-path-probe.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
struct MethodCandidate
|
||||
{
|
||||
PathProbeCandidate candidate;
|
||||
std::vector<Adjustment> adjustments;
|
||||
|
||||
static MethodCandidate get_error ()
|
||||
{
|
||||
return {PathProbeCandidate::get_error (), {}};
|
||||
}
|
||||
|
||||
bool is_error () const { return candidate.is_error (); }
|
||||
};
|
||||
|
||||
class MethodResolver : protected AutoderefCycle
|
||||
{
|
||||
public:
|
||||
struct predicate_candidate
|
||||
{
|
||||
TyTy::TypeBoundPredicateItem lookup;
|
||||
TyTy::FnType *fntype;
|
||||
};
|
||||
|
||||
static MethodCandidate Probe (const TyTy::BaseType *receiver,
|
||||
const HIR::PathIdentSegment &segment_name,
|
||||
bool autoderef_flag = false);
|
||||
|
||||
static std::vector<predicate_candidate> get_predicate_items (
|
||||
const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
|
||||
const std::vector<TyTy::TypeBoundPredicate> &specified_bounds);
|
||||
|
||||
protected:
|
||||
MethodResolver (bool autoderef_flag,
|
||||
const HIR::PathIdentSegment &segment_name);
|
||||
|
||||
void try_hook (const TyTy::BaseType &r) override;
|
||||
|
||||
bool select (const TyTy::BaseType &receiver) override;
|
||||
|
||||
private:
|
||||
// context info
|
||||
Analysis::Mappings *mappings;
|
||||
TypeCheckContext *context;
|
||||
|
||||
// search
|
||||
const HIR::PathIdentSegment &segment_name;
|
||||
std::vector<MethodResolver::predicate_candidate> predicate_items;
|
||||
|
||||
// mutable fields
|
||||
MethodCandidate try_result;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_DOT_OPERATOR
|
186
gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
Normal file
186
gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
Normal file
@ -0,0 +1,186 @@
|
||||
// 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_INHERENT_IMPL_ITEM_OVERLAP_H
|
||||
#define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class ImplItemToName : private TypeCheckBase, private HIR::HIRImplVisitor
|
||||
{
|
||||
public:
|
||||
static bool resolve (HIR::ImplItem *item, std::string &name_result)
|
||||
{
|
||||
ImplItemToName resolver (name_result);
|
||||
item->accept_vis (resolver);
|
||||
return resolver.ok;
|
||||
}
|
||||
|
||||
void visit (HIR::TypeAlias &alias) override
|
||||
{
|
||||
ok = true;
|
||||
result.assign (alias.get_new_type_name ());
|
||||
}
|
||||
|
||||
void visit (HIR::Function &function) override
|
||||
{
|
||||
ok = true;
|
||||
result.assign (function.get_function_name ());
|
||||
}
|
||||
|
||||
void visit (HIR::ConstantItem &constant) override
|
||||
{
|
||||
ok = true;
|
||||
result.assign (constant.get_identifier ());
|
||||
}
|
||||
|
||||
private:
|
||||
ImplItemToName (std::string &result)
|
||||
: TypeCheckBase (), ok (false), result (result)
|
||||
{}
|
||||
|
||||
bool ok;
|
||||
std::string &result;
|
||||
};
|
||||
|
||||
class OverlappingImplItemPass : public TypeCheckBase
|
||||
{
|
||||
public:
|
||||
static void go ()
|
||||
{
|
||||
OverlappingImplItemPass pass;
|
||||
|
||||
// generate mappings
|
||||
pass.mappings->iterate_impl_items (
|
||||
[&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool {
|
||||
// ignoring trait-impls might need thought later on
|
||||
if (impl->has_trait_ref ())
|
||||
return true;
|
||||
|
||||
pass.process_impl_item (id, impl_item, impl);
|
||||
return true;
|
||||
});
|
||||
|
||||
pass.scan ();
|
||||
}
|
||||
|
||||
void process_impl_item (HirId id, HIR::ImplItem *impl_item,
|
||||
HIR::ImplBlock *impl)
|
||||
{
|
||||
// lets make a mapping of impl-item Self type to (impl-item,name):
|
||||
// {
|
||||
// impl-type -> [ (item, name), ... ]
|
||||
// }
|
||||
|
||||
HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid ();
|
||||
TyTy::BaseType *impl_type = nullptr;
|
||||
bool ok = context->lookup_type (impl_type_id, &impl_type);
|
||||
rust_assert (ok);
|
||||
|
||||
std::string impl_item_name;
|
||||
ok = ImplItemToName::resolve (impl_item, impl_item_name);
|
||||
rust_assert (ok);
|
||||
|
||||
std::pair<HIR::ImplItem *, std::string> elem (impl_item, impl_item_name);
|
||||
impl_mappings[impl_type].insert (std::move (elem));
|
||||
}
|
||||
|
||||
void scan ()
|
||||
{
|
||||
// we can now brute force the map looking for can_eq on each of the
|
||||
// impl_items_types to look for possible colliding impl blocks;
|
||||
for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++)
|
||||
{
|
||||
TyTy::BaseType *query = it->first;
|
||||
|
||||
for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
|
||||
{
|
||||
TyTy::BaseType *candidate = iy->first;
|
||||
if (query == candidate)
|
||||
continue;
|
||||
|
||||
if (query->can_eq (candidate, false))
|
||||
{
|
||||
// we might be in the case that we have:
|
||||
//
|
||||
// *const T vs *const [T]
|
||||
//
|
||||
// so lets use an equality check when the
|
||||
// candidates are both generic to be sure we dont emit a false
|
||||
// positive
|
||||
|
||||
bool a = query->is_concrete ();
|
||||
bool b = candidate->is_concrete ();
|
||||
bool both_generic = !a && !b;
|
||||
if (both_generic)
|
||||
{
|
||||
if (!query->is_equal (*candidate))
|
||||
continue;
|
||||
}
|
||||
|
||||
possible_collision (it->second, iy->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void possible_collision (
|
||||
std::set<std::pair<HIR::ImplItem *, std::string> > query,
|
||||
std::set<std::pair<HIR::ImplItem *, std::string> > candidate)
|
||||
{
|
||||
for (auto &q : query)
|
||||
{
|
||||
HIR::ImplItem *query_impl_item = q.first;
|
||||
std::string query_impl_item_name = q.second;
|
||||
|
||||
for (auto &c : candidate)
|
||||
{
|
||||
HIR::ImplItem *candidate_impl_item = c.first;
|
||||
std::string candidate_impl_item_name = c.second;
|
||||
|
||||
if (query_impl_item_name.compare (candidate_impl_item_name) == 0)
|
||||
collision_detected (query_impl_item, candidate_impl_item,
|
||||
candidate_impl_item_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
|
||||
const std::string &name)
|
||||
{
|
||||
RichLocation r (dup->get_locus ());
|
||||
r.add_range (query->get_locus ());
|
||||
rust_error_at (r, "duplicate definitions with name %s", name.c_str ());
|
||||
}
|
||||
|
||||
private:
|
||||
OverlappingImplItemPass () : TypeCheckBase () {}
|
||||
|
||||
std::map<TyTy::BaseType *,
|
||||
std::set<std::pair<HIR::ImplItem *, std::string> > >
|
||||
impl_mappings;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
|
540
gcc/rust/typecheck/rust-hir-path-probe.h
Normal file
540
gcc/rust/typecheck/rust-hir-path-probe.h
Normal file
@ -0,0 +1,540 @@
|
||||
// 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_PATH_PROBE_H
|
||||
#define RUST_HIR_PATH_PROBE_H
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-tyty.h"
|
||||
#include "rust-substitution-mapper.h"
|
||||
#include "rust-hir-type-bounds.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
struct PathProbeCandidate
|
||||
{
|
||||
enum CandidateType
|
||||
{
|
||||
ERROR,
|
||||
|
||||
ENUM_VARIANT,
|
||||
|
||||
IMPL_CONST,
|
||||
IMPL_TYPE_ALIAS,
|
||||
IMPL_FUNC,
|
||||
|
||||
TRAIT_ITEM_CONST,
|
||||
TRAIT_TYPE_ALIAS,
|
||||
TRAIT_FUNC,
|
||||
};
|
||||
|
||||
struct EnumItemCandidate
|
||||
{
|
||||
const TyTy::ADTType *parent;
|
||||
const TyTy::VariantDef *variant;
|
||||
};
|
||||
|
||||
struct ImplItemCandidate
|
||||
{
|
||||
HIR::ImplItem *impl_item;
|
||||
HIR::ImplBlock *parent;
|
||||
};
|
||||
|
||||
struct TraitItemCandidate
|
||||
{
|
||||
const TraitReference *trait_ref;
|
||||
const TraitItemReference *item_ref;
|
||||
HIR::ImplBlock *impl;
|
||||
};
|
||||
|
||||
CandidateType type;
|
||||
TyTy::BaseType *ty;
|
||||
Location locus;
|
||||
union Candidate
|
||||
{
|
||||
EnumItemCandidate enum_field;
|
||||
ImplItemCandidate impl;
|
||||
TraitItemCandidate trait;
|
||||
|
||||
Candidate (EnumItemCandidate enum_field) : enum_field (enum_field) {}
|
||||
Candidate (ImplItemCandidate impl) : impl (impl) {}
|
||||
Candidate (TraitItemCandidate trait) : trait (trait) {}
|
||||
} item;
|
||||
|
||||
PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus,
|
||||
EnumItemCandidate enum_field)
|
||||
: type (type), ty (ty), item (enum_field)
|
||||
{}
|
||||
|
||||
PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus,
|
||||
ImplItemCandidate impl)
|
||||
: type (type), ty (ty), item (impl)
|
||||
{}
|
||||
|
||||
PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus,
|
||||
TraitItemCandidate trait)
|
||||
: type (type), ty (ty), item (trait)
|
||||
{}
|
||||
|
||||
std::string as_string () const
|
||||
{
|
||||
return "PathProbe candidate TODO - as_string";
|
||||
}
|
||||
|
||||
bool is_enum_candidate () const { return type == ENUM_VARIANT; }
|
||||
|
||||
bool is_impl_candidate () const
|
||||
{
|
||||
return type == IMPL_CONST || type == IMPL_TYPE_ALIAS || type == IMPL_FUNC;
|
||||
}
|
||||
|
||||
bool is_trait_candidate () const
|
||||
{
|
||||
return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS
|
||||
|| type == TRAIT_FUNC;
|
||||
}
|
||||
|
||||
bool is_full_trait_item_candidate () const
|
||||
{
|
||||
return is_trait_candidate () && item.trait.impl == nullptr;
|
||||
}
|
||||
|
||||
static PathProbeCandidate get_error ()
|
||||
{
|
||||
return PathProbeCandidate (ERROR, nullptr, Location (),
|
||||
ImplItemCandidate{nullptr, nullptr});
|
||||
}
|
||||
|
||||
bool is_error () const { return type == ERROR; }
|
||||
};
|
||||
|
||||
class PathProbeType : public TypeCheckBase, public HIR::HIRImplVisitor
|
||||
{
|
||||
public:
|
||||
static std::vector<PathProbeCandidate>
|
||||
Probe (const TyTy::BaseType *receiver,
|
||||
const HIR::PathIdentSegment &segment_name, bool probe_impls,
|
||||
bool probe_bounds, bool ignore_mandatory_trait_items,
|
||||
DefId specific_trait_id = UNKNOWN_DEFID)
|
||||
{
|
||||
PathProbeType probe (receiver, segment_name, specific_trait_id);
|
||||
if (probe_impls)
|
||||
{
|
||||
if (receiver->get_kind () == TyTy::TypeKind::ADT)
|
||||
{
|
||||
const TyTy::ADTType *adt
|
||||
= static_cast<const TyTy::ADTType *> (receiver);
|
||||
if (adt->is_enum ())
|
||||
probe.process_enum_item_for_candiates (adt);
|
||||
}
|
||||
|
||||
probe.process_impl_items_for_candidates ();
|
||||
}
|
||||
|
||||
if (!probe_bounds)
|
||||
return probe.candidates;
|
||||
|
||||
if (!probe.is_reciever_generic ())
|
||||
{
|
||||
std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds
|
||||
= TypeBoundsProbe::Probe (receiver);
|
||||
for (auto &candidate : probed_bounds)
|
||||
{
|
||||
const TraitReference *trait_ref = candidate.first;
|
||||
if (specific_trait_id != UNKNOWN_DEFID)
|
||||
{
|
||||
if (trait_ref->get_mappings ().get_defid ()
|
||||
!= specific_trait_id)
|
||||
continue;
|
||||
}
|
||||
|
||||
HIR::ImplBlock *impl = candidate.second;
|
||||
probe.process_associated_trait_for_candidates (
|
||||
trait_ref, impl, ignore_mandatory_trait_items);
|
||||
}
|
||||
}
|
||||
|
||||
for (const TyTy::TypeBoundPredicate &predicate :
|
||||
receiver->get_specified_bounds ())
|
||||
{
|
||||
const TraitReference *trait_ref = predicate.get ();
|
||||
if (specific_trait_id != UNKNOWN_DEFID)
|
||||
{
|
||||
if (trait_ref->get_mappings ().get_defid () != specific_trait_id)
|
||||
continue;
|
||||
}
|
||||
|
||||
probe.process_predicate_for_candidates (predicate,
|
||||
ignore_mandatory_trait_items);
|
||||
}
|
||||
|
||||
return probe.candidates;
|
||||
}
|
||||
|
||||
void visit (HIR::TypeAlias &alias) override
|
||||
{
|
||||
Identifier name = alias.get_new_type_name ();
|
||||
if (search.as_string ().compare (name) == 0)
|
||||
{
|
||||
HirId tyid = alias.get_mappings ().get_hirid ();
|
||||
TyTy::BaseType *ty = nullptr;
|
||||
bool ok = context->lookup_type (tyid, &ty);
|
||||
rust_assert (ok);
|
||||
|
||||
PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias,
|
||||
current_impl};
|
||||
PathProbeCandidate candidate{
|
||||
PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, ty,
|
||||
alias.get_locus (), impl_item_candidate};
|
||||
candidates.push_back (std::move (candidate));
|
||||
}
|
||||
}
|
||||
|
||||
void visit (HIR::ConstantItem &constant) override
|
||||
{
|
||||
Identifier name = constant.get_identifier ();
|
||||
if (search.as_string ().compare (name) == 0)
|
||||
{
|
||||
HirId tyid = constant.get_mappings ().get_hirid ();
|
||||
TyTy::BaseType *ty = nullptr;
|
||||
bool ok = context->lookup_type (tyid, &ty);
|
||||
rust_assert (ok);
|
||||
|
||||
PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant,
|
||||
current_impl};
|
||||
PathProbeCandidate candidate{
|
||||
PathProbeCandidate::CandidateType::IMPL_CONST, ty,
|
||||
constant.get_locus (), impl_item_candidate};
|
||||
candidates.push_back (std::move (candidate));
|
||||
}
|
||||
}
|
||||
|
||||
void visit (HIR::Function &function) override
|
||||
{
|
||||
Identifier name = function.get_function_name ();
|
||||
if (search.as_string ().compare (name) == 0)
|
||||
{
|
||||
HirId tyid = function.get_mappings ().get_hirid ();
|
||||
TyTy::BaseType *ty = nullptr;
|
||||
bool ok = context->lookup_type (tyid, &ty);
|
||||
rust_assert (ok);
|
||||
|
||||
PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function,
|
||||
current_impl};
|
||||
PathProbeCandidate candidate{
|
||||
PathProbeCandidate::CandidateType::IMPL_FUNC, ty,
|
||||
function.get_locus (), impl_item_candidate};
|
||||
candidates.push_back (std::move (candidate));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void process_enum_item_for_candiates (const TyTy::ADTType *adt)
|
||||
{
|
||||
if (specific_trait_id != UNKNOWN_DEFID)
|
||||
return;
|
||||
|
||||
TyTy::VariantDef *v;
|
||||
if (!adt->lookup_variant (search.as_string (), &v))
|
||||
return;
|
||||
|
||||
PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v};
|
||||
PathProbeCandidate candidate{
|
||||
PathProbeCandidate::CandidateType::ENUM_VARIANT, receiver->clone (),
|
||||
mappings->lookup_location (adt->get_ty_ref ()), enum_item_candidate};
|
||||
candidates.push_back (std::move (candidate));
|
||||
}
|
||||
|
||||
void process_impl_items_for_candidates ()
|
||||
{
|
||||
mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item,
|
||||
HIR::ImplBlock *impl) mutable -> bool {
|
||||
process_impl_item_candidate (id, item, impl);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void process_impl_item_candidate (HirId id, HIR::ImplItem *item,
|
||||
HIR::ImplBlock *impl)
|
||||
{
|
||||
current_impl = impl;
|
||||
HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid ();
|
||||
TyTy::BaseType *impl_block_ty = nullptr;
|
||||
if (!context->lookup_type (impl_ty_id, &impl_block_ty))
|
||||
return;
|
||||
|
||||
if (!receiver->can_eq (impl_block_ty, false))
|
||||
{
|
||||
if (!impl_block_ty->can_eq (receiver, false))
|
||||
return;
|
||||
}
|
||||
|
||||
// lets visit the impl_item
|
||||
item->accept_vis (*this);
|
||||
}
|
||||
|
||||
void
|
||||
process_associated_trait_for_candidates (const TraitReference *trait_ref,
|
||||
HIR::ImplBlock *impl,
|
||||
bool ignore_mandatory_trait_items)
|
||||
{
|
||||
const TraitItemReference *trait_item_ref = nullptr;
|
||||
if (!trait_ref->lookup_trait_item (search.as_string (), &trait_item_ref))
|
||||
return;
|
||||
|
||||
bool trait_item_needs_implementation = !trait_item_ref->is_optional ();
|
||||
if (ignore_mandatory_trait_items && trait_item_needs_implementation)
|
||||
return;
|
||||
|
||||
PathProbeCandidate::CandidateType candidate_type;
|
||||
switch (trait_item_ref->get_trait_item_type ())
|
||||
{
|
||||
case TraitItemReference::TraitItemType::FN:
|
||||
candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
|
||||
break;
|
||||
case TraitItemReference::TraitItemType::CONST:
|
||||
candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
|
||||
break;
|
||||
case TraitItemReference::TraitItemType::TYPE:
|
||||
candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
|
||||
break;
|
||||
|
||||
case TraitItemReference::TraitItemType::ERROR:
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
break;
|
||||
}
|
||||
|
||||
TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty ();
|
||||
|
||||
// we can substitute the Self with the receiver here
|
||||
if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF)
|
||||
{
|
||||
TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty);
|
||||
TyTy::SubstitutionParamMapping *param = nullptr;
|
||||
for (auto ¶m_mapping : fn->get_substs ())
|
||||
{
|
||||
const HIR::TypeParam &type_param
|
||||
= param_mapping.get_generic_param ();
|
||||
if (type_param.get_type_representation ().compare ("Self") == 0)
|
||||
{
|
||||
param = ¶m_mapping;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rust_assert (param != nullptr);
|
||||
|
||||
std::vector<TyTy::SubstitutionArg> mappings;
|
||||
mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ()));
|
||||
|
||||
Location locus; // FIXME
|
||||
TyTy::SubstitutionArgumentMappings args (std::move (mappings), locus);
|
||||
trait_item_tyty = SubstMapperInternal::Resolve (trait_item_tyty, args);
|
||||
}
|
||||
|
||||
PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
|
||||
trait_item_ref,
|
||||
impl};
|
||||
|
||||
PathProbeCandidate candidate{candidate_type, trait_item_tyty,
|
||||
trait_ref->get_locus (), trait_item_candidate};
|
||||
candidates.push_back (std::move (candidate));
|
||||
}
|
||||
|
||||
void
|
||||
process_predicate_for_candidates (const TyTy::TypeBoundPredicate &predicate,
|
||||
bool ignore_mandatory_trait_items)
|
||||
{
|
||||
const TraitReference *trait_ref = predicate.get ();
|
||||
|
||||
TyTy::TypeBoundPredicateItem item
|
||||
= predicate.lookup_associated_item (search.as_string ());
|
||||
if (item.is_error ())
|
||||
return;
|
||||
|
||||
if (ignore_mandatory_trait_items && item.needs_implementation ())
|
||||
return;
|
||||
|
||||
const TraitItemReference *trait_item_ref = item.get_raw_item ();
|
||||
PathProbeCandidate::CandidateType candidate_type;
|
||||
switch (trait_item_ref->get_trait_item_type ())
|
||||
{
|
||||
case TraitItemReference::TraitItemType::FN:
|
||||
candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
|
||||
break;
|
||||
case TraitItemReference::TraitItemType::CONST:
|
||||
candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
|
||||
break;
|
||||
case TraitItemReference::TraitItemType::TYPE:
|
||||
candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
|
||||
break;
|
||||
|
||||
case TraitItemReference::TraitItemType::ERROR:
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
break;
|
||||
}
|
||||
|
||||
TyTy::BaseType *trait_item_tyty = item.get_tyty_for_receiver (receiver);
|
||||
PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
|
||||
trait_item_ref,
|
||||
nullptr};
|
||||
PathProbeCandidate candidate{candidate_type, trait_item_tyty,
|
||||
trait_item_ref->get_locus (),
|
||||
trait_item_candidate};
|
||||
candidates.push_back (std::move (candidate));
|
||||
}
|
||||
|
||||
protected:
|
||||
PathProbeType (const TyTy::BaseType *receiver,
|
||||
const HIR::PathIdentSegment &query, DefId specific_trait_id)
|
||||
: TypeCheckBase (), receiver (receiver), search (query),
|
||||
current_impl (nullptr), specific_trait_id (specific_trait_id)
|
||||
{}
|
||||
|
||||
std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>>
|
||||
union_bounds (
|
||||
const std::vector<std::pair</*const*/ TraitReference *, HIR::ImplBlock *>>
|
||||
a,
|
||||
const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> b)
|
||||
const
|
||||
{
|
||||
std::map<DefId, std::pair<const TraitReference *, HIR::ImplBlock *>> mapper;
|
||||
for (auto &ref : a)
|
||||
{
|
||||
mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
|
||||
}
|
||||
for (auto &ref : b)
|
||||
{
|
||||
mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
|
||||
}
|
||||
|
||||
std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_set;
|
||||
for (auto it = mapper.begin (); it != mapper.end (); it++)
|
||||
{
|
||||
union_set.push_back ({it->second.first, it->second.second});
|
||||
}
|
||||
return union_set;
|
||||
}
|
||||
|
||||
bool is_reciever_generic () const
|
||||
{
|
||||
const TyTy::BaseType *root = receiver->get_root ();
|
||||
bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
|
||||
bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
|
||||
return receiver_is_type_param || receiver_is_dyn;
|
||||
}
|
||||
|
||||
const TyTy::BaseType *receiver;
|
||||
const HIR::PathIdentSegment &search;
|
||||
std::vector<PathProbeCandidate> candidates;
|
||||
HIR::ImplBlock *current_impl;
|
||||
DefId specific_trait_id;
|
||||
};
|
||||
|
||||
class ReportMultipleCandidateError : private TypeCheckBase,
|
||||
private HIR::HIRImplVisitor
|
||||
{
|
||||
public:
|
||||
static void Report (std::vector<PathProbeCandidate> &candidates,
|
||||
const HIR::PathIdentSegment &query, Location query_locus)
|
||||
{
|
||||
RichLocation r (query_locus);
|
||||
ReportMultipleCandidateError visitor (r);
|
||||
for (auto &c : candidates)
|
||||
{
|
||||
switch (c.type)
|
||||
{
|
||||
case PathProbeCandidate::CandidateType::ERROR:
|
||||
case PathProbeCandidate::CandidateType::ENUM_VARIANT:
|
||||
gcc_unreachable ();
|
||||
break;
|
||||
|
||||
case PathProbeCandidate::CandidateType::IMPL_CONST:
|
||||
case PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS:
|
||||
case PathProbeCandidate::CandidateType::IMPL_FUNC:
|
||||
c.item.impl.impl_item->accept_vis (visitor);
|
||||
break;
|
||||
|
||||
case PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST:
|
||||
case PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS:
|
||||
case PathProbeCandidate::CandidateType::TRAIT_FUNC:
|
||||
r.add_range (c.item.trait.item_ref->get_locus ());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rust_error_at (r, "multiple applicable items in scope for: %s",
|
||||
query.as_string ().c_str ());
|
||||
}
|
||||
|
||||
void visit (HIR::TypeAlias &alias) override
|
||||
{
|
||||
r.add_range (alias.get_locus ());
|
||||
}
|
||||
|
||||
void visit (HIR::ConstantItem &constant) override
|
||||
{
|
||||
r.add_range (constant.get_locus ());
|
||||
}
|
||||
|
||||
void visit (HIR::Function &function) override
|
||||
{
|
||||
r.add_range (function.get_locus ());
|
||||
}
|
||||
|
||||
private:
|
||||
ReportMultipleCandidateError (RichLocation &r) : TypeCheckBase (), r (r) {}
|
||||
|
||||
RichLocation &r;
|
||||
};
|
||||
|
||||
class PathProbeImplTrait : public PathProbeType
|
||||
{
|
||||
public:
|
||||
static std::vector<PathProbeCandidate>
|
||||
Probe (const TyTy::BaseType *receiver,
|
||||
const HIR::PathIdentSegment &segment_name,
|
||||
const TraitReference *trait_reference)
|
||||
{
|
||||
PathProbeImplTrait probe (receiver, segment_name, trait_reference);
|
||||
// iterate all impls for this trait and receiver
|
||||
// then search for possible candidates using base class behaviours
|
||||
probe.process_trait_impl_items_for_candidates ();
|
||||
return probe.candidates;
|
||||
}
|
||||
|
||||
private:
|
||||
void process_trait_impl_items_for_candidates ();
|
||||
|
||||
PathProbeImplTrait (const TyTy::BaseType *receiver,
|
||||
const HIR::PathIdentSegment &query,
|
||||
const TraitReference *trait_reference)
|
||||
: PathProbeType (receiver, query, UNKNOWN_DEFID),
|
||||
trait_reference (trait_reference)
|
||||
{}
|
||||
|
||||
const TraitReference *trait_reference;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_PATH_PROBE_H
|
472
gcc/rust/typecheck/rust-hir-trait-ref.h
Normal file
472
gcc/rust/typecheck/rust-hir-trait-ref.h
Normal file
@ -0,0 +1,472 @@
|
||||
// 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_REF_H
|
||||
#define RUST_HIR_TRAIT_REF_H
|
||||
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-tyty-visitor.h"
|
||||
#include "rust-hir-type-check-util.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
// Data Objects for the associated trait items in a structure we can work with
|
||||
// https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/associated-constants.html
|
||||
class TypeCheckContext;
|
||||
class TraitItemReference
|
||||
{
|
||||
public:
|
||||
enum TraitItemType
|
||||
{
|
||||
FN,
|
||||
CONST,
|
||||
TYPE,
|
||||
ERROR
|
||||
};
|
||||
|
||||
TraitItemReference (std::string identifier, bool optional, TraitItemType type,
|
||||
HIR::TraitItem *hir_trait_item, TyTy::BaseType *self,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substitutions,
|
||||
Location locus);
|
||||
|
||||
TraitItemReference (TraitItemReference const &other);
|
||||
|
||||
TraitItemReference &operator= (TraitItemReference const &other);
|
||||
|
||||
static TraitItemReference error ()
|
||||
{
|
||||
return TraitItemReference ("", false, ERROR, nullptr, nullptr, {},
|
||||
Location ());
|
||||
}
|
||||
|
||||
static TraitItemReference &error_node ()
|
||||
{
|
||||
static TraitItemReference error = TraitItemReference::error ();
|
||||
return error;
|
||||
}
|
||||
|
||||
bool is_error () const { return type == ERROR; }
|
||||
|
||||
std::string as_string () const
|
||||
{
|
||||
return "(" + trait_item_type_as_string (type) + " " + identifier + " "
|
||||
+ ")";
|
||||
}
|
||||
|
||||
static std::string trait_item_type_as_string (TraitItemType ty)
|
||||
{
|
||||
switch (ty)
|
||||
{
|
||||
case FN:
|
||||
return "FN";
|
||||
case CONST:
|
||||
return "CONST";
|
||||
case TYPE:
|
||||
return "TYPE";
|
||||
case ERROR:
|
||||
return "ERROR";
|
||||
}
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
bool is_optional () const { return optional_flag; }
|
||||
|
||||
std::string get_identifier () const { return identifier; }
|
||||
|
||||
TraitItemType get_trait_item_type () const { return type; }
|
||||
|
||||
HIR::TraitItem *get_hir_trait_item () const { return hir_trait_item; }
|
||||
|
||||
Location get_locus () const { return locus; }
|
||||
|
||||
const Analysis::NodeMapping get_mappings () const
|
||||
{
|
||||
return hir_trait_item->get_mappings ();
|
||||
}
|
||||
|
||||
TyTy::BaseType *get_tyty () const
|
||||
{
|
||||
rust_assert (hir_trait_item != nullptr);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CONST:
|
||||
return get_type_from_constant (
|
||||
static_cast</*const*/ HIR::TraitItemConst &> (*hir_trait_item));
|
||||
break;
|
||||
|
||||
case TYPE:
|
||||
return get_type_from_typealias (
|
||||
static_cast</*const*/ HIR::TraitItemType &> (*hir_trait_item));
|
||||
|
||||
case FN:
|
||||
return get_type_from_fn (
|
||||
static_cast</*const*/ HIR::TraitItemFunc &> (*hir_trait_item));
|
||||
break;
|
||||
|
||||
default:
|
||||
return get_error ();
|
||||
}
|
||||
|
||||
gcc_unreachable ();
|
||||
return get_error ();
|
||||
}
|
||||
|
||||
Analysis::NodeMapping get_parent_trait_mappings () const;
|
||||
|
||||
// this is called when the trait is completed resolution and gives the items a
|
||||
// chance to run their specific type resolution passes. If we call their
|
||||
// resolution on construction it can lead to a case where the trait being
|
||||
// resolved recursively trying to resolve the trait itself infinitely since
|
||||
// the trait will not be stored in its own map yet
|
||||
void on_resolved ();
|
||||
|
||||
void associated_type_set (TyTy::BaseType *ty) const;
|
||||
|
||||
void associated_type_reset () const;
|
||||
|
||||
bool is_object_safe () const;
|
||||
|
||||
private:
|
||||
TyTy::ErrorType *get_error () const
|
||||
{
|
||||
return new TyTy::ErrorType (get_mappings ().get_hirid ());
|
||||
}
|
||||
|
||||
TyTy::BaseType *get_type_from_typealias (/*const*/
|
||||
HIR::TraitItemType &type) const;
|
||||
|
||||
TyTy::BaseType *
|
||||
get_type_from_constant (/*const*/ HIR::TraitItemConst &constant) const;
|
||||
|
||||
TyTy::BaseType *get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const;
|
||||
|
||||
bool is_item_resolved () const;
|
||||
void resolve_item (HIR::TraitItemType &type);
|
||||
void resolve_item (HIR::TraitItemConst &constant);
|
||||
void resolve_item (HIR::TraitItemFunc &func);
|
||||
|
||||
std::string identifier;
|
||||
bool optional_flag;
|
||||
TraitItemType type;
|
||||
HIR::TraitItem *hir_trait_item;
|
||||
std::vector<TyTy::SubstitutionParamMapping> inherited_substitutions;
|
||||
Location locus;
|
||||
|
||||
TyTy::BaseType
|
||||
*self; // this is the implict Self TypeParam required for methods
|
||||
Resolver::TypeCheckContext *context;
|
||||
};
|
||||
|
||||
// this wraps up the HIR::Trait so we can do analysis on it
|
||||
|
||||
class TraitReference
|
||||
{
|
||||
public:
|
||||
TraitReference (const HIR::Trait *hir_trait_ref,
|
||||
std::vector<TraitItemReference> item_refs,
|
||||
std::vector<const TraitReference *> super_traits,
|
||||
std::vector<TyTy::SubstitutionParamMapping> substs)
|
||||
: hir_trait_ref (hir_trait_ref), item_refs (item_refs),
|
||||
super_traits (super_traits)
|
||||
{
|
||||
trait_substs.clear ();
|
||||
trait_substs.reserve (substs.size ());
|
||||
for (const auto &p : substs)
|
||||
trait_substs.push_back (p.clone ());
|
||||
}
|
||||
|
||||
TraitReference (TraitReference const &other)
|
||||
: hir_trait_ref (other.hir_trait_ref), item_refs (other.item_refs),
|
||||
super_traits (other.super_traits)
|
||||
{
|
||||
trait_substs.clear ();
|
||||
trait_substs.reserve (other.trait_substs.size ());
|
||||
for (const auto &p : other.trait_substs)
|
||||
trait_substs.push_back (p.clone ());
|
||||
}
|
||||
|
||||
TraitReference &operator= (TraitReference const &other)
|
||||
{
|
||||
hir_trait_ref = other.hir_trait_ref;
|
||||
item_refs = other.item_refs;
|
||||
super_traits = other.super_traits;
|
||||
|
||||
trait_substs.clear ();
|
||||
trait_substs.reserve (other.trait_substs.size ());
|
||||
for (const auto &p : other.trait_substs)
|
||||
trait_substs.push_back (p.clone ());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TraitReference (TraitReference &&other) = default;
|
||||
TraitReference &operator= (TraitReference &&other) = default;
|
||||
|
||||
static TraitReference error ()
|
||||
{
|
||||
return TraitReference (nullptr, {}, {}, {});
|
||||
}
|
||||
|
||||
bool is_error () const { return hir_trait_ref == nullptr; }
|
||||
|
||||
static TraitReference &error_node ()
|
||||
{
|
||||
static TraitReference trait_error_node = TraitReference::error ();
|
||||
return trait_error_node;
|
||||
}
|
||||
|
||||
Location get_locus () const { return hir_trait_ref->get_locus (); }
|
||||
|
||||
std::string get_name () const
|
||||
{
|
||||
rust_assert (!is_error ());
|
||||
return hir_trait_ref->get_name ();
|
||||
}
|
||||
|
||||
std::string as_string () const
|
||||
{
|
||||
if (is_error ())
|
||||
return "<trait-ref-error-node>";
|
||||
|
||||
std::string item_buf;
|
||||
for (auto &item : item_refs)
|
||||
{
|
||||
item_buf += item.as_string () + ", ";
|
||||
}
|
||||
return "HIR Trait: " + get_name () + "->"
|
||||
+ hir_trait_ref->get_mappings ().as_string () + " [" + item_buf
|
||||
+ "]";
|
||||
}
|
||||
|
||||
const HIR::Trait *get_hir_trait_ref () const { return hir_trait_ref; }
|
||||
|
||||
const Analysis::NodeMapping &get_mappings () const
|
||||
{
|
||||
return hir_trait_ref->get_mappings ();
|
||||
}
|
||||
|
||||
DefId get_defid () const { return get_mappings ().get_defid (); }
|
||||
|
||||
bool lookup_hir_trait_item (const HIR::TraitItem &item,
|
||||
TraitItemReference **ref)
|
||||
{
|
||||
return lookup_trait_item (item.trait_identifier (), ref);
|
||||
}
|
||||
|
||||
bool lookup_trait_item (const std::string &ident, TraitItemReference **ref)
|
||||
{
|
||||
for (auto &item : item_refs)
|
||||
{
|
||||
if (ident.compare (item.get_identifier ()) == 0)
|
||||
{
|
||||
*ref = &item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lookup_trait_item_by_type (const std::string &ident,
|
||||
TraitItemReference::TraitItemType type,
|
||||
TraitItemReference **ref)
|
||||
{
|
||||
for (auto &item : item_refs)
|
||||
{
|
||||
if (item.get_trait_item_type () != type)
|
||||
continue;
|
||||
|
||||
if (ident.compare (item.get_identifier ()) == 0)
|
||||
{
|
||||
*ref = &item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lookup_trait_item_by_type (const std::string &ident,
|
||||
TraitItemReference::TraitItemType type,
|
||||
const TraitItemReference **ref) const
|
||||
{
|
||||
for (auto &item : item_refs)
|
||||
{
|
||||
if (item.get_trait_item_type () != type)
|
||||
continue;
|
||||
|
||||
if (ident.compare (item.get_identifier ()) == 0)
|
||||
{
|
||||
*ref = &item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lookup_hir_trait_item (const HIR::TraitItem &item,
|
||||
const TraitItemReference **ref) const
|
||||
{
|
||||
return lookup_trait_item (item.trait_identifier (), ref);
|
||||
}
|
||||
|
||||
bool lookup_trait_item (const std::string &ident,
|
||||
const TraitItemReference **ref) const
|
||||
{
|
||||
for (auto &item : item_refs)
|
||||
{
|
||||
if (ident.compare (item.get_identifier ()) == 0)
|
||||
{
|
||||
*ref = &item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const TraitItemReference *
|
||||
lookup_trait_item (const std::string &ident,
|
||||
TraitItemReference::TraitItemType type) const
|
||||
{
|
||||
for (auto &item : item_refs)
|
||||
{
|
||||
if (item.get_trait_item_type () != type)
|
||||
continue;
|
||||
|
||||
if (ident.compare (item.get_identifier ()) == 0)
|
||||
return &item;
|
||||
}
|
||||
return &TraitItemReference::error_node ();
|
||||
}
|
||||
|
||||
size_t size () const { return item_refs.size (); }
|
||||
|
||||
const std::vector<TraitItemReference> &get_trait_items () const
|
||||
{
|
||||
return item_refs;
|
||||
}
|
||||
|
||||
void on_resolved ()
|
||||
{
|
||||
for (auto &item : item_refs)
|
||||
{
|
||||
item.on_resolved ();
|
||||
}
|
||||
}
|
||||
|
||||
void clear_associated_types ()
|
||||
{
|
||||
for (auto &item : item_refs)
|
||||
{
|
||||
bool is_assoc_type = item.get_trait_item_type ()
|
||||
== TraitItemReference::TraitItemType::TYPE;
|
||||
if (is_assoc_type)
|
||||
item.associated_type_reset ();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_equal (const TraitReference &other) const
|
||||
{
|
||||
DefId this_id = get_mappings ().get_defid ();
|
||||
DefId other_id = other.get_mappings ().get_defid ();
|
||||
return this_id == other_id;
|
||||
}
|
||||
|
||||
const std::vector<const TraitReference *> get_super_traits () const
|
||||
{
|
||||
return super_traits;
|
||||
}
|
||||
|
||||
bool is_object_safe (bool emit_error, Location locus) const
|
||||
{
|
||||
// https: // doc.rust-lang.org/reference/items/traits.html#object-safety
|
||||
std::vector<const TraitReference *> non_object_super_traits;
|
||||
for (auto &item : super_traits)
|
||||
{
|
||||
if (!item->is_object_safe (false, Location ()))
|
||||
non_object_super_traits.push_back (item);
|
||||
}
|
||||
|
||||
std::vector<const Resolver::TraitItemReference *> non_object_safe_items;
|
||||
for (auto &item : get_trait_items ())
|
||||
{
|
||||
if (!item.is_object_safe ())
|
||||
non_object_safe_items.push_back (&item);
|
||||
}
|
||||
|
||||
bool is_safe
|
||||
= non_object_super_traits.empty () && non_object_safe_items.empty ();
|
||||
if (emit_error && !is_safe)
|
||||
{
|
||||
RichLocation r (locus);
|
||||
for (auto &item : non_object_super_traits)
|
||||
r.add_range (item->get_locus ());
|
||||
for (auto &item : non_object_safe_items)
|
||||
r.add_range (item->get_locus ());
|
||||
|
||||
rust_error_at (r, "trait bound is not object safe");
|
||||
}
|
||||
|
||||
return is_safe;
|
||||
}
|
||||
|
||||
bool trait_has_generics () const { return !trait_substs.empty (); }
|
||||
|
||||
std::vector<TyTy::SubstitutionParamMapping> get_trait_substs () const
|
||||
{
|
||||
return trait_substs;
|
||||
}
|
||||
|
||||
private:
|
||||
const HIR::Trait *hir_trait_ref;
|
||||
std::vector<TraitItemReference> item_refs;
|
||||
std::vector<const TraitReference *> super_traits;
|
||||
std::vector<TyTy::SubstitutionParamMapping> trait_substs;
|
||||
};
|
||||
|
||||
class AssociatedImplTrait
|
||||
{
|
||||
public:
|
||||
AssociatedImplTrait (TraitReference *trait, HIR::ImplBlock *impl,
|
||||
TyTy::BaseType *self,
|
||||
Resolver::TypeCheckContext *context)
|
||||
: trait (trait), impl (impl), self (self), context (context)
|
||||
{}
|
||||
|
||||
TraitReference *get_trait () { return trait; }
|
||||
|
||||
HIR::ImplBlock *get_impl_block () { return impl; }
|
||||
|
||||
TyTy::BaseType *get_self () { return self; }
|
||||
|
||||
void setup_associated_types (const TyTy::BaseType *self,
|
||||
const TyTy::TypeBoundPredicate &bound);
|
||||
|
||||
void reset_associated_types ();
|
||||
|
||||
private:
|
||||
TraitReference *trait;
|
||||
HIR::ImplBlock *impl;
|
||||
TyTy::BaseType *self;
|
||||
Resolver::TypeCheckContext *context;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TRAIT_REF_H
|
77
gcc/rust/typecheck/rust-hir-type-bounds.h
Normal file
77
gcc/rust/typecheck/rust-hir-type-bounds.h
Normal file
@ -0,0 +1,77 @@
|
||||
// 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_BOUNDS_H
|
||||
#define RUST_HIR_TYPE_BOUNDS_H
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-tyty.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeBoundsProbe : public TypeCheckBase
|
||||
{
|
||||
public:
|
||||
static std::vector<std::pair<TraitReference *, HIR::ImplBlock *>>
|
||||
Probe (const TyTy::BaseType *receiver)
|
||||
{
|
||||
TypeBoundsProbe probe (receiver);
|
||||
probe.scan ();
|
||||
return probe.trait_references;
|
||||
}
|
||||
|
||||
static bool is_bound_satisfied_for_type (TyTy::BaseType *receiver,
|
||||
TraitReference *ref)
|
||||
{
|
||||
for (auto &bound : receiver->get_specified_bounds ())
|
||||
{
|
||||
const TraitReference *b = bound.get ();
|
||||
if (b->is_equal (*ref))
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
|
||||
= Probe (receiver);
|
||||
for (auto &bound : bounds)
|
||||
{
|
||||
const TraitReference *b = bound.first;
|
||||
if (b->is_equal (*ref))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
void scan ();
|
||||
|
||||
private:
|
||||
TypeBoundsProbe (const TyTy::BaseType *receiver)
|
||||
: TypeCheckBase (), receiver (receiver)
|
||||
{}
|
||||
|
||||
const TyTy::BaseType *receiver;
|
||||
std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> trait_references;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_HIR_TYPE_BOUNDS_H
|
77
gcc/rust/typecheck/rust-substitution-mapper.cc
Normal file
77
gcc/rust/typecheck/rust-substitution-mapper.cc
Normal file
@ -0,0 +1,77 @@
|
||||
// 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-substitution-mapper.h"
|
||||
#include "rust-hir-type-check.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TyTy::BaseType *
|
||||
SubstMapperInternal::Resolve (TyTy::BaseType *base,
|
||||
TyTy::SubstitutionArgumentMappings &mappings)
|
||||
{
|
||||
auto context = TypeCheckContext::get ();
|
||||
|
||||
SubstMapperInternal mapper (base->get_ref (), mappings);
|
||||
base->accept_vis (mapper);
|
||||
rust_assert (mapper.resolved != nullptr);
|
||||
|
||||
// insert these new implict types into the context
|
||||
TyTy::BaseType *unused = nullptr;
|
||||
bool is_ty_available
|
||||
= context->lookup_type (mapper.resolved->get_ty_ref (), &unused);
|
||||
if (!is_ty_available)
|
||||
{
|
||||
context->insert_type (
|
||||
Analysis::NodeMapping (0, 0, mapper.resolved->get_ty_ref (), 0),
|
||||
mapper.resolved);
|
||||
}
|
||||
bool is_ref_available
|
||||
= context->lookup_type (mapper.resolved->get_ref (), &unused);
|
||||
if (!is_ref_available)
|
||||
{
|
||||
context->insert_type (Analysis::NodeMapping (0, 0,
|
||||
mapper.resolved->get_ref (),
|
||||
0),
|
||||
mapper.resolved);
|
||||
}
|
||||
|
||||
return mapper.resolved;
|
||||
}
|
||||
|
||||
bool
|
||||
SubstMapperInternal::mappings_are_bound (
|
||||
TyTy::BaseType *tyseg, TyTy::SubstitutionArgumentMappings &mappings)
|
||||
{
|
||||
if (tyseg->get_kind () == TyTy::TypeKind::ADT)
|
||||
{
|
||||
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyseg);
|
||||
return adt->are_mappings_bound (mappings);
|
||||
}
|
||||
else if (tyseg->get_kind () == TyTy::TypeKind::FNDEF)
|
||||
{
|
||||
TyTy::FnType *fn = static_cast<TyTy::FnType *> (tyseg);
|
||||
return fn->are_mappings_bound (mappings);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
394
gcc/rust/typecheck/rust-substitution-mapper.h
Normal file
394
gcc/rust/typecheck/rust-substitution-mapper.h
Normal file
@ -0,0 +1,394 @@
|
||||
// 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_SUBSTITUTION_MAPPER_H
|
||||
#define RUST_SUBSTITUTION_MAPPER_H
|
||||
|
||||
#include "rust-tyty.h"
|
||||
#include "rust-tyty-visitor.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class SubstMapper : public TyTy::TyVisitor
|
||||
{
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (TyTy::BaseType *base, Location locus,
|
||||
HIR::GenericArgs *generics = nullptr)
|
||||
{
|
||||
SubstMapper mapper (base->get_ref (), generics, locus);
|
||||
base->accept_vis (mapper);
|
||||
rust_assert (mapper.resolved != nullptr);
|
||||
return mapper.resolved;
|
||||
}
|
||||
|
||||
static TyTy::BaseType *InferSubst (TyTy::BaseType *base, Location locus)
|
||||
{
|
||||
return SubstMapper::Resolve (base, locus, nullptr);
|
||||
}
|
||||
|
||||
bool have_generic_args () const { return generics != nullptr; }
|
||||
|
||||
void visit (TyTy::FnType &type) override
|
||||
{
|
||||
TyTy::FnType *concrete = nullptr;
|
||||
if (!have_generic_args ())
|
||||
{
|
||||
TyTy::BaseType *substs = type.infer_substitions (locus);
|
||||
rust_assert (substs->get_kind () == TyTy::TypeKind::FNDEF);
|
||||
concrete = static_cast<TyTy::FnType *> (substs);
|
||||
}
|
||||
else
|
||||
{
|
||||
TyTy::SubstitutionArgumentMappings mappings
|
||||
= type.get_mappings_from_generic_args (*generics);
|
||||
if (mappings.is_error ())
|
||||
return;
|
||||
|
||||
concrete = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
if (concrete != nullptr)
|
||||
resolved = concrete;
|
||||
}
|
||||
|
||||
void visit (TyTy::ADTType &type) override
|
||||
{
|
||||
TyTy::ADTType *concrete = nullptr;
|
||||
if (!have_generic_args ())
|
||||
{
|
||||
TyTy::BaseType *substs = type.infer_substitions (locus);
|
||||
rust_assert (substs->get_kind () == TyTy::TypeKind::ADT);
|
||||
concrete = static_cast<TyTy::ADTType *> (substs);
|
||||
}
|
||||
else
|
||||
{
|
||||
TyTy::SubstitutionArgumentMappings mappings
|
||||
= type.get_mappings_from_generic_args (*generics);
|
||||
if (mappings.is_error ())
|
||||
return;
|
||||
|
||||
concrete = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
if (concrete != nullptr)
|
||||
resolved = concrete;
|
||||
}
|
||||
|
||||
void visit (TyTy::PlaceholderType &type) override
|
||||
{
|
||||
rust_assert (type.can_resolve ());
|
||||
resolved = SubstMapper::Resolve (type.resolve (), locus, generics);
|
||||
}
|
||||
|
||||
void visit (TyTy::ProjectionType &type) override
|
||||
{
|
||||
TyTy::ProjectionType *concrete = nullptr;
|
||||
if (!have_generic_args ())
|
||||
{
|
||||
TyTy::BaseType *substs = type.infer_substitions (locus);
|
||||
rust_assert (substs->get_kind () == TyTy::TypeKind::ADT);
|
||||
concrete = static_cast<TyTy::ProjectionType *> (substs);
|
||||
}
|
||||
else
|
||||
{
|
||||
TyTy::SubstitutionArgumentMappings mappings
|
||||
= type.get_mappings_from_generic_args (*generics);
|
||||
if (mappings.is_error ())
|
||||
return;
|
||||
|
||||
concrete = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
if (concrete != nullptr)
|
||||
resolved = concrete;
|
||||
}
|
||||
|
||||
// nothing to do for these
|
||||
void visit (TyTy::InferType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::TupleType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::FnPtr &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ArrayType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::SliceType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::BoolType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::IntType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::UintType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::FloatType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::USizeType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ISizeType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ErrorType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::CharType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ReferenceType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::PointerType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ParamType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::StrType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::NeverType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ClosureType &) override { gcc_unreachable (); }
|
||||
|
||||
private:
|
||||
SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus)
|
||||
: resolved (new TyTy::ErrorType (ref)), generics (generics), locus (locus)
|
||||
{}
|
||||
|
||||
TyTy::BaseType *resolved;
|
||||
HIR::GenericArgs *generics;
|
||||
Location locus;
|
||||
};
|
||||
|
||||
class SubstMapperInternal : public TyTy::TyVisitor
|
||||
{
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (TyTy::BaseType *base,
|
||||
TyTy::SubstitutionArgumentMappings &mappings);
|
||||
|
||||
static bool mappings_are_bound (TyTy::BaseType *ty,
|
||||
TyTy::SubstitutionArgumentMappings &mappings);
|
||||
|
||||
void visit (TyTy::FnType &type) override
|
||||
{
|
||||
TyTy::SubstitutionArgumentMappings adjusted
|
||||
= type.adjust_mappings_for_this (mappings);
|
||||
if (adjusted.is_error ())
|
||||
return;
|
||||
|
||||
TyTy::BaseType *concrete = type.handle_substitions (adjusted);
|
||||
if (concrete != nullptr)
|
||||
resolved = concrete;
|
||||
}
|
||||
|
||||
void visit (TyTy::ADTType &type) override
|
||||
{
|
||||
TyTy::SubstitutionArgumentMappings adjusted
|
||||
= type.adjust_mappings_for_this (mappings);
|
||||
if (adjusted.is_error ())
|
||||
return;
|
||||
|
||||
TyTy::BaseType *concrete = type.handle_substitions (adjusted);
|
||||
if (concrete != nullptr)
|
||||
resolved = concrete;
|
||||
}
|
||||
|
||||
// these don't support generic arguments but might contain a type param
|
||||
void visit (TyTy::TupleType &type) override
|
||||
{
|
||||
resolved = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
void visit (TyTy::ReferenceType &type) override
|
||||
{
|
||||
resolved = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
void visit (TyTy::PointerType &type) override
|
||||
{
|
||||
resolved = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
void visit (TyTy::ParamType &type) override
|
||||
{
|
||||
resolved = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
void visit (TyTy::PlaceholderType &type) override
|
||||
{
|
||||
rust_assert (type.can_resolve ());
|
||||
if (mappings.trait_item_mode ())
|
||||
{
|
||||
resolved = type.resolve ();
|
||||
}
|
||||
else
|
||||
{
|
||||
resolved = SubstMapperInternal::Resolve (type.resolve (), mappings);
|
||||
}
|
||||
}
|
||||
|
||||
void visit (TyTy::ProjectionType &type) override
|
||||
{
|
||||
resolved = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
void visit (TyTy::ClosureType &type) override
|
||||
{
|
||||
resolved = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
void visit (TyTy::ArrayType &type) override
|
||||
{
|
||||
resolved = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
void visit (TyTy::SliceType &type) override
|
||||
{
|
||||
resolved = type.handle_substitions (mappings);
|
||||
}
|
||||
|
||||
// nothing to do for these
|
||||
void visit (TyTy::InferType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::FnPtr &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::BoolType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::IntType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::UintType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::FloatType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::USizeType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::ISizeType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::ErrorType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::CharType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::StrType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::NeverType &type) override { resolved = type.clone (); }
|
||||
void visit (TyTy::DynamicObjectType &type) override
|
||||
{
|
||||
resolved = type.clone ();
|
||||
}
|
||||
|
||||
private:
|
||||
SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings)
|
||||
: resolved (new TyTy::ErrorType (ref)), mappings (mappings)
|
||||
{}
|
||||
|
||||
TyTy::BaseType *resolved;
|
||||
TyTy::SubstitutionArgumentMappings &mappings;
|
||||
};
|
||||
|
||||
class SubstMapperFromExisting : public TyTy::TyVisitor
|
||||
{
|
||||
public:
|
||||
static TyTy::BaseType *Resolve (TyTy::BaseType *concrete,
|
||||
TyTy::BaseType *receiver)
|
||||
{
|
||||
rust_assert (concrete->get_kind () == receiver->get_kind ());
|
||||
|
||||
SubstMapperFromExisting mapper (concrete, receiver);
|
||||
concrete->accept_vis (mapper);
|
||||
return mapper.resolved;
|
||||
}
|
||||
|
||||
void visit (TyTy::FnType &type) override
|
||||
{
|
||||
rust_assert (type.was_substituted ());
|
||||
|
||||
TyTy::FnType *to_sub = static_cast<TyTy::FnType *> (receiver);
|
||||
resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
|
||||
}
|
||||
|
||||
void visit (TyTy::ADTType &type) override
|
||||
{
|
||||
rust_assert (type.was_substituted ());
|
||||
|
||||
TyTy::ADTType *to_sub = static_cast<TyTy::ADTType *> (receiver);
|
||||
resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
|
||||
}
|
||||
|
||||
void visit (TyTy::ClosureType &type) override
|
||||
{
|
||||
rust_assert (type.was_substituted ());
|
||||
|
||||
TyTy::ClosureType *to_sub = static_cast<TyTy::ClosureType *> (receiver);
|
||||
resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
|
||||
}
|
||||
|
||||
void visit (TyTy::InferType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::TupleType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::FnPtr &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ArrayType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::SliceType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::BoolType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::IntType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::UintType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::FloatType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::USizeType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ISizeType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ErrorType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::CharType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ReferenceType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::PointerType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ParamType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::StrType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::NeverType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::ProjectionType &) override { gcc_unreachable (); }
|
||||
void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); }
|
||||
|
||||
private:
|
||||
SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver)
|
||||
: concrete (concrete), receiver (receiver), resolved (nullptr)
|
||||
{}
|
||||
|
||||
TyTy::BaseType *concrete;
|
||||
TyTy::BaseType *receiver;
|
||||
|
||||
TyTy::BaseType *resolved;
|
||||
};
|
||||
|
||||
class GetUsedSubstArgs : public TyTy::TyConstVisitor
|
||||
{
|
||||
public:
|
||||
static TyTy::SubstitutionArgumentMappings From (const TyTy::BaseType *from)
|
||||
{
|
||||
GetUsedSubstArgs mapper;
|
||||
from->accept_vis (mapper);
|
||||
return mapper.args;
|
||||
}
|
||||
|
||||
void visit (const TyTy::FnType &type) override
|
||||
{
|
||||
args = type.get_substitution_arguments ();
|
||||
}
|
||||
|
||||
void visit (const TyTy::ADTType &type) override
|
||||
{
|
||||
args = type.get_substitution_arguments ();
|
||||
}
|
||||
|
||||
void visit (const TyTy::ClosureType &type) override
|
||||
{
|
||||
args = type.get_substitution_arguments ();
|
||||
}
|
||||
|
||||
void visit (const TyTy::InferType &) override {}
|
||||
void visit (const TyTy::TupleType &) override {}
|
||||
void visit (const TyTy::FnPtr &) override {}
|
||||
void visit (const TyTy::ArrayType &) override {}
|
||||
void visit (const TyTy::SliceType &) override {}
|
||||
void visit (const TyTy::BoolType &) override {}
|
||||
void visit (const TyTy::IntType &) override {}
|
||||
void visit (const TyTy::UintType &) override {}
|
||||
void visit (const TyTy::FloatType &) override {}
|
||||
void visit (const TyTy::USizeType &) override {}
|
||||
void visit (const TyTy::ISizeType &) override {}
|
||||
void visit (const TyTy::ErrorType &) override {}
|
||||
void visit (const TyTy::CharType &) override {}
|
||||
void visit (const TyTy::ReferenceType &) override {}
|
||||
void visit (const TyTy::PointerType &) override {}
|
||||
void visit (const TyTy::ParamType &) override {}
|
||||
void visit (const TyTy::StrType &) override {}
|
||||
void visit (const TyTy::NeverType &) override {}
|
||||
void visit (const TyTy::PlaceholderType &) override {}
|
||||
void visit (const TyTy::ProjectionType &) override {}
|
||||
void visit (const TyTy::DynamicObjectType &) override {}
|
||||
|
||||
private:
|
||||
GetUsedSubstArgs () : args (TyTy::SubstitutionArgumentMappings::error ()) {}
|
||||
|
||||
TyTy::SubstitutionArgumentMappings args;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_SUBSTITUTION_MAPPER_H
|
239
gcc/rust/typecheck/rust-tycheck-dump.h
Normal file
239
gcc/rust/typecheck/rust-tycheck-dump.h
Normal file
@ -0,0 +1,239 @@
|
||||
// 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_TYCHECK_DUMP
|
||||
#define RUST_TYCHECK_DUMP
|
||||
|
||||
#include "rust-hir-type-check-base.h"
|
||||
#include "rust-hir-full.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
class TypeResolverDump : private TypeCheckBase, private HIR::HIRFullVisitorBase
|
||||
{
|
||||
using HIR::HIRFullVisitorBase::visit;
|
||||
|
||||
public:
|
||||
static void go (HIR::Crate &crate, std::ofstream &out)
|
||||
{
|
||||
TypeResolverDump dumper;
|
||||
for (auto &item : crate.items)
|
||||
{
|
||||
item->accept_vis (dumper);
|
||||
dumper.dump += "\n";
|
||||
}
|
||||
|
||||
out << dumper.dump;
|
||||
}
|
||||
|
||||
void visit (HIR::StructStruct &struct_decl) override
|
||||
{
|
||||
dump += indent () + "struct " + type_string (struct_decl.get_mappings ())
|
||||
+ "\n";
|
||||
}
|
||||
|
||||
void visit (HIR::Union &union_decl) override
|
||||
{
|
||||
dump
|
||||
+= indent () + "union " + type_string (union_decl.get_mappings ()) + "\n";
|
||||
}
|
||||
|
||||
void visit (HIR::TupleStruct &struct_decl) override
|
||||
{
|
||||
dump += indent () + "struct" + type_string (struct_decl.get_mappings ())
|
||||
+ "\n";
|
||||
}
|
||||
|
||||
void visit (HIR::ImplBlock &impl_block) override
|
||||
{
|
||||
dump += indent () + "impl "
|
||||
+ type_string (impl_block.get_type ()->get_mappings ()) + " {\n";
|
||||
indentation_level++;
|
||||
|
||||
for (auto &impl_item : impl_block.get_impl_items ())
|
||||
{
|
||||
impl_item->accept_vis (*this);
|
||||
dump += "\n";
|
||||
}
|
||||
|
||||
indentation_level--;
|
||||
dump += indent () + "}\n";
|
||||
}
|
||||
|
||||
void visit (HIR::ConstantItem &constant) override
|
||||
{
|
||||
dump += indent () + "constant " + constant.get_identifier () + ":"
|
||||
+ type_string (constant.get_mappings ()) + " = ";
|
||||
constant.get_expr ()->accept_vis (*this);
|
||||
dump += ";\n";
|
||||
}
|
||||
|
||||
void visit (HIR::Function &function) override
|
||||
{
|
||||
dump += indent () + "fn " + function.get_function_name () + " "
|
||||
+ type_string (function.get_mappings ()) + "\n";
|
||||
dump += indent () + "{\n";
|
||||
|
||||
HIR::BlockExpr *function_body = function.get_definition ().get ();
|
||||
function_body->accept_vis (*this);
|
||||
|
||||
dump += indent () + "}\n";
|
||||
}
|
||||
|
||||
void visit (HIR::BlockExpr &expr) override
|
||||
{
|
||||
dump += "{\n";
|
||||
indentation_level++;
|
||||
|
||||
for (auto &s : expr.get_statements ())
|
||||
{
|
||||
dump += indent ();
|
||||
s->accept_vis (*this);
|
||||
dump += ";\n";
|
||||
}
|
||||
|
||||
if (expr.has_expr ())
|
||||
{
|
||||
dump += indent ();
|
||||
expr.expr->accept_vis (*this);
|
||||
dump += ";\n";
|
||||
}
|
||||
|
||||
indentation_level--;
|
||||
dump += "}\n";
|
||||
}
|
||||
|
||||
void visit (HIR::UnsafeBlockExpr &expr) override
|
||||
{
|
||||
dump += "unsafe ";
|
||||
expr.get_block_expr ()->accept_vis (*this);
|
||||
}
|
||||
|
||||
void visit (HIR::LetStmt &stmt) override
|
||||
{
|
||||
dump += "let " + stmt.get_pattern ()->as_string () + ":"
|
||||
+ type_string (stmt.get_pattern ()->get_pattern_mappings ());
|
||||
if (stmt.has_init_expr ())
|
||||
{
|
||||
dump += " = ";
|
||||
stmt.get_init_expr ()->accept_vis (*this);
|
||||
}
|
||||
}
|
||||
|
||||
void visit (HIR::ExprStmtWithBlock &stmt) override
|
||||
{
|
||||
stmt.get_expr ()->accept_vis (*this);
|
||||
}
|
||||
|
||||
void visit (HIR::ExprStmtWithoutBlock &stmt) override
|
||||
{
|
||||
stmt.get_expr ()->accept_vis (*this);
|
||||
}
|
||||
|
||||
void visit (HIR::AssignmentExpr &expr) override
|
||||
{
|
||||
expr.get_lhs ()->accept_vis (*this);
|
||||
dump += " = ";
|
||||
expr.get_rhs ()->accept_vis (*this);
|
||||
}
|
||||
|
||||
void visit (HIR::LiteralExpr &expr) override
|
||||
{
|
||||
dump += expr.get_literal ().as_string () + ":"
|
||||
+ type_string (expr.get_mappings ());
|
||||
}
|
||||
|
||||
void visit (HIR::ArrayExpr &expr) override
|
||||
{
|
||||
dump += type_string (expr.get_mappings ()) + ":[";
|
||||
|
||||
HIR::ArrayElems *elements = expr.get_internal_elements ();
|
||||
elements->accept_vis (*this);
|
||||
|
||||
dump += "]";
|
||||
}
|
||||
|
||||
void visit (HIR::ArrayElemsValues &elems) override
|
||||
{
|
||||
for (auto &elem : elems.get_values ())
|
||||
{
|
||||
elem->accept_vis (*this);
|
||||
dump += ",";
|
||||
}
|
||||
}
|
||||
|
||||
void visit (HIR::GroupedExpr &expr) override
|
||||
{
|
||||
HIR::Expr *paren_expr = expr.get_expr_in_parens ().get ();
|
||||
dump += "(";
|
||||
paren_expr->accept_vis (*this);
|
||||
dump += ")";
|
||||
}
|
||||
|
||||
void visit (HIR::PathInExpression &expr) override
|
||||
{
|
||||
dump += type_string (expr.get_mappings ());
|
||||
}
|
||||
|
||||
void visit (HIR::StructExprStructFields &expr) override
|
||||
{
|
||||
dump += "ctor: " + type_string (expr.get_mappings ());
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string type_string (const Analysis::NodeMapping &mappings)
|
||||
{
|
||||
TyTy::BaseType *lookup = nullptr;
|
||||
if (!context->lookup_type (mappings.get_hirid (), &lookup))
|
||||
return "<error>";
|
||||
|
||||
std::string buf = "[";
|
||||
for (auto &ref : lookup->get_combined_refs ())
|
||||
{
|
||||
buf += std::to_string (ref);
|
||||
buf += ", ";
|
||||
}
|
||||
buf += "]";
|
||||
|
||||
std::string repr = lookup->as_string ();
|
||||
return "<" + repr + " HIRID: " + std::to_string (mappings.get_hirid ())
|
||||
+ " RF:" + std::to_string (lookup->get_ref ()) + " TF:"
|
||||
+ std::to_string (lookup->get_ty_ref ()) + +" - " + buf + ">";
|
||||
}
|
||||
|
||||
std::string indent ()
|
||||
{
|
||||
std::string buf;
|
||||
for (size_t i = 0; i < indentation_level; ++i)
|
||||
buf += " ";
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private:
|
||||
TypeResolverDump () : TypeCheckBase (), indentation_level (0) {}
|
||||
|
||||
std::string dump;
|
||||
size_t indentation_level;
|
||||
};
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_TYCHECK_DUMP
|
155
gcc/rust/typecheck/rust-tyctx.cc
Normal file
155
gcc/rust/typecheck/rust-tyctx.cc
Normal file
@ -0,0 +1,155 @@
|
||||
// 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"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
TypeCheckContext *
|
||||
TypeCheckContext::get ()
|
||||
{
|
||||
static TypeCheckContext *instance;
|
||||
if (instance == nullptr)
|
||||
instance = new TypeCheckContext ();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
TypeCheckContext::TypeCheckContext () {}
|
||||
|
||||
TypeCheckContext::~TypeCheckContext () {}
|
||||
|
||||
bool
|
||||
TypeCheckContext::lookup_builtin (NodeId id, TyTy::BaseType **type)
|
||||
{
|
||||
auto ref_it = node_id_refs.find (id);
|
||||
if (ref_it == node_id_refs.end ())
|
||||
return false;
|
||||
|
||||
auto it = resolved.find (ref_it->second);
|
||||
if (it == resolved.end ())
|
||||
return false;
|
||||
|
||||
*type = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TypeCheckContext::lookup_builtin (std::string name, TyTy::BaseType **type)
|
||||
{
|
||||
for (auto &builtin : builtins)
|
||||
{
|
||||
if (name.compare (builtin->as_string ()) == 0)
|
||||
{
|
||||
*type = builtin.get ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckContext::insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type)
|
||||
{
|
||||
node_id_refs[ref] = id;
|
||||
resolved[id] = type;
|
||||
builtins.push_back (std::unique_ptr<TyTy::BaseType> (type));
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckContext::insert_type (const Analysis::NodeMapping &mappings,
|
||||
TyTy::BaseType *type)
|
||||
{
|
||||
rust_assert (type != nullptr);
|
||||
NodeId ref = mappings.get_nodeid ();
|
||||
HirId id = mappings.get_hirid ();
|
||||
node_id_refs[ref] = id;
|
||||
resolved[id] = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckContext::insert_implicit_type (TyTy::BaseType *type)
|
||||
{
|
||||
rust_assert (type != nullptr);
|
||||
resolved[type->get_ref ()] = type;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckContext::insert_implicit_type (HirId id, TyTy::BaseType *type)
|
||||
{
|
||||
rust_assert (type != nullptr);
|
||||
resolved[id] = type;
|
||||
}
|
||||
|
||||
bool
|
||||
TypeCheckContext::lookup_type (HirId id, TyTy::BaseType **type) const
|
||||
{
|
||||
auto it = resolved.find (id);
|
||||
if (it == resolved.end ())
|
||||
return false;
|
||||
|
||||
*type = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckContext::insert_type_by_node_id (NodeId ref, HirId id)
|
||||
{
|
||||
rust_assert (node_id_refs.find (ref) == node_id_refs.end ());
|
||||
node_id_refs[ref] = id;
|
||||
}
|
||||
|
||||
bool
|
||||
TypeCheckContext::lookup_type_by_node_id (NodeId ref, HirId *id)
|
||||
{
|
||||
auto it = node_id_refs.find (ref);
|
||||
if (it == node_id_refs.end ())
|
||||
return false;
|
||||
|
||||
*id = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
TyTy::BaseType *
|
||||
TypeCheckContext::peek_return_type ()
|
||||
{
|
||||
return return_type_stack.back ().second;
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckContext::push_return_type (TypeCheckContextItem item,
|
||||
TyTy::BaseType *return_type)
|
||||
{
|
||||
return_type_stack.push_back ({std::move (item), return_type});
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckContext::pop_return_type ()
|
||||
{
|
||||
return_type_stack.pop_back ();
|
||||
}
|
||||
|
||||
TypeCheckContextItem &
|
||||
TypeCheckContext::peek_context ()
|
||||
{
|
||||
return return_type_stack.back ().first;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
} // namespace Rust
|
462
gcc/rust/typecheck/rust-tyty-bounds.cc
Normal file
462
gcc/rust/typecheck/rust-tyty-bounds.cc
Normal file
@ -0,0 +1,462 @@
|
||||
// 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-bounds.h"
|
||||
#include "rust-hir-trait-resolve.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace Resolver {
|
||||
|
||||
void
|
||||
TypeBoundsProbe::scan ()
|
||||
{
|
||||
std::vector<std::pair<HIR::TypePath *, HIR::ImplBlock *>>
|
||||
possible_trait_paths;
|
||||
mappings->iterate_impl_blocks (
|
||||
[&] (HirId id, HIR::ImplBlock *impl) mutable -> bool {
|
||||
// we are filtering for trait-impl-blocks
|
||||
if (!impl->has_trait_ref ())
|
||||
return true;
|
||||
|
||||
TyTy::BaseType *impl_type = nullptr;
|
||||
bool ok
|
||||
= context->lookup_type (impl->get_type ()->get_mappings ().get_hirid (),
|
||||
&impl_type);
|
||||
if (!ok)
|
||||
return true;
|
||||
|
||||
if (!receiver->can_eq (impl_type, false))
|
||||
{
|
||||
if (!impl_type->can_eq (receiver, false))
|
||||
return true;
|
||||
}
|
||||
|
||||
possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl});
|
||||
return true;
|
||||
});
|
||||
|
||||
for (auto &path : possible_trait_paths)
|
||||
{
|
||||
HIR::TypePath *trait_path = path.first;
|
||||
TraitReference *trait_ref = TraitResolver::Resolve (*trait_path);
|
||||
|
||||
if (!trait_ref->is_error ())
|
||||
trait_references.push_back ({trait_ref, path.second});
|
||||
}
|
||||
}
|
||||
|
||||
TraitReference *
|
||||
TypeCheckBase::resolve_trait_path (HIR::TypePath &path)
|
||||
{
|
||||
return TraitResolver::Resolve (path);
|
||||
}
|
||||
|
||||
TyTy::TypeBoundPredicate
|
||||
TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path)
|
||||
{
|
||||
TraitReference *trait = resolve_trait_path (type_path);
|
||||
if (trait->is_error ())
|
||||
return TyTy::TypeBoundPredicate::error ();
|
||||
|
||||
TyTy::TypeBoundPredicate predicate (*trait, type_path.get_locus ());
|
||||
HIR::GenericArgs args
|
||||
= HIR::GenericArgs::create_empty (type_path.get_locus ());
|
||||
|
||||
auto &final_seg = type_path.get_final_segment ();
|
||||
if (final_seg->is_generic_segment ())
|
||||
{
|
||||
auto final_generic_seg
|
||||
= static_cast<HIR::TypePathSegmentGeneric *> (final_seg.get ());
|
||||
if (final_generic_seg->has_generic_args ())
|
||||
{
|
||||
args = final_generic_seg->get_generic_args ();
|
||||
}
|
||||
}
|
||||
|
||||
if (predicate.requires_generic_args ())
|
||||
{
|
||||
// this is applying generic arguments to a trait reference
|
||||
predicate.apply_generic_arguments (&args);
|
||||
}
|
||||
|
||||
return predicate;
|
||||
}
|
||||
|
||||
} // namespace Resolver
|
||||
|
||||
namespace TyTy {
|
||||
|
||||
TypeBoundPredicate::TypeBoundPredicate (
|
||||
const Resolver::TraitReference &trait_reference, Location locus)
|
||||
: SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
|
||||
reference (trait_reference.get_mappings ().get_defid ()), locus (locus),
|
||||
error_flag (false)
|
||||
{
|
||||
substitutions.clear ();
|
||||
for (const auto &p : trait_reference.get_trait_substs ())
|
||||
substitutions.push_back (p.clone ());
|
||||
|
||||
// we setup a dummy implict self argument
|
||||
SubstitutionArg placeholder_self (&get_substs ().front (), nullptr);
|
||||
used_arguments.get_mappings ().push_back (placeholder_self);
|
||||
}
|
||||
|
||||
TypeBoundPredicate::TypeBoundPredicate (
|
||||
DefId reference, std::vector<SubstitutionParamMapping> subst, Location locus)
|
||||
: SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
|
||||
reference (reference), locus (locus), error_flag (false)
|
||||
{
|
||||
substitutions.clear ();
|
||||
for (const auto &p : subst)
|
||||
substitutions.push_back (p.clone ());
|
||||
|
||||
// we setup a dummy implict self argument
|
||||
SubstitutionArg placeholder_self (&get_substs ().front (), nullptr);
|
||||
used_arguments.get_mappings ().push_back (placeholder_self);
|
||||
}
|
||||
|
||||
TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other)
|
||||
: SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
|
||||
reference (other.reference), locus (other.locus),
|
||||
error_flag (other.error_flag)
|
||||
{
|
||||
substitutions.clear ();
|
||||
for (const auto &p : other.get_substs ())
|
||||
substitutions.push_back (p.clone ());
|
||||
|
||||
std::vector<SubstitutionArg> mappings;
|
||||
for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++)
|
||||
{
|
||||
const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i);
|
||||
SubstitutionArg arg (oa);
|
||||
mappings.push_back (std::move (arg));
|
||||
}
|
||||
|
||||
// we need to remap the argument mappings based on this copied constructor
|
||||
std::vector<SubstitutionArg> copied_arg_mappings;
|
||||
size_t i = 0;
|
||||
for (const auto &m : other.used_arguments.get_mappings ())
|
||||
{
|
||||
TyTy::BaseType *argument
|
||||
= m.get_tyty () == nullptr ? nullptr : m.get_tyty ()->clone ();
|
||||
SubstitutionArg c (&substitutions.at (i++), argument);
|
||||
copied_arg_mappings.push_back (std::move (c));
|
||||
}
|
||||
|
||||
used_arguments
|
||||
= SubstitutionArgumentMappings (copied_arg_mappings,
|
||||
other.used_arguments.get_locus ());
|
||||
}
|
||||
|
||||
TypeBoundPredicate &
|
||||
TypeBoundPredicate::operator= (const TypeBoundPredicate &other)
|
||||
{
|
||||
reference = other.reference;
|
||||
locus = other.locus;
|
||||
error_flag = other.error_flag;
|
||||
used_arguments = SubstitutionArgumentMappings::error ();
|
||||
|
||||
substitutions.clear ();
|
||||
for (const auto &p : other.get_substs ())
|
||||
substitutions.push_back (p.clone ());
|
||||
|
||||
std::vector<SubstitutionArg> mappings;
|
||||
for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++)
|
||||
{
|
||||
const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i);
|
||||
SubstitutionArg arg (oa);
|
||||
mappings.push_back (std::move (arg));
|
||||
}
|
||||
|
||||
// we need to remap the argument mappings based on this copied constructor
|
||||
std::vector<SubstitutionArg> copied_arg_mappings;
|
||||
size_t i = 0;
|
||||
for (const auto &m : other.used_arguments.get_mappings ())
|
||||
{
|
||||
TyTy::BaseType *argument
|
||||
= m.get_tyty () == nullptr ? nullptr : m.get_tyty ()->clone ();
|
||||
SubstitutionArg c (&substitutions.at (i++), argument);
|
||||
copied_arg_mappings.push_back (std::move (c));
|
||||
}
|
||||
|
||||
used_arguments
|
||||
= SubstitutionArgumentMappings (copied_arg_mappings,
|
||||
other.used_arguments.get_locus ());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TypeBoundPredicate
|
||||
TypeBoundPredicate::error ()
|
||||
{
|
||||
auto p = TypeBoundPredicate (UNKNOWN_DEFID, {}, Location ());
|
||||
p.error_flag = true;
|
||||
return p;
|
||||
}
|
||||
|
||||
std::string
|
||||
TypeBoundPredicate::as_string () const
|
||||
{
|
||||
return get ()->as_string () + subst_as_string ();
|
||||
}
|
||||
|
||||
std::string
|
||||
TypeBoundPredicate::as_name () const
|
||||
{
|
||||
return get ()->get_name () + subst_as_string ();
|
||||
}
|
||||
|
||||
const Resolver::TraitReference *
|
||||
TypeBoundPredicate::get () const
|
||||
{
|
||||
auto context = Resolver::TypeCheckContext::get ();
|
||||
|
||||
Resolver::TraitReference *ref = nullptr;
|
||||
bool ok = context->lookup_trait_reference (reference, &ref);
|
||||
rust_assert (ok);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
std::string
|
||||
TypeBoundPredicate::get_name () const
|
||||
{
|
||||
return get ()->get_name ();
|
||||
}
|
||||
|
||||
bool
|
||||
TypeBoundPredicate::is_object_safe (bool emit_error, Location locus) const
|
||||
{
|
||||
const Resolver::TraitReference *trait = get ();
|
||||
rust_assert (trait != nullptr);
|
||||
return trait->is_object_safe (emit_error, locus);
|
||||
}
|
||||
|
||||
void
|
||||
TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args)
|
||||
{
|
||||
// we need to get the substitutions argument mappings but also remember that
|
||||
// we have an implicit Self argument which we must be careful to respect
|
||||
rust_assert (!used_arguments.is_empty ());
|
||||
rust_assert (!substitutions.empty ());
|
||||
|
||||
// now actually perform a substitution
|
||||
used_arguments = get_mappings_from_generic_args (*generic_args);
|
||||
|
||||
error_flag |= used_arguments.is_error ();
|
||||
auto &subst_mappings = used_arguments;
|
||||
for (auto &sub : get_substs ())
|
||||
{
|
||||
SubstitutionArg arg = SubstitutionArg::error ();
|
||||
bool ok
|
||||
= subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
|
||||
if (ok && arg.get_tyty () != nullptr)
|
||||
sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TypeBoundPredicate::contains_item (const std::string &search) const
|
||||
{
|
||||
auto trait_ref = get ();
|
||||
const Resolver::TraitItemReference *trait_item_ref = nullptr;
|
||||
return trait_ref->lookup_trait_item (search, &trait_item_ref);
|
||||
}
|
||||
|
||||
TypeBoundPredicateItem
|
||||
TypeBoundPredicate::lookup_associated_item (const std::string &search) const
|
||||
{
|
||||
auto trait_ref = get ();
|
||||
const Resolver::TraitItemReference *trait_item_ref = nullptr;
|
||||
if (!trait_ref->lookup_trait_item (search, &trait_item_ref))
|
||||
return TypeBoundPredicateItem::error ();
|
||||
|
||||
return TypeBoundPredicateItem (this, trait_item_ref);
|
||||
}
|
||||
|
||||
TypeBoundPredicateItem
|
||||
TypeBoundPredicate::lookup_associated_item (
|
||||
const Resolver::TraitItemReference *ref) const
|
||||
{
|
||||
return lookup_associated_item (ref->get_identifier ());
|
||||
}
|
||||
|
||||
BaseType *
|
||||
TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver)
|
||||
{
|
||||
TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty ();
|
||||
if (parent->get_substitution_arguments ().is_empty ())
|
||||
return trait_item_tyty;
|
||||
|
||||
const Resolver::TraitItemReference *tref = get_raw_item ();
|
||||
bool is_associated_type = tref->get_trait_item_type ();
|
||||
if (is_associated_type)
|
||||
return trait_item_tyty;
|
||||
|
||||
// set up the self mapping
|
||||
SubstitutionArgumentMappings gargs = parent->get_substitution_arguments ();
|
||||
rust_assert (!gargs.is_empty ());
|
||||
|
||||
// setup the adjusted mappings
|
||||
std::vector<SubstitutionArg> adjusted_mappings;
|
||||
for (size_t i = 0; i < gargs.get_mappings ().size (); i++)
|
||||
{
|
||||
auto &mapping = gargs.get_mappings ().at (i);
|
||||
|
||||
bool is_implicit_self = i == 0;
|
||||
TyTy::BaseType *argument
|
||||
= is_implicit_self ? receiver->clone () : mapping.get_tyty ();
|
||||
|
||||
SubstitutionArg arg (mapping.get_param_mapping (), argument);
|
||||
adjusted_mappings.push_back (std::move (arg));
|
||||
}
|
||||
|
||||
SubstitutionArgumentMappings adjusted (adjusted_mappings, gargs.get_locus (),
|
||||
gargs.get_subst_cb (),
|
||||
true /* trait-mode-flag */);
|
||||
return Resolver::SubstMapperInternal::Resolve (trait_item_tyty, adjusted);
|
||||
}
|
||||
bool
|
||||
TypeBoundPredicate::is_error () const
|
||||
{
|
||||
auto context = Resolver::TypeCheckContext::get ();
|
||||
|
||||
Resolver::TraitReference *ref = nullptr;
|
||||
bool ok = context->lookup_trait_reference (reference, &ref);
|
||||
|
||||
return !ok || error_flag;
|
||||
}
|
||||
|
||||
BaseType *
|
||||
TypeBoundPredicate::handle_substitions (
|
||||
SubstitutionArgumentMappings subst_mappings)
|
||||
{
|
||||
for (auto &sub : get_substs ())
|
||||
{
|
||||
if (sub.get_param_ty () == nullptr)
|
||||
continue;
|
||||
|
||||
ParamType *p = sub.get_param_ty ();
|
||||
BaseType *r = p->resolve ();
|
||||
BaseType *s = Resolver::SubstMapperInternal::Resolve (r, subst_mappings);
|
||||
|
||||
p->set_ty_ref (s->get_ty_ref ());
|
||||
}
|
||||
|
||||
// FIXME more error handling at some point
|
||||
// used_arguments = subst_mappings;
|
||||
// error_flag |= used_arguments.is_error ();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
TypeBoundPredicate::requires_generic_args () const
|
||||
{
|
||||
if (is_error ())
|
||||
return false;
|
||||
|
||||
return substitutions.size () > 1;
|
||||
}
|
||||
|
||||
// trait item reference
|
||||
|
||||
const Resolver::TraitItemReference *
|
||||
TypeBoundPredicateItem::get_raw_item () const
|
||||
{
|
||||
return trait_item_ref;
|
||||
}
|
||||
|
||||
bool
|
||||
TypeBoundPredicateItem::needs_implementation () const
|
||||
{
|
||||
return !get_raw_item ()->is_optional ();
|
||||
}
|
||||
|
||||
Location
|
||||
TypeBoundPredicateItem::get_locus () const
|
||||
{
|
||||
return get_raw_item ()->get_locus ();
|
||||
}
|
||||
|
||||
// TypeBoundsMappings
|
||||
|
||||
TypeBoundsMappings::TypeBoundsMappings (
|
||||
std::vector<TypeBoundPredicate> specified_bounds)
|
||||
: specified_bounds (specified_bounds)
|
||||
{}
|
||||
|
||||
std::vector<TypeBoundPredicate> &
|
||||
TypeBoundsMappings::get_specified_bounds ()
|
||||
{
|
||||
return specified_bounds;
|
||||
}
|
||||
|
||||
const std::vector<TypeBoundPredicate> &
|
||||
TypeBoundsMappings::get_specified_bounds () const
|
||||
{
|
||||
return specified_bounds;
|
||||
}
|
||||
|
||||
size_t
|
||||
TypeBoundsMappings::num_specified_bounds () const
|
||||
{
|
||||
return specified_bounds.size ();
|
||||
}
|
||||
|
||||
std::string
|
||||
TypeBoundsMappings::raw_bounds_as_string () const
|
||||
{
|
||||
std::string buf;
|
||||
for (size_t i = 0; i < specified_bounds.size (); i++)
|
||||
{
|
||||
const TypeBoundPredicate &b = specified_bounds.at (i);
|
||||
bool has_next = (i + 1) < specified_bounds.size ();
|
||||
buf += b.as_string () + (has_next ? " + " : "");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string
|
||||
TypeBoundsMappings::bounds_as_string () const
|
||||
{
|
||||
return "bounds:[" + raw_bounds_as_string () + "]";
|
||||
}
|
||||
|
||||
std::string
|
||||
TypeBoundsMappings::raw_bounds_as_name () const
|
||||
{
|
||||
std::string buf;
|
||||
for (size_t i = 0; i < specified_bounds.size (); i++)
|
||||
{
|
||||
const TypeBoundPredicate &b = specified_bounds.at (i);
|
||||
bool has_next = (i + 1) < specified_bounds.size ();
|
||||
buf += b.as_name () + (has_next ? " + " : "");
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
TypeBoundsMappings::add_bound (TypeBoundPredicate predicate)
|
||||
{
|
||||
specified_bounds.push_back (predicate);
|
||||
}
|
||||
|
||||
} // namespace TyTy
|
||||
} // namespace Rust
|
263
gcc/rust/typecheck/rust-tyty-call.cc
Normal file
263
gcc/rust/typecheck/rust-tyty-call.cc
Normal file
@ -0,0 +1,263 @@
|
||||
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-tyty-call.h"
|
||||
#include "rust-hir-type-check-expr.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace TyTy {
|
||||
|
||||
void
|
||||
TypeCheckCallExpr::visit (ADTType &type)
|
||||
{
|
||||
rust_assert (!variant.is_error ());
|
||||
if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
|
||||
{
|
||||
rust_error_at (
|
||||
call.get_locus (),
|
||||
"expected function, tuple struct or tuple variant, found struct %<%s%>",
|
||||
type.get_name ().c_str ());
|
||||
return;
|
||||
}
|
||||
|
||||
if (call.num_params () != variant.num_fields ())
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) call.num_params (),
|
||||
(unsigned long) variant.num_fields ());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (auto &argument : call.get_arguments ())
|
||||
{
|
||||
StructFieldType *field = variant.get_field_at_index (i);
|
||||
BaseType *field_tyty = field->get_field_type ();
|
||||
|
||||
BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get ());
|
||||
if (arg->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (argument->get_locus (),
|
||||
"failed to resolve argument type");
|
||||
return;
|
||||
}
|
||||
|
||||
auto res = Resolver::TypeCheckBase::coercion_site (
|
||||
argument->get_mappings ().get_hirid (), field_tyty, arg,
|
||||
argument->get_locus ());
|
||||
if (res->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
delete res;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i != call.num_params ())
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) i, (unsigned long) call.num_params ());
|
||||
return;
|
||||
}
|
||||
|
||||
resolved = type.clone ();
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckCallExpr::visit (FnType &type)
|
||||
{
|
||||
type.monomorphize ();
|
||||
if (call.num_params () != type.num_params ())
|
||||
{
|
||||
if (type.is_varadic ())
|
||||
{
|
||||
if (call.num_params () < type.num_params ())
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) call.num_params (),
|
||||
(unsigned long) type.num_params ());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) call.num_params (),
|
||||
(unsigned long) type.num_params ());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (auto &argument : call.get_arguments ())
|
||||
{
|
||||
auto argument_expr_tyty
|
||||
= Resolver::TypeCheckExpr::Resolve (argument.get ());
|
||||
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (
|
||||
argument->get_locus (),
|
||||
"failed to resolve type for argument expr in CallExpr");
|
||||
return;
|
||||
}
|
||||
|
||||
// it might be a varadic function
|
||||
if (i < type.num_params ())
|
||||
{
|
||||
auto fnparam = type.param_at (i);
|
||||
auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
|
||||
argument->get_mappings ().get_hirid (), fnparam.second,
|
||||
argument_expr_tyty, argument->get_locus ());
|
||||
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (argument->get_locus (),
|
||||
"Type Resolution failure on parameter");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < call.num_params ())
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) i, (unsigned long) call.num_params ());
|
||||
return;
|
||||
}
|
||||
|
||||
type.monomorphize ();
|
||||
resolved = type.get_return_type ()->clone ();
|
||||
}
|
||||
|
||||
void
|
||||
TypeCheckCallExpr::visit (FnPtr &type)
|
||||
{
|
||||
if (call.num_params () != type.num_params ())
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) call.num_params (),
|
||||
(unsigned long) type.num_params ());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (auto &argument : call.get_arguments ())
|
||||
{
|
||||
auto fnparam = type.param_at (i);
|
||||
auto argument_expr_tyty
|
||||
= Resolver::TypeCheckExpr::Resolve (argument.get ());
|
||||
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (
|
||||
argument->get_locus (),
|
||||
"failed to resolve type for argument expr in CallExpr");
|
||||
return;
|
||||
}
|
||||
|
||||
auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
|
||||
argument->get_mappings ().get_hirid (), fnparam, argument_expr_tyty,
|
||||
argument->get_locus ());
|
||||
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (argument->get_locus (),
|
||||
"Type Resolution failure on parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i != call.num_params ())
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) i, (unsigned long) call.num_params ());
|
||||
return;
|
||||
}
|
||||
|
||||
resolved = type.get_return_type ()->monomorphized_clone ();
|
||||
}
|
||||
|
||||
// method call checker
|
||||
|
||||
void
|
||||
TypeCheckMethodCallExpr::visit (FnType &type)
|
||||
{
|
||||
type.get_self_type ()->unify (adjusted_self);
|
||||
|
||||
// +1 for the receiver self
|
||||
size_t num_args_to_call = call.num_params () + 1;
|
||||
if (num_args_to_call != type.num_params ())
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) call.num_params (),
|
||||
(unsigned long) type.num_params ());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = 1;
|
||||
for (auto &argument : call.get_arguments ())
|
||||
{
|
||||
auto fnparam = type.param_at (i);
|
||||
auto argument_expr_tyty
|
||||
= Resolver::TypeCheckExpr::Resolve (argument.get ());
|
||||
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (
|
||||
argument->get_locus (),
|
||||
"failed to resolve type for argument expr in CallExpr");
|
||||
return;
|
||||
}
|
||||
|
||||
auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
|
||||
argument->get_mappings ().get_hirid (), fnparam.second,
|
||||
argument_expr_tyty, argument->get_locus ());
|
||||
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
|
||||
{
|
||||
rust_error_at (argument->get_locus (),
|
||||
"Type Resolution failure on parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i != num_args_to_call)
|
||||
{
|
||||
rust_error_at (call.get_locus (),
|
||||
"unexpected number of arguments %lu expected %lu",
|
||||
(unsigned long) i, (unsigned long) call.num_params ());
|
||||
return;
|
||||
}
|
||||
|
||||
type.monomorphize ();
|
||||
|
||||
resolved = type.get_return_type ()->monomorphized_clone ();
|
||||
}
|
||||
|
||||
} // namespace TyTy
|
||||
} // namespace Rust
|
147
gcc/rust/typecheck/rust-tyty-call.h
Normal file
147
gcc/rust/typecheck/rust-tyty-call.h
Normal file
@ -0,0 +1,147 @@
|
||||
// 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_CALL
|
||||
#define RUST_TYTY_CALL
|
||||
|
||||
#include "rust-diagnostics.h"
|
||||
#include "rust-hir-full.h"
|
||||
#include "rust-tyty-visitor.h"
|
||||
#include "rust-tyty.h"
|
||||
#include "rust-hir-type-check.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace TyTy {
|
||||
|
||||
class TypeCheckCallExpr : private TyVisitor
|
||||
{
|
||||
public:
|
||||
static BaseType *go (BaseType *ref, HIR::CallExpr &call,
|
||||
TyTy::VariantDef &variant,
|
||||
Resolver::TypeCheckContext *context)
|
||||
{
|
||||
TypeCheckCallExpr checker (call, variant, context);
|
||||
ref->accept_vis (checker);
|
||||
return checker.resolved;
|
||||
}
|
||||
|
||||
void visit (InferType &) override { gcc_unreachable (); }
|
||||
void visit (TupleType &) override { gcc_unreachable (); }
|
||||
void visit (ArrayType &) override { gcc_unreachable (); }
|
||||
void visit (SliceType &) override { gcc_unreachable (); }
|
||||
void visit (BoolType &) override { gcc_unreachable (); }
|
||||
void visit (IntType &) override { gcc_unreachable (); }
|
||||
void visit (UintType &) override { gcc_unreachable (); }
|
||||
void visit (FloatType &) override { gcc_unreachable (); }
|
||||
void visit (USizeType &) override { gcc_unreachable (); }
|
||||
void visit (ISizeType &) override { gcc_unreachable (); }
|
||||
void visit (ErrorType &) override { gcc_unreachable (); }
|
||||
void visit (CharType &) override { gcc_unreachable (); }
|
||||
void visit (ReferenceType &) override { gcc_unreachable (); }
|
||||
void visit (PointerType &) override { gcc_unreachable (); }
|
||||
void visit (ParamType &) override { gcc_unreachable (); }
|
||||
void visit (StrType &) override { gcc_unreachable (); }
|
||||
void visit (NeverType &) override { gcc_unreachable (); }
|
||||
void visit (PlaceholderType &) override { gcc_unreachable (); }
|
||||
void visit (ProjectionType &) override { gcc_unreachable (); }
|
||||
void visit (DynamicObjectType &) override { gcc_unreachable (); }
|
||||
void visit (ClosureType &type) override { gcc_unreachable (); }
|
||||
|
||||
// tuple-structs
|
||||
void visit (ADTType &type) override;
|
||||
|
||||
// call fns
|
||||
void visit (FnType &type) override;
|
||||
void visit (FnPtr &type) override;
|
||||
|
||||
private:
|
||||
TypeCheckCallExpr (HIR::CallExpr &c, TyTy::VariantDef &variant,
|
||||
Resolver::TypeCheckContext *context)
|
||||
: resolved (new TyTy::ErrorType (c.get_mappings ().get_hirid ())), call (c),
|
||||
variant (variant), context (context),
|
||||
mappings (Analysis::Mappings::get ())
|
||||
{}
|
||||
|
||||
BaseType *resolved;
|
||||
HIR::CallExpr &call;
|
||||
TyTy::VariantDef &variant;
|
||||
Resolver::TypeCheckContext *context;
|
||||
Analysis::Mappings *mappings;
|
||||
};
|
||||
|
||||
class TypeCheckMethodCallExpr : private TyVisitor
|
||||
{
|
||||
public:
|
||||
// Resolve the Method parameters and return back the return type
|
||||
static BaseType *go (BaseType *ref, HIR::MethodCallExpr &call,
|
||||
TyTy::BaseType *adjusted_self,
|
||||
Resolver::TypeCheckContext *context)
|
||||
{
|
||||
TypeCheckMethodCallExpr checker (call, adjusted_self, context);
|
||||
ref->accept_vis (checker);
|
||||
return checker.resolved;
|
||||
}
|
||||
|
||||
void visit (InferType &) override { gcc_unreachable (); }
|
||||
void visit (TupleType &) override { gcc_unreachable (); }
|
||||
void visit (ArrayType &) override { gcc_unreachable (); }
|
||||
void visit (SliceType &) override { gcc_unreachable (); }
|
||||
void visit (BoolType &) override { gcc_unreachable (); }
|
||||
void visit (IntType &) override { gcc_unreachable (); }
|
||||
void visit (UintType &) override { gcc_unreachable (); }
|
||||
void visit (FloatType &) override { gcc_unreachable (); }
|
||||
void visit (USizeType &) override { gcc_unreachable (); }
|
||||
void visit (ISizeType &) override { gcc_unreachable (); }
|
||||
void visit (ErrorType &) override { gcc_unreachable (); }
|
||||
void visit (ADTType &) override { gcc_unreachable (); };
|
||||
void visit (CharType &) override { gcc_unreachable (); }
|
||||
void visit (ReferenceType &) override { gcc_unreachable (); }
|
||||
void visit (PointerType &) override { gcc_unreachable (); }
|
||||
void visit (ParamType &) override { gcc_unreachable (); }
|
||||
void visit (StrType &) override { gcc_unreachable (); }
|
||||
void visit (NeverType &) override { gcc_unreachable (); }
|
||||
void visit (PlaceholderType &) override { gcc_unreachable (); }
|
||||
void visit (ProjectionType &) override { gcc_unreachable (); }
|
||||
void visit (DynamicObjectType &) override { gcc_unreachable (); }
|
||||
|
||||
// FIXME
|
||||
void visit (FnPtr &type) override { gcc_unreachable (); }
|
||||
|
||||
// call fns
|
||||
void visit (FnType &type) override;
|
||||
void visit (ClosureType &type) override { gcc_unreachable (); }
|
||||
|
||||
private:
|
||||
TypeCheckMethodCallExpr (HIR::MethodCallExpr &c,
|
||||
TyTy::BaseType *adjusted_self,
|
||||
Resolver::TypeCheckContext *context)
|
||||
: resolved (nullptr), call (c), adjusted_self (adjusted_self),
|
||||
context (context), mappings (Analysis::Mappings::get ())
|
||||
{}
|
||||
|
||||
BaseType *resolved;
|
||||
HIR::MethodCallExpr &call;
|
||||
TyTy::BaseType *adjusted_self;
|
||||
Resolver::TypeCheckContext *context;
|
||||
Analysis::Mappings *mappings;
|
||||
};
|
||||
|
||||
} // namespace TyTy
|
||||
} // namespace Rust
|
||||
|
||||
#endif // RUST_TYTY_CALL
|
1554
gcc/rust/typecheck/rust-tyty-cmp.h
Normal file
1554
gcc/rust/typecheck/rust-tyty-cmp.h
Normal file
File diff suppressed because it is too large
Load Diff
1584
gcc/rust/typecheck/rust-tyty-rules.h
Normal file
1584
gcc/rust/typecheck/rust-tyty-rules.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user