// Copyright (C) 2020-2023 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
// .
#include "rust-tyty.h"
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check-type.h"
#include "rust-tyty-visitor.h"
#include "rust-tyty-call.h"
#include "rust-hir-map.h"
#include "rust-location.h"
#include "rust-linemap.h"
#include "rust-substitution-mapper.h"
#include "rust-hir-trait-reference.h"
#include "rust-hir-type-bounds.h"
#include "rust-hir-trait-resolve.h"
#include "rust-tyty-cmp.h"
#include "rust-type-util.h"
#include "options.h"
namespace Rust {
namespace TyTy {
bool autoderef_cmp_flag = false;
void
set_cmp_autoderef_mode ()
{
autoderef_cmp_flag = true;
}
void
reset_cmp_autoderef_mode ()
{
autoderef_cmp_flag = false;
}
std::string
TypeKindFormat::to_string (TypeKind kind)
{
switch (kind)
{
case TypeKind::INFER:
return "Infer";
case TypeKind::ADT:
return "ADT";
case TypeKind::STR:
return "STR";
case TypeKind::REF:
return "REF";
case TypeKind::POINTER:
return "POINTER";
case TypeKind::PARAM:
return "PARAM";
case TypeKind::ARRAY:
return "ARRAY";
case TypeKind::SLICE:
return "SLICE";
case TypeKind::FNDEF:
return "FnDef";
case TypeKind::FNPTR:
return "FnPtr";
case TypeKind::TUPLE:
return "Tuple";
case TypeKind::BOOL:
return "Bool";
case TypeKind::CHAR:
return "Char";
case TypeKind::INT:
return "Int";
case TypeKind::UINT:
return "Uint";
case TypeKind::FLOAT:
return "Float";
case TypeKind::USIZE:
return "Usize";
case TypeKind::ISIZE:
return "Isize";
case TypeKind::NEVER:
return "Never";
case TypeKind::PLACEHOLDER:
return "Placeholder";
case TypeKind::PROJECTION:
return "Projection";
case TypeKind::DYNAMIC:
return "Dynamic";
case TypeKind::CLOSURE:
return "Closure";
case TypeKind::ERROR:
return "ERROR";
}
gcc_unreachable ();
}
bool
is_primitive_type_kind (TypeKind kind)
{
switch (kind)
{
case TypeKind::BOOL:
case TypeKind::CHAR:
case TypeKind::INT:
case TypeKind::UINT:
case TypeKind::ISIZE:
case TypeKind::USIZE:
case TypeKind::FLOAT:
case TypeKind::NEVER:
case TypeKind::STR:
return true;
default:
return false;
}
}
// BASE TYPE
BaseType::BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
std::set refs)
: TypeBoundsMappings ({}), kind (kind), ref (ref), ty_ref (ty_ref),
combined (refs), ident (ident), mappings (Analysis::Mappings::get ())
{}
BaseType::BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
std::vector specified_bounds,
std::set refs)
: TypeBoundsMappings (specified_bounds), kind (kind), ref (ref),
ty_ref (ty_ref), combined (refs), ident (ident),
mappings (Analysis::Mappings::get ())
{}
BaseType::~BaseType () {}
HirId
BaseType::get_ref () const
{
return ref;
}
void
BaseType::set_ref (HirId id)
{
if (id != ref)
append_reference (ref);
ref = id;
}
HirId
BaseType::get_ty_ref () const
{
return ty_ref;
}
void
BaseType::set_ty_ref (HirId id)
{
ty_ref = id;
}
bool
BaseType::is_equal (const BaseType &other) const
{
return get_kind () == other.get_kind ();
}
bool
BaseType::is_unit () const
{
return false;
}
TypeKind
BaseType::get_kind () const
{
return kind;
}
std::set
BaseType::get_combined_refs () const
{
return combined;
}
void
BaseType::append_reference (HirId id)
{
combined.insert (id);
}
bool
BaseType::supports_substitutions () const
{
return false;
}
bool
BaseType::has_subsititions_defined () const
{
return false;
}
bool
BaseType::can_substitute () const
{
return supports_substitutions () && has_subsititions_defined ();
}
bool
BaseType::needs_generic_substitutions () const
{
return false;
}
bool
BaseType::contains_type_parameters () const
{
return !is_concrete ();
}
const RustIdent &
BaseType::get_ident () const
{
return ident;
}
Location
BaseType::get_locus () const
{
return ident.locus;
}
// FIXME this is missing locus
bool
BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const
{
const Resolver::TraitReference *query = predicate.get ();
for (const auto &bound : specified_bounds)
{
const Resolver::TraitReference *item = bound.get ();
if (item->satisfies_bound (*query))
return true;
}
bool satisfied = false;
auto probed = Resolver::TypeBoundsProbe::Probe (this);
for (const auto &b : probed)
{
const Resolver::TraitReference *bound = b.first;
if (bound->satisfies_bound (*query))
{
satisfied = true;
break;
}
}
if (!satisfied)
return false;
for (const auto &b : probed)
{
const Resolver::TraitReference *bound = b.first;
if (!bound->is_equal (*query))
continue;
// builtin ones have no impl-block this needs fixed and use a builtin node
// of somekind
if (b.second == nullptr)
return true;
// need to check that associated types can match as well
const HIR::ImplBlock &impl = *(b.second);
for (const auto &item : impl.get_impl_items ())
{
TyTy::BaseType *impl_item_ty = nullptr;
Analysis::NodeMapping i = item->get_impl_mappings ();
bool query_ok = Resolver::query_type (i.get_hirid (), &impl_item_ty);
if (!query_ok)
return false;
std::string item_name = item->get_impl_item_name ();
TypeBoundPredicateItem lookup
= predicate.lookup_associated_item (item_name);
if (lookup.is_error ())
return false;
const auto *item_ref = lookup.get_raw_item ();
TyTy::BaseType *bound_ty = item_ref->get_tyty ();
// compare the types
if (!bound_ty->can_eq (impl_item_ty, false))
{
RichLocation r (mappings->lookup_location (get_ref ()));
r.add_range (predicate.get_locus ());
r.add_range (mappings->lookup_location (i.get_hirid ()));
rust_error_at (
r, "expected %<%s%> got %<%s%>",
bound_ty->destructure ()->get_name ().c_str (),
impl_item_ty->destructure ()->get_name ().c_str ());
return false;
}
}
return true;
}
return false;
}
bool
BaseType::bounds_compatible (const BaseType &other, Location locus,
bool emit_error) const
{
std::vector>
unsatisfied_bounds;
for (auto &bound : get_specified_bounds ())
{
if (!other.satisfies_bound (bound))
unsatisfied_bounds.push_back (bound);
}
// lets emit a single error for this
if (unsatisfied_bounds.size () > 0)
{
RichLocation r (locus);
std::string missing_preds;
for (size_t i = 0; i < unsatisfied_bounds.size (); i++)
{
const TypeBoundPredicate &pred = unsatisfied_bounds.at (i);
r.add_range (pred.get_locus ());
missing_preds += pred.get_name ();
bool have_next = (i + 1) < unsatisfied_bounds.size ();
if (have_next)
missing_preds += ", ";
}
if (emit_error)
{
rust_error_at (r,
"bounds not satisfied for %s %<%s%> is not satisfied",
other.get_name ().c_str (), missing_preds.c_str ());
// rust_assert (!emit_error);
}
}
return unsatisfied_bounds.size () == 0;
}
void
BaseType::inherit_bounds (const BaseType &other)
{
inherit_bounds (other.get_specified_bounds ());
}
void
BaseType::inherit_bounds (
const std::vector &specified_bounds)
{
for (auto &bound : specified_bounds)
{
add_bound (bound);
}
}
const BaseType *
BaseType::get_root () const
{
// FIXME this needs to be it its own visitor class with a vector adjustments
const TyTy::BaseType *root = this;
if (get_kind () == TyTy::REF)
{
const ReferenceType *r = static_cast (root);
root = r->get_base ()->get_root ();
}
else if (get_kind () == TyTy::POINTER)
{
const PointerType *r = static_cast (root);
root = r->get_base ()->get_root ();
}
// these are an unsize
else if (get_kind () == TyTy::SLICE)
{
const SliceType *r = static_cast (root);
root = r->get_element_type ()->get_root ();
}
// else if (get_kind () == TyTy::ARRAY)
// {
// const ArrayType *r = static_cast (root);
// root = r->get_element_type ()->get_root ();
// }
return root;
}
BaseType *
BaseType::destructure ()
{
int recurisve_ops = 0;
BaseType *x = this;
while (true)
{
if (recurisve_ops++ >= rust_max_recursion_depth)
{
rust_error_at (
Location (),
"% count exceeds limit of %i (use "
"% to increase the limit)",
rust_max_recursion_depth);
return new ErrorType (get_ref ());
}
switch (x->get_kind ())
{
case TyTy::TypeKind::PARAM: {
TyTy::ParamType *p = static_cast (x);
TyTy::BaseType *pr = p->resolve ();
if (pr == x)
return pr;
x = pr;
}
break;
case TyTy::TypeKind::PLACEHOLDER: {
TyTy::PlaceholderType *p = static_cast (x);
if (!p->can_resolve ())
return p;
x = p->resolve ();
}
break;
case TyTy::TypeKind::PROJECTION: {
TyTy::ProjectionType *p = static_cast (x);
x = p->get ();
}
break;
default:
return x;
}
}
return x;
}
const BaseType *
BaseType::destructure () const
{
int recurisve_ops = 0;
const BaseType *x = this;
while (true)
{
if (recurisve_ops++ >= rust_max_recursion_depth)
{
rust_error_at (
Location (),
"% count exceeds limit of %i (use "
"% to increase the limit)",
rust_max_recursion_depth);
return new ErrorType (get_ref ());
}
switch (x->get_kind ())
{
case TyTy::TypeKind::PARAM: {
const TyTy::ParamType *p = static_cast (x);
const TyTy::BaseType *pr = p->resolve ();
if (pr == x)
return pr;
x = pr;
}
break;
case TyTy::TypeKind::PLACEHOLDER: {
const TyTy::PlaceholderType *p
= static_cast (x);
if (!p->can_resolve ())
return p;
x = p->resolve ();
}
break;
case TyTy::TypeKind::PROJECTION: {
const TyTy::ProjectionType *p
= static_cast (x);
x = p->get ();
}
break;
default:
return x;
}
}
return x;
}
std::string
BaseType::mappings_str () const
{
std::string buffer = "Ref: " + std::to_string (get_ref ())
+ " TyRef: " + std::to_string (get_ty_ref ());
buffer += "[";
for (auto &ref : combined)
buffer += std::to_string (ref) + ",";
buffer += "]";
return "(" + buffer + ")";
}
std::string
BaseType::debug_str () const
{
// return TypeKindFormat::to_string (get_kind ()) + ":" + as_string () + ":"
// + mappings_str () + ":" + bounds_as_string ();
return get_name ();
}
void
BaseType::debug () const
{
rust_debug ("[%p] %s", static_cast (this),
debug_str ().c_str ());
}
// InferType
InferType::InferType (HirId ref, InferTypeKind infer_kind, Location locus,
std::set refs)
: BaseType (ref, ref, TypeKind::INFER,
{Resolver::CanonicalPath::create_empty (), locus}, refs),
infer_kind (infer_kind)
{}
InferType::InferType (HirId ref, HirId ty_ref, InferTypeKind infer_kind,
Location locus, std::set refs)
: BaseType (ref, ty_ref, TypeKind::INFER,
{Resolver::CanonicalPath::create_empty (), locus}, refs),
infer_kind (infer_kind)
{}
InferType::InferTypeKind
InferType::get_infer_kind () const
{
return infer_kind;
}
std::string
InferType::get_name () const
{
return as_string ();
}
bool
InferType::is_concrete () const
{
return true;
}
void
InferType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
InferType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
InferType::as_string () const
{
switch (infer_kind)
{
case GENERAL:
return "T?";
case INTEGRAL:
return "";
case FLOAT:
return "";
}
return "";
}
bool
InferType::can_eq (const BaseType *other, bool emit_errors) const
{
InferCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
InferType::clone () const
{
// clones for inference variables are special in that they _must_ exist within
// the type check context and we must ensure we don't loose the chain
// otherwise we will end up in the missing type annotations case
//
// This means we cannot simply take over the same reference we must generate a
// new ref just like the get_implicit_infer_var code then we can setup the
// chain of references accordingly to ensure we don't loose the ability to
// update the inference variables when we solve the type
auto mappings = Analysis::Mappings::get ();
auto context = Resolver::TypeCheckContext::get ();
InferType *clone
= new InferType (mappings->get_next_hir_id (), get_infer_kind (),
get_ident ().locus, get_combined_refs ());
context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (),
UNKNOWN_NODEID,
clone->get_ref (),
UNKNOWN_LOCAL_DEFID),
clone);
mappings->insert_location (clone->get_ref (),
mappings->lookup_location (get_ref ()));
// setup the chain to reference this
clone->append_reference (get_ref ());
return clone;
}
BaseType *
InferType::monomorphized_clone () const
{
return clone ();
}
bool
InferType::default_type (BaseType **type) const
{
auto context = Resolver::TypeCheckContext::get ();
bool ok = false;
switch (infer_kind)
{
case GENERAL:
return false;
case INTEGRAL: {
ok = context->lookup_builtin ("i32", type);
rust_assert (ok);
return ok;
}
case FLOAT: {
ok = context->lookup_builtin ("f64", type);
rust_assert (ok);
return ok;
}
}
return false;
}
// ErrorType
ErrorType::ErrorType (HirId ref, std::set refs)
: BaseType (ref, ref, TypeKind::ERROR,
{Resolver::CanonicalPath::create_empty (), Location ()}, refs)
{}
ErrorType::ErrorType (HirId ref, HirId ty_ref, std::set refs)
: BaseType (ref, ty_ref, TypeKind::ERROR,
{Resolver::CanonicalPath::create_empty (), Location ()}, refs)
{}
bool
ErrorType::is_unit () const
{
return true;
}
bool
ErrorType::is_concrete () const
{
return false;
}
std::string
ErrorType::get_name () const
{
return as_string ();
}
void
ErrorType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
ErrorType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
ErrorType::as_string () const
{
return "";
}
bool
ErrorType::can_eq (const BaseType *other, bool emit_errors) const
{
return get_kind () == other->get_kind ();
}
BaseType *
ErrorType::clone () const
{
return new ErrorType (get_ref (), get_ty_ref (), get_combined_refs ());
}
BaseType *
ErrorType::monomorphized_clone () const
{
return clone ();
}
// Struct Field type
StructFieldType::StructFieldType (HirId ref, std::string name, BaseType *ty,
Location locus)
: ref (ref), name (name), ty (ty), locus (locus)
{}
HirId
StructFieldType::get_ref () const
{
return ref;
}
std::string
StructFieldType::get_name () const
{
return name;
}
BaseType *
StructFieldType::get_field_type () const
{
return ty;
}
void
StructFieldType::set_field_type (BaseType *fty)
{
ty = fty;
}
bool
StructFieldType::is_concrete () const
{
return ty->is_concrete ();
}
void
StructFieldType::debug () const
{
rust_debug ("%s", as_string ().c_str ());
}
Location
StructFieldType::get_locus () const
{
return locus;
}
std::string
StructFieldType::as_string () const
{
return name + ":" + get_field_type ()->debug_str ();
}
bool
StructFieldType::is_equal (const StructFieldType &other) const
{
bool names_eq = get_name ().compare (other.get_name ()) == 0;
TyTy::BaseType *o = other.get_field_type ();
if (o->get_kind () == TypeKind::PARAM)
{
ParamType *op = static_cast (o);
o = op->resolve ();
}
bool types_eq = get_field_type ()->is_equal (*o);
return names_eq && types_eq;
}
StructFieldType *
StructFieldType::clone () const
{
return new StructFieldType (get_ref (), get_name (),
get_field_type ()->clone (), locus);
}
StructFieldType *
StructFieldType::monomorphized_clone () const
{
return new StructFieldType (get_ref (), get_name (),
get_field_type ()->monomorphized_clone (), locus);
}
// VariantDef
std::string
VariantDef::variant_type_string (VariantType type)
{
switch (type)
{
case NUM:
return "enumeral";
case TUPLE:
return "tuple";
case STRUCT:
return "struct";
}
gcc_unreachable ();
return "";
}
VariantDef::VariantDef (HirId id, DefId defid, std::string identifier,
RustIdent ident, HIR::Expr *discriminant)
: id (id), defid (defid), identifier (identifier), ident (ident),
discriminant (discriminant)
{
type = VariantType::NUM;
fields = {};
}
VariantDef::VariantDef (HirId id, DefId defid, std::string identifier,
RustIdent ident, VariantType type,
HIR::Expr *discriminant,
std::vector fields)
: id (id), defid (defid), identifier (identifier), ident (ident), type (type),
discriminant (discriminant), fields (fields)
{
rust_assert ((type == VariantType::NUM && fields.empty ())
|| (type == VariantType::TUPLE || type == VariantType::STRUCT));
}
VariantDef::VariantDef (const VariantDef &other)
: id (other.id), defid (other.defid), identifier (other.identifier),
ident (other.ident), type (other.type), discriminant (other.discriminant),
fields (other.fields)
{}
VariantDef &
VariantDef::operator= (const VariantDef &other)
{
id = other.id;
identifier = other.identifier;
type = other.type;
discriminant = other.discriminant;
fields = other.fields;
ident = other.ident;
return *this;
}
VariantDef &
VariantDef::get_error_node ()
{
static VariantDef node
= VariantDef (UNKNOWN_HIRID, UNKNOWN_DEFID, "",
{Resolver::CanonicalPath::create_empty (),
Linemap::unknown_location ()},
nullptr);
return node;
}
bool
VariantDef::is_error () const
{
return get_id () == UNKNOWN_HIRID;
}
HirId
VariantDef::get_id () const
{
return id;
}
DefId
VariantDef::get_defid () const
{
return defid;
}
VariantDef::VariantType
VariantDef::get_variant_type () const
{
return type;
}
bool
VariantDef::is_data_variant () const
{
return type != VariantType::NUM;
}
bool
VariantDef::is_dataless_variant () const
{
return type == VariantType::NUM;
}
std::string
VariantDef::get_identifier () const
{
return identifier;
}
size_t
VariantDef::num_fields () const
{
return fields.size ();
}
StructFieldType *
VariantDef::get_field_at_index (size_t index)
{
rust_assert (index < fields.size ());
return fields.at (index);
}
std::vector &
VariantDef::get_fields ()
{
rust_assert (type != NUM);
return fields;
}
bool
VariantDef::lookup_field (const std::string &lookup,
StructFieldType **field_lookup, size_t *index) const
{
size_t i = 0;
for (auto &field : fields)
{
if (field->get_name ().compare (lookup) == 0)
{
if (index != nullptr)
*index = i;
if (field_lookup != nullptr)
*field_lookup = field;
return true;
}
i++;
}
return false;
}
HIR::Expr *
VariantDef::get_discriminant () const
{
rust_assert (discriminant != nullptr);
return discriminant;
}
std::string
VariantDef::as_string () const
{
if (type == VariantType::NUM)
return identifier + " = " + discriminant->as_string ();
std::string buffer;
for (size_t i = 0; i < fields.size (); ++i)
{
buffer += fields.at (i)->as_string ();
if ((i + 1) < fields.size ())
buffer += ", ";
}
if (type == VariantType::TUPLE)
return identifier + " (" + buffer + ")";
else
return identifier + " {" + buffer + "}";
}
bool
VariantDef::is_equal (const VariantDef &other) const
{
if (type != other.type)
return false;
if (identifier.compare (other.identifier) != 0)
return false;
if (discriminant != other.discriminant)
return false;
if (fields.size () != other.fields.size ())
return false;
for (size_t i = 0; i < fields.size (); i++)
{
if (!fields.at (i)->is_equal (*other.fields.at (i)))
return false;
}
return true;
}
VariantDef *
VariantDef::clone () const
{
std::vector cloned_fields;
for (auto &f : fields)
cloned_fields.push_back ((StructFieldType *) f->clone ());
return new VariantDef (id, defid, identifier, ident, type, discriminant,
cloned_fields);
}
VariantDef *
VariantDef::monomorphized_clone () const
{
std::vector cloned_fields;
for (auto &f : fields)
cloned_fields.push_back ((StructFieldType *) f->monomorphized_clone ());
return new VariantDef (id, defid, identifier, ident, type, discriminant,
cloned_fields);
}
const RustIdent &
VariantDef::get_ident () const
{
return ident;
}
// ADTType
void
ADTType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
ADTType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
ADTType::as_string () const
{
std::string variants_buffer;
for (size_t i = 0; i < number_of_variants (); ++i)
{
TyTy::VariantDef *variant = variants.at (i);
variants_buffer += variant->as_string ();
if ((i + 1) < number_of_variants ())
variants_buffer += ", ";
}
return identifier + subst_as_string () + "{" + variants_buffer + "}";
}
bool
ADTType::can_eq (const BaseType *other, bool emit_errors) const
{
ADTCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
ADTType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
auto other2 = static_cast (other);
if (get_adt_kind () != other2.get_adt_kind ())
return false;
if (number_of_variants () != other2.number_of_variants ())
return false;
if (has_subsititions_defined () != other2.has_subsititions_defined ())
return false;
if (has_subsititions_defined ())
{
if (get_num_substitutions () != other2.get_num_substitutions ())
return false;
for (size_t i = 0; i < get_num_substitutions (); i++)
{
const SubstitutionParamMapping &a = substitutions.at (i);
const SubstitutionParamMapping &b = other2.substitutions.at (i);
const ParamType *aa = a.get_param_ty ();
const ParamType *bb = b.get_param_ty ();
BaseType *aaa = aa->resolve ();
BaseType *bbb = bb->resolve ();
if (!aaa->is_equal (*bbb))
return false;
}
}
for (size_t i = 0; i < number_of_variants (); i++)
{
const TyTy::VariantDef *a = get_variants ().at (i);
const TyTy::VariantDef *b = other2.get_variants ().at (i);
if (!a->is_equal (*b))
return false;
}
return true;
}
BaseType *
ADTType::clone () const
{
std::vector cloned_variants;
for (auto &variant : variants)
cloned_variants.push_back (variant->clone ());
return new ADTType (get_ref (), get_ty_ref (), identifier, ident,
get_adt_kind (), cloned_variants, clone_substs (),
get_repr_options (), used_arguments,
get_combined_refs ());
}
BaseType *
ADTType::monomorphized_clone () const
{
std::vector cloned_variants;
for (auto &variant : variants)
cloned_variants.push_back (variant->monomorphized_clone ());
return new ADTType (get_ref (), get_ty_ref (), identifier, ident,
get_adt_kind (), cloned_variants, clone_substs (),
get_repr_options (), used_arguments,
get_combined_refs ());
}
static bool
handle_substitions (SubstitutionArgumentMappings &subst_mappings,
StructFieldType *field)
{
auto fty = field->get_field_type ();
bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
if (is_param_ty)
{
ParamType *p = static_cast (fty);
SubstitutionArg arg = SubstitutionArg::error ();
bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
if (ok)
{
auto argt = arg.get_tyty ();
bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
if (arg_is_param || arg_is_concrete)
{
auto new_field = argt->clone ();
new_field->set_ref (fty->get_ref ());
field->set_field_type (new_field);
}
else
{
field->get_field_type ()->set_ty_ref (argt->get_ref ());
}
}
}
else if (fty->has_subsititions_defined () || fty->contains_type_parameters ())
{
BaseType *concrete
= Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
if (concrete->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (subst_mappings.get_locus (),
"Failed to resolve field substitution type: %s",
fty->as_string ().c_str ());
return false;
}
auto new_field = concrete->clone ();
new_field->set_ref (fty->get_ref ());
field->set_field_type (new_field);
}
return true;
}
ADTType *
ADTType::handle_substitions (SubstitutionArgumentMappings &subst_mappings)
{
ADTType *adt = static_cast (clone ());
adt->set_ty_ref (mappings->get_next_hir_id ());
adt->used_arguments = subst_mappings;
for (auto &sub : adt->get_substs ())
{
SubstitutionArg arg = SubstitutionArg::error ();
bool ok
= subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
if (ok)
sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
}
for (auto &variant : adt->get_variants ())
{
if (variant->is_dataless_variant ())
continue;
for (auto &field : variant->get_fields ())
{
bool ok = ::Rust::TyTy::handle_substitions (subst_mappings, field);
if (!ok)
return adt;
}
}
return adt;
}
// TupleType
TupleType::TupleType (HirId ref, Location locus, std::vector fields,
std::set refs)
: BaseType (ref, ref, TypeKind::TUPLE,
{Resolver::CanonicalPath::create_empty (), locus}, refs),
fields (fields)
{}
TupleType::TupleType (HirId ref, HirId ty_ref, Location locus,
std::vector fields, std::set refs)
: BaseType (ref, ty_ref, TypeKind::TUPLE,
{Resolver::CanonicalPath::create_empty (), locus}, refs),
fields (fields)
{}
TupleType *
TupleType::get_unit_type (HirId ref)
{
return new TupleType (ref, Linemap::predeclared_location ());
}
bool
TupleType::is_unit () const
{
return this->fields.empty ();
}
size_t
TupleType::num_fields () const
{
return fields.size ();
}
bool
TupleType::is_concrete () const
{
for (size_t i = 0; i < num_fields (); i++)
{
if (!get_field (i)->is_concrete ())
return false;
}
return true;
}
const std::vector &
TupleType::get_fields () const
{
return fields;
}
void
TupleType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
TupleType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
TupleType::as_string () const
{
size_t i = 0;
std::string fields_buffer;
for (const TyVar &field : get_fields ())
{
fields_buffer += field.get_tyty ()->as_string ();
bool has_next = (i + 1) < get_fields ().size ();
fields_buffer += has_next ? ", " : "";
i++;
}
return "(" + fields_buffer + ")";
}
std::string
TupleType::get_name () const
{
size_t i = 0;
std::string fields_buffer;
for (const TyVar &field : get_fields ())
{
fields_buffer += field.get_tyty ()->as_string ();
bool has_next = (i + 1) < get_fields ().size ();
fields_buffer += has_next ? ", " : "";
i++;
}
return "(" + fields_buffer + ")";
}
BaseType *
TupleType::get_field (size_t index) const
{
return fields.at (index).get_tyty ();
}
bool
TupleType::can_eq (const BaseType *other, bool emit_errors) const
{
TupleCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
TupleType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
auto other2 = static_cast (other);
if (num_fields () != other2.num_fields ())
return false;
for (size_t i = 0; i < num_fields (); i++)
{
if (!get_field (i)->is_equal (*other2.get_field (i)))
return false;
}
return true;
}
BaseType *
TupleType::clone () const
{
std::vector cloned_fields;
for (const auto &f : fields)
cloned_fields.push_back (f.clone ());
return new TupleType (get_ref (), get_ty_ref (), get_ident ().locus,
cloned_fields, get_combined_refs ());
}
BaseType *
TupleType::monomorphized_clone () const
{
std::vector cloned_fields;
for (const auto &f : fields)
cloned_fields.push_back (f.monomorphized_clone ());
return new TupleType (get_ref (), get_ty_ref (), get_ident ().locus,
cloned_fields, get_combined_refs ());
}
TupleType *
TupleType::handle_substitions (SubstitutionArgumentMappings &mappings)
{
auto mappings_table = Analysis::Mappings::get ();
TupleType *tuple = static_cast (clone ());
tuple->set_ref (mappings_table->get_next_hir_id ());
tuple->set_ty_ref (mappings_table->get_next_hir_id ());
for (size_t i = 0; i < tuple->fields.size (); i++)
{
TyVar &field = fields.at (i);
if (field.get_tyty ()->contains_type_parameters ())
{
BaseType *concrete
= Resolver::SubstMapperInternal::Resolve (field.get_tyty (),
mappings);
tuple->fields[i]
= TyVar::subst_covariant_var (field.get_tyty (), concrete);
}
}
return tuple;
}
void
FnType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
FnType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
FnType::as_string () const
{
std::string params_str = "";
for (auto ¶m : params)
{
auto pattern = param.first;
auto ty = param.second;
params_str += pattern->as_string () + " " + ty->as_string ();
params_str += ",";
}
std::string ret_str = type->as_string ();
return "fn" + subst_as_string () + " (" + params_str + ") -> " + ret_str;
}
bool
FnType::can_eq (const BaseType *other, bool emit_errors) const
{
FnCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
FnType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
auto other2 = static_cast (other);
if (get_identifier ().compare (other2.get_identifier ()) != 0)
return false;
if (!get_return_type ()->is_equal (*other2.get_return_type ()))
return false;
if (has_subsititions_defined () != other2.has_subsititions_defined ())
return false;
if (has_subsititions_defined ())
{
if (get_num_substitutions () != other2.get_num_substitutions ())
return false;
const FnType &ofn = static_cast (other);
for (size_t i = 0; i < get_num_substitutions (); i++)
{
const SubstitutionParamMapping &a = get_substs ().at (i);
const SubstitutionParamMapping &b = ofn.get_substs ().at (i);
const ParamType *pa = a.get_param_ty ();
const ParamType *pb = b.get_param_ty ();
if (!pa->is_equal (*pb))
return false;
}
}
if (num_params () != other2.num_params ())
return false;
for (size_t i = 0; i < num_params (); i++)
{
auto lhs = param_at (i).second;
auto rhs = other2.param_at (i).second;
if (!lhs->is_equal (*rhs))
return false;
}
return true;
}
BaseType *
FnType::clone () const
{
std::vector> cloned_params;
for (auto &p : params)
cloned_params.push_back ({p.first, p.second->clone ()});
return new FnType (get_ref (), get_ty_ref (), get_id (), get_identifier (),
ident, flags, abi, std::move (cloned_params),
get_return_type ()->clone (), clone_substs (),
get_combined_refs ());
}
BaseType *
FnType::monomorphized_clone () const
{
std::vector> cloned_params;
for (auto &p : params)
cloned_params.push_back ({p.first, p.second->monomorphized_clone ()});
return new FnType (get_ref (), get_ty_ref (), get_id (), get_identifier (),
ident, flags, abi, std::move (cloned_params),
get_return_type ()->clone (), clone_substs (),
get_combined_refs ());
}
FnType *
FnType::handle_substitions (SubstitutionArgumentMappings &subst_mappings)
{
FnType *fn = static_cast (clone ());
fn->set_ty_ref (mappings->get_next_hir_id ());
fn->used_arguments = subst_mappings;
for (auto &sub : fn->get_substs ())
{
SubstitutionArg arg = SubstitutionArg::error ();
bool ok
= subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
if (ok)
{
sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
}
}
auto fty = fn->get_return_type ();
bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
if (is_param_ty)
{
ParamType *p = static_cast (fty);
SubstitutionArg arg = SubstitutionArg::error ();
bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
if (ok)
{
auto argt = arg.get_tyty ();
bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
if (arg_is_param || arg_is_concrete)
{
auto new_field = argt->clone ();
new_field->set_ref (fty->get_ref ());
fn->type = new_field;
}
else
{
fty->set_ty_ref (argt->get_ref ());
}
}
}
else if (fty->needs_generic_substitutions ()
|| fty->contains_type_parameters ())
{
BaseType *concrete
= Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
if (concrete == nullptr || concrete->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (subst_mappings.get_locus (),
"Failed to resolve field substitution type: %s",
fty->as_string ().c_str ());
return nullptr;
}
auto new_field = concrete->clone ();
new_field->set_ref (fty->get_ref ());
fn->type = new_field;
}
for (auto ¶m : fn->get_params ())
{
auto fty = param.second;
bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
if (is_param_ty)
{
ParamType *p = static_cast (fty);
SubstitutionArg arg = SubstitutionArg::error ();
bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
if (ok)
{
auto argt = arg.get_tyty ();
bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
if (arg_is_param || arg_is_concrete)
{
auto new_field = argt->clone ();
new_field->set_ref (fty->get_ref ());
param.second = new_field;
}
else
{
fty->set_ty_ref (argt->get_ref ());
}
}
}
else if (fty->has_subsititions_defined ()
|| fty->contains_type_parameters ())
{
BaseType *concrete
= Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
if (concrete == nullptr
|| concrete->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (subst_mappings.get_locus (),
"Failed to resolve field substitution type: %s",
fty->as_string ().c_str ());
return nullptr;
}
auto new_field = concrete->clone ();
new_field->set_ref (fty->get_ref ());
param.second = new_field;
}
}
return fn;
}
void
FnPtr::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
FnPtr::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
FnPtr::as_string () const
{
std::string params_str;
auto ¶ms = get_params ();
for (auto &p : params)
{
params_str += p.get_tyty ()->as_string () + " ,";
}
return "fnptr (" + params_str + ") -> " + get_return_type ()->as_string ();
}
bool
FnPtr::can_eq (const BaseType *other, bool emit_errors) const
{
FnptrCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
FnPtr::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
auto other2 = static_cast (other);
auto this_ret_type = get_return_type ();
auto other_ret_type = other2.get_return_type ();
if (this_ret_type->is_equal (*other_ret_type))
return false;
if (num_params () != other2.num_params ())
return false;
for (size_t i = 0; i < num_params (); i++)
{
if (!param_at (i)->is_equal (*other2.param_at (i)))
return false;
}
return true;
}
BaseType *
FnPtr::clone () const
{
std::vector cloned_params;
for (auto &p : params)
cloned_params.push_back (TyVar (p.get_ref ()));
return new FnPtr (get_ref (), get_ty_ref (), ident.locus,
std::move (cloned_params), result_type,
get_combined_refs ());
}
BaseType *
FnPtr::monomorphized_clone () const
{
std::vector cloned_params;
for (auto &p : params)
cloned_params.push_back (p.monomorphized_clone ());
return new FnPtr (get_ref (), get_ty_ref (), ident.locus,
std::move (cloned_params), result_type,
get_combined_refs ());
}
void
ClosureType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
ClosureType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
ClosureType::as_string () const
{
std::string params_buf = parameters->as_string ();
return "|" + params_buf + "| {" + result_type.get_tyty ()->as_string () + "}";
}
bool
ClosureType::can_eq (const BaseType *other, bool emit_errors) const
{
ClosureCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
ClosureType::is_equal (const BaseType &other) const
{
if (other.get_kind () != TypeKind::CLOSURE)
return false;
const ClosureType &other2 = static_cast (other);
if (get_def_id () != other2.get_def_id ())
return false;
if (!get_parameters ().is_equal (other2.get_parameters ()))
return false;
return get_result_type ().is_equal (other2.get_result_type ());
}
BaseType *
ClosureType::clone () const
{
return new ClosureType (get_ref (), get_ty_ref (), ident, id,
(TyTy::TupleType *) parameters->clone (), result_type,
clone_substs (), captures, get_combined_refs (),
specified_bounds);
}
BaseType *
ClosureType::monomorphized_clone () const
{
return clone ();
}
ClosureType *
ClosureType::handle_substitions (SubstitutionArgumentMappings &mappings)
{
gcc_unreachable ();
return nullptr;
}
void
ClosureType::setup_fn_once_output () const
{
// lookup the lang items
auto fn_once_lang_item = Analysis::RustLangItem::ItemType::FN_ONCE;
auto fn_once_output_lang_item
= Analysis::RustLangItem::ItemType::FN_ONCE_OUTPUT;
DefId trait_id = UNKNOWN_DEFID;
bool trait_lang_item_defined
= mappings->lookup_lang_item (fn_once_lang_item, &trait_id);
rust_assert (trait_lang_item_defined);
DefId trait_item_id = UNKNOWN_DEFID;
bool trait_item_lang_item_defined
= mappings->lookup_lang_item (fn_once_output_lang_item, &trait_item_id);
rust_assert (trait_item_lang_item_defined);
// resolve to the trait
HIR::Item *item = mappings->lookup_defid (trait_id);
rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
HIR::Trait *trait = static_cast (item);
Resolver::TraitReference *trait_ref
= Resolver::TraitResolver::Resolve (*trait);
rust_assert (!trait_ref->is_error ());
// resolve to trait item
HIR::TraitItem *trait_item
= mappings->lookup_trait_item_defid (trait_item_id);
rust_assert (trait_item != nullptr);
rust_assert (trait_item->get_item_kind ()
== HIR::TraitItem::TraitItemKind::TYPE);
std::string item_identifier = trait_item->trait_identifier ();
// setup associated types #[lang = "fn_once_output"]
Resolver::TraitItemReference *item_reference = nullptr;
bool found = trait_ref->lookup_trait_item_by_type (
item_identifier, Resolver::TraitItemReference::TraitItemType::TYPE,
&item_reference);
rust_assert (found);
// setup
item_reference->associated_type_set (&get_result_type ());
}
void
ArrayType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
ArrayType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
ArrayType::as_string () const
{
return "[" + get_element_type ()->as_string () + ":" + "CAPACITY" + "]";
}
bool
ArrayType::can_eq (const BaseType *other, bool emit_errors) const
{
ArrayCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
ArrayType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
auto other2 = static_cast (other);
auto this_element_type = get_element_type ();
auto other_element_type = other2.get_element_type ();
return this_element_type->is_equal (*other_element_type);
}
BaseType *
ArrayType::get_element_type () const
{
return element_type.get_tyty ();
}
BaseType *
ArrayType::clone () const
{
return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity_expr,
element_type, get_combined_refs ());
}
BaseType *
ArrayType::monomorphized_clone () const
{
return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity_expr,
element_type.monomorphized_clone (),
get_combined_refs ());
}
ArrayType *
ArrayType::handle_substitions (SubstitutionArgumentMappings &mappings)
{
auto mappings_table = Analysis::Mappings::get ();
ArrayType *ref = static_cast (clone ());
ref->set_ty_ref (mappings_table->get_next_hir_id ());
// might be &T or &ADT so this needs to be recursive
auto base = ref->get_element_type ();
BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
ref->element_type = TyVar::subst_covariant_var (base, concrete);
return ref;
}
void
SliceType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
SliceType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
SliceType::as_string () const
{
return "[" + get_element_type ()->as_string () + "]";
}
bool
SliceType::can_eq (const BaseType *other, bool emit_errors) const
{
SliceCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
SliceType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
auto other2 = static_cast (other);
auto this_element_type = get_element_type ();
auto other_element_type = other2.get_element_type ();
return this_element_type->is_equal (*other_element_type);
}
BaseType *
SliceType::get_element_type () const
{
return element_type.get_tyty ();
}
BaseType *
SliceType::clone () const
{
return new SliceType (get_ref (), get_ty_ref (), ident.locus,
element_type.clone (), get_combined_refs ());
}
BaseType *
SliceType::monomorphized_clone () const
{
return new SliceType (get_ref (), get_ty_ref (), ident.locus,
element_type.monomorphized_clone (),
get_combined_refs ());
}
SliceType *
SliceType::handle_substitions (SubstitutionArgumentMappings &mappings)
{
auto mappings_table = Analysis::Mappings::get ();
SliceType *ref = static_cast (clone ());
ref->set_ty_ref (mappings_table->get_next_hir_id ());
// might be &T or &ADT so this needs to be recursive
auto base = ref->get_element_type ();
BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
ref->element_type = TyVar::subst_covariant_var (base, concrete);
return ref;
}
// BoolType
BoolType::BoolType (HirId ref, std::set refs)
: BaseType (ref, ref, TypeKind::BOOL,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
BoolType::BoolType (HirId ref, HirId ty_ref, std::set refs)
: BaseType (ref, ty_ref, TypeKind::BOOL,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
std::string
BoolType::get_name () const
{
return as_string ();
}
bool
BoolType::is_concrete () const
{
return true;
}
void
BoolType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
BoolType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
BoolType::as_string () const
{
return "bool";
}
bool
BoolType::can_eq (const BaseType *other, bool emit_errors) const
{
BoolCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
BoolType::clone () const
{
return new BoolType (get_ref (), get_ty_ref (), get_combined_refs ());
}
BaseType *
BoolType::monomorphized_clone () const
{
return clone ();
}
// IntType
IntType::IntType (HirId ref, IntKind kind, std::set refs)
: BaseType (ref, ref, TypeKind::INT,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
int_kind (kind)
{}
IntType::IntType (HirId ref, HirId ty_ref, IntKind kind, std::set refs)
: BaseType (ref, ty_ref, TypeKind::INT,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
int_kind (kind)
{}
std::string
IntType::get_name () const
{
return as_string ();
}
IntType::IntKind
IntType::get_int_kind () const
{
return int_kind;
}
void
IntType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
IntType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
IntType::as_string () const
{
switch (int_kind)
{
case I8:
return "i8";
case I16:
return "i16";
case I32:
return "i32";
case I64:
return "i64";
case I128:
return "i128";
}
gcc_unreachable ();
return "__unknown_int_type";
}
bool
IntType::can_eq (const BaseType *other, bool emit_errors) const
{
IntCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
IntType::clone () const
{
return new IntType (get_ref (), get_ty_ref (), get_int_kind (),
get_combined_refs ());
}
BaseType *
IntType::monomorphized_clone () const
{
return clone ();
}
bool
IntType::is_equal (const BaseType &other) const
{
if (!BaseType::is_equal (other))
return false;
const IntType &o = static_cast (other);
return get_int_kind () == o.get_int_kind ();
}
bool
IntType::is_concrete () const
{
return true;
}
// UintType
UintType::UintType (HirId ref, UintKind kind, std::set refs)
: BaseType (ref, ref, TypeKind::UINT,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
uint_kind (kind)
{}
UintType::UintType (HirId ref, HirId ty_ref, UintKind kind,
std::set refs)
: BaseType (ref, ty_ref, TypeKind::UINT,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
uint_kind (kind)
{}
std::string
UintType::get_name () const
{
return as_string ();
}
UintType::UintKind
UintType::get_uint_kind () const
{
return uint_kind;
}
void
UintType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
UintType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
UintType::as_string () const
{
switch (uint_kind)
{
case U8:
return "u8";
case U16:
return "u16";
case U32:
return "u32";
case U64:
return "u64";
case U128:
return "u128";
}
gcc_unreachable ();
return "__unknown_uint_type";
}
bool
UintType::can_eq (const BaseType *other, bool emit_errors) const
{
UintCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
UintType::clone () const
{
return new UintType (get_ref (), get_ty_ref (), get_uint_kind (),
get_combined_refs ());
}
BaseType *
UintType::monomorphized_clone () const
{
return clone ();
}
bool
UintType::is_equal (const BaseType &other) const
{
if (!BaseType::is_equal (other))
return false;
const UintType &o = static_cast (other);
return get_uint_kind () == o.get_uint_kind ();
}
bool
UintType::is_concrete () const
{
return true;
}
// FloatType
FloatType::FloatType (HirId ref, FloatKind kind, std::set refs)
: BaseType (ref, ref, TypeKind::FLOAT,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
float_kind (kind)
{}
FloatType::FloatType (HirId ref, HirId ty_ref, FloatKind kind,
std::set refs)
: BaseType (ref, ty_ref, TypeKind::FLOAT,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
float_kind (kind)
{}
std::string
FloatType::get_name () const
{
return as_string ();
}
FloatType::FloatKind
FloatType::get_float_kind () const
{
return float_kind;
}
bool
FloatType::is_concrete () const
{
return true;
}
void
FloatType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
FloatType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
FloatType::as_string () const
{
switch (float_kind)
{
case F32:
return "f32";
case F64:
return "f64";
}
gcc_unreachable ();
return "__unknown_float_type";
}
bool
FloatType::can_eq (const BaseType *other, bool emit_errors) const
{
FloatCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
FloatType::clone () const
{
return new FloatType (get_ref (), get_ty_ref (), get_float_kind (),
get_combined_refs ());
}
BaseType *
FloatType::monomorphized_clone () const
{
return clone ();
}
bool
FloatType::is_equal (const BaseType &other) const
{
if (!BaseType::is_equal (other))
return false;
const FloatType &o = static_cast (other);
return get_float_kind () == o.get_float_kind ();
}
// UsizeType
USizeType::USizeType (HirId ref, std::set refs)
: BaseType (ref, ref, TypeKind::USIZE,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
USizeType::USizeType (HirId ref, HirId ty_ref, std::set refs)
: BaseType (ref, ty_ref, TypeKind::USIZE,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
std::string
USizeType::get_name () const
{
return as_string ();
}
bool
USizeType::is_concrete () const
{
return true;
}
void
USizeType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
USizeType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
USizeType::as_string () const
{
return "usize";
}
bool
USizeType::can_eq (const BaseType *other, bool emit_errors) const
{
USizeCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
USizeType::clone () const
{
return new USizeType (get_ref (), get_ty_ref (), get_combined_refs ());
}
BaseType *
USizeType::monomorphized_clone () const
{
return clone ();
}
// ISizeType
ISizeType::ISizeType (HirId ref, std::set refs)
: BaseType (ref, ref, TypeKind::ISIZE,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
ISizeType::ISizeType (HirId ref, HirId ty_ref, std::set refs)
: BaseType (ref, ty_ref, TypeKind::ISIZE,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
std::string
ISizeType::get_name () const
{
return as_string ();
}
bool
ISizeType::is_concrete () const
{
return true;
}
void
ISizeType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
ISizeType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
ISizeType::as_string () const
{
return "isize";
}
bool
ISizeType::can_eq (const BaseType *other, bool emit_errors) const
{
ISizeCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
ISizeType::clone () const
{
return new ISizeType (get_ref (), get_ty_ref (), get_combined_refs ());
}
BaseType *
ISizeType::monomorphized_clone () const
{
return clone ();
}
// Char Type
CharType::CharType (HirId ref, std::set refs)
: BaseType (ref, ref, TypeKind::CHAR,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
CharType::CharType (HirId ref, HirId ty_ref, std::set refs)
: BaseType (ref, ty_ref, TypeKind::CHAR,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
bool
CharType::is_concrete () const
{
return true;
}
std::string
CharType::get_name () const
{
return as_string ();
}
void
CharType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
CharType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
CharType::as_string () const
{
return "char";
}
bool
CharType::can_eq (const BaseType *other, bool emit_errors) const
{
CharCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
CharType::clone () const
{
return new CharType (get_ref (), get_ty_ref (), get_combined_refs ());
}
BaseType *
CharType::monomorphized_clone () const
{
return clone ();
}
// Reference Type
ReferenceType::ReferenceType (HirId ref, TyVar base, Mutability mut,
std::set refs)
: BaseType (ref, ref, TypeKind::REF,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
base (base), mut (mut)
{}
ReferenceType::ReferenceType (HirId ref, HirId ty_ref, TyVar base,
Mutability mut, std::set refs)
: BaseType (ref, ty_ref, TypeKind::REF,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
base (base), mut (mut)
{}
bool
ReferenceType::is_concrete () const
{
return get_base ()->is_concrete ();
}
Mutability
ReferenceType::mutability () const
{
return mut;
}
bool
ReferenceType::is_mutable () const
{
return mut == Mutability::Mut;
}
bool
ReferenceType::is_dyn_object () const
{
return is_dyn_slice_type () || is_dyn_str_type ();
}
bool
ReferenceType::is_dyn_slice_type (const TyTy::SliceType **slice) const
{
const TyTy::BaseType *element = get_base ()->destructure ();
if (element->get_kind () != TyTy::TypeKind::SLICE)
return false;
if (slice == nullptr)
return true;
*slice = static_cast (element);
return true;
}
bool
ReferenceType::is_dyn_str_type (const TyTy::StrType **str) const
{
const TyTy::BaseType *element = get_base ()->destructure ();
if (element->get_kind () != TyTy::TypeKind::STR)
return false;
if (str == nullptr)
return true;
*str = static_cast (element);
return true;
}
void
ReferenceType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
ReferenceType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
ReferenceType::as_string () const
{
return std::string ("&") + (is_mutable () ? "mut" : "") + " "
+ get_base ()->as_string ();
}
std::string
ReferenceType::get_name () const
{
return std::string ("&") + (is_mutable () ? "mut" : "") + " "
+ get_base ()->get_name ();
}
bool
ReferenceType::can_eq (const BaseType *other, bool emit_errors) const
{
ReferenceCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
ReferenceType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
auto other2 = static_cast (other);
if (mutability () != other2.mutability ())
return false;
return get_base ()->is_equal (*other2.get_base ());
}
BaseType *
ReferenceType::get_base () const
{
return base.get_tyty ();
}
BaseType *
ReferenceType::clone () const
{
return new ReferenceType (get_ref (), get_ty_ref (), base, mutability (),
get_combined_refs ());
}
BaseType *
ReferenceType::monomorphized_clone () const
{
return new ReferenceType (get_ref (), get_ty_ref (),
base.monomorphized_clone (), mutability (),
get_combined_refs ());
}
ReferenceType *
ReferenceType::handle_substitions (SubstitutionArgumentMappings &mappings)
{
auto mappings_table = Analysis::Mappings::get ();
ReferenceType *ref = static_cast (clone ());
ref->set_ty_ref (mappings_table->get_next_hir_id ());
// might be &T or &ADT so this needs to be recursive
auto base = ref->get_base ();
BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
ref->base = TyVar::subst_covariant_var (base, concrete);
return ref;
}
// PointerType
PointerType::PointerType (HirId ref, TyVar base, Mutability mut,
std::set refs)
: BaseType (ref, ref, TypeKind::POINTER,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
base (base), mut (mut)
{}
PointerType::PointerType (HirId ref, HirId ty_ref, TyVar base, Mutability mut,
std::set refs)
: BaseType (ref, ty_ref, TypeKind::POINTER,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
base (base), mut (mut)
{}
bool
PointerType::is_concrete () const
{
return get_base ()->is_concrete ();
}
Mutability
PointerType::mutability () const
{
return mut;
}
bool
PointerType::is_mutable () const
{
return mut == Mutability::Mut;
}
bool
PointerType::is_const () const
{
return mut == Mutability::Imm;
}
bool
PointerType::is_dyn_object () const
{
return is_dyn_slice_type () || is_dyn_str_type ();
}
bool
PointerType::is_dyn_slice_type (const TyTy::SliceType **slice) const
{
const TyTy::BaseType *element = get_base ()->destructure ();
if (element->get_kind () != TyTy::TypeKind::SLICE)
return false;
if (slice == nullptr)
return true;
*slice = static_cast (element);
return true;
}
bool
PointerType::is_dyn_str_type (const TyTy::StrType **str) const
{
const TyTy::BaseType *element = get_base ()->destructure ();
if (element->get_kind () != TyTy::TypeKind::STR)
return false;
if (str == nullptr)
return true;
*str = static_cast (element);
return true;
}
void
PointerType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
PointerType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
PointerType::as_string () const
{
return std::string ("* ") + (is_mutable () ? "mut" : "const") + " "
+ get_base ()->as_string ();
}
std::string
PointerType::get_name () const
{
return std::string ("* ") + (is_mutable () ? "mut" : "const") + " "
+ get_base ()->get_name ();
}
bool
PointerType::can_eq (const BaseType *other, bool emit_errors) const
{
PointerCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
PointerType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
auto other2 = static_cast (other);
if (mutability () != other2.mutability ())
return false;
return get_base ()->is_equal (*other2.get_base ());
}
BaseType *
PointerType::get_base () const
{
return base.get_tyty ();
}
BaseType *
PointerType::clone () const
{
return new PointerType (get_ref (), get_ty_ref (), base, mutability (),
get_combined_refs ());
}
BaseType *
PointerType::monomorphized_clone () const
{
return new PointerType (get_ref (), get_ty_ref (),
base.monomorphized_clone (), mutability (),
get_combined_refs ());
}
PointerType *
PointerType::handle_substitions (SubstitutionArgumentMappings &mappings)
{
auto mappings_table = Analysis::Mappings::get ();
PointerType *ref = static_cast (clone ());
ref->set_ty_ref (mappings_table->get_next_hir_id ());
// might be &T or &ADT so this needs to be recursive
auto base = ref->get_base ();
BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings);
ref->base = TyVar::subst_covariant_var (base, concrete);
return ref;
}
// PARAM Type
ParamType::ParamType (std::string symbol, Location locus, HirId ref,
HIR::GenericParam ¶m,
std::vector specified_bounds,
std::set refs)
: BaseType (ref, ref, TypeKind::PARAM,
{Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
locus},
specified_bounds, refs),
is_trait_self (false), symbol (symbol), param (param)
{}
ParamType::ParamType (bool is_trait_self, std::string symbol, Location locus,
HirId ref, HirId ty_ref, HIR::GenericParam ¶m,
std::vector specified_bounds,
std::set refs)
: BaseType (ref, ty_ref, TypeKind::PARAM,
{Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
locus},
specified_bounds, refs),
is_trait_self (is_trait_self), symbol (symbol), param (param)
{}
HIR::GenericParam &
ParamType::get_generic_param ()
{
return param;
}
bool
ParamType::can_resolve () const
{
return get_ref () != get_ty_ref ();
}
bool
ParamType::is_concrete () const
{
auto r = resolve ();
if (r == this)
return false;
return r->is_concrete ();
}
void
ParamType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
ParamType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
ParamType::as_string () const
{
if (!can_resolve ())
{
return get_symbol () + " REF: " + std::to_string (get_ref ());
}
BaseType *lookup = resolve ();
return get_symbol () + "=" + lookup->as_string ();
}
std::string
ParamType::get_name () const
{
if (!can_resolve ())
return get_symbol ();
return resolve ()->get_name ();
}
bool
ParamType::can_eq (const BaseType *other, bool emit_errors) const
{
ParamCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
ParamType::clone () const
{
return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref (),
get_ty_ref (), param, get_specified_bounds (),
get_combined_refs ());
}
BaseType *
ParamType::monomorphized_clone () const
{
return resolve ()->clone ();
}
std::string
ParamType::get_symbol () const
{
return symbol;
}
BaseType *
ParamType::resolve () const
{
TyVar var (get_ty_ref ());
BaseType *r = var.get_tyty ();
while (r->get_kind () == TypeKind::PARAM)
{
ParamType *rr = static_cast (r);
if (!rr->can_resolve ())
break;
TyVar v (rr->get_ty_ref ());
BaseType *n = v.get_tyty ();
// fix infinite loop
if (r == n)
break;
r = n;
}
if (r->get_kind () == TypeKind::PARAM && (r->get_ref () == r->get_ty_ref ()))
return TyVar (r->get_ty_ref ()).get_tyty ();
return r;
}
bool
ParamType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
{
if (!can_resolve ())
return false;
return resolve ()->is_equal (other);
}
auto other2 = static_cast (other);
if (can_resolve () != other2.can_resolve ())
return false;
if (can_resolve ())
return resolve ()->can_eq (other2.resolve (), false);
return get_symbol ().compare (other2.get_symbol ()) == 0;
}
ParamType *
ParamType::handle_substitions (SubstitutionArgumentMappings &subst_mappings)
{
SubstitutionArg arg = SubstitutionArg::error ();
bool ok = subst_mappings.get_argument_for_symbol (this, &arg);
if (!ok || arg.is_error ())
return this;
ParamType *p = static_cast (clone ());
subst_mappings.on_param_subst (*p, arg);
// there are two cases one where we substitute directly to a new PARAM and
// otherwise
if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM)
{
p->set_ty_ref (arg.get_tyty ()->get_ref ());
return p;
}
// this is the new subst that this needs to pass
p->set_ref (mappings->get_next_hir_id ());
p->set_ty_ref (arg.get_tyty ()->get_ref ());
return p;
}
void
ParamType::set_implicit_self_trait ()
{
is_trait_self = true;
}
bool
ParamType::is_implicit_self_trait () const
{
return is_trait_self;
}
// StrType
StrType::StrType (HirId ref, std::set refs)
: BaseType (ref, ref, TypeKind::STR,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
StrType::StrType (HirId ref, HirId ty_ref, std::set refs)
: BaseType (ref, ty_ref, TypeKind::STR,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
std::string
StrType::get_name () const
{
return as_string ();
}
bool
StrType::is_concrete () const
{
return true;
}
BaseType *
StrType::clone () const
{
return new StrType (get_ref (), get_ty_ref (), get_combined_refs ());
}
BaseType *
StrType::monomorphized_clone () const
{
return clone ();
}
void
StrType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
StrType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
StrType::as_string () const
{
return "str";
}
bool
StrType::can_eq (const BaseType *other, bool emit_errors) const
{
StrCmp r (this, emit_errors);
return r.can_eq (other);
}
bool
StrType::is_equal (const BaseType &other) const
{
return get_kind () == other.get_kind ();
}
// Never Type
NeverType::NeverType (HirId ref, std::set refs)
: BaseType (ref, ref, TypeKind::NEVER,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
NeverType::NeverType (HirId ref, HirId ty_ref, std::set refs)
: BaseType (ref, ty_ref, TypeKind::NEVER,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs)
{}
std::string
NeverType::get_name () const
{
return as_string ();
}
bool
NeverType::is_unit () const
{
return true;
}
bool
NeverType::is_concrete () const
{
return true;
}
void
NeverType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
NeverType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
NeverType::as_string () const
{
return "!";
}
bool
NeverType::can_eq (const BaseType *other, bool emit_errors) const
{
NeverCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
NeverType::clone () const
{
return new NeverType (get_ref (), get_ty_ref (), get_combined_refs ());
}
BaseType *
NeverType::monomorphized_clone () const
{
return clone ();
}
// placeholder type
PlaceholderType::PlaceholderType (std::string symbol, HirId ref,
std::set refs)
: BaseType (ref, ref, TypeKind::PLACEHOLDER,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
symbol (symbol)
{}
PlaceholderType::PlaceholderType (std::string symbol, HirId ref, HirId ty_ref,
std::set refs)
: BaseType (ref, ty_ref, TypeKind::PLACEHOLDER,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
symbol (symbol)
{}
std::string
PlaceholderType::get_name () const
{
return as_string ();
}
bool
PlaceholderType::is_unit () const
{
rust_assert (can_resolve ());
return resolve ()->is_unit ();
}
std::string
PlaceholderType::get_symbol () const
{
return symbol;
}
bool
PlaceholderType::is_concrete () const
{
if (!can_resolve ())
return true;
return resolve ()->is_concrete ();
}
void
PlaceholderType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
PlaceholderType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
PlaceholderType::as_string () const
{
return "as_string () : "")
+ ">";
}
bool
PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const
{
PlaceholderCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
PlaceholderType::clone () const
{
return new PlaceholderType (get_symbol (), get_ref (), get_ty_ref (),
get_combined_refs ());
}
BaseType *
PlaceholderType::monomorphized_clone () const
{
if (can_resolve ())
return resolve ()->monomorphized_clone ();
return clone ();
}
void
PlaceholderType::set_associated_type (HirId ref)
{
auto context = Resolver::TypeCheckContext::get ();
context->insert_associated_type_mapping (get_ty_ref (), ref);
}
void
PlaceholderType::clear_associated_type ()
{
auto context = Resolver::TypeCheckContext::get ();
context->clear_associated_type_mapping (get_ty_ref ());
}
bool
PlaceholderType::can_resolve () const
{
auto context = Resolver::TypeCheckContext::get ();
return context->lookup_associated_type_mapping (get_ty_ref (), nullptr);
}
BaseType *
PlaceholderType::resolve () const
{
auto context = Resolver::TypeCheckContext::get ();
HirId mapping;
bool ok = context->lookup_associated_type_mapping (get_ty_ref (), &mapping);
rust_assert (ok);
return TyVar (mapping).get_tyty ();
}
bool
PlaceholderType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
{
if (!can_resolve ())
return false;
return resolve ()->is_equal (other);
}
auto other2 = static_cast (other);
return get_symbol ().compare (other2.get_symbol ()) == 0;
}
// Projection type
ProjectionType::ProjectionType (
HirId ref, BaseType *base, const Resolver::TraitReference *trait, DefId item,
std::vector subst_refs,
SubstitutionArgumentMappings generic_arguments, std::set refs)
: BaseType (ref, ref, TypeKind::PROJECTION,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
base (base), trait (trait), item (item)
{}
ProjectionType::ProjectionType (
HirId ref, HirId ty_ref, BaseType *base,
const Resolver::TraitReference *trait, DefId item,
std::vector subst_refs,
SubstitutionArgumentMappings generic_arguments, std::set refs)
: BaseType (ref, ty_ref, TypeKind::PROJECTION,
{Resolver::CanonicalPath::create_empty (),
Linemap::predeclared_location ()},
refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
base (base), trait (trait), item (item)
{}
bool
ProjectionType::is_unit () const
{
return false;
}
std::string
ProjectionType::get_name () const
{
return as_string ();
}
bool
ProjectionType::needs_generic_substitutions () const
{
return needs_substitution ();
}
bool
ProjectionType::supports_substitutions () const
{
return true;
}
bool
ProjectionType::has_subsititions_defined () const
{
return has_substitutions ();
}
const BaseType *
ProjectionType::get () const
{
return base;
}
BaseType *
ProjectionType::get ()
{
return base;
}
bool
ProjectionType::is_concrete () const
{
return base->is_concrete ();
}
void
ProjectionType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
ProjectionType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
ProjectionType::as_string () const
{
return "as_string () + ">";
}
bool
ProjectionType::can_eq (const BaseType *other, bool emit_errors) const
{
return base->can_eq (other, emit_errors);
}
BaseType *
ProjectionType::clone () const
{
return new ProjectionType (get_ref (), get_ty_ref (), base->clone (), trait,
item, clone_substs (), used_arguments,
get_combined_refs ());
}
BaseType *
ProjectionType::monomorphized_clone () const
{
return get ()->monomorphized_clone ();
}
ProjectionType *
ProjectionType::handle_substitions (
SubstitutionArgumentMappings &subst_mappings)
{
// // do we really need to substitute this?
// if (base->needs_generic_substitutions () || base->contains_type_parameters
// ())
// {
// return this;
// }
ProjectionType *projection = static_cast (clone ());
projection->set_ty_ref (mappings->get_next_hir_id ());
projection->used_arguments = subst_mappings;
auto context = Resolver::TypeCheckContext::get ();
context->insert_implicit_type (projection->get_ty_ref (), projection);
for (auto &sub : projection->get_substs ())
{
SubstitutionArg arg = SubstitutionArg::error ();
bool ok
= subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
if (ok)
sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
}
auto fty = projection->base;
bool is_param_ty = fty->get_kind () == TypeKind::PARAM;
if (is_param_ty)
{
ParamType *p = static_cast (fty);
SubstitutionArg arg = SubstitutionArg::error ();
bool ok = subst_mappings.get_argument_for_symbol (p, &arg);
if (ok)
{
auto argt = arg.get_tyty ();
bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM;
bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER;
if (arg_is_param || arg_is_concrete)
{
auto new_field = argt->clone ();
new_field->set_ref (fty->get_ref ());
projection->base = new_field;
}
else
{
fty->set_ty_ref (argt->get_ref ());
}
}
}
else if (fty->needs_generic_substitutions ()
|| fty->contains_type_parameters ())
{
BaseType *concrete
= Resolver::SubstMapperInternal::Resolve (fty, subst_mappings);
if (concrete == nullptr || concrete->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (subst_mappings.get_locus (),
"Failed to resolve field substitution type: %s",
fty->as_string ().c_str ());
return nullptr;
}
projection->base = concrete;
}
return projection;
}
// DynObjectType
DynamicObjectType::DynamicObjectType (
HirId ref, RustIdent ident, std::vector specified_bounds,
std::set refs)
: BaseType (ref, ref, TypeKind::DYNAMIC, ident, specified_bounds, refs)
{}
DynamicObjectType::DynamicObjectType (
HirId ref, HirId ty_ref, RustIdent ident,
std::vector specified_bounds, std::set refs)
: BaseType (ref, ty_ref, TypeKind::DYNAMIC, ident, specified_bounds, refs)
{}
bool
DynamicObjectType::is_concrete () const
{
return true;
}
void
DynamicObjectType::accept_vis (TyVisitor &vis)
{
vis.visit (*this);
}
void
DynamicObjectType::accept_vis (TyConstVisitor &vis) const
{
vis.visit (*this);
}
std::string
DynamicObjectType::as_string () const
{
return "dyn [" + raw_bounds_as_string () + "]";
}
bool
DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const
{
DynamicCmp r (this, emit_errors);
return r.can_eq (other);
}
BaseType *
DynamicObjectType::clone () const
{
return new DynamicObjectType (get_ref (), get_ty_ref (), ident,
specified_bounds, get_combined_refs ());
}
BaseType *
DynamicObjectType::monomorphized_clone () const
{
return clone ();
}
std::string
DynamicObjectType::get_name () const
{
return "dyn [" + raw_bounds_as_name () + "]";
}
bool
DynamicObjectType::is_equal (const BaseType &other) const
{
if (get_kind () != other.get_kind ())
return false;
if (num_specified_bounds () != other.num_specified_bounds ())
return false;
return bounds_compatible (other, Location (), false);
}
const std::vector<
std::pair>
DynamicObjectType::get_object_items () const
{
std::vector<
std::pair>
items;
for (auto &bound : get_specified_bounds ())
{
const Resolver::TraitReference *trait = bound.get ();
std::vector trait_items;
trait->get_trait_items_and_supers (trait_items);
for (auto &item : trait_items)
{
if (item->get_trait_item_type ()
== Resolver::TraitItemReference::TraitItemType::FN
&& item->is_object_safe ())
items.push_back ({item, &bound});
}
}
return items;
}
} // namespace TyTy
} // namespace Rust