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