diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-08-31 12:26:33 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-08-31 13:31:58 +0100 |
commit | 58637abaeab1459574d6535481d7fcc8f9620167 (patch) | |
tree | 74750b724153748468cb93c4051454368c5e959c | |
parent | 5e7108c3582f772c28864bd08934b00dfa3539fd (diff) | |
download | gcc-58637abaeab1459574d6535481d7fcc8f9620167.zip gcc-58637abaeab1459574d6535481d7fcc8f9620167.tar.gz gcc-58637abaeab1459574d6535481d7fcc8f9620167.tar.bz2 |
Add type resolution for qualified-type-paths
Qualified type paths are similar to qualified path expressions, in that
they must resolve the projection of the trait onto a type to receive the
correct associated type information.
-rw-r--r-- | gcc/rust/Make-lang.in | 1 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-type.cc | 229 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-type.h | 74 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/traits12.rs | 29 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/traits13.rs | 17 |
5 files changed, 284 insertions, 66 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 9c69b44..64b9247 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -83,6 +83,7 @@ GRS_OBJS = \ rust/rust-hir-type-check-util.o \ rust/rust-hir-trait-resolve.o \ rust/rust-hir-const-fold.o \ + rust/rust-hir-type-check-type.o \ rust/rust-lint-marklive.o \ rust/rust-hir-type-check-path.o \ $(END) diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc new file mode 100644 index 0000000..dd03499 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -0,0 +1,229 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-hir-type-check-type.h" +#include "rust-hir-trait-resolve.h" + +namespace Rust { +namespace Resolver { + +void +TypeCheckType::visit (HIR::TypePath &path) +{ + // lookup the Node this resolves to + NodeId ref; + auto nid = path.get_mappings ().get_nodeid (); + if (!resolver->lookup_resolved_type (nid, &ref)) + { + rust_fatal_error (path.get_locus (), "failed to resolve node '%d' to HIR", + nid); + return; + } + + HirId hir_lookup; + if (!context->lookup_type_by_node_id (ref, &hir_lookup)) + { + rust_error_at (path.get_locus (), "failed to lookup HIR %d for node '%s'", + ref, path.as_string ().c_str ()); + return; + } + + TyTy::BaseType *lookup = nullptr; + if (!context->lookup_type (hir_lookup, &lookup)) + { + rust_error_at (path.get_locus (), "failed to lookup HIR TyTy"); + return; + } + + TyTy::BaseType *path_type = lookup->clone (); + path_type->set_ref (path.get_mappings ().get_hirid ()); + + HIR::TypePathSegment *final_seg = path.get_final_segment ().get (); + HIR::GenericArgs args = TypeCheckResolveGenericArguments::resolve (final_seg); + + bool is_big_self = final_seg->is_ident_only () + && (final_seg->as_string ().compare ("Self") == 0); + + if (path_type->needs_generic_substitutions ()) + { + if (is_big_self) + { + translated = path_type; + return; + } + + translated = SubstMapper::Resolve (path_type, path.get_locus (), &args); + if (translated->get_kind () != TyTy::TypeKind::ERROR + && mappings != nullptr) + { + check_for_unconstrained (args.get_type_args ()); + } + } + else if (!args.is_empty ()) + { + rust_error_at (path.get_locus (), + "TypePath %s declares generic arguments but " + "the type %s does not have any", + path.as_string ().c_str (), + translated->as_string ().c_str ()); + } + else + { + translated = path_type; + } +} + +void +TypeCheckType::visit (HIR::QualifiedPathInType &path) +{ + HIR::QualifiedPathType qual_path_type = path.get_path_type (); + TyTy::BaseType *root + = TypeCheckType::Resolve (qual_path_type.get_type ().get ()); + if (root->get_kind () == TyTy::TypeKind::ERROR) + { + rust_debug_loc (path.get_locus (), "failed to resolve the root"); + return; + } + + if (!qual_path_type.has_as_clause ()) + { + // then this is just a normal path-in-expression + NodeId root_resolved_node_id = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_type ( + qual_path_type.get_type ()->get_mappings ().get_nodeid (), + &root_resolved_node_id); + rust_assert (ok); + + resolve_segments (root_resolved_node_id, path.get_segments (), 0, + translated, path.get_mappings (), path.get_locus ()); + } + + // Resolve the trait now + TraitReference *trait_ref + = TraitResolver::Resolve (*qual_path_type.get_trait ().get ()); + if (trait_ref->is_error ()) + return; + + // 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); + + DefId resolved_item_id = UNKNOWN_DEFID; + std::unique_ptr<HIR::TypePathSegment> &item_seg + = path.get_associated_segment (); + + const TraitItemReference *trait_item_ref = nullptr; + ok + = trait_ref->lookup_trait_item (item_seg->get_ident_segment ().as_string (), + &trait_item_ref); + if (!ok) + { + rust_error_at (item_seg->get_locus (), "unknown associated item"); + return; + } + resolved_item_id = trait_item_ref->get_mappings ().get_defid (); + + // project + lookup_associated->setup_associated_types (); + + translated = lookup_associated->get_projected_type ( + trait_item_ref, root, item_seg->get_mappings ().get_hirid (), + item_seg->get_locus ()); + + if (translated->get_kind () == TyTy::TypeKind::PLACEHOLDER) + { + // lets grab the actual projection type + TyTy::PlaceholderType *p + = static_cast<TyTy::PlaceholderType *> (translated); + if (p->can_resolve ()) + { + translated = p->resolve (); + } + } + + if (item_seg->get_type () == HIR::TypePathSegment::SegmentType::GENERIC) + { + HIR::TypePathSegmentGeneric &generic_seg + = static_cast<HIR::TypePathSegmentGeneric &> (*item_seg.get ()); + + // turbo-fish segment path::<ty> + if (generic_seg.has_generic_args ()) + { + if (!translated->can_substitute ()) + { + rust_error_at (item_seg->get_locus (), + "substitutions not supported for %s", + translated->as_string ().c_str ()); + translated + = new TyTy::ErrorType (path.get_mappings ().get_hirid ()); + return; + } + translated = SubstMapper::Resolve (translated, path.get_locus (), + &generic_seg.get_generic_args ()); + } + } + + TyTy::ProjectionType *projection + = new TyTy::ProjectionType (qual_path_type.get_mappings ().get_hirid (), + TyTy::TyVar (root->get_ref ()), trait_ref, + resolved_item_id, lookup_associated); + context->insert_type (qual_path_type.get_mappings (), projection); + + // continue on as a path-in-expression + NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid (); + bool fully_resolved = path.get_segments ().empty (); + if (fully_resolved) + { + resolver->insert_resolved_name (path.get_mappings ().get_nodeid (), + root_resolved_node_id); + context->insert_receiver (path.get_mappings ().get_hirid (), root); + return; + } + + resolve_segments (root_resolved_node_id, path.get_segments (), 0, translated, + path.get_mappings (), path.get_locus ()); +} + +void +TypeCheckType::resolve_segments ( + NodeId root_resolved_node_id, + std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset, + TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings, + Location expr_locus) +{ + gcc_unreachable (); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index 15eab25..c02a369 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -1,4 +1,3 @@ - // Copyright (C) 2020 Free Software Foundation, Inc. // This file is part of GCC. @@ -117,72 +116,9 @@ public: = new TyTy::TupleType (tuple.get_mappings ().get_hirid (), fields); } - void visit (HIR::TypePath &path) override - { - // lookup the Node this resolves to - NodeId ref; - auto nid = path.get_mappings ().get_nodeid (); - if (!resolver->lookup_resolved_type (nid, &ref)) - { - rust_fatal_error (path.get_locus (), - "failed to resolve node '%d' to HIR", nid); - return; - } - - HirId hir_lookup; - if (!context->lookup_type_by_node_id (ref, &hir_lookup)) - { - rust_error_at (path.get_locus (), - "failed to lookup HIR %d for node '%s'", ref, - path.as_string ().c_str ()); - return; - } - - TyTy::BaseType *lookup = nullptr; - if (!context->lookup_type (hir_lookup, &lookup)) - { - rust_error_at (path.get_locus (), "failed to lookup HIR TyTy"); - return; - } - - TyTy::BaseType *path_type = lookup->clone (); - path_type->set_ref (path.get_mappings ().get_hirid ()); - - HIR::TypePathSegment *final_seg = path.get_final_segment ().get (); - HIR::GenericArgs args - = TypeCheckResolveGenericArguments::resolve (final_seg); + void visit (HIR::TypePath &path) override; - bool is_big_self = final_seg->is_ident_only () - && (final_seg->as_string ().compare ("Self") == 0); - - if (path_type->needs_generic_substitutions ()) - { - if (is_big_self) - { - translated = path_type; - return; - } - - translated = SubstMapper::Resolve (path_type, path.get_locus (), &args); - if (translated->get_kind () != TyTy::TypeKind::ERROR - && mappings != nullptr) - { - check_for_unconstrained (args.get_type_args ()); - } - } - else if (!args.is_empty ()) - { - rust_error_at (path.get_locus (), - "TypePath %s declares generic arguments but " - "the type %s does not have any", - path.as_string ().c_str (), - translated->as_string ().c_str ()); - } - else - { - translated = path_type; - } - } + void visit (HIR::QualifiedPathInType &path) override; void visit (HIR::ArrayType &type) override; @@ -246,6 +182,12 @@ private: } } + void resolve_segments ( + NodeId root_resolved_node_id, + std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset, + TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings, + Location expr_locus); + std::vector<TyTy::SubstitutionParamMapping> *subst_mappings; TyTy::BaseType *translated; }; diff --git a/gcc/testsuite/rust/compile/torture/traits12.rs b/gcc/testsuite/rust/compile/torture/traits12.rs new file mode 100644 index 0000000..a55b965 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits12.rs @@ -0,0 +1,29 @@ +trait Foo { + type A; + + fn test(a: Self::A) -> Self::A { + a + } +} + +struct Bar(i32); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Foo for Bar { + type A = i32; +} + +struct Baz(f32); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Foo for Baz { + type A = f32; +} + +fn main() { + let a: <Baz as Foo>::A; + a = 123f32; + + let b; + b = <Baz as Foo>::test(a); +} diff --git a/gcc/testsuite/rust/compile/torture/traits13.rs b/gcc/testsuite/rust/compile/torture/traits13.rs new file mode 100644 index 0000000..326f039 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits13.rs @@ -0,0 +1,17 @@ +trait Trait { + const FOO: usize; + type Target; +} + +struct S; +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Trait for S { + const FOO: usize = 0; + type Target = usize; +} + +fn main() { + let a: <S as Trait>::Target; + a = <S as Trait>::FOO; +} |