blob: dc93857e60f09a24176852d1b18682cad4ddb8a4 [file] [log] [blame]
// 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
// <http://www.gnu.org/licenses/>.
#include "rust-substitution-mapper.h"
#include "rust-hir-type-check.h"
namespace Rust {
namespace Resolver {
SubstMapper::SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus)
: resolved (new TyTy::ErrorType (ref)), generics (generics), locus (locus)
{}
TyTy::BaseType *
SubstMapper::Resolve (TyTy::BaseType *base, Location locus,
HIR::GenericArgs *generics)
{
SubstMapper mapper (base->get_ref (), generics, locus);
base->accept_vis (mapper);
rust_assert (mapper.resolved != nullptr);
return mapper.resolved;
}
TyTy::BaseType *
SubstMapper::InferSubst (TyTy::BaseType *base, Location locus)
{
return SubstMapper::Resolve (base, locus, nullptr);
}
bool
SubstMapper::have_generic_args () const
{
return generics != nullptr;
}
void
SubstMapper::visit (TyTy::FnType &type)
{
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
SubstMapper::visit (TyTy::ADTType &type)
{
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
SubstMapper::visit (TyTy::PlaceholderType &type)
{
rust_assert (type.can_resolve ());
resolved = SubstMapper::Resolve (type.resolve (), locus, generics);
}
void
SubstMapper::visit (TyTy::ProjectionType &type)
{
TyTy::ProjectionType *concrete = nullptr;
if (!have_generic_args ())
{
TyTy::BaseType *substs = type.infer_substitions (locus);
rust_assert (substs->get_kind () == TyTy::TypeKind::PROJECTION);
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;
}
SubstMapperInternal::SubstMapperInternal (
HirId ref, TyTy::SubstitutionArgumentMappings &mappings)
: resolved (new TyTy::ErrorType (ref)), mappings (mappings)
{}
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;
}
void
SubstMapperInternal::visit (TyTy::FnType &type)
{
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
SubstMapperInternal::visit (TyTy::ADTType &type)
{
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
SubstMapperInternal::visit (TyTy::TupleType &type)
{
resolved = type.handle_substitions (mappings);
}
void
SubstMapperInternal::visit (TyTy::ReferenceType &type)
{
resolved = type.handle_substitions (mappings);
}
void
SubstMapperInternal::visit (TyTy::PointerType &type)
{
resolved = type.handle_substitions (mappings);
}
void
SubstMapperInternal::visit (TyTy::ParamType &type)
{
resolved = type.handle_substitions (mappings);
}
void
SubstMapperInternal::visit (TyTy::PlaceholderType &type)
{
rust_assert (type.can_resolve ());
if (mappings.trait_item_mode ())
{
resolved = type.resolve ();
}
else
{
resolved = SubstMapperInternal::Resolve (type.resolve (), mappings);
}
}
void
SubstMapperInternal::visit (TyTy::ProjectionType &type)
{
resolved = type.handle_substitions (mappings);
}
void
SubstMapperInternal::visit (TyTy::ClosureType &type)
{
resolved = type.handle_substitions (mappings);
}
void
SubstMapperInternal::visit (TyTy::ArrayType &type)
{
resolved = type.handle_substitions (mappings);
}
void
SubstMapperInternal::visit (TyTy::SliceType &type)
{
resolved = type.handle_substitions (mappings);
}
// nothing to do for these
void
SubstMapperInternal::visit (TyTy::InferType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::FnPtr &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::BoolType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::IntType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::UintType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::FloatType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::USizeType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::ISizeType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::ErrorType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::CharType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::StrType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::NeverType &type)
{
resolved = type.clone ();
}
void
SubstMapperInternal::visit (TyTy::DynamicObjectType &type)
{
resolved = type.clone ();
}
// SubstMapperFromExisting
SubstMapperFromExisting::SubstMapperFromExisting (TyTy::BaseType *concrete,
TyTy::BaseType *receiver)
: concrete (concrete), receiver (receiver), resolved (nullptr)
{}
TyTy::BaseType *
SubstMapperFromExisting::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
SubstMapperFromExisting::visit (TyTy::FnType &type)
{
rust_assert (type.was_substituted ());
TyTy::FnType *to_sub = static_cast<TyTy::FnType *> (receiver);
resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
}
void
SubstMapperFromExisting::visit (TyTy::ADTType &type)
{
rust_assert (type.was_substituted ());
TyTy::ADTType *to_sub = static_cast<TyTy::ADTType *> (receiver);
resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
}
void
SubstMapperFromExisting::visit (TyTy::ClosureType &type)
{
rust_assert (type.was_substituted ());
TyTy::ClosureType *to_sub = static_cast<TyTy::ClosureType *> (receiver);
resolved = to_sub->handle_substitions (type.get_substitution_arguments ());
}
// GetUsedSubstArgs
GetUsedSubstArgs::GetUsedSubstArgs ()
: args (TyTy::SubstitutionArgumentMappings::error ())
{}
TyTy::SubstitutionArgumentMappings
GetUsedSubstArgs::From (const TyTy::BaseType *from)
{
GetUsedSubstArgs mapper;
from->accept_vis (mapper);
return mapper.args;
}
void
GetUsedSubstArgs::visit (const TyTy::FnType &type)
{
args = type.get_substitution_arguments ();
}
void
GetUsedSubstArgs::visit (const TyTy::ADTType &type)
{
args = type.get_substitution_arguments ();
}
void
GetUsedSubstArgs::visit (const TyTy::ClosureType &type)
{
args = type.get_substitution_arguments ();
}
} // namespace Resolver
} // namespace Rust