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