https://gcc.gnu.org/g:de23057dd6e82889d69c7cdeaee3073fa78a9078
commit r17-4346-gde23057dd6e82889d69c7cdeaee3073fa78a9078 Author: Philip Herron <[email protected]> Date: Tue Sep 8 12:26:51 2026 +0100 gccrs: Fix handling where clauses into two passes Where constraints are annoying so we need to do it in two passes. 1. Register bounds on the regular single segment TypePaths so like P: Deref 2. Then register regular type bindings like I::Item or Item = U::Item As they can be order dependant as the initial predicate needs added to then param decls then onto whatever projections after. Fixes Rust-GCC/gccrs#4864 gcc/rust/ChangeLog: * hir/tree/rust-hir-item.h: missing non const helper. * typecheck/rust-hir-type-check-base.h: new defer_bindings. * typecheck/rust-hir-type-check-implitem.cc (TypeCheckTopLevelExternItem::visit): new helper (TypeCheckImplItem::resolve_function_signature): Likewise. (TypeCheckImplItem::visit): Likewise. * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): Likewise. (TypeCheckItem::resolve_function_signature): Likewise. (TypeCheckItem::resolve_impl_block_substitutions): Likewise. * typecheck/rust-hir-type-check-type.cc (ResolveWhereClauseItem::Resolve): new helper (ResolveWhereClauseItem::visit): support defer. * typecheck/rust-hir-type-check-type.h: update header. * typecheck/rust-hir-type-check.cc (TraitItemReference::get_type_from_fn): call new helper * typecheck/rust-tyty-bounds.cc: defer flag gcc/testsuite/ChangeLog: * rust/compile/issue-4864.rs: New test. Signed-off-by: Philip Herron <[email protected]> Diff: --- gcc/rust/hir/tree/rust-hir-item.h | 2 + gcc/rust/typecheck/rust-hir-type-check-base.h | 3 +- gcc/rust/typecheck/rust-hir-type-check-implitem.cc | 24 ++---- gcc/rust/typecheck/rust-hir-type-check-item.cc | 36 +++------ gcc/rust/typecheck/rust-hir-type-check-type.cc | 89 +++++++++++++++++++++- gcc/rust/typecheck/rust-hir-type-check-type.h | 8 +- gcc/rust/typecheck/rust-hir-type-check.cc | 10 +-- gcc/rust/typecheck/rust-tyty-bounds.cc | 13 +++- gcc/testsuite/rust/compile/issue-4864.rs | 22 ++++++ 9 files changed, 150 insertions(+), 57 deletions(-) diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index a956e0b530f4..9a572bf92c65 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -2559,6 +2559,8 @@ public: return where_clause; } + WARN_UNUSED_RESULT WhereClause &get_where_clause () { return where_clause; } + ExternalFunctionItem ( Analysis::NodeMapping mappings, Identifier item_name, std::vector<std::unique_ptr<GenericParam>> generic_params, diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index 3a9df89a5826..61e545149cf4 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -53,7 +53,8 @@ protected: HIR::TypePath &path, tl::optional<std::reference_wrapper<HIR::Type>> associated_self, BoundPolarity polarity = BoundPolarity::RegularBound, - bool is_qualified_type = false, bool is_super_trait = false); + bool is_qualified_type = false, bool is_super_trait = false, + bool defer_bindings = false); bool check_for_unconstrained ( const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain, diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index 9fb0d70a3401..8c65390f781c 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -80,14 +80,8 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function) } TyTy::RegionConstraints region_constraints; - if (function.has_where_clause ()) - { - for (auto &where_clause_item : function.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item, - region_constraints); - } - } + ResolveWhereClauseItem::Resolve (function.get_where_clause (), + region_constraints); TyTy::BaseType *ret_type = nullptr; if (!function.has_return_type ()) @@ -254,11 +248,8 @@ TypeCheckImplItem::resolve_function_signature (HIR::Function &function) function.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; - for (auto &where_clause_item : function.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item.get (), - region_constraints); - } + ResolveWhereClauseItem::Resolve (function.get_where_clause (), + region_constraints); TyTy::BaseType *ret_type = nullptr; if (!function.has_function_return_type ()) @@ -510,11 +501,8 @@ TypeCheckImplItem::visit (HIR::TypeAlias &alias) context->insert_type (alias.get_mappings (), actual_type); result = actual_type; TyTy::RegionConstraints region_constraints; - for (auto &where_clause_item : alias.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item.get (), - region_constraints); - } + ResolveWhereClauseItem::Resolve (alias.get_where_clause (), + region_constraints); } TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait ( diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 2f2005b71bf7..4d02e3b5c52d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -310,10 +310,8 @@ TypeCheckItem::visit (HIR::TypeAlias &alias) context->insert_type (alias.get_mappings (), actual_type); TyTy::RegionConstraints region_constraints; - for (auto &where_clause_item : alias.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints); - } + ResolveWhereClauseItem::Resolve (alias.get_where_clause (), + region_constraints); infered = actual_type; } @@ -329,10 +327,8 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) struct_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; - for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints); - } + ResolveWhereClauseItem::Resolve (struct_decl.get_where_clause (), + region_constraints); // Process #[repr(X)] attribute, if any const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); @@ -410,10 +406,8 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) struct_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; - for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints); - } + ResolveWhereClauseItem::Resolve (struct_decl.get_where_clause (), + region_constraints); // Process #[repr(X)] attribute, if any const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); @@ -577,10 +571,8 @@ TypeCheckItem::visit (HIR::Union &union_decl) union_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; - for (auto &where_clause_item : union_decl.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints); - } + ResolveWhereClauseItem::Resolve (union_decl.get_where_clause (), + region_constraints); std::vector<TyTy::StructFieldType *> fields; for (auto &variant : union_decl.get_variants ()) @@ -833,10 +825,8 @@ TypeCheckItem::resolve_function_signature (HIR::Function &function) function.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; - for (auto &where_clause_item : function.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints); - } + ResolveWhereClauseItem::Resolve (function.get_where_clause (), + region_constraints); TyTy::BaseType *ret_type = nullptr; if (!function.has_function_return_type ()) @@ -1053,10 +1043,8 @@ TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block, impl_block.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; - for (auto &where_clause_item : impl_block.get_where_clause ().get_items ()) - { - ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints); - } + ResolveWhereClauseItem::Resolve (impl_block.get_where_clause (), + region_constraints); auto specified_bound = TyTy::TypeBoundPredicate::error (); TraitReference *trait_reference = &TraitReference::error_node (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index 84baab6ffa76..5fe75cf487b8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -1023,6 +1023,64 @@ ResolveWhereClauseItem::Resolve (HIR::WhereClauseItem &item, } } +void +ResolveWhereClauseItem::Resolve (HIR::WhereClause &clause, + TyTy::RegionConstraints ®ion_constraints) +{ + ResolveWhereClauseItem resolver (region_constraints); + + class PlainTypePath : public HIR::HIRTypeVisitor + { + public: + bool matches = false; + + void visit (HIR::TypePathSegmentFunction &segment) override {} + void visit (HIR::QualifiedPathInType &path) override {} + void visit (HIR::TraitBound &bound) override {} + void visit (HIR::ImplTraitType &type) override {} + void visit (HIR::TraitObjectType &type) override {} + void visit (HIR::ParenthesisedType &type) override {} + void visit (HIR::TupleType &type) override {} + void visit (HIR::NeverType &type) override {} + void visit (HIR::RawPointerType &type) override {} + void visit (HIR::ReferenceType &type) override {} + void visit (HIR::ArrayType &type) override {} + void visit (HIR::SliceType &type) override {} + void visit (HIR::InferredType &type) override {} + void visit (HIR::BareFunctionType &type) override {} + + void visit (HIR::TypePath &path) override + { + bool is_single = path.get_segments ().size () == 1; + bool final_seg_is_reg + = path.get_final_segment ().get_type () == HIR::TypePathSegment::REG; + + matches = is_single && final_seg_is_reg; + } + }; + + resolver.defer_bindings = true; + for (auto &item : clause.get_items ()) + if (item->get_item_type () == HIR::WhereClauseItem::TYPE_BOUND) + { + auto &bound = static_cast<HIR::TypeBoundWhereClauseItem &> (*item); + PlainTypePath plain; + bound.get_bound_type ().accept_vis (plain); + if (plain.matches) + resolver.visit (bound); + } + + resolver.defer_bindings = false; + resolver.complete_bindings = true; + for (auto &item : clause.get_items ()) + { + if (item->get_item_type () == HIR::WhereClauseItem::TYPE_BOUND) + resolver.visit (static_cast<HIR::TypeBoundWhereClauseItem &> (*item)); + else + Resolve (*item, region_constraints); + } +} + void ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &item) { @@ -1060,6 +1118,9 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) = TypeCheckType::Resolve (binding_type_path, TypeCheckType::ResolutionMode::CANONICAL); + if (defer_bindings && binding->get_kind () != TyTy::TypeKind::PARAM) + return; + // FIXME double check there might be a trait cycle here see TypeParam handling std::vector<TyTy::TypeBoundPredicate> specified_bounds; @@ -1072,13 +1133,17 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) auto *b = static_cast<HIR::TraitBound *> (bound.get ()); TyTy::TypeBoundPredicate predicate - = get_predicate_from_bound (b->get_path (), binding_type_path); + = get_predicate_from_bound (b->get_path (), binding_type_path, + BoundPolarity::RegularBound, false, + false, defer_bindings); if (!predicate.is_error ()) specified_bounds.push_back (std::move (predicate)); } break; case HIR::TypeParamBound::BoundType::LIFETIME: { + if (defer_bindings) + break; if (auto param = binding->try_as<TyTy::ParamType> ()) { auto *b = static_cast<HIR::Lifetime *> (bound.get ()); @@ -1098,7 +1163,27 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) break; } } - binding->inherit_bounds (specified_bounds); + + for (const auto &predicate : specified_bounds) + { + bool replaced = false; + if (complete_bindings) + { + for (auto &bound : binding->get_specified_bounds ()) + { + if (bound.get_id () == predicate.get_id () + && bound.get_locus () == predicate.get_locus ()) + { + bound = predicate; + replaced = true; + break; + } + } + } + + if (!replaced) + binding->inherit_bound (predicate); + } } } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index 9cc0fdbc3e97..ee1d0c97d971 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -132,7 +132,7 @@ class ResolveWhereClauseItem : public TypeCheckBase TyTy::RegionConstraints ®ion_constraints; public: - static void Resolve (HIR::WhereClauseItem &item, + static void Resolve (HIR::WhereClause &clause, TyTy::RegionConstraints ®ion_constraints); protected: @@ -140,6 +140,12 @@ protected: void visit (HIR::TypeBoundWhereClauseItem &item); private: + static void Resolve (HIR::WhereClauseItem &item, + TyTy::RegionConstraints ®ion_constraints); + + bool defer_bindings = false; + bool complete_bindings = false; + ResolveWhereClauseItem (TyTy::RegionConstraints ®ion_constraints) : region_constraints (region_constraints) {} diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index d111207b7294..d4c21d09ca84 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -169,7 +169,6 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const std::vector<TyTy::SubstitutionParamMapping> substitutions = inherited_substitutions; - TyTy::RegionConstraints region_constraints; HIR::TraitFunctionDecl &function = fn.get_decl (); if (function.has_generics ()) { @@ -180,12 +179,9 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const ABI::RUST); } - if (function.has_where_clause ()) - { - for (auto &where_clause_item : function.get_where_clause ().get_items ()) - ResolveWhereClauseItem::Resolve (*where_clause_item, - region_constraints); - } + TyTy::RegionConstraints region_constraints; + ResolveWhereClauseItem::Resolve (function.get_where_clause (), + region_constraints); TyTy::BaseType *ret_type = nullptr; if (!function.has_return_type ()) diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 0240a635ca71..bb2c5ed14f15 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -261,7 +261,8 @@ TyTy::TypeBoundPredicate TypeCheckBase::get_predicate_from_bound ( HIR::TypePath &type_path, tl::optional<std::reference_wrapper<HIR::Type>> associated_self, - BoundPolarity polarity, bool is_qualified_type_path, bool is_super_trait) + BoundPolarity polarity, bool is_qualified_type_path, bool is_super_trait, + bool defer_bindings) { TyTy::TypeBoundPredicate lookup = TyTy::TypeBoundPredicate::error (); bool already_resolved @@ -340,7 +341,7 @@ TypeCheckBase::get_predicate_from_bound ( std::vector<HIR::GenericArgsBinding> bindings; - if (fn.has_return_type ()) + if (fn.has_return_type () && !defer_bindings) { TypeCheckType::Resolve (fn.get_return_type ()); @@ -377,6 +378,9 @@ TypeCheckBase::get_predicate_from_bound ( args.get_locus ()); } + if (defer_bindings) + args.get_binding_args ().clear (); + // we try to apply generic arguments when they are non empty and or when the // predicate requires them so that we get the relevant Foo expects x number // arguments but got zero see test case rust/compile/traits12.rs @@ -387,8 +391,9 @@ TypeCheckBase::get_predicate_from_bound ( is_super_trait); } - context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (), - predicate); + if (!defer_bindings) + context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (), + predicate); return predicate; } diff --git a/gcc/testsuite/rust/compile/issue-4864.rs b/gcc/testsuite/rust/compile/issue-4864.rs new file mode 100644 index 000000000000..c05000a3cadd --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4864.rs @@ -0,0 +1,22 @@ +#![feature(no_core, lang_items)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +trait Iterator { + type Item; +} +trait IntoIterator { + type Item; + type IntoIter: Iterator<Item = Self::Item>; +} +pub struct Flatten<I, U> { + pub inner: I, + pub extra: U, +} +impl<I, U> Iterator for Flatten<I, U> +where + I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>, + U: Iterator, +{ + type Item = U::Item; +}
