// 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-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 (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 (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 (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 (tyseg); return adt->are_mappings_bound (mappings); } else if (tyseg->get_kind () == TyTy::TypeKind::FNDEF) { TyTy::FnType *fn = static_cast (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 (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 (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 (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