diff options
author | Philip Herron <herron.philip@googlemail.com> | 2023-07-02 20:24:43 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2023-07-02 22:13:45 +0000 |
commit | b49a9581d559827de70196de0c1cad135e70e542 (patch) | |
tree | fabea3b2ea301fd33cb462191716e1e7c3c65132 /gcc | |
parent | cfc51d46fcdb70bde84f030557c96866f3b18e23 (diff) | |
download | gcc-b49a9581d559827de70196de0c1cad135e70e542.zip gcc-b49a9581d559827de70196de0c1cad135e70e542.tar.gz gcc-b49a9581d559827de70196de0c1cad135e70e542.tar.bz2 |
gccrs: Track fn_once output lang item properly
In order to setup the Output assoicated type we can rely on using generic
argument bindings. So for example when we have the FnOnce trait:
#[lang = "fn_once"]
pub trait FnOnce<Args> {
#[lang = "fn_once_output"]
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
Thn we might have a function such as:
pub fn map<R, F: FnOnce(T) -> R>(self, f: F) -> Option<R> { ... }
This trait bound predicate of FnOnce(T) -> R we setup generics for the
bound as:
FnOnce<(T), Output=R>
This means we can reuse our generic arguments handling to get this support.
Fixes #2105
gcc/rust/ChangeLog:
* typecheck/rust-tyty-bounds.cc (TypeCheckBase::get_predicate_from_bound): track output
* util/rust-hir-map.cc (Mappings::lookup_trait_item_lang_item): new helper
* util/rust-hir-map.h: add prototype for helper
gcc/testsuite/ChangeLog:
* rust/compile/issue-2105.rs: New test.
Signed-off-by: Philip Herron <herron.philip@googlemail.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/typecheck/rust-tyty-bounds.cc | 32 | ||||
-rw-r--r-- | gcc/rust/util/rust-hir-map.cc | 13 | ||||
-rw-r--r-- | gcc/rust/util/rust-hir-map.h | 3 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/issue-2105.rs | 23 |
4 files changed, 57 insertions, 14 deletions
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 12e6659..ec64aa7 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -227,22 +227,26 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path, std::vector<std::unique_ptr<HIR::Type>> inputs; inputs.push_back (std::unique_ptr<HIR::Type> (implicit_tuple)); + // resolve the fn_once_output type which assumes there must be an output + // set + rust_assert (fn.has_return_type ()); + TypeCheckType::Resolve (fn.get_return_type ().get ()); + + HIR::TraitItem *trait_item = mappings->lookup_trait_item_lang_item ( + Analysis::RustLangItem::ItemType::FN_ONCE_OUTPUT); + + std::vector<HIR::GenericArgsBinding> bindings; + Location output_locus = fn.get_return_type ()->get_locus (); + HIR::GenericArgsBinding binding (Identifier ( + trait_item->trait_identifier ()), + fn.get_return_type ()->clone_type (), + output_locus); + bindings.push_back (std::move (binding)); + args = HIR::GenericArgs ({} /* lifetimes */, std::move (inputs) /* type_args*/, - {} /* binding_args*/, {} /* const_args */, - final_seg->get_locus ()); - - // resolve the fn_once_output type - TyTy::BaseType *fn_once_output_ty - = fn.has_return_type () - ? TypeCheckType::Resolve (fn.get_return_type ().get ()) - : TyTy::TupleType::get_unit_type ( - final_seg->get_mappings ().get_hirid ()); - context->insert_implicit_type (final_seg->get_mappings ().get_hirid (), - fn_once_output_ty); - - // setup the associated type.. ?? - // fn_once_output_ty->debug (); + std::move (bindings) /* binding_args*/, + {} /* const_args */, final_seg->get_locus ()); } break; diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 87a3a73..3326e7e 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -1137,5 +1137,18 @@ Mappings::lookup_builtin_marker () return builtinMarker; } +HIR::TraitItem * +Mappings::lookup_trait_item_lang_item (Analysis::RustLangItem::ItemType item) +{ + DefId trait_item_id = UNKNOWN_DEFID; + bool trait_item_lang_item_defined = lookup_lang_item (item, &trait_item_id); + + // FIXME + // make this an error? what does rustc do when a lang item is not defined? + rust_assert (trait_item_lang_item_defined); + + return lookup_trait_item_defid (trait_item_id); +} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 6e6a1c8..964b626 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -321,6 +321,9 @@ public: HIR::ImplBlock *lookup_builtin_marker (); + HIR::TraitItem * + lookup_trait_item_lang_item (Analysis::RustLangItem::ItemType item); + private: Mappings (); diff --git a/gcc/testsuite/rust/compile/issue-2105.rs b/gcc/testsuite/rust/compile/issue-2105.rs new file mode 100644 index 0000000..7d1c9a1 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-2105.rs @@ -0,0 +1,23 @@ +pub enum Option<T> { + Some(T), + None, +} + +pub use Option::{None, Some}; + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +impl<T> Option<T> { + pub fn map<R, F: FnOnce(T) -> R>(self, f: F) -> Option<R> { + match self { + Some(value) => Some(f(value)), + None => None, + } + } +} |