aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-11-23 11:25:16 +0000
committerPhilip Herron <philip.herron@embecosm.com>2021-11-23 11:29:50 +0000
commit88995535f6415e70d485e48006f606b90374bc75 (patch)
tree4d86b741b4a0519b1fb4d57400dd338ee548644b
parent87da9922e66d64e2ef307d33076da86b8486bea0 (diff)
downloadgcc-88995535f6415e70d485e48006f606b90374bc75.zip
gcc-88995535f6415e70d485e48006f606b90374bc75.tar.gz
gcc-88995535f6415e70d485e48006f606b90374bc75.tar.bz2
Support QualifiedPathInType's within the same Trait
The first implementation of qualified paths assumed that they only exist within trait-impl blocks. Trait impl blocks have the same canonical paths of <type as trait_path>::segment form but this type of path is more generic than this. This patch changes the name resolver to allow for failures in looking up the qualified path within the type namespace since it will not exist in this case and updates the type checking code to be more permissive when used outside of trait impl blocks to simply allow us to resolve this type to the associated trait item as we expect. Usually the code here tries to setup any associated types based on the associated impl block but this is a difference case. Fixes #739
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h37
-rw-r--r--gcc/rust/typecheck/rust-hir-type-bounds.h12
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-type.cc58
-rw-r--r--gcc/testsuite/rust/compile/torture/associated_types1.rs14
4 files changed, 73 insertions, 48 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h
index 2bcf79d..9e5b1e2 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.h
+++ b/gcc/rust/resolve/rust-ast-resolve-type.h
@@ -191,28 +191,25 @@ class ResolveRelativeTypePath : public ResolveTypeToCanonicalPath
using ResolveTypeToCanonicalPath::visit;
public:
- static NodeId go (AST::QualifiedPathInType &path, NodeId parent,
- bool canonicalize_type_with_generics)
+ static bool go (AST::QualifiedPathInType &path, NodeId parent,
+ bool canonicalize_type_with_generics)
{
+ // resolve the type and trait path
auto &qualified_path = path.get_qualified_path_type ();
CanonicalPath result = CanonicalPath::create_empty ();
if (!resolve_qual_seg (qualified_path, result))
- return UNKNOWN_NODEID;
+ return false;
- // resolve the associated impl
+ // resolve the associated impl if available but it can also be from a trait
+ // and this is allowed to fail
auto resolver = Resolver::get ();
NodeId projection_resolved_id = UNKNOWN_NODEID;
- if (!resolver->get_name_scope ().lookup (result, &projection_resolved_id))
+ if (resolver->get_name_scope ().lookup (result, &projection_resolved_id))
{
- rust_error_at (path.get_locus (),
- "failed to resolve associated path: %s",
- result.get ().c_str ());
-
- return UNKNOWN_NODEID;
+ // mark the resolution for this
+ resolver->insert_resolved_name (qualified_path.get_node_id (),
+ projection_resolved_id);
}
- // mark the resolution for this
- resolver->insert_resolved_name (qualified_path.get_node_id (),
- projection_resolved_id);
// qualified types are similar to other paths in that we cannot guarantee
// that we can resolve the path at name resolution. We must look up
@@ -224,18 +221,16 @@ public:
associated->accept_vis (o);
if (o.failure_flag)
- return UNKNOWN_NODEID;
+ return false;
for (auto &seg : path.get_segments ())
{
seg->accept_vis (o);
if (o.failure_flag)
- return UNKNOWN_NODEID;
+ return false;
}
- // we only return the projection id for now since we need the type system to
- // resolve the associated types in this path
- return projection_resolved_id;
+ return true;
}
private:
@@ -352,10 +347,8 @@ public:
void visit (AST::QualifiedPathInType &path) override
{
- resolved_node
- = ResolveRelativeTypePath::go (path, parent,
- canonicalize_type_with_generics);
- ok = resolved_node != UNKNOWN_NODEID;
+ ok = ResolveRelativeTypePath::go (path, parent,
+ canonicalize_type_with_generics);
}
void visit (AST::ArrayType &type) override;
diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h
index 1ba6049..50cf34f 100644
--- a/gcc/rust/typecheck/rust-hir-type-bounds.h
+++ b/gcc/rust/typecheck/rust-hir-type-bounds.h
@@ -42,14 +42,22 @@ public:
static bool is_bound_satisfied_for_type (TyTy::BaseType *receiver,
TraitReference *ref)
{
+ for (auto &bound : receiver->get_specified_bounds ())
+ {
+ const TraitReference *b = bound.get ();
+ if (b->is_equal (*ref))
+ return true;
+ }
+
std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
= Probe (receiver);
for (auto &bound : bounds)
{
- TraitReference *b = bound.first;
- if (b == ref)
+ const TraitReference *b = bound.first;
+ if (b->is_equal (*ref))
return true;
}
+
return false;
}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index f1dbb6b..4256654 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -140,29 +140,16 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
// does this type actually implement this type-bound?
if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
- return;
-
- // we need resolve to the impl block
- NodeId impl_resolved_id = UNKNOWN_NODEID;
- bool ok = resolver->lookup_resolved_name (
- qual_path_type.get_mappings ().get_nodeid (), &impl_resolved_id);
- rust_assert (ok);
-
- HirId impl_block_id;
- ok = mappings->lookup_node_to_hir (path.get_mappings ().get_crate_num (),
- impl_resolved_id, &impl_block_id);
- rust_assert (ok);
-
- AssociatedImplTrait *lookup_associated = nullptr;
- bool found_impl_trait
- = context->lookup_associated_trait_impl (impl_block_id, &lookup_associated);
- rust_assert (found_impl_trait);
+ {
+ rust_error_at (qual_path_type.get_locus (),
+ "root does not satisfy specified trait-bound");
+ return;
+ }
std::unique_ptr<HIR::TypePathSegment> &item_seg
= path.get_associated_segment ();
-
const TraitItemReference *trait_item_ref = nullptr;
- ok
+ bool ok
= trait_ref->lookup_trait_item (item_seg->get_ident_segment ().as_string (),
&trait_item_ref);
if (!ok)
@@ -171,16 +158,39 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
return;
}
- // project
- lookup_associated->setup_associated_types ();
+ // this will be the placeholder from the trait but we may be able to project
+ // it based on the impl block
+ translated = trait_item_ref->get_tyty ();
+ // this is the associated generics we need to potentially apply
HIR::GenericArgs trait_generics = qual_path_type.trait_has_generic_args ()
? qual_path_type.get_trait_generic_args ()
: HIR::GenericArgs::create_empty ();
- translated = lookup_associated->get_projected_type (
- trait_item_ref, root, item_seg->get_mappings ().get_hirid (),
- trait_generics, item_seg->get_locus ());
+ // we need resolve to the impl block
+ NodeId impl_resolved_id = UNKNOWN_NODEID;
+ bool have_associated_impl = resolver->lookup_resolved_name (
+ qual_path_type.get_mappings ().get_nodeid (), &impl_resolved_id);
+ if (have_associated_impl)
+ {
+ HirId impl_block_id;
+ bool ok
+ = mappings->lookup_node_to_hir (path.get_mappings ().get_crate_num (),
+ impl_resolved_id, &impl_block_id);
+ rust_assert (ok);
+
+ AssociatedImplTrait *lookup_associated = nullptr;
+ bool found_impl_trait
+ = context->lookup_associated_trait_impl (impl_block_id,
+ &lookup_associated);
+ rust_assert (found_impl_trait);
+
+ // project
+ lookup_associated->setup_associated_types ();
+ translated = lookup_associated->get_projected_type (
+ trait_item_ref, root, item_seg->get_mappings ().get_hirid (),
+ trait_generics, item_seg->get_locus ());
+ }
if (translated->get_kind () == TyTy::TypeKind::PLACEHOLDER)
{
diff --git a/gcc/testsuite/rust/compile/torture/associated_types1.rs b/gcc/testsuite/rust/compile/torture/associated_types1.rs
new file mode 100644
index 0000000..0d4b4c7
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/associated_types1.rs
@@ -0,0 +1,14 @@
+pub trait Foo {
+ type A;
+
+ fn boo(&self) -> <Self as Foo>::A;
+ // { dg-warning "unused name .self." "" { target *-*-* } .-1 }
+}
+
+fn foo2<I: Foo>(x: I) {
+ // { dg-warning "function is never used: .foo2." "" { target *-*-* } .-1 }
+ // { dg-warning "unused name .foo2." "" { target *-*-* } .-2 }
+ x.boo();
+}
+
+pub fn main() {}