https://gcc.gnu.org/g:bb01719f0e1665a777b2b475e5feaafd01aa3ac8

commit bb01719f0e1665a777b2b475e5feaafd01aa3ac8
Author: Philip Herron <herron.phi...@googlemail.com>
Date:   Wed Apr 16 20:38:17 2025 +0100

    gccrs: Add check for placeholder (infer) type in return position
    
    It is not allowed to have a declared inference variable in the return
    position of a function as this may never get infered you need good points
    of truth.
    
    Ideally if we get a student for GSoC 25 we will get the Default Hir Visitor
    so that we can grab the HIR::InferredType locus instead of using the ref
    location lookups.
    
    Fixes Rust-GCC#402
    
    gcc/rust/ChangeLog:
    
            * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): add 
diagnostic
            * typecheck/rust-tyty.cc (BaseType::contains_infer): new helper to 
grab first infer var
            * typecheck/rust-tyty.h: prototype
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/issue-402.rs: New test.
    
    Signed-off-by: Philip Herron <herron.phi...@googlemail.com>

Diff:
---
 gcc/rust/typecheck/rust-hir-type-check-item.cc | 32 ++++++++++
 gcc/rust/typecheck/rust-tyty.cc                | 85 ++++++++++++++++++++++++++
 gcc/rust/typecheck/rust-tyty.h                 |  3 +
 gcc/testsuite/rust/compile/issue-402.rs        | 14 +++++
 4 files changed, 134 insertions(+)

diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc 
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index a29f0432397a..e3889949c42e 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -649,6 +649,38 @@ TypeCheckItem::visit (HIR::Function &function)
   context->switch_to_fn_body ();
   auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ());
 
+  // emit check for
+  // error[E0121]: the type placeholder `_` is not allowed within types on item
+  const auto placeholder = ret_type->contains_infer ();
+  if (placeholder != nullptr && function.has_return_type ())
+    {
+      // FIXME
+      // this will be a great place for the Default Hir Visitor we want to
+      // grab the locations of the placeholders (HIR::InferredType) their
+      // location, for now maybe we can use their hirid to lookup the location
+      location_t placeholder_locus
+       = mappings.lookup_location (placeholder->get_ref ());
+      location_t type_locus = function.get_return_type ().get_locus ();
+      rich_location r (line_table, placeholder_locus);
+
+      bool have_expected_type
+       = block_expr_ty != nullptr && !block_expr_ty->is<TyTy::ErrorType> ();
+      if (!have_expected_type)
+       {
+         r.add_range (type_locus);
+       }
+      else
+       {
+         std::string fixit
+           = "replace with the correct type " + block_expr_ty->get_name ();
+         r.add_fixit_replace (type_locus, fixit.c_str ());
+       }
+
+      rust_error_at (r, ErrorCode::E0121,
+                    "the type placeholder %<_%> is not allowed within types "
+                    "on item signatures");
+    }
+
   location_t fn_return_locus = function.has_function_return_type ()
                                 ? function.get_return_type ().get_locus ()
                                 : function.get_locus ();
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 28c99a986ad6..4da51ffdbfd1 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -682,6 +682,91 @@ BaseType::debug () const
              debug_str ().c_str ());
 }
 
+const TyTy::BaseType *
+BaseType::contains_infer () const
+{
+  const TyTy::BaseType *x = destructure ();
+
+  if (auto fn = x->try_as<const FnType> ())
+    {
+      for (const auto &param : fn->get_params ())
+       {
+         auto infer = param.get_type ()->contains_infer ();
+         if (infer)
+           return infer;
+       }
+      return fn->get_return_type ()->contains_infer ();
+    }
+  else if (auto fn = x->try_as<const FnPtr> ())
+    {
+      for (const auto &param : fn->get_params ())
+       {
+         auto infer = param.get_tyty ()->contains_infer ();
+         if (infer)
+           return infer;
+       }
+      return fn->get_return_type ()->contains_infer ();
+    }
+  else if (auto adt = x->try_as<const ADTType> ())
+    {
+      for (auto &variant : adt->get_variants ())
+       {
+         bool is_num_variant
+           = variant->get_variant_type () == VariantDef::VariantType::NUM;
+         if (is_num_variant)
+           continue;
+
+         for (auto &field : variant->get_fields ())
+           {
+             const BaseType *field_type = field->get_field_type ();
+             auto infer = (field_type->contains_infer ());
+             if (infer)
+               return infer;
+           }
+       }
+      return nullptr;
+    }
+  else if (auto arr = x->try_as<const ArrayType> ())
+    {
+      return arr->get_element_type ()->contains_infer ();
+    }
+  else if (auto slice = x->try_as<const SliceType> ())
+    {
+      return slice->get_element_type ()->contains_infer ();
+    }
+  else if (auto ptr = x->try_as<const PointerType> ())
+    {
+      return ptr->get_base ()->contains_infer ();
+    }
+  else if (auto ref = x->try_as<const ReferenceType> ())
+    {
+      return ref->get_base ()->contains_infer ();
+    }
+  else if (auto tuple = x->try_as<const TupleType> ())
+    {
+      for (size_t i = 0; i < tuple->num_fields (); i++)
+       {
+         auto infer = (tuple->get_field (i)->contains_infer ());
+         if (infer)
+           return infer;
+       }
+      return nullptr;
+    }
+  else if (auto closure = x->try_as<const ClosureType> ())
+    {
+      auto infer = (closure->get_parameters ().contains_infer ());
+      if (infer)
+       return infer;
+      return closure->get_result_type ().contains_infer ();
+    }
+  else if (x->is<InferType> ())
+    {
+      return x;
+    }
+
+  return nullptr;
+}
+
 bool
 BaseType::is_concrete () const
 {
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index e1370e0964db..b14e9f25221d 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -137,6 +137,9 @@ public:
   void inherit_bounds (
     const std::vector<TyTy::TypeBoundPredicate> &specified_bounds);
 
+  // contains_infer checks if there is an inference variable inside the type
+  const TyTy::BaseType *contains_infer () const;
+
   // is_unit returns whether this is just a unit-struct
   bool is_unit () const;
 
diff --git a/gcc/testsuite/rust/compile/issue-402.rs 
b/gcc/testsuite/rust/compile/issue-402.rs
new file mode 100644
index 000000000000..2c99fc8f2485
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-402.rs
@@ -0,0 +1,14 @@
+#[lang = "sized"]
+pub trait Sized {}
+
+struct GenericStruct<T>(T, usize);
+
+pub fn test() -> GenericStruct<_> {
+    // { dg-error "the type placeholder ._. is not allowed within types on 
item signatures .E0121." "" { target *-*-* } .-1 }
+    GenericStruct(1, 2)
+}
+
+fn square(num: i32) -> _ {
+    // { dg-error "the type placeholder ._. is not allowed within types on 
item signatures .E0121." "" { target *-*-* } .-1 }
+    num * num
+}

Reply via email to