From: Philip Herron <[email protected]>
This patch is used to address where constraints on projections for example
fn test<P: Deref)
where
P::Target: PartialOrd<Q::Target>
When we do fn test<P: Deref) we can specify the bound of Deref on P directly so
its directly
available. But when we do where P::Target ... that P::Target resolves the trait
position
Target of Deref but thats a trait position decl so this information is lost
during path
resolution. This patch addes a scan so when we generate predicates we track
them in the
type check context so we can look them up so it adds a loop to get any other
associcated
predicates in this position. Its not performant but we can fix that later we
just need
to progress libcore for now.
Fixes Rust-GCC/gccrs#4865
gcc/rust/ChangeLog:
* typecheck/rust-hir-dot-operator.cc (MethodResolver::try_hook): use
new helper
* typecheck/rust-hir-path-probe-expr.cc (PathProbeExpr::probe_bounds):
likewise
* typecheck/rust-hir-path-probe-type.cc (TypePathProbe::probe_generic):
likewise
* typecheck/rust-hir-type-check-type.cc
(TypeResolveGenericParam::visit): likewise
(TypeResolveGenericParam::apply_trait_bounds): track new decl id
* typecheck/rust-hir-type-check.h: new helper
* typecheck/rust-typecheck-context.cc
(TypeCheckContext::predicates_for_type): impl
* typecheck/rust-tyty.cc (ParamType::ParamType): new decl id
(ParamType::clone): likewise
* typecheck/rust-tyty.h: likewise
gcc/testsuite/ChangeLog:
* rust/compile/issues/4865-1.rs: New test.
* rust/compile/issues/4865-2.rs: New test.
* rust/compile/projection-bound-decl-id.rs: New test.
Signed-off-by: Philip Herron <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github:
https://github.com/Rust-GCC/gccrs/commit/884c26f09db98cc5ac1477fc92bfaebd7e2a8aab
The commit has been mentioned in the following issue(s):
- Rust-GCC/gccrs#4865: https://github.com/Rust-GCC/gccrs/issues/4865
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4921
gcc/rust/typecheck/rust-hir-dot-operator.cc | 6 +-
.../typecheck/rust-hir-path-probe-expr.cc | 2 +-
.../typecheck/rust-hir-path-probe-type.cc | 2 +-
.../typecheck/rust-hir-type-check-type.cc | 2 +
gcc/rust/typecheck/rust-hir-type-check.h | 2 +
gcc/rust/typecheck/rust-typecheck-context.cc | 81 +++++++++++++++++++
gcc/rust/typecheck/rust-tyty.cc | 12 +--
gcc/rust/typecheck/rust-tyty.h | 8 +-
gcc/testsuite/rust/compile/issues/4865-1.rs | 16 ++++
gcc/testsuite/rust/compile/issues/4865-2.rs | 20 +++++
.../rust/compile/projection-bound-decl-id.rs | 14 ++++
11 files changed, 153 insertions(+), 12 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/issues/4865-1.rs
create mode 100644 gcc/testsuite/rust/compile/issues/4865-2.rs
create mode 100644 gcc/testsuite/rust/compile/projection-bound-decl-id.rs
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc
b/gcc/rust/typecheck/rust-hir-dot-operator.cc
index 24b8b8ccc..9a125eb7b 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.cc
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -106,7 +106,7 @@ MethodResolver::try_hook (const TyTy::BaseType &r)
{
rust_debug ("MethodResolver::try_hook get_predicate_items: [%s]",
r.debug_str ().c_str ());
- const auto &specified_bounds = r.get_specified_bounds ();
+ auto specified_bounds = context->predicates_for_type (&r);
predicate_items = get_predicate_items (segment_name, r, specified_bounds);
if (predicate_items.size () > 0)
@@ -117,14 +117,14 @@ MethodResolver::try_hook (const TyTy::BaseType &r)
const auto &ref = static_cast<const TyTy::ReferenceType &> (r);
const auto &element = ref.get_var_element_type ();
const auto &element_ty = *element.get_tyty ();
- const auto &specified_bounds = element_ty.get_specified_bounds ();
+ auto specified_bounds = context->predicates_for_type (&element_ty);
predicate_items
= get_predicate_items (segment_name, element_ty, specified_bounds);
}
else if (auto inner
= TyTy::try_get_box_inner_type (const_cast<TyTy::BaseType *> (&r)))
{
- const auto &specified_bounds = (*inner)->get_specified_bounds ();
+ auto specified_bounds = context->predicates_for_type (*inner);
predicate_items
= get_predicate_items (segment_name, **inner, specified_bounds);
}
diff --git a/gcc/rust/typecheck/rust-hir-path-probe-expr.cc
b/gcc/rust/typecheck/rust-hir-path-probe-expr.cc
index d95c931b1..461f60eaa 100644
--- a/gcc/rust/typecheck/rust-hir-path-probe-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-path-probe-expr.cc
@@ -193,7 +193,7 @@ PathProbeExpr::probe_bounds ()
}
for (const TyTy::TypeBoundPredicate &predicate :
- receiver->get_specified_bounds ())
+ context->predicates_for_type (receiver))
{
process_predicate_for_candidates (predicate);
}
diff --git a/gcc/rust/typecheck/rust-hir-path-probe-type.cc
b/gcc/rust/typecheck/rust-hir-path-probe-type.cc
index 79179627d..7b18bb80d 100644
--- a/gcc/rust/typecheck/rust-hir-path-probe-type.cc
+++ b/gcc/rust/typecheck/rust-hir-path-probe-type.cc
@@ -60,7 +60,7 @@ void
TypePathProbe::probe_generic ()
{
for (const TyTy::TypeBoundPredicate &predicate :
- receiver->get_specified_bounds ())
+ TypeCheckContext::get ()->predicates_for_type (receiver))
{
auto candidate = process_predicate_for_candidates (predicate);
insert_candidate (std::move (candidate));
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc
b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index 8bf304fa0..7ff160b14 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -892,6 +892,7 @@ TypeResolveGenericParam::visit (HIR::TypeParam ¶m)
resolved = new TyTy::ParamType (param.get_type_representation ().as_string
(),
param.get_locus (),
+ param.get_mappings ().get_hirid (),
param.get_mappings ().get_hirid (), {});
if (resolve_trait_bounds)
@@ -912,6 +913,7 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam
¶m,
TyTy::ParamType *p
= new TyTy::ParamType (param.get_type_representation ().as_string (),
param.get_locus (), implicit_id,
+ pty->get_decl_id (),
{} /*empty specified bounds*/);
context->insert_implicit_type (implicit_id, p);
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h
b/gcc/rust/typecheck/rust-hir-type-check.h
index c9572b13c..41e02bb00 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -311,6 +311,8 @@ public:
void insert_resolved_predicate (HirId id,
const TyTy::TypeBoundPredicate &predicate);
bool lookup_predicate (HirId id, TyTy::TypeBoundPredicate *result);
+ std::vector<TyTy::TypeBoundPredicate>
+ predicates_for_type (const TyTy::BaseType *receiver) const;
void insert_query (HirId id);
void query_completed (HirId id);
diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc
b/gcc/rust/typecheck/rust-typecheck-context.cc
index fe6bc888c..440b8b805 100644
--- a/gcc/rust/typecheck/rust-typecheck-context.cc
+++ b/gcc/rust/typecheck/rust-typecheck-context.cc
@@ -644,6 +644,87 @@ TypeCheckContext::lookup_predicate (HirId id,
TyTy::TypeBoundPredicate *result)
return true;
}
+std::vector<TyTy::TypeBoundPredicate>
+TypeCheckContext::predicates_for_type (const TyTy::BaseType *receiver) const
+{
+ std::vector<TyTy::TypeBoundPredicate> result
+ = receiver->get_specified_bounds ();
+
+ for (const auto &entry : predicates)
+ {
+ const auto &predicate = entry.second;
+ const auto &args = predicate.get_substitution_arguments ();
+ if (args.get_mappings ().empty ())
+ continue;
+
+ TyTy::BaseType *bound_self = args.get_mappings ().front ().get_tyty ();
+ if (bound_self == nullptr
+ || bound_self->get_kind () == TyTy::TypeKind::ERROR)
+ continue;
+
+ if (receiver->get_kind () != TyTy::TypeKind::PROJECTION
+ || bound_self->get_kind () != TyTy::TypeKind::PROJECTION)
+ continue;
+
+ const auto *receiver_projection
+ = static_cast<const TyTy::ProjectionType *> (receiver);
+ const auto *bound_projection
+ = static_cast<const TyTy::ProjectionType *> (bound_self);
+
+ DefId receiver_item_defid = receiver_projection->get_item_defid ();
+ DefId bound_item_defid = bound_projection->get_item_defid ();
+ bool same_item = receiver_item_defid == bound_item_defid;
+ if (!same_item)
+ continue;
+
+ DefId receiver_trait_defid
+ = receiver_projection->get_trait_ref ()->get_mappings ().get_defid ();
+ DefId bound_trait_defid
+ = bound_projection->get_trait_ref ()->get_mappings ().get_defid ();
+ bool same_trait = receiver_trait_defid == bound_trait_defid;
+ if (!same_trait)
+ continue;
+
+ // Compatibility can unify unrelated parameters. Match their declaration
+ // identities instead; copies and synthetic bound parameters retain them.
+ const TyTy::BaseType *receiver_self = receiver_projection->get_self ();
+ const TyTy::BaseType *bound_self_ty = bound_projection->get_self ();
+ const auto *receiver_param
+ = receiver_self->try_as<const TyTy::ParamType> ();
+ const auto *bound_param = bound_self_ty->try_as<const TyTy::ParamType>
();
+
+ bool either_self_is_param
+ = receiver_param != nullptr || bound_param != nullptr;
+ if (either_self_is_param)
+ {
+ bool both_selfs_are_param
+ = receiver_param != nullptr && bound_param != nullptr;
+ bool same_declaration
+ = both_selfs_are_param
+ && receiver_param->get_decl_id () == bound_param->get_decl_id ();
+ if (!same_declaration)
+ continue;
+ }
+ else
+ {
+ bool selfs_compatible = types_compatable (
+ TyTy::TyWithLocation (const_cast<TyTy::BaseType *> (receiver_self)),
+ TyTy::TyWithLocation (const_cast<TyTy::BaseType *> (bound_self_ty)),
+ UNKNOWN_LOCATION, false, false);
+ if (!selfs_compatible)
+ continue;
+ }
+
+ bool projections_compatible = types_compatable (
+ TyTy::TyWithLocation (const_cast<TyTy::BaseType *> (receiver)),
+ TyTy::TyWithLocation (bound_self), UNKNOWN_LOCATION, false, false);
+ if (projections_compatible)
+ result.push_back (predicate);
+ }
+
+ return result;
+}
+
void
TypeCheckContext::insert_query (HirId id)
{
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 93061b1fc..a9b3dcc5e 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -3742,24 +3742,25 @@ PointerType::handle_substitions
(SubstitutionArgumentMappings &mappings)
// PARAM Type
ParamType::ParamType (std::string symbol, location_t locus, HirId ref,
+ HirId decl_id,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs)
: BaseGeneric (ref, ref, KIND,
{Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
locus},
std::move (specified_bounds), refs),
- is_trait_self (false), symbol (symbol)
+ decl_id (decl_id), is_trait_self (false), symbol (symbol)
{}
ParamType::ParamType (bool is_trait_self, std::string symbol, location_t locus,
- HirId ref, HirId ty_ref,
+ HirId ref, HirId ty_ref, HirId decl_id,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs)
: BaseGeneric (ref, ty_ref, KIND,
{Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
locus},
std::move (specified_bounds), refs),
- is_trait_self (is_trait_self), symbol (symbol)
+ decl_id (decl_id), is_trait_self (is_trait_self), symbol (symbol)
{}
bool
@@ -3814,11 +3815,12 @@ ParamType::clone () const
bool cycle = Resolver::ScopedPush<HirId>::contains (active, get_ty_ref ());
if (cycle)
return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref
(),
- get_ty_ref (), {}, get_combined_refs ());
+ get_ty_ref (), get_decl_id (), {},
+ get_combined_refs ());
Resolver::ScopedPush<HirId> guard (active, get_ty_ref ());
return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref (),
- get_ty_ref (), get_specified_bounds (),
+ get_ty_ref (), get_decl_id (), get_specified_bounds (),
get_combined_refs ());
}
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index c4f0ad59a..98daa831b 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -515,12 +515,12 @@ class ParamType : public BaseGeneric
public:
static constexpr auto KIND = TypeKind::PARAM;
- ParamType (std::string symbol, location_t locus, HirId ref,
+ ParamType (std::string symbol, location_t locus, HirId ref, HirId decl_id,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
ParamType (bool is_trait_self, std::string symbol, location_t locus,
- HirId ref, HirId ty_ref,
+ HirId ref, HirId ty_ref, HirId decl_id,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
@@ -546,7 +546,11 @@ public:
void set_implicit_self_trait ();
bool is_implicit_self_trait () const;
+ HirId get_decl_id () const { return decl_id; }
+
private:
+ // Identity of the original HIR parameter, preserved through substitution.
+ const HirId decl_id;
bool is_trait_self;
std::string symbol;
};
diff --git a/gcc/testsuite/rust/compile/issues/4865-1.rs
b/gcc/testsuite/rust/compile/issues/4865-1.rs
new file mode 100644
index 000000000..f6bdcb274
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/4865-1.rs
@@ -0,0 +1,16 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+#[lang = "sized"]
+pub trait Sized {}
+trait Deref {
+ type Target: ?Sized;
+}
+trait PartialOrd<Rhs: ?Sized = Self> {
+ fn gt(&self, rhs: &Rhs) -> bool;
+}
+pub fn compare<P: Deref, Q: Deref>(x: &P::Target, y: &Q::Target) -> bool
+where
+ P::Target: PartialOrd<Q::Target>,
+{
+ P::Target::gt(x, y)
+}
diff --git a/gcc/testsuite/rust/compile/issues/4865-2.rs
b/gcc/testsuite/rust/compile/issues/4865-2.rs
new file mode 100644
index 000000000..a89bf6768
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/4865-2.rs
@@ -0,0 +1,20 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+#[lang = "sized"]
+pub trait Sized {}
+trait Deref {
+ type Target: ?Sized;
+}
+trait PartialOrd<Rhs: ?Sized = Self> {
+ fn gt(&self, rhs: &Rhs) -> bool;
+}
+pub fn compare<P: Deref, Q: Deref>(x: &P::Target, y: &Q::Target) -> bool
+where
+ P::Target: PartialOrd<Q::Target>,
+{
+ P::Target::gt(x, y)
+}
+pub fn compare_unbounded<R: Deref, S: Deref>(x: &R::Target, y: &S::Target) ->
bool {
+ R::Target::gt(x, y)
+ // { dg-error "failed to resolve path segment using an impl Probe" "" {
target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/projection-bound-decl-id.rs
b/gcc/testsuite/rust/compile/projection-bound-decl-id.rs
new file mode 100644
index 000000000..96f057e23
--- /dev/null
+++ b/gcc/testsuite/rust/compile/projection-bound-decl-id.rs
@@ -0,0 +1,14 @@
+// { dg-options "-w" }
+
+#![feature(no_core, lang_items)]
+#![no_core]
+#[lang = "sized"]
+pub trait Sized {}
+trait Source { type Item; }
+trait Marker { fn check(&self); }
+fn bounded<T: Source>(x: &T::Item) where T::Item: Marker {
+ T::Item::check(x);
+}
+fn unbounded<T: Source>(x: &T::Item) {
+ T::Item::check(x); // { dg-error "failed to resolve path segment" }
+}
base-commit: 215416773ce7d0dcd27a9593d05563facc5c7e56
--
2.55.0