Skip to content

Commit

Permalink
gccrs: Track fn_once output lang item properly
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
philberty committed Jul 2, 2023
1 parent cfc51d4 commit b49a958
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 14 deletions.
32 changes: 18 additions & 14 deletions gcc/rust/typecheck/rust-tyty-bounds.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
13 changes: 13 additions & 0 deletions gcc/rust/util/rust-hir-map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions gcc/rust/util/rust-hir-map.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ class Mappings

HIR::ImplBlock *lookup_builtin_marker ();

HIR::TraitItem *
lookup_trait_item_lang_item (Analysis::RustLangItem::ItemType item);

private:
Mappings ();

Expand Down
23 changes: 23 additions & 0 deletions gcc/testsuite/rust/compile/issue-2105.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
}

0 comments on commit b49a958

Please sign in to comment.