https://gcc.gnu.org/g:b6b3a48249b3269dcaa9bf96d0eb69b9eb396ee6
commit r17-4306-gb6b3a48249b3269dcaa9bf96d0eb69b9eb396ee6 Author: Philip Herron <[email protected]> Date: Fri Aug 28 22:20:21 2026 +0100 gccrs: seperate implitem fntype and body resolution This builds upon the previous patch to seperate fn hir item body and signiture resolution to stop crate cascades. gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-implitem.cc (TypeCheckImplItem::visit): check need to resolve body * typecheck/rust-hir-type-check-implitem.h: new resolve sig * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::Resolve): check recursion (TypeCheckItem::ResolveFunctionSignature): new helper (TypeCheckItem::ResolveImplBlockSelf): missing lifetime pin (TypeCheckItem::visit): likewise * typecheck/rust-hir-type-check-item.h: new helper * typecheck/rust-hir-type-check.h: track function body pending * typecheck/rust-type-util.cc (query_type): track associated self (normalize_projection): check compatable * typecheck/rust-typecheck-context.cc (TypeCheckContext::mark_function_body_pending): marker to make sure body gets resolved later (TypeCheckContext::clear_function_body_pending): clear market (TypeCheckContext::function_body_pending): new set Signed-off-by: Philip Herron <[email protected]> Diff: --- gcc/rust/typecheck/rust-hir-type-check-implitem.cc | 29 +++++++- gcc/rust/typecheck/rust-hir-type-check-implitem.h | 4 ++ gcc/rust/typecheck/rust-hir-type-check-item.cc | 26 +++++++- gcc/rust/typecheck/rust-hir-type-check-item.h | 2 + gcc/rust/typecheck/rust-hir-type-check.h | 6 ++ gcc/rust/typecheck/rust-type-util.cc | 77 +++++++++++++++------- gcc/rust/typecheck/rust-typecheck-context.cc | 42 +++++++++++- 7 files changed, 159 insertions(+), 27 deletions(-) diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index f8808351e10c..57f1718e9500 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -191,7 +191,14 @@ TypeCheckImplItem::Resolve ( bool already_resolved = context->lookup_type (item.get_impl_mappings ().get_hirid (), &resolved); if (already_resolved) - return resolved; + { + bool function_body_pending = false; + if (auto fn = resolved->try_as<TyTy::FnType> ()) + function_body_pending = context->function_body_pending (fn->get_id ()); + + if (!function_body_pending) + return resolved; + } // resolve TypeCheckImplItem resolver (parent, self, substitutions); @@ -203,6 +210,22 @@ TypeCheckImplItem::Resolve ( return resolver.result; } +TyTy::FnType * +TypeCheckImplItem::ResolveFunctionSignature ( + HIR::ImplBlock &parent, HIR::Function &function, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions) +{ + TypeCheckImplItem resolver (parent, self, std::move (substitutions)); + auto binder_pin = resolver.context->push_lifetime_binder (); + resolver.context->block_context ().enter ( + TypeCheckBlockContextItem (&parent)); + TyTy::FnType *result = resolver.resolve_function_signature (function); + resolver.context->block_context ().exit (); + if (result != nullptr) + resolver.context->mark_function_body_pending (result->get_id ()); + return result; +} + TyTy::FnType * TypeCheckImplItem::resolve_function_signature (HIR::Function &function) { @@ -388,6 +411,10 @@ TypeCheckImplItem::visit (HIR::Function &function) if (resolve_fn_type == nullptr) return; + // Mark the body as claimed before resolving it. Recursive queries from the + // body must reuse the cached signature rather than re-entering this body. + context->clear_function_body_pending (resolve_fn_type->get_id ()); + // need to get the return type from this auto expected_ret_tyty = resolve_fn_type->get_return_type (); context->push_return_type (TypeCheckContextItem (parent, &function), diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index cba105434c9e..6cef0353fd1b 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -50,6 +50,10 @@ public: Resolve (HIR::ImplBlock &parent, HIR::ImplItem &item, TyTy::BaseType *self, std::vector<TyTy::SubstitutionParamMapping> substitutions); + static TyTy::FnType *ResolveFunctionSignature ( + HIR::ImplBlock &parent, HIR::Function &function, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions); + void visit (HIR::Function &function) override; void visit (HIR::ConstantItem &const_item) override; void visit (HIR::TypeAlias &type_alias) override; diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 25fa97a368b3..ba4017adc1a3 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -93,7 +93,14 @@ TypeCheckItem::Resolve (HIR::Item &item) bool already_resolved = context->lookup_type (item.get_mappings ().get_hirid (), &resolved); if (already_resolved) - return resolved; + { + bool function_body_pending = false; + if (auto fn = resolved->try_as<TyTy::FnType> ()) + function_body_pending = context->function_body_pending (fn->get_id ()); + + if (!function_body_pending) + return resolved; + } rust_assert (item.get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM); HIR::VisItem &vis_item = static_cast<HIR::VisItem &> (item); @@ -103,6 +110,17 @@ TypeCheckItem::Resolve (HIR::Item &item) return resolver.infered; } +TyTy::FnType * +TypeCheckItem::ResolveFunctionSignature (HIR::Function &function) +{ + TypeCheckItem resolver; + auto lifetime_pin = resolver.context->push_clean_lifetime_resolver (); + TyTy::FnType *result = resolver.resolve_function_signature (function); + if (result != nullptr) + resolver.context->mark_function_body_pending (result->get_id ()); + return result; +} + TyTy::BaseType * TypeCheckItem::ResolveImplItem (HIR::ImplBlock &impl_block, HIR::ImplItem &item) { @@ -114,6 +132,7 @@ TyTy::BaseType * TypeCheckItem::ResolveImplBlockSelf (HIR::ImplBlock &impl_block) { TypeCheckItem resolver; + auto lifetime_pin = resolver.context->push_clean_lifetime_resolver (true); bool failed_flag = false; auto result @@ -135,6 +154,7 @@ TypeCheckItem::ResolveImplBlockSelfWithInference ( TyTy::SubstitutionArgumentMappings *infer_arguments) { TypeCheckItem resolver; + auto lifetime_pin = resolver.context->push_clean_lifetime_resolver (true); bool failed_flag = false; auto result = resolver.resolve_impl_block_substitutions (impl, failed_flag); @@ -876,6 +896,10 @@ TypeCheckItem::visit (HIR::Function &function) if (resolved_fn_type == nullptr) return; + // Mark the body as claimed before resolving it. Recursive queries from the + // body must reuse the cached signature rather than re-entering this body. + context->clear_function_body_pending (resolved_fn_type->get_id ()); + // need to get the return type from this auto expected_ret_tyty = resolved_fn_type->get_return_type (); context->push_return_type (TypeCheckContextItem (&function), diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 389b0fd9af5f..9b223f291ac8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -30,6 +30,8 @@ class TypeCheckItem : private TypeCheckBase, private HIR::HIRVisItemVisitor public: static TyTy::BaseType *Resolve (HIR::Item &item); + static TyTy::FnType *ResolveFunctionSignature (HIR::Function &function); + static TyTy::BaseType *ResolveImplItem (HIR::ImplBlock &impl_block, HIR::ImplItem &item); diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 916ee2f2d9b6..1e830713ee84 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -209,6 +209,10 @@ public: bool lookup_type (HirId id, TyTy::BaseType **type) const; void clear_type (TyTy::BaseType *ty); + void mark_function_body_pending (DefId id); + void clear_function_body_pending (DefId id); + bool function_body_pending (DefId id) const; + void insert_implicit_type (HirId id, TyTy::BaseType *type); void insert_type_by_node_id (NodeId ref, HirId id); @@ -239,6 +243,7 @@ public: bool find_matching_impl_trait_frame (const TraitReference &tref, + TyTy::BaseType &self, struct ImplTraitContextFrame *find) const; bool have_impl_trait_context () const; void push_impl_trait_context (struct ImplTraitContextFrame frame); @@ -329,6 +334,7 @@ private: std::map<NodeId, HirId> node_id_refs; std::map<HirId, TyTy::BaseType *> resolved; + std::set<DefId> function_bodies_pending; std::vector<std::unique_ptr<TyTy::BaseType>> builtins; std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>> return_type_stack; diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index 97ff25d43685..1ba486626786 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -16,6 +16,7 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "rust-hir-item.h" #include "rust-system.h" #include "rust-type-util.h" #include "rust-diagnostics.h" @@ -73,7 +74,21 @@ query_type (HirId reference, TyTy::BaseType **result) { rust_debug_loc (item.value ()->get_locus (), "resolved item {%u} to", reference); - *result = TypeCheckItem::Resolve (*item.value ()); + + DefId item_defid = item.value ()->get_mappings ().get_defid (); + bool is_local = item_defid.crateNum == mappings.get_current_crate (); + bool is_fn + = item.value ()->get_item_kind () == HIR::Item::ItemKind::Function; + if (is_fn && is_local) + { + HIR::Function &fn = *static_cast<HIR::Function *> (item.value ()); + *result = TypeCheckItem::ResolveFunctionSignature (fn); + } + else + { + *result = TypeCheckItem::Resolve (*item.value ()); + } + context->query_completed (reference); return true; } @@ -82,30 +97,33 @@ query_type (HirId reference, TyTy::BaseType **result) { auto impl_block = mappings.lookup_hir_impl_block (impl_item->second).value (); + auto lifetime_pin = context->push_clean_lifetime_resolver (true); - tl::optional<ImplTraitFrameGuard> guard; - if (impl_block->has_trait_ref ()) + bool failure_flag = false; + auto substitutions + = TypeCheckItem::ResolveImplBlockSubstitutions (*impl_block, + failure_flag); + if (failure_flag) { - bool failure_flag = false; - auto substitutions - = TypeCheckItem::ResolveImplBlockSubstitutions (*impl_block, - failure_flag); - if (failure_flag) - { - context->query_completed (reference); - return false; - } + *result + = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item->first); + context->query_completed (reference); + return true; + } - TyTy::BaseType *self = nullptr; - bool ok - = query_type (impl_block->get_type ().get_mappings ().get_hirid (), - &self); - if (!ok) - { - context->query_completed (reference); - return false; - } + TyTy::BaseType *self = nullptr; + bool ok + = query_type (impl_block->get_type ().get_mappings ().get_hirid (), + &self); + if (!ok) + { + context->query_completed (reference); + return false; + } + tl::optional<ImplTraitFrameGuard> guard; + if (impl_block->has_trait_ref ()) + { HIR::TypePath &ref = impl_block->get_trait_ref (); auto trait_reference = TraitResolver::Resolve (ref); if (trait_reference->is_error ()) @@ -132,7 +150,19 @@ query_type (HirId reference, TyTy::BaseType **result) rust_debug_loc (impl_item->first->get_locus (), "resolved impl-item {%u} to", reference); - *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item->first); + DefId item_defid = impl_item->first->get_impl_mappings ().get_defid (); + bool is_local = item_defid.crateNum == mappings.get_current_crate (); + if (impl_item->first->get_impl_item_type () == HIR::ImplItem::FUNCTION + && is_local) + { + HIR::Function &fn = *static_cast<HIR::Function *> (impl_item->first); + *result = TypeCheckImplItem::ResolveFunctionSignature ( + *impl_block, fn, self, std::move (substitutions)); + } + else + *result = TypeCheckImplItem::Resolve (*impl_block, *impl_item->first, + self, std::move (substitutions)); + context->query_completed (reference); return true; } @@ -606,7 +636,8 @@ normalize_projection (TyTy::ProjectionType *proj, location_t locus, } ImplTraitContextFrame frame; - if (!ctx->find_matching_impl_trait_frame (*proj->get_trait_ref (), &frame)) + if (!ctx->find_matching_impl_trait_frame (*proj->get_trait_ref (), + *proj->get_self (), &frame)) { // No concrete impl frame check WHERE clause bindings on the self type // diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc index 5b482dd9f3bb..44744730b53f 100644 --- a/gcc/rust/typecheck/rust-typecheck-context.cc +++ b/gcc/rust/typecheck/rust-typecheck-context.cc @@ -109,6 +109,24 @@ TypeCheckContext::lookup_type (HirId id, TyTy::BaseType **type) const return true; } +void +TypeCheckContext::mark_function_body_pending (DefId id) +{ + function_bodies_pending.insert (id); +} + +void +TypeCheckContext::clear_function_body_pending (DefId id) +{ + function_bodies_pending.erase (id); +} + +bool +TypeCheckContext::function_body_pending (DefId id) const +{ + return function_bodies_pending.find (id) != function_bodies_pending.end (); +} + void TypeCheckContext::clear_type (TyTy::BaseType *ty) { @@ -253,7 +271,8 @@ TypeCheckContext::swap_head_loop_context (TyTy::BaseType *val) bool TypeCheckContext::find_matching_impl_trait_frame ( - const TraitReference &tref, struct ImplTraitContextFrame *find) const + const TraitReference &tref, TyTy::BaseType &self, + struct ImplTraitContextFrame *find) const { if (!have_impl_trait_context ()) return false; @@ -262,7 +281,26 @@ TypeCheckContext::find_matching_impl_trait_frame ( it != impl_trait_frame_stack.rend (); ++it) { const auto &i = *it; - if (i.trait->is_equal (tref)) + if (!i.trait->is_equal (tref)) + continue; + + TyTy::BaseType *resolved_self = &self; + bool unresolved_trait_self = false; + if (auto param = self.try_as<TyTy::ParamType> ()) + { + if (param->can_resolve ()) + resolved_self = param->resolve (); + else + unresolved_trait_self = param->is_implicit_self_trait (); + } + + bool compatible_self + = unresolved_trait_self + || types_compatable (TyTy::TyWithLocation (i.self), + TyTy::TyWithLocation (resolved_self), + UNDEF_LOCATION, false /* emit_errors */, + false /* check_bounds */); + if (compatible_self) { *find = i; return true;
