diff options
author | Philip Herron <herron.philip@googlemail.com> | 2023-04-20 17:10:15 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2023-04-28 10:16:43 +0000 |
commit | 187f4b9eb897a08c124742e018b323c1ad6c9189 (patch) | |
tree | d307e2a7e363275c220fbe14f69fb77e074a1432 | |
parent | c13032e55c0bd39557c6366729e4afca3890c6c1 (diff) | |
download | gcc-187f4b9eb897a08c124742e018b323c1ad6c9189.tar.gz |
gccrs: qualified path syntax is used to disambiguate predicates
When resolving a qualified path we need to use the predicate to lookup the
relevant assoicated impl block where possible. The issue here is that
it might not have one due to a valid error in the impl block or it might
be used within a trait this is a valid case. Generally we will be able to
resolve to an impl block then it can grab that type and move on.
Fixes #2135
gcc/rust/ChangeLog:
* typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::visit): use the predicate
(TypeCheckExpr::resolve_segments): cleanup
gcc/testsuite/ChangeLog:
* rust/compile/issue-2135.rs: New test.
Signed-off-by: Philip Herron <herron.philip@googlemail.com>
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-path.cc | 82 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/issue-2135.rs | 19 |
2 files changed, 66 insertions, 35 deletions
diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index d43587f6f35..67b8d24b5a9 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -69,49 +69,63 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) // inherit the bound root->inherit_bounds ({specified_bound}); - // setup the associated types - const TraitReference *specified_bound_ref = specified_bound.get (); - auto candidates = TypeBoundsProbe::Probe (root); - AssociatedImplTrait *associated_impl_trait = nullptr; - for (auto &probed_bound : candidates) + // lookup the associated item from the specified bound + HIR::PathExprSegment &item_seg = expr.get_segments ().at (0); + HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment (); + TyTy::TypeBoundPredicateItem item + = specified_bound.lookup_associated_item (item_seg_identifier.as_string ()); + if (item.is_error ()) { - const TraitReference *bound_trait_ref = probed_bound.first; - const HIR::ImplBlock *associated_impl = probed_bound.second; - - HirId impl_block_id = associated_impl->get_mappings ().get_hirid (); - AssociatedImplTrait *associated = nullptr; - bool found_impl_trait - = context->lookup_associated_trait_impl (impl_block_id, &associated); - if (found_impl_trait) + rust_error_at (item_seg.get_locus (), "unknown associated item"); + return; + } + + // we try to look for the real impl item if possible + HIR::ImplItem *impl_item = nullptr; + + // lookup the associated impl trait for this if we can (it might be generic) + AssociatedImplTrait *associated_impl_trait + = lookup_associated_impl_block (specified_bound, root); + if (associated_impl_trait != nullptr) + { + for (auto &i : + associated_impl_trait->get_impl_block ()->get_impl_items ()) { - bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref); - bool found_self = associated->get_self ()->can_eq (root, false); - if (found_trait && found_self) + bool found = i->get_impl_item_name ().compare ( + item_seg_identifier.as_string ()) + == 0; + if (found) { - associated_impl_trait = associated; + impl_item = i.get (); break; } } } - if (associated_impl_trait != nullptr) + NodeId root_resolved_node_id = UNKNOWN_NODEID; + if (impl_item == nullptr) { - associated_impl_trait->setup_associated_types (root, specified_bound); + // this may be valid as there could be a default trait implementation here + // and we dont need to worry if the trait item is actually implemented or + // not because this will have already been validated as part of the trait + // impl block + infered = item.get_tyty_for_receiver (root); + root_resolved_node_id + = item.get_raw_item ()->get_mappings ().get_nodeid (); } - - // lookup the associated item from the specified bound - HIR::PathExprSegment &item_seg = expr.get_segments ().at (0); - HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment (); - TyTy::TypeBoundPredicateItem item - = specified_bound.lookup_associated_item (item_seg_identifier.as_string ()); - if (item.is_error ()) + else { - rust_error_at (item_seg.get_locus (), "unknown associated item"); - return; - } + HirId impl_item_id = impl_item->get_impl_mappings ().get_hirid (); + bool ok = query_type (impl_item_id, &infered); + if (!ok) + { + // FIXME + // I think query_type should error if required here anyway + return; + } - // infer the root type - infered = item.get_tyty_for_receiver (root); + root_resolved_node_id = impl_item->get_impl_mappings ().get_nodeid (); + } // turbo-fish segment path::<ty> if (item_seg.has_generic_args ()) @@ -129,10 +143,7 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) } // continue on as a path-in-expression - const TraitItemReference *trait_item_ref = item.get_raw_item (); - NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid (); bool fully_resolved = expr.get_segments ().size () <= 1; - if (fully_resolved) { resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), @@ -321,7 +332,8 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, // candidate is found then we search extensions from traits auto candidates = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls, - false, true /*ignore_mandatory_trait_items*/); + false /*probe_bounds*/, + true /*ignore_mandatory_trait_items*/); if (candidates.size () == 0) { candidates diff --git a/gcc/testsuite/rust/compile/issue-2135.rs b/gcc/testsuite/rust/compile/issue-2135.rs new file mode 100644 index 00000000000..563345efee3 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-2135.rs @@ -0,0 +1,19 @@ +pub trait Foo<A> { + fn foo(self, _: A) -> u16; +} + +impl Foo<u16> for u16 { + fn foo(self, _: u16) -> u16 { + self + } +} + +impl Foo<u8> for u16 { + fn foo(self, _: u8) -> u16 { + self + } +} + +pub fn bar() -> u16 { + <u16 as Foo<u16>>::foo(0u16, 0u16) +} |