From: Philip Herron <[email protected]>

Const generics bind values which can be accessed like a normal path but the 
difference
is that they can be true expression values not just type paths. This patch adds 
support
to resolving a method inference which passes a generic value into the method 
and fixes
some missed bugs along the way. The tricky part was that there is a case where 
in the
return position of a method returning a const param type vs the type of the 
method
there is a special case in the unify rules so that we unify the specified type 
of the
const param type not the const param itself.

gcc/rust/ChangeLog:

        * backend/rust-compile-resolve-path.cc: handle const param values
        * typecheck/rust-hir-type-check-item.cc: generate const infer vars when 
required
        * typecheck/rust-type-util.cc (unify_site_and): handle a null param 
cleanup
        * typecheck/rust-tyty-util.cc (TyVar::get_implicit_const_infer_var): 
helper interface
        * typecheck/rust-tyty-util.h: update header prototypes
        * typecheck/rust-tyty.cc (BaseType::is_concrete): correctly handle 
const types
        (ConstParamType::get_name): emit the specified type
        (ConstParamType::is_equal): fix recursion loop
        * typecheck/rust-unify.cc (UnifyRules::go): const infer vars need 
cleanup too
        * typecheck/rust-unify.h: support base generics

gcc/testsuite/ChangeLog:

        * rust/execute/torture/const-generics-2.rs: New test.

Signed-off-by: Philip Herron <[email protected]>
---
 gcc/rust/backend/rust-compile-resolve-path.cc | 21 ++++---
 .../typecheck/rust-hir-type-check-item.cc     | 22 +++++--
 gcc/rust/typecheck/rust-type-util.cc          | 10 +--
 gcc/rust/typecheck/rust-tyty-util.cc          |  7 ++-
 gcc/rust/typecheck/rust-tyty-util.h           |  3 +-
 gcc/rust/typecheck/rust-tyty.cc               | 36 ++++++++---
 gcc/rust/typecheck/rust-unify.cc              | 62 ++++++++++++++-----
 gcc/rust/typecheck/rust-unify.h               |  8 +--
 .../rust/execute/torture/const-generics-2.rs  | 20 ++++++
 9 files changed, 141 insertions(+), 48 deletions(-)
 create mode 100644 gcc/testsuite/rust/execute/torture/const-generics-2.rs

diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc 
b/gcc/rust/backend/rust-compile-resolve-path.cc
index c33d0b072d0..5f306620f7b 100644
--- a/gcc/rust/backend/rust-compile-resolve-path.cc
+++ b/gcc/rust/backend/rust-compile-resolve-path.cc
@@ -132,10 +132,8 @@ ResolvePathRef::resolve_with_node_id (
   tl::optional<HirId> hid
     = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
   if (!hid.has_value ())
-    {
-      rust_error_at (expr_locus, "reverse call path lookup failure");
-      return error_mark_node;
-    }
+    return error_mark_node;
+
   auto ref = hid.value ();
 
   // might be a constant
@@ -189,6 +187,17 @@ ResolvePathRef::resolve_with_node_id (
        }
     }
 
+  // possibly a const expr value
+  if (lookup->get_kind () == TyTy::TypeKind::CONST)
+    {
+      auto d = lookup->destructure ();
+      rust_assert (d->get_kind () == TyTy::TypeKind::CONST);
+      auto c = d->as_const_type ();
+      rust_assert (c->const_kind () == TyTy::BaseConstType::ConstKind::Value);
+      auto val = static_cast<TyTy::ConstValueType *> (c);
+      return val->get_value ();
+    }
+
   // Handle unit struct
   tree resolved_item = error_mark_node;
   if (lookup->get_kind () == TyTy::TypeKind::ADT)
@@ -203,9 +212,7 @@ ResolvePathRef::resolve_with_node_id (
   resolved_item = query_compile (ref, lookup, final_segment, mappings,
                                 expr_locus, is_qualified_path);
   if (resolved_item != error_mark_node)
-    {
-      TREE_USED (resolved_item) = 1;
-    }
+    TREE_USED (resolved_item) = 1;
 
   return resolved_item;
 }
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc 
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 4987c88ab70..ee5c4e98fba 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -112,17 +112,27 @@ TypeCheckItem::ResolveImplBlockSelfWithInference (
   std::vector<TyTy::SubstitutionArg> args;
   for (auto &p : substitutions)
     {
-      if (p.needs_substitution ())
+      auto param = p.get_param_ty ();
+      if (!p.needs_substitution ())
        {
-         TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus);
-         args.emplace_back (&p, infer_var.get_tyty ());
+         auto resolved = param->destructure ();
+         args.emplace_back (&p, resolved);
+
+         continue;
+       }
+
+      TyTy::BaseType *argument = nullptr;
+      if (param->get_kind () == TyTy::TypeKind::CONST)
+       {
+         auto i = TyTy::TyVar::get_implicit_const_infer_var (locus);
+         argument = i.get_tyty ();
        }
       else
        {
-         auto param = p.get_param_ty ();
-         auto resolved = param->destructure ();
-         args.emplace_back (&p, resolved);
+         auto i = TyTy::TyVar::get_implicit_infer_var (locus);
+         argument = i.get_tyty ();
        }
+      args.emplace_back (&p, argument);
     }
 
   // create argument mappings
diff --git a/gcc/rust/typecheck/rust-type-util.cc 
b/gcc/rust/typecheck/rust-type-util.cc
index 6f30ebf49e9..a6b99665848 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -221,13 +221,13 @@ unify_site_and (HirId id, TyTy::TyWithLocation lhs, 
TyTy::TyWithLocation rhs,
     }
   else if (cleanup)
     {
-      // FIXME
-      // reset the get_next_hir_id
-
       for (auto &i : infers)
        {
-         i.param->set_ref (i.pref);
-         i.param->set_ty_ref (i.ptyref);
+         if (i.param != nullptr)
+           {
+             i.param->set_ref (i.pref);
+             i.param->set_ty_ref (i.ptyref);
+           }
 
          // remove the inference variable
          context.clear_type (i.infer);
diff --git a/gcc/rust/typecheck/rust-tyty-util.cc 
b/gcc/rust/typecheck/rust-tyty-util.cc
index 72761d9842b..b780eaac743 100644
--- a/gcc/rust/typecheck/rust-tyty-util.cc
+++ b/gcc/rust/typecheck/rust-tyty-util.cc
@@ -62,14 +62,15 @@ TyVar::get_implicit_infer_var (location_t locus)
 }
 
 TyVar
-TyVar::get_implicit_const_infer_var (location_t locus)
+TyVar::get_implicit_const_infer_var (location_t locus, TyVar *implicit_type)
 {
   auto &mappings = Analysis::Mappings::get ();
   auto context = Resolver::TypeCheckContext::get ();
 
-  TyVar ty_infer = get_implicit_infer_var (locus);
+  TyVar it = (implicit_type != nullptr) ? *implicit_type
+                                       : get_implicit_infer_var (locus);
   HirId next = mappings.get_next_hir_id ();
-  auto infer = new ConstInferType (ty_infer.get_tyty (), next, next, {});
+  auto infer = new ConstInferType (it.get_tyty (), next, next, {});
 
   context->insert_implicit_type (infer->get_ref (), infer);
   mappings.insert_location (infer->get_ref (), locus);
diff --git a/gcc/rust/typecheck/rust-tyty-util.h 
b/gcc/rust/typecheck/rust-tyty-util.h
index 26101fd4d93..b132487eb5e 100644
--- a/gcc/rust/typecheck/rust-tyty-util.h
+++ b/gcc/rust/typecheck/rust-tyty-util.h
@@ -43,7 +43,8 @@ public:
 
   static TyVar get_implicit_infer_var (location_t locus);
 
-  static TyVar get_implicit_const_infer_var (location_t locus);
+  static TyVar get_implicit_const_infer_var (location_t locus,
+                                            TyVar *implicit_type = nullptr);
 
   static TyVar subst_covariant_var (TyTy::BaseType *orig,
                                    TyTy::BaseType *subst);
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index da5c35049fa..480e244fd38 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -785,11 +785,18 @@ BaseType::is_concrete () const
 {
   const TyTy::BaseType *x = destructure ();
 
-  if (x->is<ParamType> () || x->is<ProjectionType> ()
-      || x->is<ConstParamType> ())
+  if (x->is<ParamType> () || x->is<ProjectionType> ())
     {
       return false;
     }
+  else if (x->get_kind () == TyTy::TypeKind::CONST)
+    {
+      auto p = x->as_const_type ();
+      if (p->const_kind () == BaseConstType::ConstKind::Decl)
+       return false;
+
+      return true;
+    }
   // placeholder is a special case for this case when it is not resolvable
   // it means we its just an empty placeholder associated type which is
   // concrete
@@ -3633,9 +3640,8 @@ ConstParamType::get_name () const
     return get_symbol ();
 
   BaseType *lookup = resolve ();
-  // Avoid infinite recursion if resolve() returns this same type
   if (lookup == this->as_base_type ())
-    return get_symbol ();
+    return get_symbol () + ":" + get_specified_type ()->get_name ();
 
   return lookup->get_name ();
 }
@@ -3660,9 +3666,25 @@ ConstParamType::is_equal (const BaseType &other) const
     return false;
 
   if (can_resolve ())
-    return Resolver::types_compatable (TyTy::TyWithLocation (resolve ()),
-                                      TyTy::TyWithLocation (other2.resolve ()),
-                                      ident.locus, false);
+    {
+      // Compare the resolved ty_ref values to avoid infinite recursion
+      // through types_compatable/unification
+      BaseType *lhs = resolve ();
+      BaseType *rhs = other2.resolve ();
+
+      // If they resolve to the same type (same ty_ref), they're equal
+      if (lhs->get_ty_ref () == rhs->get_ty_ref ())
+       return true;
+
+      // Otherwise check if the resolved types are equal
+      // Avoid recursion by checking if we'd be comparing ConstParamTypes again
+      if (lhs->get_kind () == TypeKind::CONST
+         && lhs->as_const_type ()->const_kind ()
+              == BaseConstType::ConstKind::Decl)
+       return false; // Would cause recursion, so not equal
+
+      return lhs->is_equal (*rhs);
+    }
 
   return get_symbol ().compare (other2.get_symbol ()) == 0;
 }
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc
index 43dd6dca617..36dbc0e187e 100644
--- a/gcc/rust/typecheck/rust-unify.cc
+++ b/gcc/rust/typecheck/rust-unify.cc
@@ -18,8 +18,8 @@
 
 #include "rust-unify.h"
 #include "fold-const.h"
+#include "rust-tyty-util.h"
 #include "rust-tyty.h"
-#include "tree.h"
 
 namespace Rust {
 namespace Resolver {
@@ -302,35 +302,67 @@ UnifyRules::go ()
       else if (ltype->get_kind () == TyTy::TypeKind::CONST
               && rtype->get_kind () == TyTy::TypeKind::CONST)
        {
-         const auto &lhs = *ltype->as_const_type ();
-         const auto &rhs = *rtype->as_const_type ();
+         auto lhs = ltype->as_const_type ();
+         auto rhs = rtype->as_const_type ();
 
          bool both_are_decls
-           = lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl
-             && rhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl;
+           = lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl
+             && rhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl;
          bool have_decls
-           = lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl
-             || rhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl;
+           = lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl
+             || rhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl;
 
          if (have_decls && !both_are_decls)
            {
-             if (lhs.const_kind () == TyTy::BaseConstType::ConstKind::Decl)
+             if (lhs->const_kind () == TyTy::BaseConstType::ConstKind::Decl)
                {
-                 TyTy::TyVar iv = TyTy::TyVar::get_implicit_const_infer_var (
-                   lhs.as_base_type ()->get_locus ());
-                 ltype = iv.get_tyty ();
+                 auto l = lhs->as_base_type ()->get_locus ();
+                 auto p = static_cast<TyTy::ConstParamType *> (lhs);
+                 auto it = TyTy::TyVar::get_implicit_infer_var (l);
+                 auto iv = TyTy::TyVar::get_implicit_const_infer_var (l, &it);
+                 auto ivt = iv.get_tyty ();
+
+                 infers.emplace_back (0, 0, nullptr, it.get_tyty ());
+                 infers.emplace_back (ltype->get_ref (), ltype->get_ty_ref (),
+                                      p, ivt);
+
+                 ltype = ivt;
+                 p->set_ty_ref (ltype->get_ref ());
                }
-             else if (rhs.const_kind ()
+             else if (rhs->const_kind ()
                       == TyTy::BaseConstType::ConstKind::Decl)
                {
-                 TyTy::TyVar iv = TyTy::TyVar::get_implicit_const_infer_var (
-                   rhs.as_base_type ()->get_locus ());
-                 rtype = iv.get_tyty ();
+                 auto l = rhs->as_base_type ()->get_locus ();
+                 auto p = static_cast<TyTy::ConstParamType *> (rhs);
+                 auto it = TyTy::TyVar::get_implicit_infer_var (l);
+                 auto iv = TyTy::TyVar::get_implicit_const_infer_var (l, &it);
+                 auto ivt = iv.get_tyty ();
+
+                 infers.emplace_back (0, 0, nullptr, it.get_tyty ());
+                 infers.emplace_back (rtype->get_ref (), rtype->get_ty_ref (),
+                                      p, ivt);
+
+                 rtype = ivt;
+                 p->set_ty_ref (rtype->get_ref ());
                }
            }
        }
     }
 
+  if (ltype->get_kind () != TyTy::TypeKind::CONST
+      && rtype->get_kind () == TyTy::TypeKind::CONST)
+    {
+      auto *rc = rtype->as_const_type ();
+      rtype = rc->get_specified_type ();
+    }
+
+  if (ltype->get_kind () == TyTy::TypeKind::CONST
+      && rtype->get_kind () != TyTy::TypeKind::CONST)
+    {
+      auto *lc = ltype->as_const_type ();
+      ltype = lc->get_specified_type ();
+    }
+
   switch (ltype->get_kind ())
     {
     case TyTy::INFER:
diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h
index 4bed24c924f..2b772feb8b9 100644
--- a/gcc/rust/typecheck/rust-unify.h
+++ b/gcc/rust/typecheck/rust-unify.h
@@ -30,15 +30,15 @@ class UnifyRules
 public:
   struct InferenceSite
   {
-    InferenceSite (HirId pref, HirId ptyref, TyTy::ParamType *param,
-                  TyTy::InferType *infer)
+    InferenceSite (HirId pref, HirId ptyref, TyTy::BaseGeneric *param,
+                  TyTy::BaseType *infer)
       : pref (pref), ptyref (ptyref), param (param), infer (infer)
     {}
 
     HirId pref;
     HirId ptyref;
-    TyTy::ParamType *param;
-    TyTy::InferType *infer;
+    TyTy::BaseGeneric *param;
+    TyTy::BaseType *infer;
   };
   struct CommitSite
   {
diff --git a/gcc/testsuite/rust/execute/torture/const-generics-2.rs 
b/gcc/testsuite/rust/execute/torture/const-generics-2.rs
new file mode 100644
index 00000000000..cf92953a37a
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/const-generics-2.rs
@@ -0,0 +1,20 @@
+#[lang = "sized"]
+trait Sized {}
+
+trait Magic {
+    fn magic(&self) -> usize;
+}
+
+struct Foo<const N: usize>;
+
+impl<const N: usize> Magic for Foo<N> {
+    fn magic(&self) -> usize {
+        N
+    }
+}
+
+fn main() -> i32 {
+    let f = Foo::<7> {};
+    let n = f.magic();
+    n as i32 - 7
+}
-- 
2.50.1

Reply via email to