]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Track fn_once output lang item properly
authorPhilip Herron <herron.philip@googlemail.com>
Sun, 2 Jul 2023 19:24:43 +0000 (20:24 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:49:30 +0000 (18:49 +0100)
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>
gcc/rust/typecheck/rust-tyty-bounds.cc
gcc/rust/util/rust-hir-map.cc
gcc/rust/util/rust-hir-map.h
gcc/testsuite/rust/compile/issue-2105.rs [new file with mode: 0644]

index fec80ddc26527fec0bf2ed2c0b05922e2e5d3a97..af172d6b6507993fbe313b38a59387fa147841b7 100644 (file)
@@ -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;
 
index fd78e564aece691a7c7549234bc26393326e0117..e023f1fe76c1424158c6ee72b53681dd9d17ea3d 100644 (file)
@@ -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
index 60498dec91ce64fa1be8ab259c6b51285faa0193..5c962286218ea8cb0f738a4c342f535ef08ef663 100644 (file)
@@ -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 (file)
index 0000000..7d1c9a1
--- /dev/null
@@ -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,
+        }
+    }
+}