aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-10-21 22:48:18 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-10-22 11:48:43 +0100
commit92a31969774e1e9b46800c6475d1a58ccc5ca436 (patch)
treee7c9a6d82870937b5b0bc17a036cb00a93b35828 /gcc
parentf3bd3f0dd8d145469598dcccc597ae69500369ae (diff)
downloadgcc-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.h77
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-type.h20
-rw-r--r--gcc/rust/typecheck/rust-tyty-bounds.cc79
-rw-r--r--gcc/rust/typecheck/rust-tyty.h53
-rw-r--r--gcc/testsuite/rust/execute/torture/trait9.rs38
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 &param_mapping : fn->get_substs ())
+ {
+ const HIR::TypeParam &type_param = param_mapping.get_generic_param ();
+ if (type_param.get_type_representation ().compare ("Self") == 0)
+ {
+ param = &param_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
+}