diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-07-16 16:50:26 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-08-05 19:07:11 +0100 |
commit | 65ef30eb84314ae7525be4a4d7dd79d2868e3e3c (patch) | |
tree | bb7172a61dc354681743d86f708e021b4613cc9f | |
parent | 0db1c804562aff23344cd5882db6fc65596e0966 (diff) | |
download | gcc-65ef30eb84314ae7525be4a4d7dd79d2868e3e3c.zip gcc-65ef30eb84314ae7525be4a4d7dd79d2868e3e3c.tar.gz gcc-65ef30eb84314ae7525be4a4d7dd79d2868e3e3c.tar.bz2 |
Support TypeBounds on Generic functions
TypeBounds are what make generics useful in Rust. They act in some ways
similar to interfaces in modern Java.
Fixes #583
20 files changed, 845 insertions, 128 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 794c7a3..f4bc9ea 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -79,6 +79,7 @@ GRS_OBJS = \ rust/rust-hir-type-check.o \ rust/rust-tyty.o \ rust/rust-tyctx.o \ + rust/rust-tyty-bounds.o \ rust/rust-hir-const-fold.o \ rust/rust-lint-marklive.o \ $(END) diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index af8d609..c87b477 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -20,6 +20,8 @@ #include "rust-backend.h" #include "rust-compile-resolve-path.h" #include "rust-compile-item.h" +#include "rust-hir-trait-resolve.h" +#include "rust-hir-path-probe.h" namespace Rust { namespace Compile { @@ -94,7 +96,76 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) HIR::ImplItem *resolved_item = ctx->get_mappings ()->lookup_hir_implitem ( expr.get_mappings ().get_crate_num (), ref, &parent_impl_id); - if (resolved_item != nullptr) + + if (resolved_item == nullptr) + { + // it might be resolved to a trait item + HIR::TraitItem *trait_item + = ctx->get_mappings ()->lookup_hir_trait_item ( + expr.get_mappings ().get_crate_num (), ref); + HIR::Trait *trait + = ctx->get_mappings ()->lookup_trait_item_mapping ( + trait_item->get_mappings ().get_hirid ()); + + Resolver::TraitReference &trait_ref + = Resolver::TraitResolver::error_node (); + bool ok = ctx->get_tyctx ()->lookup_trait_reference ( + trait->get_mappings ().get_defid (), trait_ref); + rust_assert (ok); + + TyTy::BaseType *receiver = nullptr; + ok = ctx->get_tyctx ()->lookup_receiver ( + expr.get_mappings ().get_hirid (), &receiver); + rust_assert (ok); + + if (receiver->get_kind () == TyTy::TypeKind::PARAM) + { + TyTy::ParamType *p + = static_cast<TyTy::ParamType *> (receiver); + receiver = p->resolve (); + } + + // the type resolver can only resolve type bounds to their trait + // item so its up to us to figure out if this path should resolve + // to an trait-impl-block-item or if it can be defaulted to the + // trait-impl-item's definition + std::vector<Resolver::PathProbeCandidate> candidates + = Resolver::PathProbeType::Probe ( + receiver, expr.get_final_segment ().get_segment (), true, + false, true); + + if (candidates.size () == 0) + { + // this means we are defaulting back to the trait_item if + // possible + // TODO + gcc_unreachable (); + } + else + { + Resolver::PathProbeCandidate &candidate = candidates.at (0); + rust_assert (candidate.is_impl_candidate ()); + + HIR::ImplBlock *impl = candidate.item.impl.parent; + HIR::ImplItem *impl_item = candidate.item.impl.impl_item; + + TyTy::BaseType *self = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + impl->get_type ()->get_mappings ().get_hirid (), &self); + rust_assert (ok); + + if (!lookup->has_subsititions_defined ()) + CompileInherentImplItem::Compile (self, impl_item, ctx, + true); + else + CompileInherentImplItem::Compile (self, impl_item, ctx, + true, lookup); + + lookup->set_ty_ref ( + impl_item->get_impl_mappings ().get_hirid ()); + } + } + else { rust_assert (parent_impl_id != UNKNOWN_HIRID); HIR::Item *impl_ref = ctx->get_mappings ()->lookup_hir_item ( @@ -114,18 +185,13 @@ ResolvePathRef::visit (HIR::PathInExpression &expr) CompileInherentImplItem::Compile (self, resolved_item, ctx, true, lookup); } - else - { - rust_error_at (expr.get_locus (), - "failed to lookup definition declaration"); - return; - } } if (!ctx->lookup_function_decl (lookup->get_ty_ref (), &fn)) { - rust_fatal_error (expr.get_locus (), - "forward declaration was not compiled"); + resolved = ctx->get_backend ()->error_expression (); + rust_error_at (expr.get_locus (), + "forward declaration was not compiled"); return; } } diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index aa9aa2d..f422572 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -20,6 +20,8 @@ #include "rust-compile-item.h" #include "rust-compile-expr.h" #include "rust-compile-struct-field-expr.h" +#include "rust-hir-trait-resolve.h" +#include "rust-hir-path-probe.h" #include "fnv-hash.h" namespace Rust { @@ -141,31 +143,105 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) expr.get_mappings ().get_crate_num (), ref, nullptr); if (resolved_item == nullptr) { - rust_error_at (expr.get_locus (), - "failed to lookup forward declaration"); - return; - } + // it might be resolved to a trait item + HIR::TraitItem *trait_item + = ctx->get_mappings ()->lookup_hir_trait_item ( + expr.get_mappings ().get_crate_num (), ref); + HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping ( + trait_item->get_mappings ().get_hirid ()); + + Resolver::TraitReference &trait_ref + = Resolver::TraitResolver::error_node (); + bool ok = ctx->get_tyctx ()->lookup_trait_reference ( + trait->get_mappings ().get_defid (), trait_ref); + rust_assert (ok); + + TyTy::BaseType *receiver = nullptr; + ok = ctx->get_tyctx ()->lookup_receiver ( + expr.get_mappings ().get_hirid (), &receiver); + rust_assert (ok); + + if (receiver->get_kind () == TyTy::TypeKind::PARAM) + { + TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver); + receiver = p->resolve (); + } - TyTy::BaseType *self_type = nullptr; - if (!ctx->get_tyctx ()->lookup_type ( - expr.get_receiver ()->get_mappings ().get_hirid (), &self_type)) - { - rust_error_at (expr.get_locus (), - "failed to resolve type for self param"); - return; - } + // the type resolver can only resolve type bounds to their trait + // item so its up to us to figure out if this path should resolve + // to an trait-impl-block-item or if it can be defaulted to the + // trait-impl-item's definition + std::vector<Resolver::PathProbeCandidate> candidates + = Resolver::PathProbeType::Probe ( + receiver, expr.get_method_name ().get_segment (), true, false, + true); - if (!fntype->has_subsititions_defined ()) - CompileInherentImplItem::Compile (self_type, resolved_item, ctx, true); + if (candidates.size () == 0) + { + // this means we are defaulting back to the trait_item if + // possible + // TODO + gcc_unreachable (); + } + else + { + Resolver::PathProbeCandidate &candidate = candidates.at (0); + rust_assert (candidate.is_impl_candidate ()); + + HIR::ImplItem *impl_item = candidate.item.impl.impl_item; + + TyTy::BaseType *self_type = nullptr; + if (!ctx->get_tyctx ()->lookup_type ( + expr.get_receiver ()->get_mappings ().get_hirid (), + &self_type)) + { + rust_error_at (expr.get_locus (), + "failed to resolve type for self param"); + return; + } + + if (!fntype->has_subsititions_defined ()) + CompileInherentImplItem::Compile (self_type, impl_item, ctx, + true); + else + CompileInherentImplItem::Compile (self_type, impl_item, ctx, + true, fntype); + + if (!ctx->lookup_function_decl ( + impl_item->get_impl_mappings ().get_hirid (), &fn)) + { + translated = ctx->get_backend ()->error_expression (); + rust_error_at (expr.get_locus (), + "forward declaration was not compiled"); + return; + } + } + } else - CompileInherentImplItem::Compile (self_type, resolved_item, ctx, true, - fntype); - - if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) { - rust_error_at (expr.get_locus (), - "forward declaration was not compiled"); - return; + TyTy::BaseType *self_type = nullptr; + if (!ctx->get_tyctx ()->lookup_type ( + expr.get_receiver ()->get_mappings ().get_hirid (), &self_type)) + { + rust_error_at (expr.get_locus (), + "failed to resolve type for self param"); + return; + } + + if (!fntype->has_subsititions_defined ()) + CompileInherentImplItem::Compile (self_type, resolved_item, ctx, + true); + else + CompileInherentImplItem::Compile (self_type, resolved_item, ctx, + true, fntype); + + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) + { + translated = ctx->get_backend ()->error_expression (); + rust_error_at (expr.get_locus (), + "forward declaration was not compiled"); + return; + } } } diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 3ad06c8..ba04339 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -124,6 +124,11 @@ public: return type->get_mappings (); } + std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () + { + return type_param_bounds; + } + protected: // Clone function implementation as (not pure) virtual method TypeParam *clone_generic_param_impl () const override diff --git a/gcc/rust/hir/tree/rust-hir-type.h b/gcc/rust/hir/tree/rust-hir-type.h index 87dffcf..8d75d02 100644 --- a/gcc/rust/hir/tree/rust-hir-type.h +++ b/gcc/rust/hir/tree/rust-hir-type.h @@ -67,6 +67,10 @@ public: BoundType get_bound_type () const final override { return TRAITBOUND; } + TypePath &get_path () { return type_path; } + + const TypePath &get_path () const { return type_path; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index 1b7aa4d..8e3ca31 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -23,6 +23,7 @@ #include "rust-hir-full.h" #include "rust-tyty.h" #include "rust-substitution-mapper.h" +#include "rust-hir-type-bounds.h" namespace Rust { namespace Resolver { @@ -34,12 +35,80 @@ struct PathProbeCandidate IMPL_CONST, IMPL_TYPE_ALIAS, IMPL_FUNC, + + TRAIT_ITEM_CONST, + TRAIT_TYPE_ALIAS, + TRAIT_FUNC, + }; + + struct ImplItemCandidate + { + HIR::ImplItem *impl_item; + HIR::ImplBlock *parent; + }; + + struct TraitItemCandidate + { + const TraitReference &trait_ref; + const TraitItemReference &item_ref; }; CandidateType type; - HIR::ImplItem *impl_item; TyTy::BaseType *ty; - HIR::ImplBlock *parent; + Location locus; + union Candidate + { + ImplItemCandidate impl; + TraitItemCandidate trait; + + Candidate (ImplItemCandidate impl) : impl (impl) {} + Candidate (TraitItemCandidate trait) : trait (trait) {} + } item; + + PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus, + ImplItemCandidate impl) + : type (type), ty (ty), item (impl) + {} + + PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus, + TraitItemCandidate trait) + : type (type), ty (ty), item (trait) + {} + + std::string as_string () const + { + return "PathProbe candidate TODO - as_string"; + } + + bool is_impl_candidate () const + { + switch (type) + { + case IMPL_CONST: + case IMPL_TYPE_ALIAS: + case IMPL_FUNC: + return true; + + default: + return false; + } + gcc_unreachable (); + } + + bool is_trait_candidate () const + { + switch (type) + { + case TRAIT_ITEM_CONST: + case TRAIT_TYPE_ALIAS: + case TRAIT_FUNC: + return true; + + default: + return false; + } + gcc_unreachable (); + } }; class PathProbeType : public TypeCheckBase @@ -48,32 +117,33 @@ class PathProbeType : public TypeCheckBase public: static std::vector<PathProbeCandidate> - Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name) + Probe (const TyTy::BaseType *receiver, + const HIR::PathIdentSegment &segment_name, bool probe_impls, + bool probe_bounds, bool ignore_mandatory_trait_items) { PathProbeType probe (receiver, segment_name); - probe.mappings->iterate_impl_items ( - [&] (HirId id, HIR::ImplItem *item, - HIR::ImplBlock *impl) mutable -> bool { - probe.process_candidate (id, item, impl); - return true; - }); + if (probe_impls) + probe.process_impl_items_for_candidates (); - return probe.candidates; - } + if (!probe_bounds) + return probe.candidates; - void process_candidate (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) - { - current_impl = impl; - HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid (); - TyTy::BaseType *impl_block_ty = nullptr; - bool ok = context->lookup_type (impl_ty_id, &impl_block_ty); - rust_assert (ok); + std::vector<std::reference_wrapper<TraitReference>> probed_bounds + = TypeBoundsProbe::Probe (receiver); - if (!receiver->can_eq (impl_block_ty, false)) - return; + std::vector<std::reference_wrapper<const TraitReference>> specified_bounds; + for (const TyTy::TypeBoundPredicate &predicate : + receiver->get_specified_bounds ()) + { + const TraitReference *trait_item = predicate.get (); + specified_bounds.push_back (*trait_item); + } - // lets visit the impl_item - item->accept_vis (*this); + std::vector<std::reference_wrapper<const TraitReference>> union_type_bounds + = probe.union_bounds (probed_bounds, specified_bounds); + probe.process_traits_for_candidates (union_type_bounds, + ignore_mandatory_trait_items); + return probe.candidates; } void visit (HIR::TypeAlias &alias) override @@ -86,9 +156,11 @@ public: bool ok = context->lookup_type (tyid, &ty); rust_assert (ok); + PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias, + current_impl}; PathProbeCandidate candidate{ - PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, &alias, ty, - current_impl}; + PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, ty, + alias.get_locus (), impl_item_candidate}; candidates.push_back (std::move (candidate)); } } @@ -103,9 +175,11 @@ public: bool ok = context->lookup_type (tyid, &ty); rust_assert (ok); + PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant, + current_impl}; PathProbeCandidate candidate{ - PathProbeCandidate::CandidateType::IMPL_CONST, &constant, ty, - current_impl}; + PathProbeCandidate::CandidateType::IMPL_CONST, ty, + constant.get_locus (), impl_item_candidate}; candidates.push_back (std::move (candidate)); } } @@ -120,20 +194,146 @@ public: bool ok = context->lookup_type (tyid, &ty); rust_assert (ok); + PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function, + current_impl}; PathProbeCandidate candidate{ - PathProbeCandidate::CandidateType::IMPL_FUNC, &function, ty, - current_impl}; + PathProbeCandidate::CandidateType::IMPL_FUNC, ty, + function.get_locus (), impl_item_candidate}; candidates.push_back (std::move (candidate)); } } private: - PathProbeType (TyTy::BaseType *receiver, const HIR::PathIdentSegment &query) + void process_impl_items_for_candidates () + { + mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item, + HIR::ImplBlock *impl) mutable -> bool { + process_impl_item_candidate (id, item, impl); + return true; + }); + } + + void process_impl_item_candidate (HirId id, HIR::ImplItem *item, + HIR::ImplBlock *impl) + { + current_impl = impl; + HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid (); + TyTy::BaseType *impl_block_ty = nullptr; + bool ok = context->lookup_type (impl_ty_id, &impl_block_ty); + rust_assert (ok); + + if (!receiver->can_eq (impl_block_ty, false)) + return; + + // lets visit the impl_item + item->accept_vis (*this); + } + + void process_traits_for_candidates ( + const std::vector<std::reference_wrapper<const TraitReference>> traits, + bool ignore_mandatory_trait_items) + { + for (const TraitReference &trait_ref : traits) + { + const TraitItemReference &trait_item_ref + = trait_ref.lookup_trait_item (search.as_string ()); + if (trait_item_ref.is_error ()) + continue; + + bool trait_item_needs_implementation = !trait_item_ref.is_optional (); + if (ignore_mandatory_trait_items && trait_item_needs_implementation) + continue; + + PathProbeCandidate::CandidateType candidate_type; + switch (trait_item_ref.get_trait_item_type ()) + { + case TraitItemReference::TraitItemType::FN: + candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC; + break; + case TraitItemReference::TraitItemType::CONST: + candidate_type + = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST; + break; + case TraitItemReference::TraitItemType::TYPE: + candidate_type + = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS; + break; + + case TraitItemReference::TraitItemType::ERROR: + gcc_unreachable (); + break; + } + + TyTy::BaseType *trait_item_tyty = trait_item_ref.get_tyty (); + + // we can substitute the Self with the receiver here + if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF) + { + TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty); + TyTy::SubstitutionParamMapping *param = nullptr; + for (auto ¶m_mapping : fn->get_substs ()) + { + const HIR::TypeParam &type_param + = param_mapping.get_generic_param (); + if (type_param.get_type_representation ().compare ("Self") == 0) + { + param = ¶m_mapping; + break; + } + } + rust_assert (param != nullptr); + + std::vector<TyTy::SubstitutionArg> mappings; + mappings.push_back ( + TyTy::SubstitutionArg (param, receiver->clone ())); + + Location locus; // FIXME + TyTy::SubstitutionArgumentMappings args (std::move (mappings), + locus); + trait_item_tyty + = SubstMapperInternal::Resolve (trait_item_tyty, args); + } + + PathProbeCandidate::TraitItemCandidate trait_item_candidate{ + trait_ref, trait_item_ref}; + PathProbeCandidate candidate{candidate_type, + trait_item_tyty, + trait_ref.get_locus (), + {trait_item_candidate}}; + candidates.push_back (std::move (candidate)); + } + } + +private: + PathProbeType (const TyTy::BaseType *receiver, + const HIR::PathIdentSegment &query) : TypeCheckBase (), receiver (receiver), search (query), current_impl (nullptr) {} - TyTy::BaseType *receiver; + std::vector<std::reference_wrapper<const TraitReference>> union_bounds ( + const std::vector<std::reference_wrapper</*const*/ TraitReference>> a, + const std::vector<std::reference_wrapper<const TraitReference>> b) const + { + std::map<DefId, std::reference_wrapper<const TraitReference>> mapper; + for (const TraitReference &ref : a) + { + mapper.insert ({ref.get_mappings ().get_defid (), ref}); + } + for (const TraitReference &ref : b) + { + mapper.insert ({ref.get_mappings ().get_defid (), ref}); + } + + std::vector<std::reference_wrapper<const TraitReference>> union_set; + for (auto it = mapper.begin (); it != mapper.end (); it++) + { + union_set.push_back (it->second); + } + return union_set; + } + + const TyTy::BaseType *receiver; const HIR::PathIdentSegment &search; std::vector<PathProbeCandidate> candidates; HIR::ImplBlock *current_impl; @@ -150,7 +350,22 @@ public: RichLocation r (query_locus); ReportMultipleCandidateError visitor (r); for (auto &c : candidates) - c.impl_item->accept_vis (visitor); + { + switch (c.type) + { + case PathProbeCandidate::CandidateType::IMPL_CONST: + case PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS: + case PathProbeCandidate::CandidateType::IMPL_FUNC: + c.item.impl.impl_item->accept_vis (visitor); + break; + + case PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST: + case PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS: + case PathProbeCandidate::CandidateType::TRAIT_FUNC: + r.add_range (c.item.trait.item_ref.get_locus ()); + break; + } + } rust_error_at (r, "multiple applicable items in scope for: %s", query.as_string ().c_str ()); diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index 35c0fef..b19c38a 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -56,6 +56,7 @@ public: locus = other.locus; context = other.context; + inherited_substitutions.clear (); inherited_substitutions.reserve (other.inherited_substitutions.size ()); for (size_t i = 0; i < other.inherited_substitutions.size (); i++) inherited_substitutions.push_back (other.inherited_substitutions.at (i)); @@ -221,6 +222,21 @@ public: + "]"; } + const Analysis::NodeMapping &get_mappings () const + { + return hir_trait_ref->get_mappings (); + } + + const TraitItemReference &lookup_trait_item (const std::string &ident) const + { + for (auto &item : item_refs) + { + if (ident.compare (item.get_identifier ()) == 0) + return item; + } + return TraitItemReference::error_node (); + } + const TraitItemReference & lookup_trait_item (const std::string &ident, TraitItemReference::TraitItemType type) const diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 3de68c8..6d7c864 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -121,8 +121,7 @@ private: if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (), &ref)) { - rust_fatal_error (path.get_locus (), - "Failed to resolve path to node-id"); + rust_error_at (path.get_locus (), "Failed to resolve path to node-id"); return error_node (); } @@ -130,8 +129,7 @@ private: if (!mappings->lookup_node_to_hir (mappings->get_current_crate (), ref, &hir_node)) { - rust_fatal_error (path.get_locus (), - "Failed to resolve path to hir-id"); + rust_error_at (path.get_locus (), "Failed to resolve path to hir-id"); return error_node (); } diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h new file mode 100644 index 0000000..d97c0f5 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -0,0 +1,57 @@ +// Copyright (C) 2021 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/>. + +#ifndef RUST_HIR_TYPE_BOUNDS_H +#define RUST_HIR_TYPE_BOUNDS_H + +#include "rust-hir-type-check-base.h" +#include "rust-hir-full.h" +#include "rust-tyty.h" + +namespace Rust { +namespace Resolver { + +class TypeBoundsProbe : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static std::vector<std::reference_wrapper<TraitReference>> + Probe (const TyTy::BaseType *receiver) + { + TypeBoundsProbe probe (receiver); + probe.scan (); + return probe.trait_references; + } + +private: + void scan (); + +private: + TypeBoundsProbe (const TyTy::BaseType *receiver) + : TypeCheckBase (), receiver (receiver) + {} + + const TyTy::BaseType *receiver; + std::vector<std::reference_wrapper<TraitReference>> trait_references; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_HIR_TYPE_BOUNDS_H diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index ae71611..f05ab86 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -28,6 +28,8 @@ namespace Rust { namespace Resolver { +class TraitReference; + // base class to allow derivatives to overload as needed class TypeCheckBase : public HIR::HIRVisitor { @@ -200,6 +202,8 @@ protected: context (TypeCheckContext::get ()) {} + TraitReference &resolve_trait_path (HIR::TypePath &); + Analysis::Mappings *mappings; Resolver *resolver; TypeCheckContext *context; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index bd42b4c..7f1a83d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -205,15 +205,25 @@ public: return; } + context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty); + // https://doc.rust-lang.org/reference/expressions/method-call-expr.html // method resolution is complex in rust once we start handling generics and // traits. For now we only support looking up the valid name in impl blocks // which is simple. There will need to be adjustments to ensure we can turn // the receiver into borrowed references etc + bool reciever_is_generic + = receiver_tyty->get_kind () == TyTy::TypeKind::PARAM; + bool probe_bounds = true; + bool probe_impls = !reciever_is_generic; + bool ignore_mandatory_trait_items = !reciever_is_generic; + auto candidates = PathProbeType::Probe (receiver_tyty, - expr.get_method_name ().get_segment ()); + expr.get_method_name ().get_segment (), + probe_impls, probe_bounds, + ignore_mandatory_trait_items); if (candidates.size () == 0) { rust_error_at (expr.get_locus (), @@ -229,13 +239,18 @@ public: } auto resolved_candidate = candidates.at (0); - HIR::ImplItem *resolved_method = resolved_candidate.impl_item; TyTy::BaseType *lookup_tyty = resolved_candidate.ty; + NodeId resolved_node_id + = resolved_candidate.is_impl_candidate () + ? resolved_candidate.item.impl.impl_item->get_impl_mappings () + .get_nodeid () + : resolved_candidate.item.trait.item_ref.get_mappings () + .get_nodeid (); if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF) { RichLocation r (expr.get_method_name ().get_locus ()); - r.add_range (resolved_method->get_impl_locus ()); + r.add_range (resolved_candidate.locus); rust_error_at (r, "associated impl item is not a method"); return; } @@ -245,7 +260,7 @@ public: if (!fn->is_method ()) { RichLocation r (expr.get_method_name ().get_locus ()); - r.add_range (resolved_method->get_impl_locus ()); + r.add_range (resolved_candidate.locus); rust_error_at (r, "associated function is not a method"); return; } @@ -303,20 +318,25 @@ public: } } - // apply any remaining generic arguments - if (expr.get_method_name ().has_generic_args ()) - { - HIR::GenericArgs &args = expr.get_method_name ().get_generic_args (); - lookup - = SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (), - &args); - if (lookup->get_kind () == TyTy::TypeKind::ERROR) - return; - } - else if (lookup->needs_generic_substitutions ()) + if (!reciever_is_generic) { - lookup = SubstMapper::InferSubst (lookup, - expr.get_method_name ().get_locus ()); + // apply any remaining generic arguments + if (expr.get_method_name ().has_generic_args ()) + { + HIR::GenericArgs &args + = expr.get_method_name ().get_generic_args (); + lookup = SubstMapper::Resolve (lookup, + expr.get_method_name ().get_locus (), + &args); + if (lookup->get_kind () == TyTy::TypeKind::ERROR) + return; + } + else if (lookup->needs_generic_substitutions ()) + { + lookup + = SubstMapper::InferSubst (lookup, + expr.get_method_name ().get_locus ()); + } } TyTy::BaseType *function_ret_tyty @@ -333,9 +353,8 @@ public: context->insert_type (expr.get_method_name ().get_mappings (), lookup); // set up the resolved name on the path - resolver->insert_resolved_name ( - expr.get_mappings ().get_nodeid (), - resolved_method->get_impl_mappings ().get_nodeid ()); + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + resolved_node_id); // return the result of the function back infered = function_ret_tyty; @@ -429,7 +448,7 @@ public: if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), ref_node_id, &ref)) { - rust_error_at (expr.get_locus (), "reverse lookup failure"); + rust_error_at (expr.get_locus (), "123 reverse lookup failure"); return; } @@ -937,8 +956,16 @@ public: { HIR::PathExprSegment &seg = expr.get_segments ().at (i); + bool reciever_is_generic + = prev_segment->get_kind () == TyTy::TypeKind::PARAM; + bool probe_bounds = true; + bool probe_impls = !reciever_is_generic; + bool ignore_mandatory_trait_items = !reciever_is_generic; + // probe the path - auto candidates = PathProbeType::Probe (tyseg, seg.get_segment ()); + auto candidates + = PathProbeType::Probe (tyseg, seg.get_segment (), probe_impls, + probe_bounds, ignore_mandatory_trait_items); if (candidates.size () == 0) { rust_error_at ( @@ -954,11 +981,21 @@ public: return; } - auto candidate = candidates.at (0); + auto &candidate = candidates.at (0); prev_segment = tyseg; tyseg = candidate.ty; - resolved_node_id - = candidate.impl_item->get_impl_mappings ().get_nodeid (); + + if (candidate.is_impl_candidate ()) + { + resolved_node_id + = candidate.item.impl.impl_item->get_impl_mappings () + .get_nodeid (); + } + else + { + resolved_node_id + = candidate.item.trait.item_ref.get_mappings ().get_nodeid (); + } if (seg.has_generic_args ()) { @@ -977,6 +1014,7 @@ public: } } + context->insert_receiver (expr.get_mappings ().get_hirid (), prev_segment); if (tyseg->needs_generic_substitutions ()) { Location locus = expr.get_segments ().back ().get_locus (); @@ -984,8 +1022,9 @@ public: { auto used_args_in_prev_segment = GetUsedSubstArgs::From (prev_segment); - tyseg - = SubstMapperInternal::Resolve (tyseg, used_args_in_prev_segment); + if (!used_args_in_prev_segment.is_error ()) + tyseg = SubstMapperInternal::Resolve (tyseg, + used_args_in_prev_segment); } else { @@ -1214,7 +1253,13 @@ private: { if (is_root) { - rust_error_at (seg.get_locus (), "reverse lookup failure"); + rust_error_at (seg.get_locus (), "456 reverse lookup failure"); + rust_debug_loc ( + seg.get_locus (), + "failure with [%s] mappings [%s] ref_node_id [%u]", + seg.as_string ().c_str (), + seg.get_mappings ().as_string ().c_str (), ref_node_id); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); } return root_tyty; diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index 0f75c54..91d9c53 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -215,7 +215,7 @@ private: {} void - check_for_unconstrained (std::vector<std::unique_ptr<HIR::Type> > &type_args) + check_for_unconstrained (std::vector<std::unique_ptr<HIR::Type>> &type_args) { std::map<std::string, Location> param_location_map; std::set<std::string> param_tys; @@ -270,8 +270,31 @@ public: if (param.has_type ()) TypeCheckType::Resolve (param.get_type ().get ()); + std::vector<TyTy::TypeBoundPredicate> specified_bounds; + if (param.has_type_param_bounds ()) + { + for (auto &bound : param.get_type_param_bounds ()) + { + switch (bound->get_bound_type ()) + { + case HIR::TypeParamBound::BoundType::TRAITBOUND: { + HIR::TraitBound *b + = static_cast<HIR::TraitBound *> (bound.get ()); + TyTy::TypeBoundPredicate predicate ( + &resolve_trait_path (b->get_path ())); + specified_bounds.push_back (std::move (predicate)); + } + break; + + default: + break; + } + } + } + resolved = new TyTy::ParamType (param.get_type_representation (), - param.get_mappings ().get_hirid (), param); + param.get_mappings ().get_hirid (), param, + specified_bounds); } private: diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 66adfcb..4b66fdb 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -418,6 +418,7 @@ TraitItemReference::TraitItemReference (TraitItemReference const &other) type (other.type), hir_trait_item (other.hir_trait_item), locus (other.locus), self (other.self), context (TypeCheckContext::get ()) { + inherited_substitutions.clear (); inherited_substitutions.reserve (other.inherited_substitutions.size ()); for (size_t i = 0; i < other.inherited_substitutions.size (); i++) inherited_substitutions.push_back (other.inherited_substitutions.at (i)); diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 0298068..b171123 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -102,6 +102,21 @@ public: return true; } + void insert_receiver (HirId id, TyTy::BaseType *t) + { + receiver_context[id] = t; + } + + bool lookup_receiver (HirId id, TyTy::BaseType **ref) + { + auto it = receiver_context.find (id); + if (it == receiver_context.end ()) + return false; + + *ref = it->second; + return true; + } + private: TypeCheckContext (); @@ -111,6 +126,7 @@ private: std::vector<TyTy::BaseType *> return_type_stack; std::vector<TyTy::BaseType *> loop_type_stack; std::map<DefId, TraitReference> trait_context; + std::map<HirId, TyTy::BaseType *> receiver_context; }; class TypeResolution diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index 3730faa..a3c00da 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -280,24 +280,24 @@ public: args = type.get_substitution_arguments (); } - void visit (TyTy::InferType &) override { gcc_unreachable (); } - void visit (TyTy::TupleType &) override { gcc_unreachable (); } - void visit (TyTy::FnPtr &) override { gcc_unreachable (); } - void visit (TyTy::ArrayType &) override { gcc_unreachable (); } - void visit (TyTy::BoolType &) override { gcc_unreachable (); } - void visit (TyTy::IntType &) override { gcc_unreachable (); } - void visit (TyTy::UintType &) override { gcc_unreachable (); } - void visit (TyTy::FloatType &) override { gcc_unreachable (); } - void visit (TyTy::USizeType &) override { gcc_unreachable (); } - void visit (TyTy::ISizeType &) override { gcc_unreachable (); } - void visit (TyTy::ErrorType &) override { gcc_unreachable (); } - void visit (TyTy::CharType &) override { gcc_unreachable (); } - void visit (TyTy::ReferenceType &) override { gcc_unreachable (); } - void visit (TyTy::PointerType &) override { gcc_unreachable (); } - void visit (TyTy::ParamType &) override { gcc_unreachable (); } - void visit (TyTy::StrType &) override { gcc_unreachable (); } - void visit (TyTy::NeverType &) override { gcc_unreachable (); } - void visit (TyTy::PlaceholderType &) override { gcc_unreachable (); } + void visit (TyTy::InferType &) override {} + void visit (TyTy::TupleType &) override {} + void visit (TyTy::FnPtr &) override {} + void visit (TyTy::ArrayType &) override {} + void visit (TyTy::BoolType &) override {} + void visit (TyTy::IntType &) override {} + void visit (TyTy::UintType &) override {} + void visit (TyTy::FloatType &) override {} + void visit (TyTy::USizeType &) override {} + void visit (TyTy::ISizeType &) override {} + void visit (TyTy::ErrorType &) override {} + void visit (TyTy::CharType &) override {} + void visit (TyTy::ReferenceType &) override {} + void visit (TyTy::PointerType &) override {} + void visit (TyTy::ParamType &) override {} + void visit (TyTy::StrType &) override {} + void visit (TyTy::NeverType &) override {} + void visit (TyTy::PlaceholderType &) override {} private: GetUsedSubstArgs () : args (TyTy::SubstitutionArgumentMappings::error ()) {} diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc new file mode 100644 index 0000000..a480155 --- /dev/null +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2021 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-bounds.h" +#include "rust-hir-trait-resolve.h" + +namespace Rust { +namespace Resolver { + +void +TypeBoundsProbe::scan () +{ + std::vector<HIR::TypePath *> possible_trait_paths; + mappings->iterate_impl_blocks ( + [&] (HirId id, HIR::ImplBlock *impl) mutable -> bool { + // we are filtering for trait-impl-blocks + if (!impl->has_trait_ref ()) + return true; + + TyTy::BaseType *impl_type = nullptr; + bool ok + = context->lookup_type (impl->get_type ()->get_mappings ().get_hirid (), + &impl_type); + if (!ok) + return true; + + if (!receiver->can_eq (impl_type, false)) + return true; + + possible_trait_paths.push_back (impl->get_trait_ref ().get ()); + return true; + }); + + for (auto &trait_path : possible_trait_paths) + { + TraitReference &trait_ref = TraitResolver::Resolve (*trait_path); + + if (!trait_ref.is_error ()) + trait_references.push_back (trait_ref); + } +} + +TraitReference & +TypeCheckBase::resolve_trait_path (HIR::TypePath &path) +{ + return TraitResolver::Resolve (path); +} + +} // namespace Resolver + +namespace TyTy { + +std::string +TypeBoundPredicate::as_string () const +{ + return reference->as_string (); +} + +} // namespace TyTy +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index a1315fb..a2ae4fa 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -243,6 +243,7 @@ SubstitutionParamMapping::override_context () auto mappings = Analysis::Mappings::get (); auto context = Resolver::TypeCheckContext::get (); + context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), UNKNOWN_NODEID, param->get_ref (), @@ -1768,7 +1769,7 @@ BaseType * ParamType::clone () const { return new ParamType (get_symbol (), get_ref (), get_ty_ref (), param, - get_combined_refs ()); + get_specified_bounds (), get_combined_refs ()); } std::string @@ -1780,8 +1781,6 @@ ParamType::get_symbol () const BaseType * ParamType::resolve () const { - rust_assert (can_resolve ()); - TyVar var (get_ty_ref ()); BaseType *r = var.get_tyty (); @@ -1795,7 +1794,10 @@ ParamType::resolve () const r = v.get_tyty (); } - return TyVar (r->get_ty_ref ()).get_tyty (); + if (r->get_kind () == TypeKind::PARAM && (r->get_ref () == r->get_ty_ref ())) + return TyVar (r->get_ty_ref ()).get_tyty (); + + return r; } bool diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 6abae53..13bab90 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -25,6 +25,10 @@ #include "rust-diagnostics.h" namespace Rust { +namespace Resolver { +class TraitReference; +} + namespace TyTy { // https://rustc-dev-guide.rust-lang.org/type-inference.html#inference-variables @@ -125,9 +129,56 @@ public: } }; +class TypeBoundPredicate +{ +public: + TypeBoundPredicate (Resolver::TraitReference *reference) + : reference (reference) + {} + + TypeBoundPredicate (const TypeBoundPredicate &other) + : reference (other.reference) + {} + + TypeBoundPredicate &operator= (const TypeBoundPredicate &other) + { + reference = other.reference; + return *this; + } + + std::string as_string () const; + + const Resolver::TraitReference *get () const { return reference; } + +private: + Resolver::TraitReference *reference; +}; + +class TypeBoundsMappings +{ +protected: + TypeBoundsMappings (std::vector<TypeBoundPredicate> specified_bounds) + : specified_bounds (specified_bounds) + {} + +public: + std::vector<TypeBoundPredicate> &get_specified_bounds () + { + return specified_bounds; + } + + const std::vector<TypeBoundPredicate> &get_specified_bounds () const + { + return specified_bounds; + } + +protected: + std::vector<TypeBoundPredicate> specified_bounds; +}; + class TyVisitor; class TyConstVisitor; -class BaseType +class BaseType : public TypeBoundsMappings { public: virtual ~BaseType () {} @@ -240,8 +291,15 @@ public: protected: BaseType (HirId ref, HirId ty_ref, TypeKind kind, std::set<HirId> refs = std::set<HirId> ()) - : kind (kind), ref (ref), ty_ref (ty_ref), combined (refs), - mappings (Analysis::Mappings::get ()) + : TypeBoundsMappings ({}), kind (kind), ref (ref), ty_ref (ty_ref), + combined (refs), mappings (Analysis::Mappings::get ()) + {} + + BaseType (HirId ref, HirId ty_ref, TypeKind kind, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs = std::set<HirId> ()) + : TypeBoundsMappings (specified_bounds), kind (kind), ref (ref), + ty_ref (ty_ref), combined (refs), mappings (Analysis::Mappings::get ()) {} TypeKind kind; @@ -347,15 +405,18 @@ class ParamType : public BaseType { public: ParamType (std::string symbol, HirId ref, HIR::GenericParam ¶m, + std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::PARAM, refs), symbol (symbol), param (param) + : BaseType (ref, ref, TypeKind::PARAM, specified_bounds, refs), + symbol (symbol), param (param) {} ParamType (std::string symbol, HirId ref, HirId ty_ref, HIR::GenericParam ¶m, + std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::PARAM, refs), symbol (symbol), - param (param) + : BaseType (ref, ty_ref, TypeKind::PARAM, specified_bounds, refs), + symbol (symbol), param (param) {} void accept_vis (TyVisitor &vis) override; @@ -986,7 +1047,7 @@ public: #define FNTYPE_IS_VARADIC_FLAG 0X04 FnType (HirId ref, DefId id, std::string identifier, uint8_t flags, - std::vector<std::pair<HIR::Pattern *, BaseType *> > params, + std::vector<std::pair<HIR::Pattern *, BaseType *>> params, BaseType *type, std::vector<SubstitutionParamMapping> subst_refs, std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ref, TypeKind::FNDEF, refs), @@ -1001,7 +1062,7 @@ public: FnType (HirId ref, HirId ty_ref, DefId id, std::string identifier, uint8_t flags, - std::vector<std::pair<HIR::Pattern *, BaseType *> > params, + std::vector<std::pair<HIR::Pattern *, BaseType *>> params, BaseType *type, std::vector<SubstitutionParamMapping> subst_refs, std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ty_ref, TypeKind::FNDEF, refs), @@ -1054,12 +1115,12 @@ public: return get_params ().at (0).second; } - std::vector<std::pair<HIR::Pattern *, BaseType *> > &get_params () + std::vector<std::pair<HIR::Pattern *, BaseType *>> &get_params () { return params; } - const std::vector<std::pair<HIR::Pattern *, BaseType *> > &get_params () const + const std::vector<std::pair<HIR::Pattern *, BaseType *>> &get_params () const { return params; } @@ -1094,7 +1155,7 @@ public: handle_substitions (SubstitutionArgumentMappings mappings) override final; private: - std::vector<std::pair<HIR::Pattern *, BaseType *> > params; + std::vector<std::pair<HIR::Pattern *, BaseType *>> params; BaseType *type; uint8_t flags; std::string identifier; diff --git a/gcc/testsuite/rust/compile/torture/traits8.rs b/gcc/testsuite/rust/compile/torture/traits8.rs new file mode 100644 index 0000000..0e83a7d --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits8.rs @@ -0,0 +1,22 @@ +trait Foo { + fn default() -> i32; +} + +struct Bar(i32); +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl Foo for Bar { + fn default() -> i32 { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + 123 + } +} + +fn type_bound_test<T: Foo>() -> i32 { + T::default() +} + +fn main() { + let a; + a = type_bound_test::<Bar>(); +} diff --git a/gcc/testsuite/rust/compile/torture/traits9.rs b/gcc/testsuite/rust/compile/torture/traits9.rs new file mode 100644 index 0000000..075a219 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits9.rs @@ -0,0 +1,30 @@ +trait Foo { + fn default() -> i32; + fn get(self) -> i32; + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +struct Bar(i32); +impl Foo for Bar { + fn default() -> i32 { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + 123 + } + + fn get(self) -> i32 { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + self.0 + } +} + +fn type_bound_test<T: Foo>(a: T) -> i32 { + T::default() + a.get() +} + +fn main() { + let a; + a = Bar(456); + + let b; + b = type_bound_test(a); +} |