diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-11-23 11:25:16 +0000 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-11-23 11:29:50 +0000 |
commit | 88995535f6415e70d485e48006f606b90374bc75 (patch) | |
tree | 4d86b741b4a0519b1fb4d57400dd338ee548644b /gcc | |
parent | 87da9922e66d64e2ef307d33076da86b8486bea0 (diff) | |
download | gcc-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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-type.h | 37 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-bounds.h | 12 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-type.cc | 58 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/associated_types1.rs | 14 |
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() {} |