[COMMITTED 69/83] gccrs: Fix handling where clauses into two passes
arthur.cohen@opensrcsec.com
arthur.cohen@opensrcsec.com
Wed Sep 16 12:30:28 GMT 2026
From: Philip Herron <herron.philip@googlemail.com>
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 <herron.philip@googlemail.com>
---
gcc/rust/hir/tree/rust-hir-item.h | 2 +
gcc/rust/typecheck/rust-hir-type-check-base.h | 3 +-
.../typecheck/rust-hir-type-check-implitem.cc | 24 ++---
.../typecheck/rust-hir-type-check-item.cc | 36 +++-----
.../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(-)
create mode 100644 gcc/testsuite/rust/compile/issue-4864.rs
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index a956e0b530f..9a572bf92c6 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 3a9df89a582..61e545149cf 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 9fb0d70a340..8c65390f781 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 2f2005b71bf..4d02e3b5c52 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 84baab6ffa7..5fe75cf487b 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 9cc0fdbc3e9..ee1d0c97d97 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 d111207b729..d4c21d09ca8 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 0240a635ca7..bb2c5ed14f1 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 00000000000..c05000a3cad
--- /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;
+}
--
2.50.1
More information about the Gcc-rust
mailing list