diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-10-21 22:48:18 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-10-22 11:48:43 +0100 |
commit | 92a31969774e1e9b46800c6475d1a58ccc5ca436 (patch) | |
tree | e7c9a6d82870937b5b0bc17a036cb00a93b35828 /gcc | |
parent | f3bd3f0dd8d145469598dcccc597ae69500369ae (diff) | |
download | gcc-92a31969774e1e9b46800c6475d1a58ccc5ca436.zip gcc-92a31969774e1e9b46800c6475d1a58ccc5ca436.tar.gz gcc-92a31969774e1e9b46800c6475d1a58ccc5ca436.tar.bz2 |
Support generic arguments on TypeBounds
This adds support to managing generic arguments within type bounds. Such
as:
```rust
fn test<T: GenericBound<i32>>(a:T) { ... }
```
The interesting piece here is that for any usage of the bounds on T the
items must be substituted with the inherited arguments specified within
the bound.
This fixes the test case from #743 by removing the lifetimes and where
constraint which needs to be implemented in #442. This associated test
case will fail the rust borrow checker but we need a way to work though
bugs in the short term in some senario's.
Fixes #743
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/typecheck/rust-hir-path-probe.h | 77 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-type.h | 20 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty-bounds.cc | 79 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.h | 53 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/trait9.rs | 38 |
5 files changed, 247 insertions, 20 deletions
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index 326adb4..6e39fa3 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -130,28 +130,24 @@ public: if (!probe_bounds) return probe.candidates; - std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds - = TypeBoundsProbe::Probe (receiver); - - std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> - specified_bounds; - for (const TyTy::TypeBoundPredicate &predicate : - receiver->get_specified_bounds ()) + if (!probe.is_reciever_generic ()) { - const TraitReference *trait_item = predicate.get (); - - // FIXME lookup impl_block for this trait impl for this receiver - specified_bounds.push_back ({trait_item, nullptr}); + std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds + = TypeBoundsProbe::Probe (receiver); + for (auto &candidate : probed_bounds) + { + const TraitReference *trait_ref = candidate.first; + HIR::ImplBlock *impl = candidate.second; + probe.process_associated_trait_for_candidates ( + trait_ref, impl, ignore_mandatory_trait_items); + } } - std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> - union_type_bounds = probe.union_bounds (probed_bounds, specified_bounds); - for (auto &candidate : union_type_bounds) + for (const TyTy::TypeBoundPredicate &predicate : + receiver->get_specified_bounds ()) { - const TraitReference *trait_ref = candidate.first; - HIR::ImplBlock *impl = candidate.second; - probe.process_associated_trait_for_candidates ( - trait_ref, impl, ignore_mandatory_trait_items); + probe.process_predicate_for_candidates (predicate, + ignore_mandatory_trait_items); } return probe.candidates; @@ -321,6 +317,51 @@ protected: candidates.push_back (std::move (candidate)); } + void + process_predicate_for_candidates (const TyTy::TypeBoundPredicate &predicate, + bool ignore_mandatory_trait_items) + { + const TraitReference *trait_ref = predicate.get (); + + TyTy::TypeBoundPredicateItem item + = predicate.lookup_associated_item (search.as_string ()); + if (item.is_error ()) + return; + + if (ignore_mandatory_trait_items && item.needs_implementation ()) + return; + + const TraitItemReference *trait_item_ref = item.get_raw_item (); + 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: + default: + gcc_unreachable (); + break; + } + + TyTy::BaseType *trait_item_tyty = item.get_tyty_for_receiver (receiver); + PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref, + trait_item_ref, + nullptr}; + PathProbeCandidate candidate{candidate_type, + trait_item_tyty, + trait_item_ref->get_locus (), + {trait_item_candidate}}; + candidates.push_back (std::move (candidate)); + } + protected: PathProbeType (const TyTy::BaseType *receiver, const HIR::PathIdentSegment &query) diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index e0c0e91..91c49e0 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -234,10 +234,28 @@ public: HIR::TraitBound *b = static_cast<HIR::TraitBound *> (bound.get ()); - TraitReference *trait = resolve_trait_path (b->get_path ()); + auto &type_path = b->get_path (); + TraitReference *trait = resolve_trait_path (type_path); TyTy::TypeBoundPredicate predicate ( trait->get_mappings ().get_defid (), b->get_locus ()); + auto &final_seg = type_path.get_final_segment (); + if (final_seg->is_generic_segment ()) + { + auto final_generic_seg + = static_cast<HIR::TypePathSegmentGeneric *> ( + final_seg.get ()); + if (final_generic_seg->has_generic_args ()) + { + HIR::GenericArgs &generic_args + = final_generic_seg->get_generic_args (); + + // this is applying generic arguments to a trait + // reference + predicate.apply_generic_arguments (&generic_args); + } + } + specified_bounds.push_back (std::move (predicate)); } break; diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 8909394..88c94d2 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -108,5 +108,84 @@ TypeBoundPredicate::is_object_safe (bool emit_error, Location locus) const return trait->is_object_safe (emit_error, locus); } +void +TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args) +{ + args = generic_args; + // TODO verify these arguments are valid and not too many were added +} + +bool +TypeBoundPredicate::contains_item (const std::string &search) const +{ + auto trait_ref = get (); + const Resolver::TraitItemReference *trait_item_ref = nullptr; + return trait_ref->lookup_trait_item (search, &trait_item_ref); +} + +TypeBoundPredicateItem +TypeBoundPredicate::lookup_associated_item (const std::string &search) const +{ + auto trait_ref = get (); + const Resolver::TraitItemReference *trait_item_ref = nullptr; + if (!trait_ref->lookup_trait_item (search, &trait_item_ref)) + return TypeBoundPredicateItem::error (); + + return TypeBoundPredicateItem (this, trait_item_ref); +} + +BaseType * +TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver) +{ + TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty (); + 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 + = Resolver::SubstMapperInternal::Resolve (trait_item_tyty, args); + } + + if (!parent->has_generic_args ()) + return trait_item_tyty; + + // FIXME LEAK this should really be const + const HIR::GenericArgs *args = parent->get_generic_args (); + HIR::GenericArgs *generic_args = new HIR::GenericArgs (*args); + TyTy::BaseType *resolved + = Resolver::SubstMapper::Resolve (trait_item_tyty, parent->get_locus (), + generic_args); + + return resolved; +} + +const Resolver::TraitItemReference * +TypeBoundPredicateItem::get_raw_item () const +{ + return trait_item_ref; +} + +bool +TypeBoundPredicateItem::needs_implementation () const +{ + return !get_raw_item ()->is_optional (); +} + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 27daa7c..20bad10 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -146,11 +146,42 @@ public: } }; +class BaseType; +class TypeBoundPredicate; +class TypeBoundPredicateItem +{ +public: + TypeBoundPredicateItem (const TypeBoundPredicate *parent, + const Resolver::TraitItemReference *trait_item_ref) + : parent (parent), trait_item_ref (trait_item_ref) + {} + + static TypeBoundPredicateItem error () + { + return TypeBoundPredicateItem (nullptr, nullptr); + } + + bool is_error () const + { + return parent == nullptr || trait_item_ref == nullptr; + } + + BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver); + + const Resolver::TraitItemReference *get_raw_item () const; + + bool needs_implementation () const; + +private: + const TypeBoundPredicate *parent; + const Resolver::TraitItemReference *trait_item_ref; +}; + class TypeBoundPredicate { public: TypeBoundPredicate (DefId reference, Location locus) - : reference (reference), locus (locus) + : reference (reference), locus (locus), args (nullptr) {} std::string as_string () const; @@ -165,9 +196,29 @@ public: // https://doc.rust-lang.org/reference/items/traits.html#object-safety bool is_object_safe (bool emit_error, Location locus) const; + void apply_generic_arguments (HIR::GenericArgs *generic_args); + + bool contains_item (const std::string &search) const; + + TypeBoundPredicateItem + lookup_associated_item (const std::string &search) const; + + HIR::GenericArgs *get_generic_args () { return args; } + + const HIR::GenericArgs *get_generic_args () const { return args; } + + bool has_generic_args () const + { + if (args == nullptr) + return false; + + return args->has_generic_args (); + } + private: DefId reference; Location locus; + HIR::GenericArgs *args; }; class TypeBoundsMappings diff --git a/gcc/testsuite/rust/execute/torture/trait9.rs b/gcc/testsuite/rust/execute/torture/trait9.rs new file mode 100644 index 0000000..1fe77e3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/trait9.rs @@ -0,0 +1,38 @@ +/* { dg-output "3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +trait FnLike<A, R> { + fn call(&self, arg: A) -> R; + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + // { dg-warning "unused name .arg." "" { target *-*-* } .-2 } +} + +struct S; +impl<T> FnLike<&T, &T> for S { + fn call(&self, arg: &T) -> &T { + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + // { dg-warning "unused name .<S as FnLike>::call." "" { target *-*-* } .-2 } + arg + } +} + +fn indirect<F: FnLike<&isize, &isize>>(f: F) { + let x = 3; + let y = f.call(&x); + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, *y); + } +} + +fn main() -> i32 { + indirect(S); + + 0 +} |